vlambda博客
学习文章列表

数字滤波算法汇总与C语言实现

滤波是信号分析与处理过程中的一个非常重要的环节,滤波的效果的好坏可以直接影响后续一系列的对信号的处理效果。滤波可以分为硬件滤波和数字滤波。后者由于稳定性好、灵活性高、成本低的优势,在一些含有微机的控制系统中获得了极为广泛的应用。本文主要总结并比较几种常用的数字滤波技术,并给出它们的C语言实现。


为了便于叙述,我们假设滤波器的输入为采样器的输出,滤波器的输出视为有效信号。


 1. 限幅滤波


所谓限幅滤波,就是指当某个值比着它上一个值相差较大时,我们把这个值视为有噪声干扰引起的异常值,这时我们用上一个值代替这个异常值。用数学表达式表示即为:


上面的THRESHOLD为阈值,一般根据实际情况人为设定。这种滤波算法可以有效地过滤到超低频的、干扰性强的、偶然发生的噪声信号。C语言实现如下:


float LimitAmpFilter(float PreVal,float NowVal,float thresh){ if(fabs(PreVal-NowVal) <= thresh) { return NowVal; //f(n) } else { return PreVal; //f(n-1) }}



 2. 中位值滤波


顾名思义,这种滤波算法就是选取一组n个离散采样信号,先按大小排序,然后取其中位值作为这一组数据的有效值。很明显,每组数据这种算法会舍弃n-1个采样值,只保留一个,所以n值不宜过大,否则计算量会很大,n一般取奇数3或5即可。这种滤波算法也能有效地过滤掉偶然的、低频的噪声信号。C语言实现如下:


void Insert_sort(float *Arr,u8 n)//Arr是数组名,n表示数组长度,插入排序。{ u8 i,j,k; for(i=1;i<n;i++)  { k = Arr[i]; j = i-1; while(j>=0 && k<Arr[j])  { Arr[j+1] = Arr[j]; j--; } Arr[j+1] = k; } return;}

float MidianFilter(float val[],u8 len){ Insert_sort(val,len); return (val[len/2]);}



 3. 算术平均滤波


算术平均滤波即是取一组待滤波的采样值,取其算术平均值作为此组数据的有效值。其数学表达式为:

数字滤波算法汇总与C语言实现


和中位值滤波一样,它的n值也不可设置的过大。不过,这种算法可以有效地过滤掉某些周期性干扰信号。C语言实现如下:


float AverageFilter(float val[],u8 len){ u8 i = 0; float res = 0.0; for(;i<len;i++) { res += (val[i]/len); } return res;}



 4. 递推平均滤波


递推滤波算法是在算术滤波算法的基础上改进而得,可以解决采样值“浪费”这个问题。其思路为:每采样一个最新值,将其放到一列数据的队尾,然后舍去队首旧值保持队列长度不变,再计算新队列的算术平均值。数学公式为:

数字滤波算法汇总与C语言实现


从上面的叙述可知:改进后的滤波算法有效地利用了每一次的采样值,这时就允许n比着普通的算术平均滤波算法大一些。C语言实现如下:


float AverageFilter(float val[],u8 len){ u8 i = 0; float res = 0.0; for(;i<len;i++) { res += (val[i]/len); } return res;}



递推平均滤波器又叫滑动滤波器,但它的本质还是同权重地计算一组数的算术平均值,所以此段程序与上面的算术平均滤波算法相同,二者的差别将体现在形参中的浮点型数组上。


 5. 加权递推平均滤波


加权递推滤波算法是在递推平均滤波算法的基础上改进得到,普通的递推平均滤波算法在计算时给”队列“中每一个值相同的权重,而有时这种安排并不合理,有的时候我们希望在计算时给新值的权重大一些,于是,此算法应运而生。其数学公式为:


在实际的应用中,C的下标越小,C值越大。这种安排适用于具有滞后性的被控系统。C语言实现:


float WeightedAverFilter(float val[],float wht[],u8 len){ u8 i = 0; float res = 0.0; for(;i<len;i++) { res += (val[len-1-i]*wht[i]); } return res;}



 6. 一阶惯性滤波

一阶惯性滤波器本质是低通滤波器,其数学表达式为:


上式中:y输出为当前滤波器输出,Xn为本次采样值,yn-1为滤波器输出的前一个值,a为滤波系数。a的大小会影响系统的灵敏度和平稳性:a越小,滤波器当前输出受上一次滤波输出影响越严重,这会降低系统的灵敏性;反之,a越大,滤波效果会变差。实际应用中,我们可以根据这一特性调试出一个最佳的a值。C语言程序:


float FirstOrderInertialFilter(float SamVal,float PreVal,float coe) //coe为加权系数{ float res = 0.0; res = coe * SamVal + (1-coe) * PreVal; return res;}



为了测试上面的几种算法效果,以stm32为例,利用其ADC、DMA、串口等外设,对模拟电压测量,并通过串口将滤波前后的信号发送到上位机,绘制时域曲线观察、对比并分析结果。上面的stm32完整的C语言工程文件,回复“数字滤波”即可获取。