FFT大量细节围绕特定频率。

4
我有一个任意信号,需要知道该信号的频谱,我通过FFT来实现。问题是,我需要在一个特定的频率周围获得大量的分辨率。但是如果我增加窗口宽度或者提高采样率,会导致处理速度变慢,并且在其他地方也会出现很多细节。我只想在一个点上获得很多细节,而其他地方尽可能少。
我尝试使用Goertzel滤波器仅在需要的区域进行滤波,然后在其他地方进行FFT,但这并没有给我更多的分辨率,这可能是可以预料的。
你有什么好的想法吗?目前我唯一的想法是在我想要的值周围进行扫描和内积运算。
谢谢。

FFT 基本上是用基底在整个频率范围内进行卷积,也许你可以通过使用只有一个特定频率的基底来简化此过程? - michaeltang
是的,那是我的目前想法。我以某种方式在我想要的频率周围扫描基础。 - Jean-Luc
1个回答

7
增加采样率不会提高光谱分辨率,只会提供更多高频信息,而您并不感兴趣。唯一提高光谱分辨率的方法是增加窗口长度。有一种通过零填充人为增加窗口长度的方法,但这只能给您带来“虚假分辨率”,它只会在常规点之间产生平滑曲线。因此,唯一的方法是在更长的时间内测量数据,没有免费的午餐。
对于您所描述的问题,减少FFT计算时间的标准方法是使用解调(或混频,不确定官方名称是什么)。将数据与接近您感兴趣的频率的正弦波相乘(可以是确切的频率,但这并非必要),然后抽取数据(低通滤波器的截止频率略低于下采样采样率的奈奎斯特频率,然后进行下采样)。这样,您会得到较少的点,因此您的FFT速度会更快。得到的光谱将类似于原始光谱,但仅仅是由解调频率移位。因此,在制作图表时,只需将f_demod添加到x轴即可。
需要注意的一件事是,如果您用实数正弦相乘,则下采样的光谱实际上将是两个镜像光谱的总和,因为实数正弦由正负频率组成。有两种解决方法:
1. 同时通过正弦和余弦乘以相同频率进行解调,这样您就可以得到2个光谱,然后取和或差即可获得您的光谱。
2. 通过乘以形式为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()

结果:

enter image description here

如果你放大看,你会注意到在抽取滤波器的通带内,结果几乎相同。需要注意的一件事是,在decimate中使用的低通滤波器如果使用远大于10的抽取比率将变得数值不稳定。解决这个问题的方法是对于大比率进行多次抽取,例如对于1000的抽取比率,你可以通过3次10倍抽取来实现。


谢谢你的回答,非常清晰易懂!我的问题是增加窗口大小需要太长时间。我有更多的样本(由于增加的窗口长度或更高的采样率),需要解决更多的方程,所以需要更长的时间。理想情况下,我希望解决相同数量的方程,但在某些频率周围获得更高的分辨率,在其他频率周围获得更低的分辨率。不过我认为这可能没有意义。尽管如此,你的想法对我仍然非常有用,谢谢。 - Jean-Luc
1
每次抽取都会减少方程的数量,从而为相同计算量提供更长的窗口。 - hotpaw2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接