数字滤波算法汇总与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. 算术平均滤波
算术平均滤波即是取一组待滤波的采样值,取其算术平均值作为此组数据的有效值。其数学表达式为:
和中位值滤波一样,它的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. 递推平均滤波
递推滤波算法是在算术滤波算法的基础上改进而得,可以解决采样值“浪费”这个问题。其思路为:每采样一个最新值,将其放到一列数据的队尾,然后舍去队首旧值保持队列长度不变,再计算新队列的算术平均值。数学公式为:
从上面的叙述可知:改进后的滤波算法有效地利用了每一次的采样值,这时就允许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语言工程文件,回复“数字滤波”即可获取。