如何通俗易懂地理解FIR/IIR滤波器?

A.关于FIR

今天开始,本专栏将开通一个关于滤波的新专题。

数字滤波器中最基础的莫过于FIR和IIR这两个类型,而且这两类方法也有着系统的理论基础。相关课程中虽然对其有着非常详尽且专业的讲解,但是对于部分同学可能不那么容易理解。

本篇将从FIR入手,形象地讲解有限冲激响应数字滤波的理论知识,相信跟着阅读完,你一定能有所收获。
 

一、任务描述

如下图,我们仿真生成了两段信号。其中一条是未加入噪声的纯净信号,另外一条是加入白噪声后的含噪声信号。其中纯净信号使用了一段正弦信号。我们的目的就是将含噪声信号中的噪声部分滤除,得到一条尽量还原纯净信号的滤波结果。

二、一种直观的解决方案

从上图容易看出,含噪声信号是在纯净信号上下波动的,所以很容易想到,如果取某几个含噪声信号的平均值,作为滤波结果,则可以抵消掉噪声在上下随机波动中的干扰效果。假如我们每3个点做一次平均,实现过程见下图(为了便于观察,使用前0.25秒数据演示):

能够看出,经过该方法处理后的数据相对于纯净信号的波动幅值得到了一定程度的抑制,也就是可以取得一定程度的滤波效果。

这是一种最简单的FIR滤波器,也可以叫做滑动平均滤波方法。

三、另外一种理解角度——引入权重系数概念

上边讲到的滑动平均,是将3个相邻信号求取平均值,这也可以理解为这3个值分别乘以权重系数1/3再求和,那么上述滤波过程可以用下边这张动图来演示,应该是比较直观的了:

图3. 选取了前10个数据点作为演示

看到这里大家想到什么了吗。是的——是卷积

四、重温卷积的概念

这里大家可能存在两个疑问:为什么上图能联系到卷积?卷积怎样影响到滤波算法的构造?

1.先解答第一个疑惑,为什么上图能联系到卷积。

在之前的文章里比较详细地讲解了卷积的概念:Mr.看海:这篇文章能让你明白卷积,大家在读完本篇文章后如果感兴趣可以再跳转过去看,现在我们继续讲。

在那篇文章里,我引用了一个形象的例子:

比如说老板命令 张三干活,张三却到楼下打台球去了,后来被老板发现,他非常气愤,扇了张三一巴掌(注意,这就是输入信号,脉冲),于是张三的脸上会渐渐地(贱贱地)鼓起来一个包,张三的脸就是一个系统,而鼓起来的包就是张三的脸对巴掌的响应,好,这样就和信号系统建立起来意义对应的联系。下面还需要一些假设来保证论证的严谨:假定张三的脸是 线性时不变系统,也就是说,无论什么时候老板打张三一巴掌,打在张三脸的同一位置(这似乎要求张三的脸足够光滑,如果张三长了很多青春痘,甚至整个脸皮处处连续处处不可导,那难度太大了,我就无话可说了哈哈),张三的脸上总是会在相同的时间间隔内鼓起来一个相同高度的包来,并且假定以鼓起来的包的大小作为系统输出。好了,那么,下面可以进入核心内容——卷积了!
如果张三每天都到地下去打台球,那么老板每天都要扇张三一巴掌,不过当老板打张三一巴掌后,一天后就消肿了,所以时间长了,张三甚至就适应这种生活了……如果有一天,老板忍无可忍,以0.5秒的间隔开始不间断的扇张三的过程,这样问题就来了,第一次扇张三鼓起来的包还没消肿,第二个巴掌就来了,张三脸上的包就可能鼓起来两倍高,老板不断扇张三,脉冲不断作用在张三脸上,效果不断叠加了,这样这些效果就可以求和了,结果就是张三脸上的包的高度随时间变化的一个函数了(注意理解);如果老板再狠一点,频率越来越高,以至于都辨别不清时间间隔了,那么,求和就变成积分了。可以这样理解,在这个过程中的某一固定的时刻,张三的脸上的包的鼓起程度和什么有关呢?和之前每次打张三都有关!但是各次的贡献是不一样的,越早打的巴掌,贡献越小,所以这就是说,某一时刻的输出是之前很多次输入乘以各自的衰减系数之后的叠加而形成某一点的输出,然后再把不同时刻的输出点放在一起,形成一个函数,这就是卷积,卷积之后的函数就是张三脸上的包的大小随时间变化的函数。本来张三的包几分钟就可以消肿,可是如果连续打,几个小时也消不了肿了,这难道不是一种平滑过程么?反映到剑桥大学的公式上,f(a)就是第a个巴掌,g(x-a)就是第a个巴掌在x时刻的作用程度,乘起来再叠加就ok了,大家说是不是这个道理呢?我想这个例子已经非常形象了,你对卷积有了更加具体深刻的了解了吗?
转自GSDzone论坛
来源:人人网

