MATLAB 做 FFT 频谱分析:峰值泄漏从哪来?窗函数与补零的工程取舍
做信号处理实验时,很多人都遇到过这个现象:一个明明是单频正弦的信号,用 MATLAB 的 fft 一算,频谱主峰两边拖出一串“裙摆”,峰值也不正好落在某个频点上。换一台示波器看时域波形又很干净——问题不在信号,而在我们对一段有限长数据做 FFT 的方式本身。本文把泄漏的成因、窗函数的取舍和补零的真实作用一次讲清。
一、泄漏的根源:截断等于加了矩形窗
FFT 默认我们给的 N 个采样点就是信号的全部。但只要信号频率不是采样频率除以 N 的整数倍(即非整周期截断),这段数据在 FFT 眼里就相当于被周期延拓后首尾不连续。时域上的一次跳变,对应频域上 sinc 形的旁瓣扩散,这就是频谱泄漏。
举个具体例子:采样率 fs=1000 Hz,取 N=1000 个点,信号频率 50.5 Hz。50.5 不是 1 Hz 频率分辨率的整数倍,FFT 的能量必然分散到 50 Hz、51 Hz 及周边多个频点上,峰值读数也因此偏低。反过来,若信号恰好是 50 Hz 整周期截断,频谱就只有一根干净的谱线。所以“泄漏”不是噪声,而是截断方式与信号频率不匹配的必然结果。
二、窗函数:用主瓣换旁瓣
加窗就是在做 FFT 之前先给数据乘一个两端渐变到零的权重,压住首尾跳变。代价是主瓣变宽、频率分辨率下降,换来的是旁瓣大幅压低,弱信号不再被强信号的裙摆淹没。
常用选择可以这样记:矩形窗分辨率最高、旁瓣最差(约 -13 dB),只适合整周期或信噪比极高的场合;汉宁窗(Hann)旁瓣约 -31 dB,是通用折中;布莱克曼窗旁瓣约 -58 dB,适合在强干扰旁边找弱信号,但主瓣最宽;平顶窗(Flattop)幅值精度最好,适合只关心幅值、不关心分辨两个邻近频率的场合。没有“最好”的窗,只有与任务匹配的窗:测两个邻近频率用矩形或汉宁,测弱信号用布莱克曼,标定幅值用平顶窗。
三、补零不是提高分辨率
很多人以为 fft(x, 4*N) 把频率分辨率提高了 4 倍。其实补零只是在频域做插值:它让谱线画得更密、峰值位置读得更准,但并不能把两个原本靠得太近的频率分开。真正的频率分辨率只由观测时长 T=N/fs 决定,约等于 1/T。想分辨 2 Hz 的两个频率,至少需要约 0.5 秒的数据,再怎么补零也变不出来。
但补零并非无用:配合窗函数与抛物线插值,它能把峰值频率的估计误差从半个频点压到百分之几个频点,对测频、标定幅值很有帮助。关键是分清“谱线变密”与“分辨率提高”是两回事。
四、MATLAB 实操:一段可直接跑的代码
fs = 1000; N = 1000; t = (0:N-1)/fs;
x = sin(2*pi*50.5*t) + 0.05*sin(2*pi*120*t); % 50.5 Hz 强信号 + 120 Hz 弱信号
% 矩形窗对照
X_rect = abs(fft(x));
% 汉宁窗 + 4 倍补零
win = hann(N).';
X_hann = abs(fft(x.*win, 4*N));
f = (0:4*N-1)*(fs/(4*N));
plot(f(1:200), 20*log10(X_hann(1:200)+eps));
xlabel('频率 (Hz)'); ylabel('幅值 (dB)');
跑这段代码可以直观对比:矩形窗下 120 Hz 的弱峰会被 50.5 Hz 的旁瓣抬高、甚至淹没;换汉宁窗后弱峰清晰出现,但 50.5 Hz 的主瓣变宽了。这就是工程取舍的现场演示。
五、工程 checklist
做 FFT 之前先问自己四件事:第一,信号是否整周期截断,不是就加窗;第二,任务是分辨频率还是找弱信号还是标定幅值,据此选窗;第三,观测时长够不够分辨目标频率差,不够就加长数据而不是补零;第四,读峰值时是否做了插值或补零修正,否则幅值与频率都会系统性偏低。按这个顺序排查,大多数“频谱不对”的问题在加窗这一步就解决了。
结论:泄漏不是玄学,是截断的数学后果。窗函数用分辨率换动态范围,补零用计算量换读数精度,观测时长才是分辨率的硬约束。理解这三条分工,FFT 频谱就不再是一张需要猜的图。
- 点赞
- 收藏
- 关注作者
评论(0)