使用 MATLAB 去除高通滤波中的瞬态

信息处理 matlab 过滤
2022-01-19 01:13:23

我制作了一个简单的一阶 IIR 高通滤波器,在 z = 1 处为零,在 z = 0.9 处有一个极点。它的频率响应如下所示:

在此处输入图像描述

现在,我使用此滤波器过滤直流信号。这是我用来执行此操作的 MATLAB 代码:

b = [1 -1]; % Zero at z = 1
a = [1 -0.9]; %Pole at z = 0.9

figure(1)
freqz(b, a)

t = 1:100;
x(1:length(t)) = 1; % Constant function

y = filter(b, a, x);

figure(2)
plot(t, x)
xlabel('Time');
ylabel('Input Signal');

figure(3)
plot(t, y)
xlabel('Time');
ylabel('Output Signal');

由于我的滤波器是高通的,我预计 DC 会变为零,或者至少会严重衰减。但是,我得到的输出信号如下所示:

指数衰减的输出信号

据我了解,这个指数输出是由于我没有正确设置初始条件而产生的瞬态。果然,设置 x[-1] = 1 解决了这个问题。然而,这只适用于这个特定的输入直流信号。对于任何通用输入信号,我如何设置初始条件以免产生瞬变?

编辑:我知道 filtfilt() 函数通过瞬态最小化进行前向后向过滤,但我真的想将过滤器移植到嵌入式平台,所以我需要了解瞬态删除的工作原理。在此先感谢您的帮助!

编辑 2:正如 Kuba Ober 所建议的,我尝试将 x[-1] 设置为它实际上应该是的值。它适用于直流输入,但对于正弦输入来说,情况如下:

clc; clear all;
p = 0.9

a = [1 -p]
b = [1 -1]


n = 1:100; % Samples
f = 0.2; % Frequency in Hz
Fs = 10; % Sampling rate in samples per second
t = n/Fs; % Time axis

x = sin(2*pi*f*t);

% Filter with the appropriate initial conditions
y = filter(b, a, x, filtic(b, a, [], [sin(2*pi*f*0)])); 

figure(1)
plot(t, x)
xlabel('Time');
ylabel('Input Signal');

figure(2)
plot(t, y)
xlabel('Time');
ylabel('Output Signal');

这是输入信号:

在此处输入图像描述

这是输出:

在此处输入图像描述

第一个峰值明显小于第二个峰值,这表明存在一些瞬变。我对此并不完全确定,但我认为它不起作用的原因是因为仅设置 x[-1] 是不够的,我还需要设置 y[-1]。这里的问题是没有办法找出 y[-1] 实际上应该是什么。

编辑 3:让我提供有关我正在处理的问题的更多信息。我正在尝试使用滤波器来消除嵌入式平台中 ECG(心电图)信号中的噪声。这是过滤后的典型心电图信号:

在此处输入图像描述

以下是 ECG 信号在过滤前的样子:

在此处输入图像描述

注意滤波前信号中的直流偏移。对于滤波,我需要一个陷波滤波器来去除高频电源线噪声和一个高通滤波器来去除直流和信号的低频“漂移”。

我使用的滤波器需要是线性相位的,因为 ECG 信号的时域形态对于诊断非常重要。但是,我的过滤器不需要是实时的,因为我在从患者那里获取 ECG 信号后离线进行处理。因此,为了实现非线性相位 IIR 滤波器,我目前正在使用前向后向零相位滤波。

@Matt L. 和 @Royi 共享的一个观点是瞬态在实时滤波中是不可避免的,我应该使用更长的输入信号并剪掉滤波输出的前几秒。这是我想避免的事情,因为从活着的病人那里获取长的心电图有点困难。此外,我不必实时过滤,因此任何依赖于提前了解整个信号的瞬态去除技术都是完全可以的。任何帮助表示赞赏!

1个回答

的一阶滤波器递归a,b,c

y[n]=ax[n]+bx[n1]cy[n1]

处具有两个初始内存状态x[1]y[1]n=0

您的“无瞬态”条件可以转换为和必要的第二个条件,以便您可以解决两种记忆状态。第二个条件可能是,的离散导数也在处消失,因此您也可以采取任何其他您认为合理的条件。y[0]=0yn=0y[0]y[1]=0

这两个方程为您提供了两个未知记忆的唯一解,即:

y[1]=0
x[1]=abx[0]

或者,您的条件最好选择为y[0]=0y[0]y[1]=x[0]x[1]为了捕捉输入的初始斜率。得到的递归方程在n=0那么是

0=ax[0]+bx[1]+c(x[0]x[1])
给你解决方案
x[1]=a+cbcx[0]
y[1]=(1+a+cbc)x[0]

(请检查我的计算!)

但一般来说,你不能指望一个简单的初始条件给你与知道信号历史相同的结果。所以你只能把它带到某个点,一般来说,如果你只是丢弃输出的瞬态响应可能会更好。