看一下下图,红线的方波代表“打了一巴掌”,蓝线是肿起来的鼓包的高度。假设鼓包一天的时间(24小时)可以完全回复,也就是高度会变为0。

需要注意,“鼓包的高度”不是随着时间的推移无限趋近于0,而是在1天后就变成了0,也就是对于巴掌这个“冲激”的响应是“有限的”,这就是有限冲激响应。在这里我们假设“鼓包的高度”随时间的推移用g(t)表示,很明显g(0)=1,而g(1)=0。

如果进一步增加扇巴掌的频次,如果时间间隔小于24小时,那么第二次的鼓包就会叠加上上一次没有消除的鼓包高度,对应鼓包高度会像下图这样:

假如我们只求整时刻(即0.1的整数倍)的鼓包情况,为了更便于理解,干脆将“鼓包的高度”这个冲激响应也离散化,这并不影响我们对于整时刻的求解:

对于每一个时刻,其鼓包高度的计算是前几次为消除鼓包高度的叠加,对于0.3天这个时刻,此时鼓包的高度就是:

0.3天这一刻刚刚打了一巴掌,刚刚出炉的鼓包高度很明显是1,用公式表示就是g(0)
0.2天这一刻打的巴掌,距离0.3天已经过去0.1天,鼓包高度还残余g(0.1)
0.1天这一刻打的巴掌,距离0.3天已经过去0.2天,鼓包高度还残余g(0.2)
0天这一刻打的巴掌,距离0.3天已经过去0.3天, 鼓包高度还残余g(0.3)
所以第0.3天这一刻的鼓包高度就是 g(0)+g(0.1)+g(0.2)+g(0.3)g(0)+g(0.1)+g(0.2)+g(0.3)

现在再贴近现实一些,老板也很难控制每次巴掌力度的一致,如果他用了两倍的力气,那鼓包的高度很容易理解就是2了(因为是线性时不变系统),这里我们引入一个变量f(t),表示t时刻老板的力度。那么对于0.3天这个时刻,此时鼓包的高度就变成:

0.3天这一刻刚刚打了一巴掌,此时力气值是f(0.3),用鼓包高度就是f(0.3)g(0)
0.2天这一刻打的巴掌,此时 力气值是f(0.2),距离0.3天已经过去0.1天,鼓包高度还残余f(0.2)g(0.1)
0.1天这一刻打的巴掌,此时力气值是f(0.1),距离0.3天已经过去0.2天,鼓包高度还残余f(0.1)g(0.2)
0天这一刻打的巴掌,此时力气值是f(0),距离0.3天已经过去0.3天,鼓包高度还残余f(0)g(0.3)
所以第0.3天这一刻的鼓包高度就是 f(0.3)g(0)+f(0.2)g(0.1)+f(0.1)g(0.2)+f(0)g(0.3)f(0.3)g(0)+f(0.2)g(0.1)+f(0.1)g(0.2)+f(0)g(0.3)

如果老板2天之内使用了如下的“连环掌”:

那张三脸上的鼓包将会是怎样呢。

请开始表演:

