数字滤波算法汇总与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}
上面的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
    和中位值滤波一样,它的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
从上面的叙述可知:改进后的滤波算法有效地利用了每一次的采样值,这时就允许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
   在实际的应用中,常取 C 0 > C 1 > > C n 1 C_0>C_1>\cdots>C_{n-1} 。这种安排适用于具有滞后性的被控系统。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}}
    上式中: y n \overline{y_n} 为当前滤波器输出, x n x_n 为本次采样值, y n 1 \overline{y_{n-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语言工程文件共享在公众号“24K纯学渣”上,回复“数字滤波”即可获取。

发布了25 篇原创文章 · 获赞 9 · 访问量 6195

猜你喜欢

转载自blog.csdn.net/qq_42144047/article/details/103928010