一阶IIR滤波器的C语言设计和优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq446252221/article/details/79973441

对于N阶IIR的计算方程式为:


其中N表示滤波器的级数,当N=1的时候,其方程可以展开为如下所示:


本文的研究对象就是这个一阶方程,其中y为输出数据,x为输入数据,a和b为滤波器的系数。

x[n]为本次要滤波的输入数据,x[n-1]为上一次滤波前的输入数据,y[n-1]为上一次滤波器输出的数据。

设计这个滤波器,主要就是设计其中的系数a和b。

######################################

几乎网上的所有资料都是叫你使用matlab中的fdtool来设计参数,其实如果只是计算滤波参数,

完全不用安装matlab这个几百兆的大家伙,可以使用下面介绍的小工具完成任务:

1.直接在线计算:http://www-users.cs.york.ac.uk/~fisher/mkfilter

2.下载专用小软件ScopeIIR,官方网站:http://iowegian.com/scopeiir

3.下载专用小软件FiWiz,官方网站:http://www1.icsi.berkeley.edu/~storn/fiwiz.html

4.下载专用小软件Iowa Hill,官方网站:http://iowahills.com/8DownloadPage.html

#####################################

无论使用哪种方式计算参数,都要输入采样率,滤波器类型,滤波级数,截止频率等参数。

最后都会得到A0,A1,A2,B0,B1,B2这样的滤波器系数,直接代入到公式中计算就可以了。

默认情况下,公式中的数据用代码都是采用浮点数float或者double来计算,这样可以提高精度,
但是大量的浮点乘法计算量比较大,特别是对于主频不高的单片机而言就更为吃力;
所以我们希望可以使用定点整数以减少计算量,甚至希望用移位器和加法器来代替乘法。

下面就举一个实例来研究如何减少计算量:

我们要设计一个采样率为1000,截止频率为100,滤波器类型为Butterworth,阶数为1的IIR低通滤波器,
通过计算得到如下参数:

B[0]=+1.000000
B[1]=+1.000000
A[1]=-0.509525

(细心的人可能会发现高通滤波器和低通滤波器的区别只有B[1]这个参数,一个为+1.00,一个为-1.00)

代入公式得到:y[n]=x[n]+x[n-1]+0.509525*y[n-1]

我们优化的重点就是这个0.50952*y[n-1],利用移位法来代替小数乘法,
原理就是把小数分解为1/M[0]+1/M[1]+...的方式,其中M[n]必须为2的整数次幂,
分解的次数越多,分母越大,误差就越小,可以根据实际情况需要选择分解的精度。

分解过程:

0.509525 * 1024 = 521(注:需要更高精度,可以把1024改为2048,4096,8192.......)

=521/1024

=(512+8+1)/1024

=512/1024+8/1024+1/1024

=1/2+1/8+1/1024

所以这个公式可以改写为:y[n]=x[n]+x[n-1]+y[n-1]/2+y[n-1]/8+y[n-1]/1024

最后附上C语言代码:

/*************************************************************************************************
* 输入待滤波的数据,返回滤波后的数据
* 由于输入输出都是整型数据,为了防止数据溢出或数据太小,可以将输入数据先左/右移N位,最后返回时再右/左移N位
**************************************************************************************************/
int iir_filter(int x1)
{
    static int x0;
    static int y0;
    int y1;
    y1 = x1 + x0 + (y0>>1) + (y0>>3) + (y0>>10);
    x0 = x1;
    y0 = y1;
    return y1;
}


猜你喜欢

转载自blog.csdn.net/qq446252221/article/details/79973441