FFT中的补零操作

前言

​ 在做信号处理的时候,我们经常遇到需要的将时域信号补零后进行FFT的操作,比如ADC的采样信号不满足2的N次方的情况,我们需要对信号进行补零处理来使得信号满足2的N次方来进行FFT处理。这是因为FFT算法的核心思想是将一个长度为N的离散傅里叶变换(DFT)问题分解成两个长度为N/2的DFT问题,并通过递归地分解和合并来实现高效的计算。那么对信号补零会改变什么以及无法改变什么?

​ 先说明结论:使用补零不会改变频率分辨率(Frequency Resolution),但是会减弱栅栏效应(FFT Leakage Effect),提高频谱分辨率(Spectral Resolution),也就是频谱的采样点增加会导致频谱之间的采样间隔减少。注意区分频率分辨率和频谱分辨率的区别。

  • 频率分辨率:频率分辨率指的是能够区分出两个不同频率的最小间隔。在频域上,它表示能够分辨出两个频率成分的能力。频率分辨率通常由采样率确定,即采样率越高,频率分辨率越好。在数字信号处理中,频率分辨率可以通过奈奎斯特采样定理计算得到,即频率分辨率等于采样率的一半。

  • 频谱分辨率:频谱分辨率是指在频谱分析中最小频谱间隔对应的频率。

实例

  • 在信号处理中使用采样的频率100Hz对正弦波采样,并且产生频率为10hz和20hz的正弦波。

  • 对产生的正弦波进行叠加得到叠加波进行FFT处理

  • 使用不同的补零数观察得到频谱图




% 设置参数
fs = 100; % 采样率为100Hz
duration = 1; % 信号持续时间为1秒

% 生成时间轴
t = 0:1/fs:duration-1/fs;

% 生成第一个正弦号(频率为10Hz)
f1 = 10; % 第一个号的频率为10Hz
x1 = sin(2*pi*f1*t);

% 生成二个正弦号(频率为20Hz)
f2 = 20; % 第二个信号的频率为20Hz
x2 = sin(2*pi*f2*t);

% 两个信号叠加
x3 = x1+x2;

%FFT补零处理
FFT_POINTS = 256;
fft_res = abs(fft(x3,FFT_POINTS));
plot(fft_res);
xlim([0 FFT_POINTS/2])
str = strcat("采样点为100,补零数量为",num2str(FFT_POINTS-100));
title(str);

从以上各图可以看出,随着填零数量的增加,频谱的基本轮廓并未改变,只是变得更细腻(提高了频率颗粒度,即频谱分辨率)。如果这个时候将叠加波10hz和20hz改变为11hz和12hz。但是并不能提高频率分辨率,从图形上直观体现为主瓣尖峰宽度不变,图中11Hz和11.5Hz的正弦信号频谱峰值难以分辨;

​ 从原理上分析,采样率100Hz,N=100点,则FFT频率分辨率fs/N= 1Hz,则本例中0.5Hz的差异是无法分辨的,不断的填充0相当于在频域进行插值,随着填零数量的增加,100点的FFT信号频谱将不断逼近离散时间傅里叶变换(DTFT)的结果;反过来理解(将图按从下往上的顺序看),在N=100不变的情况下,填零后FFT相当于在100点信号DTFT结果中一个频域周期内进行等间隔采样而来。


​ 提高频率分辨率需要增加观测时间(即有效数据长度),如需要分辨0.5Hz的频率,就需要至少1/0.5Hz=2s的有效观测时长;下面看看增加采样点数后频谱的变化,图中分别有11、11.5Hz两个频率的独立频谱和时域叠加后的频谱,可以看到在N大于200点开始,叠加信号主瓣上开始出现两个非相邻独立峰值点,N越大,区分越明显。单频信号的主瓣宽度随着N增加而变窄。

clc;
clear;
% 设置参数
fs = 100; % 采样率为100Hz
duration = 4; % 信号持续时间为1秒

% 生成时间轴
t = 0:1/fs:duration-1/fs;

% 生成第一个正弦号(频率为10Hz)
f1 = 11; % 第一个号的频率为10Hz
x1 = sin(2*pi*f1*t);

% 生成二个正弦号(频率为20Hz)
f2 = 11.5; % 第二个信号的频率为20Hz
x2 = sin(2*pi*f2*t);

% 两个信号叠加
x3 = x1+x2;


% 独立FFT结果
FFT_POINTS = 400;
fft_x1 = abs(fft(x1,FFT_POINTS));
fft_x2 = abs(fft(x2,FFT_POINTS));
x = (1:FFT_POINTS).*(100/FFT_POINTS);
plot(x,fft_x1);
hold on;
plot(x,fft_x2);
legend('11Hz','11.5Hz');
set(gca,'XLim',[5,20]);
str = strcat("采样点为",num2str(FFT_POINTS));
xlabel("频率/Hz");
title(str);

posted @ 2023-07-22 14:11  Kroner  阅读(704)  评论(0编辑  收藏  举报