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

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

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

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

f ( n ) = { f ( n ) , if  ∣ f ( n ) − f ( n − 1 ) ∣ < = T H R E S H O L D f ( n − 1 ) , if  ∣ f ( n ) − f ( n − 1 ) ∣ > T H R E S H O L D f(n) = \begin{cases} f(n), & \text{if $|f(n)-f(n-1)| <= THRESHOLD$} \\ f(n-1), & \text{if $|f(n)-f(n-1)| > THRESHOLD$} \end{cases} f(n)={f(n),f(n1),if ∣f(n)f(n1)<=THRESHOLDif ∣f(n)f(n1)>THRESHOLD
上面的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)
		}
}
  1. 中位值滤波
       顾名思义,这种滤波算法就是选取一组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]);
}
  1. 算术平均滤波
       算术平均滤波即是取一组待滤波的采样值,取其算术平均值作为此组数据的有效值。其数学表达式为:
    y n = 1 N ∑ i = 1 N y i y_n = \frac{1}{N}\sum_{i=1}^N y_i\quad yn=N1i=1Nyi
    和中位值滤波一样,它的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;
}
  1. 递推平均滤波
       递推滤波算法是在算术滤波算法的基础上改进而得,可以解决采样值“浪费”这个问题。其思路为:每采样一个最新值,将其放到一列数据的队尾,然后舍去队首旧值保持队列长度不变,再计算新队列的算术平均值。数学公式为:

y n = 1 N ∑ i = 0 N − 1 y n − i y_n = \frac{1}{N}\sum_{i=0}^{N-1} y_{n-i}\quad yn=N1i=0N1yni
从上面的叙述可知:改进后的滤波算法有效地利用了每一次的采样值,这时就允许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. 加权递推平均滤波
   加权递推滤波算法是在递推平均滤波算法的基础上改进得到,普通的递推平均滤波算法在计算时给”队列“中每一个值相同的权重,而有时这种安排并不合理,有的时候我们希望在计算时给新值的权重大一些,于是,此算法应运而生。其数学公式为:
y n = ∑ i = 0 N − 1 y n − i ∗ C i , 其 中 ∑ i = 0 N − 1 C i = 1 y_n = \sum_{i=0}^{N-1} y_{n-i}*C_i\quad ,其中\sum_{i=0}^{N-1} C_i = 1 yn=i=0N1yniCi,i=0N1Ci=1
   在实际的应用中,常取 C 0 > C 1 > ⋯ > C n − 1 C_0>C_1>\cdots>C_{n-1} C0>C1>>Cn1。这种安排适用于具有滞后性的被控系统。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;
}
  1. 一阶惯性滤波
       一阶惯性滤波器本质是低通滤波器,其数学表达式为:
    y n ‾ = a ∗ x n + ( 1 − a ) ∗ y n − 1 ‾ \overline{y_n} = a * x_n + (1-a) * \overline{y_{n-1}} yn=axn+(1a)yn1
    上式中: y n ‾ \overline{y_n} yn为当前滤波器输出, x n x_n xn为本次采样值, y n − 1 ‾ \overline{y_{n-1}} yn1为滤波器输出的前一个值, a 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语言工程文件共享在公众号“24K纯学渣”上,回复“数字滤波”即可获取。

  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值