为什么我从 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 的响应,从而减少重叠。
我尝试用 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;等等。
这不是您代码中的错误。它与 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 的响应,从而减少重叠。