看完上图有没有觉得有点眼熟,是的!和图3简直一毛一样!

所以综上可以得到一个直观的结论:当一组数像滑窗一样滑过另外一组数时,将对应的数据相乘并求和得到一组新的数,这个过程必然和卷积有着莫大的关系。

在后边可能会讲到的卷积神经网络中,只是将一维数据扩展到了二维平面,但这种滑窗求和的基本思想是一脉相承的,乃至于该卷积思想可以推广到多维空间当中。就像下图:

图10. 来源:https://mlnotebook.github.io/post/CNN1/

不过这里我们不做过多扩展了。

我们只需要知道:FIR滤波就是在时域上卷积的过程。

2.再解答第二个疑惑,上述卷积怎样影响到滤波算法的构造。

卷积有一个重要性质:时域的卷积等于频域相乘。

这个性质可以说和滤波是息息相关的,因为滤波的目的就是想要得到某特定的频率段。

而频域相乘恰恰能够实现这个筛选的目的。

回到文章最开始的例子,想要对含噪声信号滤波,那我们不妨先看看他的频谱:

图11. 含噪声信号及其对应频谱

可以看到我们想要保留的频率段范围基本在3Hz以下,高于3Hz的都可以抛弃,很自然地,我们可以想到一个办法,即构造如下一组频域信号:

此时将图11中的频谱和图12相乘,高于3Hz的数值就全部变为了0,此时频谱就成了:

再将此频域数值进行傅里叶逆变换,得到时域数值:

可以看到我们近乎完美的实现了滤波。一句话表述上述滤波过程:设计一个频域滤波器(将想要保留的频率段赋值为1,其他频率段赋值为0),将其与含噪声信号的频谱在频域上相乘,再将乘积做傅里叶逆变换,即可实现滤波,这种滤波器叫频域滤波器。

虽然得到了较好的滤波结果,但是事情到这里还没完,不要忘记这篇文章是讲FIR滤波器的~

注意看上边那段话中的加黑字体:在频域上相乘。回想起来了吗?

时域的卷积等于频域相乘!

所以,上述在频域空间的一大堆操作,可以简单地转化成在时域上的卷积操作,具体来说,就是将含噪声信号与低通滤波器的傅里叶逆变换值进行卷积,这个过程就是FIR滤波。

我用一张图表示他们之间的关系:

到这里你应该已经理解了,FIR滤波器的本质是设计一组系数,这组系数实际就是滤波器的IFFT(冲激响应,还记得张三的鼓包吗)离散化以后的结果。

五、FIR滤波器表达式

将上述的理论浓缩成一个表达式,表示FIR滤波器:

y[n]=a0x[n]+a1x[n−1]+a2x[n−2]+...y[n]=a_0x[n]+a_1x[n-1]+a_2x[n-2]+...

上式中的x代表待滤波数据,y代表输出数据;系数a0、a1、a2...就是滤波器的冲激响应系数。所以在FIR滤波器中,每一时刻的输出取决于之前的有限个输入,因此就是“有限冲激响应”。

B.关于IIR

上一篇文章中我们讲了FIR有限冲激响应的概念,今天就轮到无限冲激响应IIR了。

一、概念引入

上一篇中我们讲到,FIR是从滑动平均方法牵引出来的基于卷积的一种滤波方法,可以说FIR天然是具有直观的“数字处理”的特性的;而今天讲到的IIR方法是和物理世界有着对应的联系,或者说它是对“模拟滤波器”的数字表达。

如果你学习过模拟电路,那一定知道模拟电路中的滤波器设计:

对于上图中的模拟滤波器,是有着对应的频响曲线的,比如低通滤波的频响曲线大概是这样:

目前IIR数字滤波器设计的最通用方法是借助于模拟滤波器的设计方法 [1]。模拟滤波器已经有了一套相当成熟的方法,它不但有完整的设计公式,而且还有较为完整的图表供查询,因此,充分利用这些已经有的资源会给数字滤波器的设计代理很大的方便。

二、IIR滤波器的设计

