Matlab `filtfilt` 提供了过多的瞬态

信息处理 matlab 过滤器 无限脉冲响应 带通 线性相位
2022-01-24 22:27:50

我观察到当我提供具有陡峭过渡带的 IIR 带通滤波器时,filtfilt 会出现不良行为。具体来说,输出信号表现出过度的瞬态响应;尽管如此,如果我使用基于filter. 我想这不是涉及滤波器系数或结构的数值问题,也不是filter函数。

% design bandpass filter having transition bandwidth of 200 Hz (Fs = 8000)
bp = designfilt('bandpassiir', 'StopbandFrequency1', 50, 'PassbandFrequency1', 250,...
    'PassbandFrequency2', 3600, 'StopbandFrequency2', 3800, 'StopbandAttenuation1', 30,...
    'PassbandRipple', 0.1, 'StopbandAttenuation2', 30, 'SampleRate', 8000, 'DesignMethod', 'cheby2');
% check stability
assert(isstable(bp),'Unstable filter');
% apply filtfilt to a random (white) long input signal; output signal shows an undesirable transient
x = randn(2^20,1);
y = filtfilt(bp,x);
% apply 'home-made' filtfilt to the same input; output signal shows a more acceptable transient
y2 = flipud(filter(bp,flipud(filter(bp,x))));
% compare effects
figure; semilogy(abs(y-y2));

根据经验,随着过渡带变窄,效果会增加,而随着过渡带变宽,效果往往会消失。

哪里有问题?我是否错过了函数帮助中的一些建议或提示?

2个回答

它必须与函数使用的初始条件有关filtfilt.m这个想法是以一种最小化启动和结束瞬态的方式匹配初始条件。然而,这似乎并不总是有效,而且对于您的过滤器规格,它似乎弊大于利。据我所知,没有办法告诉filtfilt.m不要弄乱初始条件。在这种情况下剩下的就是简单地实现一个简单的版本,就像你做的那样。

也看看这个相关的答案

编辑:

我试图用 Octave 重现你的结果,但我没有得到你描述的任何效果。我用一个10th订购 Chebyshev 2 滤波器(这是满足您的规格的最低阶),我使用了一个修改版本,filtfilt允许我打开和关闭初始条件的使用和输入信号的外推。对此有两种解释:要么你的 Matlab 版本filtfilt有错误,要么你的滤波器与我的有很大不同,它引入了数值问题(由于极点非常接近单位圆),当输入信号时,这些问题恰好表现出来是外推的,和/或在使用特殊初始条件时(如 的情况filtfilt)。如果您提供您的滤波器系数,我们或许可以解开这个谜团。

编辑2:

Tendero 使用问题中提供的 Matlab 命令再现了滤波器系数:

B = [0.682585947577945 -0.012906667355225 -3.354515884719406 0.025370108447479 6.651816094305592 -0.000000000000000 -6.651816094305592 -0.025370108447479 3.354515884719406 0.012906667355225 -0.682585947577945];
A = [1.000000000000000 -0.194376467633997 -4.144930396202897 0.592472615834755 7.013126532356848 -0.691483043645839 -6.033921428993976 0.364443043103532 2.633924737223088 -0.072944768631229 -0.465923573748158];

我在 Octave 中将这些系数filtfilt.m与带有随机输入信号的函数一起使用x = randn(2^20,1),就像在问题中一样。如上所述,我使用了 的修改版本,filtfilt.m以便能够打开和关闭减少瞬变的不同措施:

  1. 不外推输入信号,零初始条件
  2. 不外推输入信号,最佳初始条件(在标准版本中实现filtfilt.m
  3. 输入信号的外推,零初始条件
  4. 输入信号的外推,最佳初始条件

最后一个组合是在标准版本中实现的处理filtfilt.m

下图显示了第一个和最后一个50的样本4不同的输出信号。对于所有其他样本,信号几乎相同。 在此处输入图像描述

正如预期的那样,在启动过程中和结束时可以看到细微的差异,但这些差异非常小,使用原始滤波器系数和 Octave 函数无法重现 OP 的问题filtfilt.mOP使用的Matlab版本中必须存在错误filtfilt.m,或者与滤波器系数或函数无关的另一个问题filtfilt.m

查看脚本filtfilt.m,与您在一行中执行的简单实现有两点不同。

首先,马特在他的回答中说了什么。该函数filtfilt在调用函数时使用初始条件filter(您可以查看Mathworks 的文档)。

另一个区别是filtfilt调用filter,它不用x作输入,而是在函数中创建另一个数组。我不明白那个信号为什么或什么,但我相信这就是我们得到那个奇怪峰值的原因。在 Octave 的版本中,filtfilt执行以下操作(将过滤器延迟初始化为零,即修改后的filtfilt):

lx = size(x,1);
lb = length(b);
la = length(a);
n = max(lb, la);
lrefl = 3 * (n - 1);
if la < n, a(n) = 0; endif
if lb < n, b(n) = 0; endif

v = [ 2*x(1) - x((lrefl+1):-1:2);
      x(:);
      2*x(end) - x((end-1):-1:end-lrefl)];

v = filter(b,a,v);                   # forward filter
v = flipud(filter(b,a,flipud(v)));   # reverse filter
y = v((lrefl+1):(lx+lrefl));

也许有人可以帮助我们理解它v代表什么以及它为什么有用,但这是我能发现的filtfilt与您的“自制”实现之间的唯一区别,所以我期望这是不受欢迎的瞬态的原因。