A,_常用滤波算法">
赞
踩
一.修改记录
2024-01-26修改
1.中值滤波负数时失效,补充一下。
二.修改记录
1、限幅消抖滤波法(又称程序判断滤波法)
2、中位值滤波法
3、算术平均滤波法
4.一阶滞后滤波法
5.加权递推平均滤波法
6.消抖滤波法
7、递推平均滤波法(又称滑动平均滤波法)
8、中位值平均滤波法(又称防脉冲干扰平均滤波法)
9、限幅平均滤波法
在嵌入式开发中经常会用到一些滤波算法,我整理了一些资料把这些算法封装成可以直接调用的函数,方便以后的开发,包括限幅滤波、中位值滤波法、 算术平均滤波法、一阶滞后滤波法、加权递推平均滤波法、消抖滤波法 ,其他的一些包括卡尔曼滤波什么的之后有机会再整理
- #include "filter.h"
-
- /*
- 限幅滤波
- A方法: 根据经验判断,确定两次采样允许的最大偏差值(设为A),每次检测到新值时判断: 如果本次值与上次值之差<=A,则本次值有效,如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值。
- B优点: 能有效克服因偶然因素引起的脉冲干扰。
- C缺点: 无法抑制那种周期性的干扰,平滑度差。
- A值可根据实际情况调整
- value为有效值,new_value为当前采样值
- 滤波程序返回有效的实际值
- */
-
- #define DEVIATION 10
-
- float limit_filter(float new_value)
- {
- static int num = 0;
- static float value = 0; //需要赋一个初值
- num ++;
- if(num == 1)
- value = new_value;
- else
- {
- if ( ( new_value - value > DEVIATION ) || ( value - new_value > DEVIATION ))
- return value;
- }
- return new_value;
- }
-
-
- /*
- 中位值滤波法
- A方法: 取之前采样的N次(N取奇数),把N次采样值按大小排列,取中间值为本次有效值。
- B优点: 能有效克服因偶然因素引起的波动干扰,对温度、液位的变化缓慢的被测参数有良好的滤波效果。
- C缺点: 对流量、速度等快速变化的参数不宜。
- 排序采用冒泡法 只需要移动最后一个元素即可
- */
- #define MIDDLE_FILTER_N 11
-
- float middle_filter( float new_value)
- {
- static float value_buf[MIDDLE_FILTER_N];
- float temp ;
- uint8_t count, i;
- for ( count = 0; count < MIDDLE_FILTER_N - 1; count++)
- {
- value_buf[count] = value_buf[count + 1] ;
- }
- value_buf[MIDDLE_FILTER_N - 1] = new_value;
-
- for (i = MIDDLE_FILTER_N; i > 0 ; i --)
- {
- #if 0
- if ( value_buf[i] < value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- #endif
- if(value_buf[i] > 0)
- {
- if ( value_buf[i] < value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- }
- else if(value_buf[i] < 0)
- {
- if ( value_buf[i] > value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- }
- }
- return value_buf[(MIDDLE_FILTER_N - 1) / 2];
- }
-
-
- /*
- 算术平均滤波法
- A方法: 连续取N个采样值进行算术平均运算,N值较大时:信号平滑度较高,但灵敏度较低;N值较小时:信号平滑度较低,但灵敏度较高。N值的选取:一般流量,N=12;压力:N=4。
- B优点: 适用于对一般具有随机干扰的信号进行滤波,这样信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
- C缺点: 对于测量速度较慢或要求数据计算速度较快的实时控制不适用,比较浪费RAM 。
- 无需每次求一编所有的和,减去第一个数据加上新数据
- */
-
- #define AVERAGE_N 12
-
- float average_filter(float new_value)
- {
- static float average_value_buf[AVERAGE_N];
- static float average_sum = 0;
- uint8_t count;
- average_sum -= average_value_buf[0];
- for ( count = 0; count < AVERAGE_N - 1; count++)
- {
- average_value_buf[count] = average_value_buf[count + 1] ;
- }
- average_value_buf[AVERAGE_N - 1] = new_value;
- average_sum += average_value_buf[11];
-
- return (average_sum /(AVERAGE_N * 1.0) );
- }
-
-
-
- /*
- 一阶滞后滤波法
- A方法: 取a=0~1,本次滤波结果=(1-a)*本次采样值+a*上次滤波结果。
- B优点: 对周期性干扰具有良好的抑制作用,适用于波动频率较高的场合。
- C缺点:相位滞后,灵敏度低,滞后程度取决于a值大小,不能消除滤波频率高于采样频率的1/2的干扰信号。
- 为加快程序处理速度假定基数为100,a=0~100
- */
-
- #define FIRST_LAG_PROPORTION 0.4
-
- float first_order_lag_filter( float new_value)
- {
- static float first_order_value , first_order_last_value;
- first_order_value = first_order_last_value;
- first_order_last_value = new_value;
- return (1 - FIRST_LAG_PROPORTION) * first_order_value + FIRST_LAG_PROPORTION * new_value;
- }
-
-
- /*
- 加权递推平均滤波法
- A方法: 是对递推平均滤波法的改进,即不同时刻的数据加以不同的权,通常是,越接近现时刻的资料,权取得越大,给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低。
- B优点: 适用于有较大纯滞后时间常数的对象和采样周期较短的系统。
- C缺点: 对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号,不能迅速反应系统当前所受干扰的严重程度,滤波效果差。
- coe数组为加权系数表,存在程序存储区。
- */
-
- #define WEIGHT_AVERAGE_N 12
-
-
-
- uint8_t coe[WEIGHT_AVERAGE_N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- uint8_t sum_coe = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12;
-
- float weighted_filter(float new_value)
- {
- static float weight_average_buf[WEIGHT_AVERAGE_N];
- uint8_t count;
- float sum = 0;
- for ( count = 0; count < AVERAGE_N - 1 ; count++)
- {
- weight_average_buf[count] = weight_average_buf[count+ 1] ;
- }
- weight_average_buf[AVERAGE_N - 1] = new_value;
-
- for (count = 0 ; count < WEIGHT_AVERAGE_N; count++)
- sum += weight_average_buf[count] * coe[count];
- return (sum / (sum_coe * 1.0));
- }
-
- /*
- 消抖滤波法
- A方法: 设置一个滤波计数器,将每次采样值与当前有效值比较: 如果采样值=当前有效值,则计数器清零。如果采样值<>当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出),如果计数器溢出,则将本次值替换当前有效值,并清计数器。
- B优点: 对于变化缓慢的被测参数有较好的滤波效果,可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动。
- C缺点: 对于快速变化的参数不宜,如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统。
- */
-
- #define SHAKE_N 12
-
- float shake_filter( float new_value , float now_value)
- {
- static uint8_t count = 0;
- if(now_value != new_value)
- {
- count++;
- if (count >= SHAKE_N)
- {
- count = 0;
- return new_value;
- }
- }
- return now_value;
- }
-
-
本文链接:几种常用的滤波算法_给定系统函数如何进行滤波-CSDN博客
instance analysis1:限幅滤波:
- #include <stdio.h>
-
- /*
- 限幅滤波
- A方法: 根据经验判断,确定两次采样允许的最大偏差值(设为A),每次检测到新值时判断: 如果本次值与上次值之差<=A,则本次值有效,如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值。
- B优点: 能有效克服因偶然因素引起的脉冲干扰。
- C缺点: 无法抑制那种周期性的干扰,平滑度差。
- A值可根据实际情况调整
- value为有效值,new_value为当前采样值
- 滤波程序返回有效的实际值
- */
- #define DEVIATION 10
-
- float limit_filter(float new_value)
- {
- static int num = 0;
- static float value = 0; //需要赋一个初值
- num ++;
- if(num == 1)
- value = new_value;
- else
- {
- if ( ( new_value - value > DEVIATION ) || ( value - new_value > DEVIATION ))
- return value;
- }
- return new_value;
- }
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,65536,13,31,15,16,17,68,15};
- for(i = 0; i < 10; i++)
- {
- result = limit_filter(a[i]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
65536大幅度值确实可以过滤
instance analysis2:中位值滤波法
- #include <stdio.h>
-
- /*
- 中位值滤波法
- A方法: 取之前采样的N次(N取奇数),把N次采样值按大小排列,取中间值为本次有效值。
- B优点: 能有效克服因偶然因素引起的波动干扰,对温度、液位的变化缓慢的被测参数有良好的滤波效果。
- C缺点: 对流量、速度等快速变化的参数不宜。
- 排序采用冒泡法 只需要移动最后一个元素即可
- */
- #define MIDDLE_FILTER_N 11
-
- float middle_filter( float new_value)
- {
- static float value_buf[MIDDLE_FILTER_N];
- float temp ;
- unsigned char count, i;
- for ( count = 0; count < MIDDLE_FILTER_N - 1; count++)
- {
- value_buf[count] = value_buf[count + 1] ;
- }
- value_buf[MIDDLE_FILTER_N - 1] = new_value;
-
- //for (i = MIDDLE_FILTER_N; i > 0 ; i --)
- for (i = MIDDLE_FILTER_N-1; i > 0 ; i --)
- {
- #if 0
- if ( value_buf[i] < value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- #endif
- if(value_buf[i] > 0)
- {
- if ( value_buf[i] < value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- }
- else if(value_buf[i] < 0)
- {
- if ( value_buf[i] > value_buf[i - 1] )
- {
- temp = value_buf[i];
- value_buf[i] = value_buf[i - 1];
- value_buf[i - 1] = temp;
- }
- }
- }
- return value_buf[(MIDDLE_FILTER_N - 1) / 2];
- }
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,65536,13,31,15,16,17,68,15};
- for(i = 0; i < 10; i++)
- {
- result = middle_filter(a[i]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
打印截图:
瞬间变化值不易过滤
instance analysis3 算术平均滤波法:
- #include <stdio.h>
-
- /*
- 算术平均滤波法
- A方法: 连续取N个采样值进行算术平均运算,N值较大时:信号平滑度较高,但灵敏度较低;N值较小时:信号平滑度较低,但灵敏度较高。N值的选取:一般流量,N=12;压力:N=4。
- B优点: 适用于对一般具有随机干扰的信号进行滤波,这样信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
- C缺点: 对于测量速度较慢或要求数据计算速度较快的实时控制不适用,比较浪费RAM 。
- 无需每次求一编所有的和,减去第一个数据加上新数据
- */
-
- #define AVERAGE_N 12
-
- float average_filter(float new_value)
- {
- static float average_value_buf[AVERAGE_N];
- static float average_sum = 0;
- unsigned char count;
- average_sum -= average_value_buf[0];
- for ( count = 0; count < AVERAGE_N - 1; count++)
- {
- average_value_buf[count] = average_value_buf[count + 1] ;
- }
- average_value_buf[AVERAGE_N - 1] = new_value;
- average_sum += average_value_buf[11];
-
- return (average_sum /(AVERAGE_N * 1.0) );
- }
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,65536,13,31,15,16,17,68,15};
- for(i = 0; i < 10; i++)
- {
- result = average_filter(a[i]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
第3个值改为65536
天啊,拉高了整体平均值。对有突变的大值不适用。
instance analysis4 一阶滞后滤波法:
- #include <stdio.h>
-
- /*
- 一阶滞后滤波法
- A方法: 取a=0~1,本次滤波结果=(1-a)*本次采样值+a*上次滤波结果。
- B优点: 对周期性干扰具有良好的抑制作用,适用于波动频率较高的场合。
- C缺点:相位滞后,灵敏度低,滞后程度取决于a值大小,不能消除滤波频率高于采样频率的1/2的干扰信号。
- 为加快程序处理速度假定基数为100,a=0~100
- */
-
- #define FIRST_LAG_PROPORTION 0.4
-
- float first_order_lag_filter( float new_value)
- {
- static float first_order_value , first_order_last_value;
- first_order_value = first_order_last_value;
- first_order_last_value = new_value;
- return (1 - FIRST_LAG_PROPORTION) * first_order_value + FIRST_LAG_PROPORTION * new_value;
- }
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,65,13,31,15,16,17,68,15};
- for(i = 0; i < 10; i++)
- {
- result = first_order_lag_filter(a[i]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
一般值可以,大值还是有点吓人。
instance analysis5 加权递推平均滤波法:
- #include <stdio.h>
- #include <stdint.h>
- /*
- 加权递推平均滤波法
- A方法: 是对递推平均滤波法的改进,即不同时刻的数据加以不同的权,通常是,越接近现时刻的资料,权取得越大,给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低。
- B优点: 适用于有较大纯滞后时间常数的对象和采样周期较短的系统。
- C缺点: 对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号,不能迅速反应系统当前所受干扰的严重程度,滤波效果差。
- coe数组为加权系数表,存在程序存储区。
- */
-
- #define WEIGHT_AVERAGE_N 12
-
- uint8_t coe[WEIGHT_AVERAGE_N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- uint8_t sum_coe = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12;
-
- float weighted_filter(float new_value)
- {
- static float weight_average_buf[WEIGHT_AVERAGE_N];
- uint8_t count;
- float sum = 0;
- for ( count = 0; count < WEIGHT_AVERAGE_N - 1 ; count++)
- {
- weight_average_buf[count] = weight_average_buf[count+ 1] ;
- }
- weight_average_buf[WEIGHT_AVERAGE_N - 1] = new_value;
-
- for (count = 0 ; count < WEIGHT_AVERAGE_N; count++)
- sum += weight_average_buf[count] * coe[count];
- return (sum / (sum_coe * 1.0));
- }
-
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,25,13,31,15,16,17,68,15};
- for(i = 0; i < 10; i++)
- {
- result = weighted_filter(a[i]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
第3个值改为255
instance analysis6 消抖滤波法:
- #include <stdio.h>
- #include <stdint.h>
-
- /*
- 消抖滤波法
- A方法: 设置一个滤波计数器,将每次采样值与当前有效值比较: 如果采样值=当前有效值,则计数器清零。如果采样值 >当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出),如果计数器溢出,则将本次值替换当前有效值,并清计数器。
- B优点: 对于变化缓慢的被测参数有较好的滤波效果,可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动。
- C缺点: 对于快速变化的参数不宜,如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统。
- */
-
- #define SHAKE_N 12
-
- float shake_filter( float new_value , float now_value)
- {
- static uint8_t count = 0;
- if(now_value != new_value)
- {
- count++;
- if (count >= SHAKE_N)
- {
- count = 0;
- return new_value;
- }
- }
- return now_value;
- }
-
- int main()
- {
- int i = 0;
- float result = 0;
- int a[10] = {15,11,255,13,31,15,16,17,68,15};
- for(i = 0; i < 9; i++)
- {
- result = shake_filter(a[0],a[i+1]);
- printf("result:%f \n", result);
- }
-
- return 0;
- }
总结:滤波各有各的长度和不足,需要使用组合滤波。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。