我正在编写一个程序,用一个五阶巴特沃斯滤波器离线过滤一个 20,000 个样本的信号。我可以访问 FFT 实现。实现过滤似乎有两种选择:
- 将信号与时域中的脉冲响应进行卷积,或
- 将信号与频域中的脉冲响应相乘并对结果进行逆变换
这些方法在理论上的 FT 情况下是相同的。不过,在现实生活中使用 DFT 进行操作,我想情况会有所不同。其中一种方法在数值上更稳定吗?还有其他我应该注意的问题吗?计算次数并不重要。
我正在编写一个程序,用一个五阶巴特沃斯滤波器离线过滤一个 20,000 个样本的信号。我可以访问 FFT 实现。实现过滤似乎有两种选择:
这些方法在理论上的 FT 情况下是相同的。不过,在现实生活中使用 DFT 进行操作,我想情况会有所不同。其中一种方法在数值上更稳定吗?还有其他我应该注意的问题吗?计算次数并不重要。
使用卷积,你不会遇到任何稳定性问题,因为没有递归过滤,所以你不会累积任何错误。换句话说,系统全为零,没有极点。我听说过基于 FFT 的卷积比时域卷积具有更低的误差,但我自己没有得到验证,这仅仅是因为它具有 O(n log n) 算术运算而不是 O(n^2)。
通常,据我所知,巴特沃斯滤波器是作为递归 (IIR) 滤波器实现的,所以这是一个不同的主题。IIR 滤波器有极点和零点,因此在实践中可能存在稳定性问题。此外,对于 IIR 滤波器,基于 FFT 的方法不是一种选择,但从好的方面来说,IIR 滤波器往往是非常低阶的。
至于 IIR 滤波器的稳定性问题,它们往往会在更高阶出现问题——我只是抛出一个数字并说大约 6 阶正在推动它。相反,它们通常被实现为级联双二阶(二阶滤波器部分)。对于您的 5 阶滤波器,将其写为 z 域传递函数(它将是 5 次有理函数),然后将其分解为 5 个极点和 5 个零点。收集复共轭,您将拥有两个双二阶和一个一阶滤波器。一般来说,随着极点越来越接近单位圆,稳定性问题往往会出现。
IIR 滤波器中的噪声和限制周期也可能存在问题,因此有不同的滤波器拓扑(即直接形式 I,直接形式 II)具有不同的数值属性,但我不会过度考虑这一点 - 只需使用 double-精度,它几乎肯定会足够好。
在几乎所有情况下,您的最佳选择既不是卷积也不是 FFT,而是直接应用 IIR 滤波器(例如使用 sosfilt() 函数)。就 CPU 和内存消耗而言,这将大大提高效率。
是否产生数值差异取决于特定的过滤器。唯一可能出现一些差异的情况是极点非常非常接近单位圆。即使有一些技巧可以提供帮助。不要使用传递函数表示和 filter(),而是在 sosfilt() 中使用极点和零点。这是差异的示例。
n = 2^16; % filter length
fs = 44100; % sample rate
x = zeros(n,1); x(1) = 1;
f0 = 15; % cutoff frequency in Hz
% design with poles and zeroes
[z,p,k] = butter(5,f0*2/fs);
clf
plot(sosfilt(zp2sos(z,p,k),x));
% design with transfer function
[b,a] = butter(5,f0*2/fs);
hold on
plot(filter(b,a,x),'k');
filter() 在大约 15Hz @44.1kHz 的截止频率处变坏。对于 sosfilt(),截止频率可以远低于 1/100 Hz @44.1kHz,没有任何问题。
如果您有稳定性问题,FFT 也无济于事。由于您的滤波器是 IIR 滤波器,因此脉冲响应是无限的,必须先截断。在这些非常低的频率下,脉冲响应变得如此之长,以至于 FFT 也变得不切实际。
例如,如果您想要 1/100 Hz @ 44.1 kHz 的截止频率并想要 100 dB 脉冲响应的动态范围,您需要大约 2500 万个样本!!!在 44.1 kHz 下这几乎是 10 分钟,比原始信号长很多很多倍
为什么你认为事情会有所不同?理论概念应该转化为实际应用,唯一的区别是浮点问题,我们无法逃避。您可以通过 MATLAB 中的简单示例轻松验证:
x=randn(5,1);
y=randn(5,1);
X=fft(x,length(x)+length(y)-1);
Y=fft(y,length(x)+length(y)-1);
z1=conv(x,y);z2=ifft(X.*Y);
z1-z2
ans =
1.0e-15 *
-0.4441
-0.6661
0
-0.2220
0.8882
-0.2220
0
-0.4441
0.8882
正如你所看到的,误差是机器精度的数量级。不应该有任何理由不使用 FFT 方法。正如 Endolith 所提到的,使用 FFT 方法进行过滤/卷积/互相关等更为常见,并且速度更快,除了非常小的样本(如本例中)。并不是说时域处理永远不会完成……这一切都归结为应用程序、需求和约束。