为什么我从 FFT 获得偏斜的频谱? (Matlab)

Why do I obtain a skewed spectrum from the FFT? (Matlab)

我尝试用 Matlab 找到最强的频率分量。它有效,但如果数据点和周期没有很好地对齐,我需要对我的数据进行零填充以提高 FFT 分辨率。到目前为止一切顺利。

问题是,当我零填充太多时,最大功率的频率会发生变化,即使一切都很好地对齐,我希望得到一个清晰的结果。

这是我的 MWE:

Tmax = 1024;
resolution = 1024;
period = 512;

X = linspace(0,Tmax,resolution);
Y = sin(2*pi*X/period);

% N_fft = 2^12; % still fine, max_period is 512
N_fft = 2^13; % now max_period is 546.1333

F = fft(Y,N_fft);
power = abs(F(1:N_fft/2)).^2;

dt = Tmax/resolution;
freq = (0:N_fft/2-1)/N_fft/dt;

[~, ind] = max(power);
max_period = 1/freq(ind)

零填充到 2^12 一切正常,但是当我零填充到 2^13 时,我得到了错误的结果。似乎过多的零填充会改变频谱,但我对此表示怀疑。我宁愿在我的代码中发现一个错误,但我找不到它。我做错了什么?

编辑: 似乎频谱偏向低频。零填充只是让它可见:

为什么我的频谱偏斜?不应该是对称的吗?

这是对您做错了什么的图形解释(主要是分辨率问题)。 编辑:这显示了每个 fft 数据点的功率,映射到 2^14 数据集的索引。也就是说,编号为 1、2、3 的 2^13 数据的索引在此图中映射到 1、3、5;编号为 1、2、3 的 2^12 数据的索引映射到 1、5、9;等等。

。 您可以看到 "true" 值实际上不应该是 512——您的索引偏移了 1 或 1 的一小部分。

这不是您代码中的错误。它与 DFT 的属性有关(因此与 FFT 的属性有关,FFT 只是 DFT 的快速版本)。

当你补零时,你增加了频率分辨率,特别是在低端。

此处您使用正弦波作为测试,因此您基本上是将有限长度的正弦波与有限正弦波和有限余弦波(参见此处 https://en.wikipedia.org/wiki/Fast_Fourier_transform 详细信息)进行卷积,它们具有几乎相同或更低的频率。

如果你正在做一个 "proper" fft,即做从 -inf 到 +inf 的积分,即使那些低频分量也会给你 FFT 的零系数,但是因为你做的是有限和,这些卷积的结果不为零,因此实际计算的傅立叶变换不准确。

TL;DR: 使用更好的 window 函数!

长版:

经过进一步搜索,我终于找到了解释。既不是索引问题,也不是零填充添加的额外低频分量。矩形 window 的频率响应与 频率分量相结合是罪魁祸首。我在解释 window 函数时发现 this website

我做了更多的情节来解释:

顶部: 没有 windowing 的频率响应:两个 增量峰值,一个在正极,一个在正极负频率。我总是绘制积极的部分,因为我没想到需要负频率分量。 中间:矩形window函数的频率响应。它相对广泛,但我不在乎,因为我认为我只有一个峰。 底部: 零填充信号的频率响应。在时域中,这是 window 函数与正弦波的乘积。在频域中,这相当于 window 函数的频率响应与完美正弦的频率响应的卷积。由于有两个峰值,window 的相对较宽的频率响应显着重叠 ,导致频谱偏斜,从而导致峰值偏移。

解决方案: 一种避免这种情况的方法是使用适当的 window 函数,例如 Hamming window,以获得更小的频率window 的响应,从而减少重叠。