IIR 滤波器设计的基本方法 [2]:先设计一个合适的模拟滤波器(模拟原型滤波器),然后利用复值映射把模拟滤波器变换成数字滤波器。

2.1 关于模拟原型滤波器

常用的模拟原值滤波器有很多种,比如巴特沃斯滤波器、切比雪夫滤波器、贝塞尔滤波器、椭圆滤波器等。

他们的特点如下[3]

巴特沃斯滤波器通带最平坦,阻带下降慢。
切比雪夫滤波器通带等纹波,阻带下降较快。
贝塞尔滤波器通带等纹波,阻带下降慢。也就是说幅频特性的选频特性最差。但是,贝塞尔滤波器具有最佳的线性相位特性。
椭圆滤波器在通带等纹波(阻带平坦或等纹波),阻带下降最快。

2.2 模拟滤波器到数字滤波器的变换

变换主要方法有脉冲响应不变法和双线性变换法。

脉冲响应不变法:从时域响应出发,使数字滤波器的单位脉冲响应h(n) 模仿模拟滤波器的单位冲激响应ha(t) ,h(n)等于ha(t)的取样值。
双线性变换法:从频率响应出发,直接使数字滤波器的频率响应逼近模拟滤波器的频率响应,进而求得数字滤波器的系统函数。

具体的数学推导涉及到比较复杂的概念,由于这篇文章作为入门的引子,这里不做具体的讲解了。有需要的同学建议参看奥本海姆的《信号与系统》或者这里

三、对IIR滤波器的理解

IIR相对于FIR的最大区别就在于“无限冲激响应”,这个无限要怎么理解呢?

3.1 第一种理解方式:

可以从物理层面上去理解,就像之前举的例子,IIR是对模拟滤波器的复刻,当下图中的电路,在IN的位置给一个电压值后,电容会被充电,当IN的电压取消后(此时相当于给IN处加了一个冲激信号),电容的电量会被逐渐放掉,但是理论上永远不会变成0,所以输入信号会在后续无限长的时间内产生影响,也就是“无限冲激响应”。

3.2 第二种理解方式:

上一篇文章讲到,FIR滤波器的表达式为:

y[n]=a0x[n]+a1x[n−1]+a2x[n−2]+...y[n]=a_0x[n]+a_1x[n-1]+a_2x[n-2]+...

上式中的x代表待滤波数据,y代表输出数据。在FIR滤波器中,每一时刻的输出取决于之前的有限个输入,因此就是“有限冲激响应”。

与之对应的,IIR滤波器的表达式为:

上式通过将输入信号的值乘以“a”系数,将先前从输出信号计算的值乘以“b”系数,并将乘积相加,可以找到输出信号中的每个点,上式称为递归公式。

由于本步骤的输出会作为下一步骤的输入,无限递归下去,所以一个时刻的影响就是无限的,也就是“无限冲激响应”。

本篇文章先讲到这里吧,涉及到IIR的数学理论如果要深入研究还是比较艰涩的,鉴于本专栏更偏重于通用性、易读性和应用性的介绍,就不过多介绍了。对于IIR还有什么想知道的,可以在文章下边留言。

C.FIR、IIR在MATLAB中的实现方法

一、MATLAB中滤波器的设计方法

MATLAB为滤波设置了种工具,比如图形化的设计工具filterDesginer、根据差分方程直接设计滤波器的filter函数、根据滤波目的进行设计的lowpass函数、highpass函数等等。

不过我最终选用了designfilt函数进行FIR、IIR滤波器设计实现。因为该函数兼具了方法的全面性统一性,而且相对于图形界面,纯代码的形式在很多场景下也更便于调用。

二、使用designfilt函数进行滤波

这里我们举一个例子来说明designfilt函数的用法。

准备滤波的对象数据如下,我们对该数据进行低通滤波:

滤波前数据

1.导入数据。

我们将该数据命名为data,在程序中使用如下代码进行导入:

%% 1.导入数据
load data.mat

