通过零填充 FFT 进行插值

信息处理 fft 频率 插值 零填充
2022-02-15 15:37:56

我目前正在研究 Robert Bond Randall 的《基于振动的状态监测》一书(第二版)。

我试图在 Matlab 中实现一种算法来“增加”给定信号的采样率。本书第 148 页说明了两种方式:

  • 在时域中“在每个实际样本之间插入适当数量的零,然后应用数字低通滤波器将频率范围限制为原始最大值(它还需要与采样因子成比例地重新调整);
  • 在频域中“通过在中心用零填充 FFT 频谱,然后将增加的(两侧)频谱逆变换为相同数量的时间样本。”

我的实现如下


N   = 32;
pad = 34;

t1  = linspace(0,1,N);
t2  = linspace(0,1,N+pad);

s   = sin(2*pi*t1);
N   = length(s);

% FFT
S = fft(s);
paddedS = [S(1:N/2-1) S(N/2)/2 zeros(1,pad-1) S(N/2)/2 S(N/2+1:end)];

% Inverse transform
K = (N+pad)/N; % Scaling factor
i = ifft(S);
paddedI = ifft(paddedS)*K;

% Plot
plot(t1,i, '-o')
hold on
plot(t2,paddedI, '-o')

不过我对结果不满意,函数的最后部分有一个工件,如下所示

在此处输入图像描述

我认为问题出在“paddedS”定义中,但对我来说似乎是正确的,你能发现错误吗?

先感谢您。

2个回答

两个问题:(1)您的信号不是周期性的以隐藏窗口效应和(2)错误的频域填充。

抛出最后的样本并仔细管理长度:

N   = 32;
pad = 34;

t1  = linspace(0,1,N);
t2  = linspace(0,1,N+pad);
t1=t1(1:end-1);
t2=t2(1:end-1);

s   = sin(2*pi*t1);

% FFT
S = fft(s);
paddedS = [S(1:floor(length(S)/2)) zeros(1,pad) S(floor(length(S)/2)+1:end)];

% Inverse transform
K = length(paddedS)/length(S); % Scaling factor
i = ifft(S);
paddedI = ifft(paddedS)*K;

close all
figure;
% Plot
plot(t1,i, '-o')
hold on
plot(t2,paddedI, '-o')

您正在看到我认为等同于 FFT 中的频谱泄漏伪影的东西,在这种情况下特别是时域混叠。我会推荐第一种插值方法,注意零插入将以原始采样率的倍数复制频谱。最佳滤波器将无失真地通过您的原始通带,并完全消除以的每个倍数为中心的图像(最终速率为。使用最小二乘算法设计的多频带滤波器(MATLAB、Octave 和Python scipy.signal)可以有效地做到这一点,因为它们可以将拒绝带集中在需要的地方。fsNfs