Спектр: что показывает частотная картина
Учимся читать вторую проекцию сигнала — частотную, где видно, из каких тонов он состоит.
Спектр — представление сигнала в частотной области: какие частоты в нём есть и с какой амплитудой. Это «рентген» сигнала, дополняющий вид во времени.
У сигнала есть две равноправные проекции. Временная (осциллограмма) отвечает на вопрос «как меняется значение во времени». Частотная (спектр) отвечает «из каких частот сигнал собран». Одни задачи проще решать во времени, другие — в частоте. Умение переключаться между проекциями — ключевой навык DSP.
Две проекции одного сигнала
| Вопрос | Временная область | Частотная область (спектр) |
| Что видно | значение в каждый момент | амплитуда каждой частоты |
| Удобно для | задержки, импульсы, форма | тоны, шум, фильтрация полос |
| Прибор | осциллограф | анализатор спектра |
| Ось X | время (с) | частота (Гц) |
Спектр чистого тона — одна линия
У идеального синуса спектр предельно прост: единственная вертикальная линия на его частоте. Покажем это качественно через скалярное произведение с пробными синусами (упрощённый анализ).
import math
N = 16
fs = 16.0
# Чистый тон 3 Гц
sig = [math.sin(2 * math.pi * 3 * n / fs) for n in range(N)]
def energy_at(f):
re = sum(s * math.cos(2 * math.pi * f * n / fs) for n, s in enumerate(sig))
im = sum(s * math.sin(2 * math.pi * f * n / fs) for n, s in enumerate(sig))
return round((re * re + im * im) ** 0.5 / (N / 2), 3)
for f in range(0, 8):
bar = "#" * int(round(energy_at(f) * 20))
print(f"{f} Гц | {bar} {energy_at(f)}")
Вывод:
0 Гц | 0.0 1 Гц | 0.0 2 Гц | 0.0 3 Гц | #################### 1.0 4 Гц | 0.0 5 Гц | 0.0 6 Гц | 0.0 7 Гц | 0.0
Вся энергия собралась в одну линию на 3 Гц с амплитудой 1.0 — ровно параметры нашего тона. Спектр «опознал» сигнал.
Спектр смеси тонов
Сложим два тона — и спектр покажет две линии. Это то, чего нельзя «увидеть» на осциллограмме: там просто сложная волна, а спектр сразу раскладывает её на составляющие.
import math
N = 16
fs = 16.0
# 2 Гц амплитудой 1.0 + 5 Гц амплитудой 0.5
sig = [math.sin(2 * math.pi * 2 * n / fs) + 0.5 * math.sin(2 * math.pi * 5 * n / fs)
for n in range(N)]
def energy_at(f):
re = sum(s * math.cos(2 * math.pi * f * n / fs) for n, s in enumerate(sig))
im = sum(s * math.sin(2 * math.pi * f * n / fs) for n, s in enumerate(sig))
return round((re * re + im * im) ** 0.5 / (N / 2), 3)
for f in range(0, 8):
print(f"{f} Гц -> {energy_at(f)}")
Вывод:
0 Гц -> 0.0 1 Гц -> 0.0 2 Гц -> 1.0 3 Гц -> 0.0 4 Гц -> 0.0 5 Гц -> 0.5 6 Гц -> 0.0 7 Гц -> 0.0
Две линии: 2 Гц с амплитудой 1.0 и 5 Гц с амплитудой 0.5 — в точности наши слагаемые. Спектр восстановил рецепт сигнала.
Как работает под капотом
То, что мы посчитали вручную (умножить сигнал на пробный синус/косинус и просуммировать), — это и есть один коэффициент преобразования Фурье. Вещественная часть re измеряет «сколько косинуса» этой частоты в сигнале, мнимая im — «сколько синуса»; вместе они дают амплитуду sqrt(re²+im²) и фазу atan2(im, re). В следующем уроке мы запишем это компактно через комплексную экспоненту и получим формулу ДПФ. Важно: спектр реального (вещественного) сигнала симметричен — частоты выше Найквиста зеркалят нижние, поэтому смотрят только на первую половину, до fs/2.
Частые ошибки
- Смотреть только во времени. Периодическую помеху (наводку 50 Гц) на осциллограмме легко не заметить, а в спектре она — яркая линия.
- Игнорировать симметрию спектра. У вещественного сигнала верхняя половина — зеркало нижней; реальная информация в диапазоне 0..fs/2.
- Считать амплитуду без нормировки. Сырые коэффициенты ДПФ зависят от длины
N; чтобы получить физическую амплитуду тона, делят наN/2.
Итог
- Спектр — частотная проекция сигнала: какие частоты и с какой амплитудой в нём есть.
- Чистый тон даёт одну линию; смесь тонов — несколько линий.
- Спектр получают, измеряя «сколько» каждой частоты через косинус и синус.
- У вещественного сигнала спектр симметричен; смотрят диапазон 0..fs/2.