此步骤也可以是导入其他格式的数据文件,比如Excel、csv、txt、一些音频格式等等;也可以不导入数据而是使用仿真数据,那么此处就对应改成数据仿真的计算公式。

2.参数设置

下面我们设计一个FIR低通滤波器,所以type设置成了“lowpassfir”,此外根据滤波器类型和设计方法的不同,可以选择:'lowpassfir''lowpassiir''highpassfir''highpassiir''bandpassfir''bandpassiir''bandstopfir''bandstopiir'

在这个例子里边我们需要指定四个参数,分别是滤波器阶数、低通截止频率、数据采样频率、设计方法。

type = 'lowpassfir';
order = 50;      %滤波器阶数
CutoffFrequency = 75;  %低通截止频率
Fs = 500;  %数据采样频率
DesignMethod = 'window'  %设计方法

3.实现滤波并画图

下边这行代码是将上述参数导入designfilt函数,得到设计完成的滤波器d。

d =designfilt(type,'FilterOrder',order,...'CutoffFrequency',Fst,'SampleRate',Fs,'DesignMethod',DesignMethod);

然后调用filter函数,实现滤波,filter入口参数为滤波器d和待滤波数据data。

xf = filter(d,data);  %xf为滤波后数据

此时绘制一下滤波前数据和滤波后数据的对比图:

可以看到滤波结果是有相位延迟的,对于相位延迟,在之前的文章中也介绍过。由于FIR滤波的相位延迟是线性的,可以通过平移进行延迟补偿(不用担心,IIR滤波器也可以相位补偿):

相位补偿后的结果

四、关于designfilt函数的其他规范集

这里要提到一个“规范集”的概念,可以看一下下图:

lowpassfir的规范集

上图是lowpassfir的规范集,对于其他七种方法,都有这样一张规范集列表。所谓的“规范集”简单来说就是designfilt函数支持不同的滤波器设计方法(这里的设计方法不是指FIR或者IIR,而是更加细分的“window、butter”等等),而在不同的设计方法中,需要输入的各种参数都会有所不同。而上表就是列出在不同的设计方法下需要设置哪些参数。

我们在上边程序中用到的规范集是下边红框框出来的这一行:

如果在你的研究需求中,要使用其他规范集,就需要参考到这张表了。

三、代码的傻瓜化封装——一行代码实现FIR/IIR滤波

通过上述方法结合官方教程文档,我们可以实现滤波器的设计,但是对于新手来说多少还是有一些门槛的,而且对于很多应用场景,我们并不需要考虑那么多种规范集形式。

有没有一种更简便易用,兼顾专业性,最好还可以多功能分析画图的实现方法呢?

现在有了——笔者按照专栏以往的的代码风格,对FIR、IIR算法进行了二次封装,实现了“一行代码”完成滤波的效果。我将封装后的函数命名为funFirIirFliter

比如还是对于上边的例子,只需要像下边这样设置参数并调用funFirIirFliter函数:

resp = 'lowpassfir';  %选择滤波器类型
option.order = 50;    %设置滤波器阶数
option.CutoffFrequency = 75;  %设置滤波器截止频率
option.Fs = 500;              %设置信号采样频率
compFlag = 'on';     %compFlag:是否进行延迟补偿,'on'为开启补偿,'off'为关闭补偿。      
%% 3.调用funFirIirFliter实现滤波
dataOut = funFirIirFliter(data,resp,option,compFlag);

就可以得到如下结果:

图1. 滤波器响应图

图2. 滤波效果图

图1是设计得到的滤波器响应图;图2是滤波效果图,其中包括滤波前信号及频谱、滤波后信号及频谱、滤波前后信号对比图(可以用于比较相位滞后情况)。

也就是说只要向funFirIirFliter函数导入待分析的数据、选择滤波器类型(如'firlowpass'等)、进行option相关参数设置(对于不同的滤波器类型设置大概3-4个参数),还可以选择是否进行相位补偿(通过设置compFlag参数为'on'或'off')。然后调用一行“funFirIirFliter(data,resp,option,compFlag);”,就可以实现上述所有功能了。

