FFT在某些频率周围的详细信息
我有一个信号,想知道这个信号的频率成分,所以我用快速傅里叶变换(FFT)来处理。问题是,我只想在一个特定的频率附近得到很多细节。可是,如果我增加窗口的宽度,或者提高采样率,处理速度就会变得很慢,而且我会得到很多地方的细节,这样反而不太好。我只想在那个特定的频率点上有很多细节,其他地方的细节尽量少一点。
我尝试过在我需要的频率范围内使用Goertzel滤波器,然后在其他地方用FFT,但这样并没有让我在需要的地方得到更多的细节,这也是我预料之中的。
有没有什么好的主意?我现在唯一想到的办法是围绕我想要的值进行扫频和内积运算。
谢谢。
1 个回答
提高采样率并不会让你的频谱分辨率变高,它只会让你得到更多高频信息,而这些信息其实你并不需要。要提高频谱分辨率,唯一的方法就是增加窗口的长度。你可以通过在数据后面加零来人为增加窗口长度,但这只会给你“假分辨率”,结果只是让正常的数据点之间的曲线变得平滑。所以,真正的方法是要在更长的时间内测量数据,这没有免费的午餐。
针对你描述的问题,减少FFT计算时间的标准方法是使用解调(或者叫做异频处理,不确定官方名称是什么)。你可以用一个频率接近你感兴趣频率的正弦波去乘你的数据(可以是完全相同的频率,但这并不是必须的),然后对数据进行降采样(低通滤波,截止频率稍低于你降采样后采样率的奈奎斯特频率,接着再降采样)。这样,你的数据点就会少很多,所以FFT的计算会更快。得到的频谱会和你原来的频谱相似,只是会因为解调频率而移动。所以在绘图时,只需在x轴上加上f_demod
。
需要注意的是,如果你用真实的正弦波去乘数据,你降采样后的频谱实际上会是两个镜像频谱的和,因为真实的正弦波包含正频率和负频率。对此有两个解决方案:
用同一频率的正弦波和余弦波进行解调,这样你会得到两个频谱,然后取它们的和或差就能得到你的频谱。
用形式为
exp(2*pi*i*f_demod*t)
的复数正弦波进行解调。这样你输入FFT的数据将是复数的,所以你需要计算双侧频谱。但这正是你想要的,你会得到f_demod
上下的频率。
我更喜欢第二个解决方案。快速示例:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import psd
from scipy.signal import decimate
f_line = 123.456
f_demod = 122
f_sample = 1000
t_total = 100
t_win = 10
ratio = 10
t = np.arange(0, t_total, 1 / f_sample)
x = np.sin(2*np.pi*f_line * t) + np.random.randn(len(t)) # sine plus white noise
lo = 2**.5 * np.exp(-2j*np.pi*f_demod * t) # local oscillator
y = decimate(x * lo, ratio) # demodulate and decimate to 100 Hz
z = decimate(y, ratio) # decimate further to 10 Hz
nfft = int(round(f_sample * t_win))
X, fx = psd(x, NFFT = nfft, noverlap = nfft/2, Fs = f_sample)
nfft = int(round(f_sample * t_win / ratio))
Y, fy = psd(y, NFFT = nfft, noverlap = nfft/2, Fs = f_sample / ratio)
nfft = int(round(f_sample * t_win / ratio**2))
Z, fz = psd(z, NFFT = nfft, noverlap = nfft/2, Fs = f_sample / ratio**2)
plt.semilogy(fx, X, fy + f_demod, Y, fz + f_demod, Z)
plt.xlabel('Frequency (Hz)')
plt.ylabel('PSD (V^2/Hz)')
plt.legend(('Full bandwidth FFT', '100 Hz FFT', '10 Hz FFT'))
plt.show()
结果:
如果你放大查看,会发现结果在降采样滤波器的通带内几乎是完全相同的。需要注意的是,如果你在decimate
中使用的低通滤波器的降采样比率大于10,可能会变得不稳定。解决这个问题的方法是对大比率进行多次降采样,比如要降采样1000倍,可以分三次每次降采样10倍。