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

Posted

技术标签:

【中文标题】FFT 围绕特定频率的大量细节【英文标题】:FFT lots of detail around certain frequency 【发布时间】:2014-04-12 05:12:15 【问题描述】:

我有一个任意信号,我需要知道信号的频谱,这是我通过 FFT 获得的。问题是,我需要很多关于这个特定频率的分辨率。问题是,如果我增加我的窗口宽度,或者如果我提高采样率,它就会变得太慢,我最终会得到很多细节。我只希望在某一点上有很多细节,而在其他地方只需要很少的细节。

我尝试在我需要的区域周围使用 Goertzel 过滤器,然后在其他任何地方使用 FFT,但这并没有让我获得更多的分辨率,我认为这是意料之中的。

有什么想法吗?我目前唯一的想法是围绕我想要的价值进行扫描和内积。

谢谢。

【问题讨论】:

FFT 基本上是用基础展开所有频率范围的卷积,也许你可以简单地通过只用一个特定的基础和你想要的频率进行卷积来改变这个过程? ? 是的,这是我目前的想法。在某种程度上,我会在我想要的频率周围扫描基础。 【参考方案1】:

增加采样率不会给你更高的光谱分辨率,它只会给你更多你不感兴趣的高频信息。提高光谱分辨率的唯一方法是增加窗口长度。有一种方法可以通过零填充人为地增加窗口的长度,但这只会给你“假分辨率”,它只会在正常点之间产生平滑的曲线。所以唯一的方法是测量更长时期的数据,没有免费的午餐。

对于您描述的问题,减少 FFT 计算时间的标准方法是使用解调(或外差,不确定正式名称是什么)。将您的数据与频率接近您感兴趣的频率的正弦相乘(可能是确切的频率,但这不是必需的),然后抽取您的日期(低通滤波,拐角频率刚好低于您的奈奎斯特频率采样率,然后是下采样)。这样,您的积分会少得多,因此您的 FFT 会更快。生成的频谱将与您的原始频谱相似,但只是通过解调频率移动。因此,在制作绘图时,只需将 f_demod 添加到您的 x 轴即可。

需要注意的一点是,如果与实正弦相乘,您的下采样频谱实际上将是两个镜像频谱的总和,因为实正弦由正负频率组成。有两种解决方案

    用相同频率的正弦和余弦解调,得到 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()

结果:

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

【讨论】:

感谢您的回答,非常有意义!我的问题是增加窗口大小需要太长时间。我拥有的样本越多(由于增加的窗口长度或更高的采样率),需要求解的方程越多,所需的时间就越长。理想情况下,我想解决相同数量的方程,但在某些频率附近获得更高的分辨率,而在其他频率附近获得更低的分辨率。我不认为这是有道理的。尽管如此,你的想法对我还是很有用的,谢谢。 每次抽取都会减少方程的数量,从而为相同的计算量提供更长的窗口。

以上是关于FFT 围绕特定频率的大量细节的主要内容,如果未能解决你的问题,请参考以下文章

使用 JavaScript 进行 FFT 分析:如何找到特定频率?

Android音频FFT使用audiorecord检索特定频率幅度

使用 FFT 查找音频频率变化的非常简单的解释 [关闭]

如何将 FFT 应用于录音以获取频率?

如何在每个FFT计算中检索不同的原始频率并且在java中没有任何频率泄漏

MATLAB中fft的频率轴怎么计算