Действительно, если кадр длится T
секунд, частоты ДПФ составляют k/T
Гц, где k - целое число.Как следствие, передискретизация не улучшает точность расчетной частоты, если эти частоты идентифицированы как максимумы величины ДПФ.Напротив, рассмотрение более длинных кадров продолжительностью 100 с приведет к разнесению между частотами DFT 0,01 Гц, что может быть достаточно для получения ожидаемой частоты. Можно добиться гораздо лучшего, оценив частоту пика как его среднюю частоту с учетом плотности мощности.
Рисунок 1: дажепосле применения окна Тьюки ДПФ оконного сигнала не является суммой Дирака: все еще есть некоторая спектральная утечка в нижней части пиков.Эта мощность должна учитываться при оценке частот.
Другая проблема заключается в том, что длина кадра не кратна периоду сигнала, который в любом случае не может быть периодическим.Тем не менее, ДПФ вычисляется так, как если бы сигнал был периодическим, но прерывистым на границе кадра.Он вызывает скачкообразные частоты, описываемые как спектральная утечка .Оконное управление является эталонным методом для решения таких проблем и смягчения проблемы, связанной с искусственным разрывом.Действительно, значение окна непрерывно уменьшается до нуля вблизи краев кадра. Существует список оконных функций , и множество оконных функций доступно в scipy.signal .Окно применяется как:
tuckey_window=signal.tukey(len(data),0.5,True)
data=data*tuckey_window
. В этот момент частоты, наибольшие значения которых по-прежнему составляют 262, 330 и 392. Применение окна только делает пики более заметными: ДПФ оконного сигнала обладаеттри выделенных пика, каждый из которых имеет центральный лепесток и боковые лепестки, в зависимости от DFT окна. лепестки этих окон симметричны: поэтому центральная частота может быть вычислена как средняя частота пика относительно плотности мощности.
import numpy as np
from scipy import signal
import scipy
sr = 44100 # sample rate
x = np.linspace(0, 1, sr) # one second of signal
tpi = 2 * np.pi
data = np.sin(261.63 * tpi * x) + np.sin(329.63 * tpi * x) + np.sin(392.00 * tpi * x)
#a window...
tuckey_window=signal.tukey(len(data),0.5,True)
data=data*tuckey_window
data -= np.mean(data)
fft = np.fft.rfft(data, norm="ortho")
def abs2(x):
return x.real**2 + x.imag**2
fftmag=abs2(fft)[:1000]
peaks, _= signal.find_peaks(fftmag, height=np.max(fftmag)*0.1)
print "potential frequencies ", peaks
#compute the mean frequency of the peak with respect to power density
powerpeak=np.zeros(len(peaks))
powerpeaktimefrequency=np.zeros(len(peaks))
for i in range(1000):
dist=1000
jnear=0
for j in range(len(peaks)):
if dist>np.abs(i-peaks[j]):
dist=np.abs(i-peaks[j])
jnear=j
powerpeak[jnear]+=fftmag[i]
powerpeaktimefrequency[jnear]+=fftmag[i]*i
powerpeaktimefrequency=np.divide(powerpeaktimefrequency,powerpeak)
print 'corrected frequencies', powerpeaktimefrequency
Результирующие расчетные частоты составляют 261,6359Гц, 329,637 Гц и 392,0088 Гц: он намного лучше, чем 262, 330 и 392 Гц, и удовлетворяет требуемой точности 0,01 Гц для такого чистого бесшумного входного сигнала.