赞
踩
滤波是单片机开发中的重要操作,经常接触底层常常用到,比如ADC采样、控制系统、信号处理等场合,需要过滤掉一些干扰的参数。本文主要介绍常用的数值滤波算法,主要用于一些如ADC采样数据的滤波
方法:根据经验判断,确定两次采样允许的最大偏差值(设为FILTER_A),每次检测到新值时判断:
①如果本次值与上次值之差<=A,则本次值有效
②如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值
优缺点:能有效克服因偶然因素引起的脉冲干扰,但无法抑制那种周期性的干扰,平滑度差。
#define FILTER_A 1 //定义偏差值
int Filter(int NewValue,int Value) {
if(((NewValue - Value) > FILTER_A) || ((Value - NewValue) > FILTER_A))
return Value;
else
return NewValue;
}
方法:连续采样N次,只保存数据大小在中间的数值。
优缺点:对温度、液位的变化缓慢的被测参数有良好的滤波效果。对流量、速度等快速变化的参数不宜。
uint16_t GetMiddleValue( uint16_t *pusBuffer, uint8_t ucLength ) { uint8_t i; uint16_t usMiddle,usMax,usCount = 0,usPoint; while( usCount <= (ucLength/2) ) { usPoint = 0; usMax = pusBuffer[0]; for( i=1;i<ucLength;i++ ) //取最大值 { if( pusBuffer[i] > usMax ) { usMax = pusBuffer[i]; usPoint = i; } } usMiddle = usMax; pusBuffer[usPoint] = 0; //将原来的最大值变为0 usCount++; //重新循环直到一半的数据为0 } return usMiddle; }
也可以先排序再取值
uint16_t GetMiddleValue( uint16_t *pusBuffer, uint8_t ucLength ) { int i,j,filter_temp; uint16_t usMiddle,usPoint; //冒泡法 for(j = 0; j < ucLength - 1; j++) { for(i = 0; i < ucLength - 1 - j; i++) { if(pusBuffer[i] > pusBuffer[i + 1]) { filter_temp = pusBuffer[i]; pusBuffer[i] = pusBuffer[i + 1]; pusBuffer[i + 1] = filter_temp; } } } return usMiddle; }
方法:连续取N个采样值累加后求平均值
优缺点:达到平滑的作用,适用性广泛,元素越多滤波效果越好时延越高。但是对于测量速度较慢或要求数据计算速度较快的实时控制不适用;
//data[]放入一段时间里的数值,length:data数组的长度
uint16_t Average(uint16_t data[],uint16_t length)
{
uint32_t add=0;
uint16_t result;
int i;
for(i=0;i<length;i++)
{
add += data[i];
}
result=add/length;
return result;
}
方法:把连续取得的N个采样值看成一个队列,队列的长度固定为N,每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据,把新的队列中的N个数据进行算术平均运算,获得新的滤波结果。
优缺点:对周期性干扰有良好的抑制作用,平滑度高;但是不易消除由于脉冲干扰所引起的采样值偏差,不适用于脉冲干扰比较严重的场合;
#define FILTER_N 12
int filter_buf[FILTER_N + 1];
int Filter(int NewValue) {
int i;
int filter_sum = 0;
filter_buf[FILTER_N] = NewValue; //新的采集值放入数组
for(i = 0; i < FILTER_N; i++) {
filter_buf[i] = filter_buf[i + 1]; // 所有数据左移,低位仍掉
filter_sum += filter_buf[i];
}
return (int)(filter_sum / FILTER_N);
}
方法: 相当于“中位值滤波法”+“算术平均滤波法”。先采N个数据去掉最大值和最小值后取平均值,然后计算这N-2个数据的算术平均值。
优缺点: 对于偶然出现的脉冲性干扰,可消除由其所引起的采样值偏差,对周期干扰有良好的抑制作用,平滑度高,适于高频振荡的系统。但是计算速度慢,加大CPU开销
①直接找极值
#define FILTER_N 100 int filter_buf[FILTER_N]; /*给filter_buf[]赋值*/ int Filter() { int i; int filter_sum = 0; int filter_max, filter_min; filter_max = filter_buf[0]; filter_min = filter_buf[0]; filter_sum = filter_buf[0]; for(i = FILTER_N - 1; i > 0; i--) { if(filter_buf[i] > filter_max) filter_max=filter_buf[i]; else if(filter_buf[i] < filter_min) filter_min=filter_buf[i]; filter_sum = filter_sum + filter_buf[i]; filter_buf[i] = filter_buf[i - 1]; } filter_sum = (filter_sum - filter_max - filter_min) / (FILTER_N - 2); return filter_sum; }
②先排序,后去极值
#define FILTER_N 100 int filter_buf[FILTER_N]; /*给filter_buf[]赋值*/ int Filter(int NewValue) { int i, j; int filter_temp, filter_sum = 0; filter_buf[FILTER_N-1] = NewValue; //新数据给队列 // 采样值从小到大排列(冒泡法) for(j = 0; j < FILTER_N - 1; j++) { for(i = 0; i < FILTER_N - 1 - j; i++) { if(filter_buf[i] > filter_buf[i + 1]) { filter_temp = filter_buf[i]; filter_buf[i] = filter_buf[i + 1]; filter_buf[i + 1] = filter_temp; } } } // 去除最大最小极值后求平均 for(i = 1; i < FILTER_N - 1; i++) filter_sum += filter_buf; return filter_sum / (FILTER_N - 2); }
方法:相当于“限幅滤波法”+“递推平均滤波法”。每次采样到的新数据先进行限幅处理,再送入队列进行递推平均滤波处理。
优缺点: 对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差。但是CPU开销大
#define FILTER_A 1
int Filter(int NewValue) {
int i;
int filter_sum = 0;
filter_buf[FILTER_N - 1] = NewValue;
//限幅
if(((filter_buf[FILTER_N - 1] - filter_buf[FILTER_N - 2]) > FILTER_A) || ((filter_buf[FILTER_N - 2] - filter_buf[FILTER_N - 1]) > FILTER_A))
filter_buf[FILTER_N - 1] = filter_buf[FILTER_N - 2];
//求平均
for(i = 0; i < FILTER_N - 1; i++) {
filter_buf[i] = filter_buf[i + 1];
filter_sum += filter_buf[i];
}
return (int)filter_sum / (FILTER_N - 1);
}
方法:取一个滤波系数a(范围0-1),本次滤波结果 = a×本次采样值 + (1-a)×上次滤波结果
优缺点:对周期性干扰具有良好的抑制作用,适用于波动频率较高的场合。但是相位滞后,灵敏度低,滞后程度取决于a值大小,不能消除滤波频率高于采样频率1/2的干扰信号。
#define FILTER_A 0.01 //滤波系数
int Value;
/*给Value赋值*/
int Filter(int NewValue) {
Value = (int)((float)NewValue * FILTER_A + (1.0 - FILTER_A) * (float)Value);
return Value;
}
方法:在均值滤波的基础上,加上比例系数,最新的数据具有更大的比例,增加时效性。
优缺点:适用于有较大纯滞后时间常数的对象,和采样周期较短的系统。但是对于纯滞后时间常数较小、采样周期较长、变化缓慢的信号,不能迅速反应系统当前所受干扰的严重程度,滤波效果差。
#define PROPORTIONNEW 0.55
#define PROPORTIONMID 0.35
#define PROPORTIONLAST (1- PROPORTIONNEW -PROPORTIONMID )
double LowPassFilter_Silding(double dataNewest,double dataMiddle,double dataLast)
{
double result;
result = PROPORTIONNEW *dataNewest+ PROPORTIONMID *dataMiddle+PROPORTIONLAST *dataLast;
return result;
}
方法:设置一个滤波计数器,将每次采样值与当前有效值比较:
如果采样值=当前有效值,则计数器清零;
如果采样值<或>当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出);
如果计数器溢出,则将本次值替换当前有效值,并清计数器。
优缺点: 对于变化缓慢的被测参数有较好的滤波效果,可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动。但是对于快速变化的参数不宜,如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统。
#define FILTER_N 12
int i = 0;
int value = 3;//设置有效值
int Filter(int new_value) {
if(Value != new_value) {
i++;
if(i > FILTER_N) {
i = 0;
Value = new_value;
}
}
else i = 0;
return Value;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。