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

转载博客:https://blog.csdn.net/qq446252221/article/details/79973441?utm_medium=distribute.down_relevant_right.none-task-blog-BlogCommendFromBaidu-6.nonecase&depth_1-utm_source=distribute.down_relevant_right.none-task-blog-BlogCommendFromBaidu-6.nonecase(本文为CSDN博主「星沉地动」的原创文章,原文链接:https://blog.csdn.net/qq446252221/article/details/79973441)

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

 

一阶IIR滤波器的C语言设计和优化_第1张图片

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

 

本文的研究对象就是这个一阶方程,其中y为输出数据,x为输入数据,a和b为滤波器的系数。x[n]为本次要滤波的输入数据,x[n-1]为上一次滤波前的输入数据,y[n-1]为上一次滤波器输出的数据。设计这个滤波器,主要就是设计其中的系数a和b

 确定滤波器的系数方法有很多:下面列举了一些

但是笔者只用过matlab的fdtool来设计参数,下面一下可以尝试

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]

所以整个滤波算法就是完成对公式y[n]=x[n]+x[n-1]+0.509525*y[n-1]进行C语言编写

我们优化的重点就是这个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;
}

                  

你可能感兴趣的:(信号处理)