对于funFirIirFliter函数更详细的注释说明如下:

function [dataOut,d] = funFirIirFliter(data,resp,option,compFlag)
% 进行FIR或者IIR滤波,可以实现滤波器设计、滤波、画图
% 如需对下述代码进行二次开发,可参考此官方帮助文档:https://ww2.mathworks.cn/help/signal/ref/designfilt.html?s_tid=doc_ta
% 输入:
% data:待滤波数据
% resp:滤波器响应类型和滤波类型,具体包含:
%       -'lowpassfir'      FIR低通滤波器,采用'window'设计方法对应的规范集,需要设置的参数包括:
%                          - option.order 滤波器阶数
%                          - option.CutoffFrequency 滤波器截止频率
%                          - option.Fs 采样频率
%       -'lowpassiir'      IIR低通滤波器,采用最小阶设计对应的规范集
%                          - option.Fs 采样频率
%                          - option.PassbandFrequency     通带频率
%                          - option.StopbandFrequency     阻带频率
%                          - option.DesignMethod     设计方法,选项: 'butter'、'cheby1'、'cheby2'、'ellip'
%       -'highpassfir'      FIR高通滤波器,采用'window'设计方法对应的规范集,需要设置的参数包括:
%                          - option.order 滤波器阶数
%                          - option.CutoffFrequency 滤波器截止频率
%                          - option.Fs 采样频率
%       -'highpassiir'     IIR高通滤波器,采用最小阶设计对应的规范集
%                          - option.Fs 采样频率
%                          - option.PassbandFrequency     通带频率
%                          - option.StopbandFrequency     阻带频率
%                          - option.DesignMethod     设计方法,选项: 'butter'、'cheby1'、'cheby2'、'ellip'
%       -'bandpassfir'     FIR带通滤波器,采用'window'设计方法对应的规范集,需要设置的参数包括:
%                          - option.order 滤波器阶数
%                          - option.CutoffFrequency1,... %通带起始频率
%                          - option.CutoffFrequency2,... %通带结束频率
%                          - option.Fs 采样频率
%       -'bandpassiir'     IIR带通滤波器,采用最小阶设计对应的规范集
%                          - option.Fs 采样频率
%                          - option.StopbandFrequency1, ...    % 阻带起始频率
%                          - option.PassbandFrequency1, ...    % 通带起始频率
%                          - option.PassbandFrequency2, ...    % 阻带截止频率
%                          - option.StopbandFrequency2, ...    % 通带截止频率
%                          - option.DesignMethod     设计方法,选项: 'butter'、'cheby1'、'cheby2'、'ellip'
%       -'bandstopfir'     FIR带阻滤波器,采用'window'设计方法对应的规范集,需要设置的参数包括:
%                          - option.order 滤波器阶数
%                          - option.CutoffFrequency1,... %通带起始频率
%                          - option.CutoffFrequency2,... %通带结束频率
%                          - option.Fs 采样频率
%       -'bandstopiir'     IIR带阻滤波器
%                          - option.order 滤波器阶数
%                          - option.CutoffFrequency1,... %通带起始频率
%                          - option.CutoffFrequency2,... %通带结束频率
%                          - option.Fs 采样频率
%
% compFlag:是否进行延迟补偿,'on'为开启补偿,'off'为关闭补偿。-对于fir方法,开启补偿会使得滤波后的数据变短,这是由于通过时移对其数据导致的,会删除最后 delay 个采样点
%            
% 输出:
% dataOut:滤波后数据
% d:设计好的滤波器

上述函数选择了每种滤波器类型较为常用的规范集,同学们可以不用再选择恐惧症,而是把精力更多放在应用效果上。对于有进阶需求的同学,还可以在封装函数里进行二次开发,自行换用其他规范集,可以说比较灵活易用了。

需要上边这个函数文件以及测试代码的同学,可以在公众号 khscience(看海的城堡)中回复“FIR”获取。

猜你喜欢

转载自blog.csdn.net/u013066730/article/details/131263349