fft 的幅度小于预期的幅度

信息处理 fft 振幅 音调产生
2022-02-14 22:07:29

这是我的 MATLAB 代码

Amp = 0.3;
freqHz = 1000;
fsHz = 160000;
dt = 1/fsHz;
t = 0:dt:2000*dt;
sine = Amp * sin(2*pi*freqHz*t);
t = 0:2000
subplot(2,2,1)
plot(t,sine)

y1 = sine;
Fs = 160000;                   % samples per second
N = length(y1);            % samples
dF = Fs/N;                 % hertz per sample
f = -Fs/2:dF:Fs/2-dF + (dF/2)*mod(N,2);      % hertz
Y1_fft = fftshift(fft(y1))/N;
subplot(2,2,2)
plot(f , (abs(Y1_fft)) - min((abs(Y1_fft))));
legend(num2str(i))
shg;

这是结果: 在此处输入图像描述

我的 sin 幅度为 0.3,因此我希望在 1Khz 处获得幅度为 0.15 的 FFT 信号,而幅度为 0.096。我的目标是在不同频率中提取音调的幅度。

4个回答

对于在 FFT 长度中不完全是整数周期的频率,幅度峰值隐藏在 FFT 结果箱之间。但是您可以进行插值以找到这些频率的结果。尝试对实部和虚部进行加窗 Sinc 插值,然后计算复数结果的大小。如果您不知道确切的频率,您可以使用逐次逼近法来找到 FFT 结果箱之间的插值幅度峰值。

请注意,如果您确实知道确切的频率(可以在分数 bin 位置)并且只对幅度和相位感兴趣,那么 FFT 除了不准确之外效率很低。

更好的方法是goertzel解调或正交解调。

如果您尝试使用 FFT 来估计正弦曲线的频率和/或幅度,当您的信号频率不完全落在 FFT 箱上时,您会遇到问题。在这种情况下,FFT 的结果会导致能量泄漏到附近的 FFT 箱中 - 通常称为扇形损失。减少扇形损失的常用方法是使用窗,例如 Hamming、Blackman 等。虽然使用窗可以减少扇形效应,但还有一些额外的副作用,其中两个是:相干能量损失(如您所见的幅度损失)和效应 FFT bin 大小的增加(FFT 频率分辨率 - 名义上的采样频率/FFT 大小)。

您的问题有几个可能的解决方案:首先,使用所谓的平顶窗口。这是一个试图保持振幅的特殊窗口,即它试图避免相干能量损失。请参阅此处查看 Richard Lyons 的一篇文章,该文章对此进行了描述。请注意,有几个稍微不同版本的平顶窗口。

另一种方法是使用具有峰值幅度的 FFT bin 和相邻 FFT bin 的幅度。对频率和幅度估计值进行插值。通常,在估计幅度之前,您需要知道频率。插值机制可以变化:线性、二次、样条等。

这里有几个参考:

参考 1 - 马特·多纳迪奥

Ref 2 - 埃里克·雅各布森

注意 - 在以下情况下也会出现一些问题:

  • 存在噪音
  • 附近有正弦曲线/信号将能量泄漏到您用于频率估计的 FFT 箱中。

您的信号频率为 1000 Hz,而您的采样频率为 160 kHz。由于每个周期有 160 个样本,因此 FFT 的点数应该是 160 的倍数。在这种情况下,我使用了 1600 个点。

Amp = 0.3;
NbPoints  = 1600;
freqHz = 1000;
fsHz = 160000;
dt = 1/fsHz;
t = 0:dt:(NbPoints-1)*dt;
sine = Amp * sin(2*pi*freqHz*t);
n = 1 : NbPoints;
subplot(2,2,1)
plot(t,sine)

y1 = sine;
Fs = 160000;                   % samples per second
N = length(y1);            % samples
dF = Fs/N;                 % hertz per sample
f = -Fs/2:dF:Fs/2-dF + (dF/2)*mod(N,2);      % hertz
Y1_fft = fftshift(fft(y1))/N;
subplot(2,2,2)
plot(f , (abs(Y1_fft)) - min((abs(Y1_fft))));
legend(num2str(1))
shg;