目录
1.前言
1.1 应用场景
嵌入式系统设备进行数据采集时,会遇到数据的随机误差。
随机误差是由随机干扰引起的,其特点是在相同条件下测量同一量时,其大小和符号会现无规则的变化而无法预测,但多次测量的结果符合统计规律。
为克服随机干扰引起的误差,硬件上可采用滤波技术(R\L\C组合成的滤波电路),软件上可采用软件算法实现数字滤波。
1.2 算法优势
(1)数字滤波无需其他的硬件成本,只用一个计算过程,可靠性高,不存在阻抗匹配问题。尤其是数字滤波可以对频率很低的信号进行滤波,这是模拟滤波器做不到的。
(2)数字滤波使用软件算法实现,多输入通道可共用一个滤波程序,降低系统开支。
(3)只要适当改变滤波器的滤波程序或运算,就能方便地改变其滤波特性,这对于滤除低频干扰和随机信号会有较大的效果。
2.常用滤波算法
2.1 限幅滤波算法
- 思想:
将两次相邻的采样相减,求出其增量,然后将增量的绝对值,与两次采样允许的最大差值A进行比较。A的大小由被测对象的具体情况而定,如果小于或等于允许的最大差值,则本次采样有效;否则取上次采样值作为本次数据的样本。
- 注意:
限幅滤波主要用于处理变化较为缓慢的数据,如温度、物体的位置等。使用时,关键要选取合适的门限值A,通常可由经验数据获得,必要时也可通过实验得到。
- 程序实现(伪代码):
#define A 200//允许的最大差值
size_t LimitingFilter(size_t (*get_data)(void))
{
static size_t last_data = 0; //记录上一次获取的数据
size_t new_data = 0;
size_t filter_out_data = 0;
new_data = get_data(); //获得新数据变量
if((new_data - last_data) > A || (last_data - new_data > A))
{
filter_out_data = last_data;
last_data = filter_out_data;
}
else
{
filter_out_data = new_data;
last_data = new_data;
}
return filter_out_data;
}
2.2 中值滤波算法
- 思想:
对某一参数连续采样N次(N一般为奇数),然后把N次采样的值按从小到大排列,再取中间值作为本次采样值,整个过程实际上是一个序列排序的过程。
- 注意:
中值滤波比较适用于去掉由偶然因素引起的波动和采样器不稳定而引起的脉动干扰。若被测量值变化比较慢,采用中值滤波法效果会比较好,但如果数据变化比较快,则不宜采用此方法。
- 程序实现(伪代码):
#define N 11 //定义获得的数据个数(奇数个)
size_t MidValFilter(size_t (*get_data)(void))
{
size_t value_buff[N]; //定义存储数据的数组
size_t count,i,j,temp;
for(count = 0; count < N; count++)
{
value_buf[count] = get_data();
delay(); //如果数据采集比较慢,那么就需要延时或中断
}
//冒泡排序
for(i = 0; i < N - 1; i++)
{
for(j = 0; j < N - 1 - i; j++ )
{
if(value_buff[i] > value_buffer[i + 1])
{
temp = value_buff[i];
value_buff[i] = value_buff[i + 1];
value_buff[i + 1] = temp;
}
}
}
return value_buff[(N-1)/2];
}
2.3 算术平均滤波算法
- 思想:
连续取N次采样值后进行算术平均。
- 注意:
算术平均滤波算法适用于对具有随机干扰的信号进行滤波。这种信号的特点是信号在某一数值附近上下波动。
信号的平均平滑程度完全到决于N值。
当N较大时,平滑度高,灵敏度低;当N较小时,平滑度低,但灵敏度高。
为了方便求平均值,N一般取4、8、16、32之类的2的整数幂,以便在程序中用右移位操作来代替除法。
- 程序实现(伪代码):
#define AVE_N 16
size_t AveFilter(size_t (*get_data)(void))
{
size_t sum = 0;
for(size_t count = 0; count < AVE_N; count++)
{
sum += get_data();
delay():
}
return (size_t)(sum / AVE_N);
}
2.4 加权平均滤波算法
- 思想:
“算术平均滤波算法”存在平滑度和灵敏度之间的矛盾。为了协调平滑度和灵敏度之间的关系,可采用加权平均滤波。它的原理是对连续N次采样值分别乘上不同的加权系数之后再求累加,加权系数一般先小后大,以突出后面若干采样的效果,加强系统对参数变化趋势的认识。各个加权系数均小于1的小数,且满足总和等于1的结束条件。这样加权运算之后的累加和即为有效采样值。设D为N个采样值的加权平均值:XN-i为第N-i次采样值;N为采样次数;Ci为加权系数。加权系数Ci体现了各种采样值在平均值中所占的比例。一般来说采样次数越靠后,取的比例越大,这样可增加新采样在平均值中所占的比重。
- 注意:
加权平均值滤波法可突出一部分信号抵制另一部分信号,以提高采样值变化的灵敏度。
- 程序实现(伪代码):
//如果在C51上实现这个算法,建议把加权系数数组的存储类型改为code,使数据存放与程序存储区,如下所示
/*
size_t code Jq[12]={1,2,3,4,5,6,7,8,9,10,11,12}; //code数组为加权系数表,存在程序存储区
size_t code JqSum=1+2+3+4+5+6+7+8+9+10+11+12;
*/
//下面写一个通式做法!
size_t Jq[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
size_t JqAveFilter(size_t (*get_data)(void), size_t *jq_coef, size_t coef_num)
{
size_t sum = 0;
size_t jq_coefficient_sum = 0;
if(!num)
{
return 0;
}
for(size_t count = 0; count < coef_num; count++)
{
sum += (jq_coef[count] * get_data());
jq_coefficient_sum += jq_coef[count];
delay();
}
return (size_t)(sum / jq_coefficient_sum);
}
2.5 滑动平均滤波算法
- 思想:
每获取一个有效采样值必须连续进行若干次采样,当采速度慢时,系统的实时得不到保证。这里介绍的滑动平均滤波算法只采样一次,将一次采样值和过去的若干次采样值一起求平均,得到的有效采样值即可投入使用。如果取N个采样值求平均,存储区中必须开辟N个数据的暂存区。每新采集一个数据便存入暂存区中,同时去掉一个最老数据,保存这N个数据始终是最新更新的数据。采用环型队列结构可以方便地实现这种数据存放方式。
- 注意:
无
- 程序实现(伪代码):
#define N 10
size_t SlideAveFilter(size_t (*get_data)(void))
{
size_t sum = 0;
static size_t i = 0;
static size_t value_buff[N] = {0};
value_buff[i++] = get_data();
if(i == N) {
sum += value_buff[i-1];
i = 0;
} else {
sum += value_buff[i];
}
return (size_t)(sum / N);
}
2.6 低通滤波算法
- 思想:
将硬件RC低通滤波器的微分方程用差分方程来表示,故可以采用软件算法来模拟硬件低通滤波的功能,经推导,低通滤波算法如下:
...........(1)
式(1)中,为本次采样值;为上次滤波输出值;a为滤波系数,其值通常原小于1;为本次滤波输出值。
由上式可以看出,本次滤波的输出值主要取决于上次滤波的输出值(注意不是上次的采样值,这和加权平均滤波是有本质区别的),本次采样值对滤波输出的贡献是比较小的,但多少有些修正作用,这种算法便模拟了具体有教大惯性的低通滤波器功能。滤波算法的截止频率可用以下式计算:
fL = a/(2pi*t) pi为圆周率3.14…
式中 a——滤波系数; t——采样间隔时间;
例如:当t=0.5s(即每秒2次),a=1/32时,fL=(1/32)/(2*3.14*0.5)=0.01Hz
当目标参数为变化很慢的物理量时,这是很有效的。另外一方面,它不能滤除高于1/2采样频率的干搅信号,本例中采样频率为2Hz,故对1Hz以上的干搅信号应采用其他方式滤除,低通滤波算法程序于加权平均滤波相似,但加权系数只有两个:a和1-a。为计算方便,a取一整数,1-a用256-a,来代替,计算结果舍去最低字节即可,因为只有两项,a和1-a,均以立即数的形式编入程序中,不另外设表格。虽然采样值为单元字节(8位A/D)。为保证运算精度,滤波输出值用双字节表示,其中一个字节整数,一字节小数,否则有可能因为每次舍去尾数而使输出不会变化。
设Yn-1存放在30H(整数)和31H(小数)两单元中,Yn存放在32H(整数)和33H(小数)中。
- 注意:
无
- 程序实现(伪代码):
无