我有一个任意信号,我需要知道该信号的频谱,这是通过执行FFT获得的。问题是,在这个特定频率附近,我需要很多分辨率[[only。问题是,如果我增加窗口宽度,或者提高采样率,它会变得太慢,并且到处都会产生很多细节。我只想在一点上提供很多细节,而在其他地方则只需要最小的细节。
[我尝试仅在所需区域周围使用Goertzel滤波器,然后在其他地方进行FFT,但这并没有给我带来更多的分辨率,这是我所期望的。有什么想法吗?目前,我唯一的想法是围绕我想要的价值扫荡和生产内积。
谢谢。
对于您描述的问题,减少FFT计算时间的标准方法是使用解调(或外差功能,不确定官方名称是什么)。将您的数据与正弦频率相近的正弦相乘(可能是确切的频率,但这不是必需的),然后抽取日期(转折频率刚好低于下降的奈奎斯特频率的低通滤波) -采样的采样率,然后进行下采样)。这样,您的点数少得多,因此FFT会更快。产生的频谱将类似于您的原始频谱,但只是被解调频率所偏移。因此,在绘制图时,只需将f_demod
添加到x轴即可。
要注意的一件事是,如果您乘以一个正弦,则您的下采样频谱实际上将是两个镜像频谱的总和,因为一个正弦由正负频率组成。有两种解决方案]
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()
结果:<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS95WnBpNi5wbmcifQ==” alt =“在此处输入图像描述”>
如果放大,您会注意到结果在抽取滤波器的通带内实际上是相同的。要注意的一件事是,如果使用的抽取比远大于10,则
decimate
中使用的低通滤波器在数值上将变得不稳定。解决方案是对多个比例进行多次抽取,即按1000倍,则将3倍减少10倍。