Обратное ДПФ, амплитудный и фазовый спектр
Замыкаем круг: возвращаемся из спектра во время и разбираем две части спектра — амплитуду и фазу.
Обратное ДПФ восстанавливает сигнал из спектра:
x[n] = (1/N)*sum(X[k]*exp(+2j*pi*k*n/N)). Прямое и обратное ДПФ — это пара, переводящая сигнал туда и обратно без потерь.
ДПФ обратимо: из спектра можно точно собрать исходный сигнал. Это критично для практики — фильтрация в частотной области работает так: перешли в спектр, что-то поправили, вернулись во время. А ещё спектр состоит из двух частей — амплитудной и фазовой, — и важно понимать роль каждой.
Обратное ДПФ: туда и обратно
Формула обратного ДПФ отличается знаком в экспоненте (плюс вместо минуса) и делением на N. Проверим, что прямое ДПФ с последующим обратным точно возвращают сигнал.
import math, cmath
def dft(x):
N = len(x)
return [sum(x[n] * cmath.exp(-2j * math.pi * k * n / N) for n in range(N))
for k in range(N)]
def idft(X):
N = len(X)
return [sum(X[k] * cmath.exp(2j * math.pi * k * n / N) for k in range(N)).real / N
for n in range(N)]
x = [1.0, 2.0, 3.0, 4.0]
X = dft(x)
restored = [round(v, 3) for v in idft(X)]
print("исходный: ", x)
print("ДПФ -> оДПФ:", restored)
Вывод:
исходный: [1.0, 2.0, 3.0, 4.0] ДПФ -> оДПФ: [1.0, 2.0, 3.0, 4.0]
Сигнал восстановлен в точности. Прямое и обратное ДПФ — обратимая пара, ничего не теряется.
Амплитудный и фазовый спектр
Комплексный X[k] распадается на две вещественные кривые. Амплитудный спектр |X[k]| — «сколько» каждой частоты (громкость тона). Фазовый спектр arg(X[k]) — «когда» каждая частота начинается (сдвиг). Возьмём косинус с фазой pi/4 и убедимся, что ДПФ восстановит и амплитуду, и фазу.
import math, cmath
def dft(x):
N = len(x)
return [sum(x[n] * cmath.exp(-2j * math.pi * k * n / N) for n in range(N))
for k in range(N)]
N = 8
sig = [math.cos(2 * math.pi * 1 * n / N + math.pi / 4) for n in range(N)]
X = dft(sig)
amps = [round(abs(c) / (N / 2), 3) or 0.0 for c in X[:N // 2 + 1]]
phases = [round(cmath.phase(c), 3) if abs(c) > 1e-6 else 0.0 for c in X[:N // 2 + 1]]
print("амплитуды:", amps)
print("фазы(рад):", phases)
print("pi/4 =", round(math.pi / 4, 3))
Вывод:
амплитуды: [0.0, 1.0, 0.0, 0.0, 0.0] фазы(рад): [0.0, 0.785, 0.0, 0.0, 0.0] pi/4 = 0.785
Амплитудный спектр показывает линию на бине 1 с амплитудой 1.0 (наш косинус). Фазовый спектр на том же бине даёт 0.785 — это ровно pi/4, фаза, которую мы заложили. ДПФ восстановил оба параметра.
Как работает под капотом
Почему фаза важна? Амплитудный спектр говорит, какие частоты есть, но не как они выстроены во времени. Два сигнала с одинаковым амплитудным спектром, но разными фазами, звучат и выглядят по-разному. Классический пример: если у речевого сигнала сохранить амплитудный спектр, но обнулить фазы, разборчивость пропадёт — именно фаза несёт информацию о форме и временной структуре. Поэтому при обработке в частотной области нельзя выбрасывать фазу: меняем амплитуды (фильтрация), но фазу обычно сохраняем или корректируем аккуратно. Энергия сигнала при этом сохраняется и во времени, и в спектре — это теорема Парсеваля: sum(x[n]²) = (1/N)*sum(|X[k]|²).
Частые ошибки
- Терять мнимую часть при обратном ДПФ. Из-за округлений она крошечная, но игнорировать структуру нельзя; для вещественного сигнала берут
.realосознанно. - Считать фазу неважной. Фаза несёт временную структуру; её порча разрушает сигнал даже при правильных амплитудах.
- Забывать делитель
Nв обратном ДПФ. Без него амплитуда восстановленного сигнала вырастет вNраз.
Итог
- Обратное ДПФ восстанавливает сигнал из спектра: знак «+» в экспоненте и делитель
N. - Прямое и обратное ДПФ — обратимая пара без потерь.
- Амплитудный спектр — «сколько» частоты, фазовый — «когда» она начинается.
- Фаза несёт временную структуру; её нельзя выбрасывать при обработке.