经典滤波器之一:Butterworth滤波器
来源:互联网 发布:linux换行符替换 编辑:程序博客网 时间:2024/05/17 04:54
我们常说的经典滤波器是根据傅里叶分析和变换设计出来的,只允许一定频率范围内的信号成分正常通过,而阻止另一部分频率成分通过。按照最佳逼近特性或者滤波通带特性分类,主要为巴特沃斯滤波器(Butterworth)、切比雪夫滤波器(Chebyshev)、贝塞尔滤波器(Bessel)和椭圆滤波器(Elliptic)四种。每种MATLAB都有相应的函数,用起来也比较方便,但是却缺少C/C++的程序,于是自己仔细研究了每种滤波器的特性和原理,并且部分滤波器实现了C语言的代码化,接下来的时间会对这些滤波器的原理和C语言的实现进行介绍。
该系列均以低通滤波器为原型来介绍,其他类型的滤波器可以由低通滤波器通过频率变换转换得到,这里不过多介绍。低通滤波器的主要性能指标有以下几个:通带截止频率fp、阻带截止频率fs、通带衰减 ( Ap)、阻带衰减 ( As) 以及归一化频率时需要用到的-3dB的转折频率fc。
1. Butterworth滤波器原理
Butterworth滤波器因其在通带内的幅值特性具有最大平坦的特性而闻名,是四种经典滤波器中最简单的,巴特沃斯滤波器只需要两个参数表征,滤波器的阶数N和-3dB处的截止频率。其幅度平方函数为:
N是滤波器的阶数,从幅度平方函数可以看出,N阶滤波器有2N个极点,而且这2N个极点均布在一个圆上,圆的半径为,称之为Butterworth圆,Butterworth滤波器系统是一个线性系统,要使其稳定,其极点必须位于S平面的左半平面,所以取左半平面内的N个极点作为滤波器的极点,滤波器就是稳定的了,求出极点之后,计算模拟滤波器的系数as、bs,然后通过双线性变换(不懂得自行查书)由模拟域到数字域,求出系数az和bz 。最后通过差分方程就可以计算滤波结果了。
2. C语言实现
A.求阶数
公式:
代码:
N = ceil(0.5*( log10 (( pow (10, Stopband_attenuation/10) - 1)/ ( pow (10, Passband_attenuation/10) - 1)) / log10 (Stopband/Passband) ));
B.求极点
公式:代码:
for(k = 0;k <= ((2*N)-1) ; k++) {if(Cutoff*cos((2*k+N-1)*(pi/(2*N))) < 0.0) { poles[count].x = -Cutoff*cos((2*k+N-1)*(pi/(2*N)));poles[count].y = -Cutoff*sin((2*k+N-1)*(pi/(2*N))); count++; if (count == N) break; } }
C.计算模拟滤波器系数
公式:
Res[0].x = poles[0].x; Res[0].y = poles[0].y; Res[1].x = 1; Res[1].y= 0; for(count_1 = 0;count_1 < N-1;count_1++)//N个极点相乘次数 { for(count = 0;count <= count_1 + 2;count++) { if(0 == count) { Res_Save[count] = ComplexMul( Res[count], poles[count_1+1] ); } else if((count_1 + 2) == count) { Res_Save[count].x += Res[count - 1].x;Res_Save[count].y += Res[count - 1].y; } else {Res_Save[count] = ComplexMul( Res[count], poles[count_1+1] ); Res_Save[count].x += Res[count - 1].x; Res_Save[count].y += Res[count - 1].y; } } for(count = 0;count <= N;count++)//Res[i]=a(i),i越大次数越高 {Res[count].x = Res_Save[count].x; Res[count].y = Res_Save[count].y; *(a + N - count) = Res[count].x; } } *(b+N) = *(a+N);
D.双线性变换
用下式进行替换 中的s变量,得到H(z) ,然后类似上面的计算方法计算Z域的系数az和bz,其中T为采样周期,但是因为在计算中会被约去,所以简化计算,这里取1。
公式:int Count = 0,Count_1 = 0,Count_2 = 0,Count_Z = 0; double *Res, *Res_Save; Res = new double[N+1](); Res_Save = new double[N+1](); memset(Res, 0, sizeof(double)*(N+1)); memset(Res_Save, 0, sizeof(double)*(N+1)); for(Count_Z = 0;Count_Z <= N;Count_Z++){ *(az+Count_Z) = 0; *(bz+Count_Z) = 0;}for(Count = 0;Count<=N;Count++){ for(Count_Z = 0;Count_Z <= N;Count_Z++) { Res[Count_Z] = 0;Res_Save[Count_Z] = 0; } Res_Save [0] = 1; for(Count_1 = 0; Count_1 < N-Count;Count_1++)//计算(1-Z^-1)^N-Count的系数, {//Res_Save[]=Z^-1多项式的系数,从常数项开始for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++){ if(Count_2 == 0) { Res[Count_2] += Res_Save[Count_2]; } else if((Count_2 == (Count_1+1))&&(Count_1 != 0)) { Res[Count_2] += -Res_Save[Count_2 - 1]; } else { Res[Count_2] += Res_Save[Count_2] - Res_Save[Count_2 - 1]; } } for(Count_Z = 0;Count_Z<= N;Count_Z++) { Res_Save[Count_Z] = Res[Count_Z] ; Res[Count_Z] = 0; } }for(Count_1 = (N-Count); Count_1 < N;Count_1++)//计算(1-Z^-1)^N-Count*(1+Z^-1)^Count的系数, {//Res_Save[]=Z^-1多项式的系数,从常数项开始 for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++){ if(Count_2 == 0) { Res[Count_2] += Res_Save[Count_2]; } else if((Count_2 == (Count_1+1))&&(Count_1 != 0)) { Res[Count_2] += Res_Save[Count_2 - 1]; } else { Res[Count_2] += Res_Save[Count_2] + Res_Save[Count_2 - 1]; } } for(Count_Z = 0;Count_Z<= N;Count_Z++) { Res_Save[Count_Z] = Res[Count_Z] ; Res[Count_Z] = 0; } }for(Count_Z = 0;Count_Z<= N;Count_Z++){ *(az+Count_Z) += pow(2,N-Count) * (*(as+Count)) * Res_Save[Count_Z];*(bz+Count_Z) += (*(bs+Count)) * Res_Save[Count_Z]; }}//最外层for循环 for(Count_Z = N;Count_Z >= 0;Count_Z--) { *(bz+Count_Z) = (*(bz+Count_Z))/(*(az+0)); *(az+Count_Z) = (*(az+Count_Z))/(*(az+0)); }
E.由由差分方程计算滤波结果
采用滤波器直接II型结构,可以减少一半的中间缓存内存,具体代码如下:
double FiltButter(double *pdAz,//滤波器参数表1 double *pdBz,//滤波器参数表2 intnABLen,//参数序列的长度 double dDataIn,//输入数据 double *pdBuf)//数据缓冲区{inti;intnALen;int nBLen;intnBufLen;doubledOut;if( nABLen<1 )return 0.0;//根据参数,自动求取序列有效长度nALen = nABLen;for( i=nABLen-1; i; --i ){if( *(pdAz+i) != 0.0 )//从最后一个系数判断是否为0{nALen = i+1;break;}}//printf("%lf ", nALen);if( i==0 ) nALen = 0;nBLen = nABLen;for( i=nABLen-1; i; --i ){if( *(pdBz+i) != 0.0 ){nBLen = i+1;break;}}//printf("%lf ", nBLen);if( i==0 ) nBLen = 0;//计算缓冲区有效长度nBufLen = nALen;if( nALen < nBLen)nBufLen = nBLen;//滤波: 与系数a卷乘dOut = ( *pdAz ) * dDataIn; // a(0) * x(i) for( i=1; i<nALen; i++)// a(i) * w(n-i),i=1toN{dOut -= *(pdAz+i) * *(pdBuf + (nBufLen - 1) - i);} //卷乘结果保存为缓冲序列的最后一个*(pdBuf + nBufLen - 1) = dOut;//滤波: 与系数b卷乘dOut = 0.0;for( i=0; i<nBLen; i++)// b(i) * w(n-i){ dOut += *(pdBz+i) * *(pdBuf + (nBufLen - 1) - i);}//丢弃缓冲序列中最早的一个数, 最后一个数清零for( i=0; i<nBufLen-1; i++){*(pdBuf + i) = *(pdBuf + i + 1);}*(pdBuf + nBufLen - 1) = 0;//返回输出值return dOut; }VC6.0开发环境滤波结果如下:
参考资料:http://blog.csdn.net/zhoufan900428/article/details/9069475
源码地址:http://download.csdn.net/detail/zhwzhaowei/9830114
- 经典滤波器之一:Butterworth滤波器
- Matlab实现Butterworth滤波器
- butterWorth低通滤波器
- butterworth chebyshev bezier滤波器区别
- 滤波器
- 滤波器
- 滤波器
- 滤波器
- 经典滤波器设计
- 经典滤波器的设计
- 经典滤波器设计
- 卡尔曼滤波器学习之一最小二乘法
- 简单理解滤波器(入门经典)
- 域变换保边滤波器经典论文
- 什么是滤波器?
- kalman滤波器
- 滤波器设计
- 空间滤波器
- Android设备挂断电话·笔记
- android基于socket聊天的思路与常见问题
- avl的实现代码-摘自数据结构实现java版本(个人笔记整理)
- 安卓实现一个简单的导航软件
- 创业失败那天我在做什么
- 经典滤波器之一:Butterworth滤波器
- Spring学习总结——Spring实现AOP的多种方式
- 系统恢复技术-systemd初始化出现问题,如何修复
- Java解惑学习有感(五)---类之谜
- 基于一维级联快速腐蚀与膨胀算法
- Java内部类
- SE6新特性之集合Set、Map、WeakSet和WeakMap详解
- Spring实现AOP的4种方式
- Restful后台系统搭建(五)【终章】提供源码