Arduino玩转ArduinoArduino 专题学习

五大滤波算法原理、场景及实践

2020-01-03  本文已影响0人  Bing的天涯路

在传感器采集数据的过程中,难免因为各种各样的干扰产生异常值,滤波分为电路滤波和算法滤波。电路滤波是从源头上解决(缓解)问题,但是使用成本比较高,即使使用了电路滤波也是不能保证每次采集的数据都是准确的,因为在实际的工作状态中遇到的干扰各种各样,算法滤波的成本比较低,基本思想是采集多次数据对这些采集的数据进行处理最后选择(或计算)出一个可靠的数据放入数据库,要注意算法滤波需要建立在电路滤波的基础上,因此将两者结合起来才能够保证每次写入数据库的数据是可靠的。

限幅滤波法(又称程序判断滤波法)

A、思路: 根据经验判断,确定两次采样允许的最大偏差值(设为A),每次检测到新值时判断:如果本次值与上次值之差<=A,则本次值有效,如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值。
B、优点: 能有效克服因偶然因素引起的脉冲干扰。
C、缺点: 无法抑制那种周期性的干扰。 平滑度差。

int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Value = Filter_Value;          // 最近一次有效采样的值,该变量为全局变量
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 限幅滤波法(又称程序判断滤波法)
#define FILTER_A 1
int Filter() {
  int NewValue;
  NewValue = Get_AD();
  if(((NewValue - Value) > FILTER_A) || ((Value - NewValue) > FILTER_A))
    return Value;
  else
    return NewValue;
}

中位值滤波法

A、方法:

连续采样N次(N取奇数),把N次采样值按大小排列,

取中间值为本次有效值。

B、优点:

能有效克服因偶然因素引起的波动干扰;

对温度、液位的变化缓慢的被测参数有良好的滤波效果。

C、缺点:

对流量、速度等快速变化的参数不宜。

int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 中位值滤波法
#define FILTER_N 101
int Filter() {
  int filter_buf[FILTER_N];
  int i, j;
  int filter_temp;
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = Get_AD();
    delay(1);
  }
  // 采样值从小到大排列(冒泡法)
  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;
      }
    }
  }
  return filter_buf[(FILTER_N - 1) / 2];
}

算术平均滤波法

A、方法:

连续取N个采样值进行算术平均运算:

N值较大时:信号平滑度较高,但灵敏度较低;

N值较小时:信号平滑度较低,但灵敏度较高;

N值的选取:一般流量,N=12;压力:N=4。

B、优点:

适用于对一般具有随机干扰的信号进行滤波;

这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。

C、缺点:

对于测量速度较慢或要求数据计算速度较快的实时控制不适用;

比较浪费RAM。

int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 算术平均滤波法
#define FILTER_N 12
int Filter() {
  int i;
  int filter_sum = 0;
  for(i = 0; i < FILTER_N; i++) {
    filter_sum += Get_AD();
    delay(1);
  }
  return (int)(filter_sum / FILTER_N);
}

一阶滞后滤波法

A、方法:

取a=0-1,本次滤波结果=(1-a)本次采样值+a上次滤波结果。

B、优点:

对周期性干扰具有良好的抑制作用;

适用于波动频率较高的场合。

C、缺点:

相位滞后,灵敏度低;

滞后程度取决于a值大小;

不能消除滤波频率高于采样频率1/2的干扰信号。

int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 一阶滞后滤波法
#define FILTER_A 0.01
int Filter() {
  int NewValue;
  NewValue = Get_AD();
  Value = (int)((float)NewValue * FILTER_A + (1.0 - FILTER_A) * (float)Value);
  return Value;
}

限幅消抖滤波法

A、方法:

相当于“限幅滤波法”+“消抖滤波法”;

先限幅,后消抖。

B、优点:

继承了“限幅”和“消抖”的优点;

改进了“消抖滤波法”中的某些缺陷,避免将干扰值导入系统。

C、缺点:

对于快速变化的参数不宜。

int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 限幅消抖滤波法
#define FILTER_A 1
#define FILTER_N 5
int i = 0;
int Filter() {
  int NewValue;
  int new_value;
  NewValue = Get_AD();
  if(((NewValue - Value) > FILTER_A) || ((Value - NewValue) > FILTER_A))
    new_value = Value;
  else
    new_value = NewValue;
  if(Value != new_value) {
    i++;
    if(i > FILTER_N) {
      i = 0;
      Value = new_value;
    }
  }
  else
    i = 0;
  return Value;
}

本文作者熊冰,个人网站Bing的天涯路,转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读