# 限幅滤波法(又称程序判断滤波法)
# A、方法:
- 根据经验判断,确定两次采样允许的最大偏差值(假设设为 A)
- 每次检测到新值时判断:
如果本次值与上次值之差 <= A, 则本次值有效
如果本次值与上次值之差 > A,则本次值无效,放弃本次值,用上次值代替本次值
# B、优点:
- 能有效克服因偶然因素引起的脉冲干扰
# C、缺点:
- 无法抑制那种周期性的干扰
- 平滑度差
# D、代码:
#if LIMITING | |
Data_Typedef Limiting_Filter( Data_Typedef Value, int Range ) | |
{ | |
Data_Typedef new_value; | |
new_value = Get_AD(); | |
DUBUG_PRINTF("A%f\r\n", new_value); | |
if((new_value - Value > Range) | |
|| (Value - new_value > Range)) | |
{ | |
return Value; | |
} | |
return new_value; | |
} | |
#endif /* LIMITING */ |
# 中位值滤波法
# A、方法:
- 连续采样 N 次(N 取奇数)
- 把 N 次采样值按大小排列
- 取中间值为本次有效值
# B、优点:
- 能有效克服因偶然因素引起的波动干扰
- 对温度、液位的变化缓慢的被测参数有良好的滤波效果
# C、缺点:
- 对流量、速度等快速变化的参数不宜
# D、代码:
#if MEDIAN | |
Data_Typedef Median_Filter( int Count ) | |
{ | |
int i,j; | |
Data_Typedef temp; | |
Data_Typedef *str; | |
if(0 == Count % 2) | |
Count++; | |
str = (Data_Typedef*)malloc(Count * sizeof(Data_Typedef)); | |
if(str != NULL) { | |
for(i = 0; i < Count; i++) { | |
temp = Get_AD(); | |
*(str + i) = temp; | |
DUBUG_PRINTF("A%f\r\n", temp); | |
Delay(0x10F); | |
} | |
/* 冒泡排序 */ | |
for(j = 0; j < Count - 1; j++) { | |
for(i = 0; i < Count - j - 1; i++) { | |
if(*(str + i) > *(str + i + 1)) { | |
temp = *(str + i); | |
*(str + i) = *(str + i + 1); | |
*(str + i + 1) = temp; | |
} | |
} | |
} | |
} else { | |
return -1; | |
} | |
temp = *(str + (Count-1)/2); | |
free(str); | |
return temp; | |
} | |
#endif /* MEDIAN */ |
# 算术平均滤波法
# A、方法:
- 连续取 N 个采样值进行算术平均运算
- N 值较大时:信号平滑度较高,但灵敏度较低
- N 值较小时:信号平滑度较低,但灵敏度较高
- N 值的选取:一般流量,N=12;压力:N=4
# B、优点:
- 适用于对一般具有随机干扰的信号进行滤波
- 这样信号的特点是有一个平均值,信号在某一数值范围附近上下波动
# C、缺点:
- 对于测量速度较慢或要求数据计算速度较快的实时控制不适用
- 比较浪费 RAM
# D、代码:
#if MEAN | |
Data_Typedef Mean_Filter( int Count ) | |
{ | |
int i; | |
Data_Typedef temp; | |
Data_Typedef sum = 0; | |
for(i = 0; i < Count; i++) { | |
temp = Get_AD(); | |
sum += temp; | |
DUBUG_PRINTF("A%f\r\n", temp); | |
Delay(0x10F); | |
} | |
return (Data_Typedef)(sum / Count); | |
} | |
#endif /* MEAN */ |
# 递推平均滤波法
# A、方法:
- 把连续取 N 个采样值看成一个队列
- 队列的长度固定为 N
- 每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据.(先进先出原则)
- 把队列中的 N 个数据进行算术平均运算,就可获得新的滤波结果
- N 值的选取:流量,N=12;压力:N=4;液面,N=4 ~ 12; 温度,N=1 ~ 4
# B、优点:
- 对周期性干扰有良好的抑制作用,平滑度高
- 适用于高频振荡的系统
# C、缺点:
- 灵敏度低
- 对偶然出现的脉冲性干扰的抑制作用较差
- 不易消除由于脉冲干扰所引起的采样值偏差
- 不适用于脉冲干扰比较严重的场合
- 比较浪费 RAM
# D、代码:
#if RECURSIVE_MEAN | |
Data_Typedef Recursive_Mean_Filter( int Count ) | |
{ | |
static int Start = 0; | |
static int Num = 0; | |
int i; | |
Data_Typedef temp; | |
Data_Typedef sum = 0; | |
Data_Typedef *str; | |
if(0 == Start) { | |
Start = Count; | |
str = (Data_Typedef*)calloc(Count, sizeof(Data_Typedef)); | |
} else if(Start != Count) { | |
Start = Count; | |
str = (Data_Typedef*)realloc(str, Count); // 重新分配 | |
} | |
if(str != NULL) { | |
temp = Get_AD(); | |
*(str + Num++) = temp; | |
DUBUG_PRINTF("A%f\r\n", temp); | |
// 覆盖最早采样的数据,相当于递推数据 FIFO | |
if(Num >= Count) | |
Num = 0; | |
for(i = 0; i < Count; i++) { | |
sum += *(str + i); | |
} | |
} else { | |
return -1; | |
} | |
return (Data_Typedef)(sum / Count); | |
} | |
#endif /* RECURSIVE_MEAN */ |
# 中位值平均滤波法
# A、方法:
- 相当于 “中位值滤波法” + “算术平均滤波法”
- 连续采样 N 个数据,去掉一个最大值和一个最小值
- 然后计算 N-2 个数据的算术平均值
- N 值的选取:3~14
# B、优点:
- 融合了两种滤波法的优点
- 对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差
# C、缺点:
- 测量速度较慢,和算术平均滤波法一样
- 比较浪费 RAM
# D、代码:
#if MEDIAN_MEAN | |
Data_Typedef Median_Mean_Filter( int Count ) | |
{ | |
int i,j; | |
Data_Typedef temp; | |
Data_Typedef sum = 0; | |
Data_Typedef *str; | |
if(0 == Count % 2) | |
Count++; | |
str = (Data_Typedef*)malloc(Count * sizeof(Data_Typedef)); | |
if(str != NULL) { | |
for(i = 0; i < Count; i++) { | |
temp = Get_AD(); | |
*(str + i) = temp; | |
DUBUG_PRINTF("A%f\r\n", temp); | |
Delay(0x10F); | |
} | |
for(j = 0; j < Count - 1; j++) { | |
for(i = 0; i < Count - j - 1; i++) { | |
if(*(str + i) > *(str + i + 1)) { | |
temp = *(str + i); | |
*(str + i) = *(str + i + 1); | |
*(str + i + 1) = temp; | |
} | |
} | |
} | |
} else { | |
return -1; | |
} | |
/* 去除最大最小极值后求平均 */ | |
for(i = 1; i < Count - 1; i++) | |
sum += *(str + i); | |
free(str); | |
return (Data_Typedef)(sum / (Count - 2)); | |
} | |
#endif /* MEDIAN_MEAN */ |
# 限幅平均滤波法
# A、方法:
- 相当于 “限幅滤波法” + “递推平均滤波法”
- 每次采样到的新数据先进行限幅处理
- 再送入队列进行递推平均滤波处理
# B、优点:
- 融合了两种滤波法的优点
- 对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差
# C、缺点:
- 比较浪费 RAM
# D、代码:
#if LIMITING_MEAN | |
Data_Typedef Limiting_Mean_Filter( int Range, int Count ) | |
{ | |
static int Start = 0; | |
static int Num = 0; | |
static Data_Typedef Value = 0; | |
int i; | |
Data_Typedef new_value; | |
Data_Typedef sum = 0; | |
Data_Typedef *str; | |
if(0 == Start) { | |
Start = Count; | |
Value = Get_AD(); | |
str = (Data_Typedef*)calloc(Count, sizeof(Data_Typedef)); | |
} else if(Start != Count) { | |
Start = Count; | |
Value = Get_AD(); | |
str = (Data_Typedef*)realloc(str, Count); // 重新分配 | |
} | |
if(str != NULL) { | |
new_value = Get_AD(); | |
if((new_value - Value > Range) | |
|| (Value - new_value > Range)) | |
{ | |
*(str + Num++) = Value; | |
} else { | |
*(str + Num++) = new_value; | |
Value = new_value; | |
} | |
DUBUG_PRINTF("A%f\r\n", Value); | |
if(Num >= Count) | |
Num = 0; | |
for(i = 0; i < Count; i++) { | |
sum += *(str + i); | |
} | |
} else { | |
return -1; | |
} | |
return (Data_Typedef)(sum / Count); | |
} | |
#endif /* LIMITING_MEAN */ |
# 一阶滞后滤波法
# A、方法:
- 取滤波系数 a=0~1
- 本次滤波结果 =(1-a)× 上次滤波结果 + a× 本次采样值
# B、优点:
- 对周期性干扰具有良好的抑制作用
- 适用于波动频率较高的场合
# C、缺点:
- 相位滞后,灵敏度低
- 滞后程度取决于 a 值大小
- 不能消除滤波频率高于采样频率的 1/2 的干扰信号
# D、代码:
#if LOW_PASS | |
Data_Typedef Low_Pass_Filter( Data_Typedef Value, float Factor ) | |
{ | |
Data_Typedef new_value; | |
new_value = Get_AD(); | |
DUBUG_PRINTF("A%f\r\n", new_value); | |
new_value = (Data_Typedef)(new_value * Factor + (1.0f - Factor) * Value); | |
return new_value; | |
} | |
#endif /* LOW_PASS */ |
# 加权递推平均滤波法
# A、方法:
- 是对递推平均滤波法的改进,即不同时刻的数据加以不同的权
- 通常是,越接近现时刻的数据,权取得越大。
- 给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低
# B、优点:
- 适用于有较大纯滞后时间常数的对象
- 和采样周期较短的系统
# C、缺点:
- 对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号
- 不能迅速反应系统当前所受干扰的严重程度,滤波效果差
# D、代码:
#if WEIGHTED_RECURSIVE_MEAN | |
Data_Typedef Weighted_Recursive_Mean_Filter( char *Weight_factor, int Count ) | |
{ | |
static int Sum_coe; | |
static int Start = 0; | |
static int Num = 0; | |
int i; | |
Data_Typedef temp; | |
Data_Typedef sum = 0; | |
Data_Typedef *str; | |
if(0 == Start) { | |
Start = Count; | |
str = (Data_Typedef*)calloc(Count, sizeof(Data_Typedef)); | |
for(i = 0; i < Count; i++) { | |
Sum_coe += *(Weight_factor + i); | |
} | |
} else if(Start != Count) { | |
Start = Count; | |
str = (Data_Typedef*)realloc(str, Count); // 重新分配 | |
for(i = 0; i < Count; i++) { | |
Sum_coe += *(Weight_factor + i); | |
} | |
} | |
if(str != NULL) { | |
temp = Get_AD(); | |
*(str + Num++) = temp; | |
DUBUG_PRINTF("A%f\r\n", temp); | |
// 覆盖最早采样的数据,相当于递推数据 FIFO | |
if(Num >= Count) | |
Num = 0; | |
for(i = 0; i < Count; i++) { | |
sum += *(str + i) * *(Weight_factor + i); | |
} | |
} else { | |
return -1; | |
} | |
return (Data_Typedef)(sum / Sum_coe); | |
} | |
#endif /* WEIGHTED_RECURSIVE_MEAN */ |
# 消抖滤波法
# A、方法:
- 设置一个滤波计数器
- 将每次采样值与当前有效值比较:
如果采样值=当前有效值,则计数器清零
如果采样值 <> 当前有效值,则计数器 + 1,并判断计数器是否>= 上限 N (溢出)
如果计数器溢出,则将本次值替换当前有效值,并清计数器
# B、优点:
- 对于变化缓慢的被测参数有较好的滤波效果
- 可避免在临界值附近控制器的反复开 / 关跳动或显示器上数值抖动
# C、缺点:
- 对于快速变化的参数不宜
- 如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统
# D、代码:
#if DEBOUNCE | |
Data_Typedef Debounce_Filter( Data_Typedef Value, int Count ) | |
{ | |
static int Num = 0; | |
Data_Typedef new_value; | |
new_value = Get_AD(); | |
DUBUG_PRINTF("A%f\r\n", new_value); | |
if(Value != new_value) { | |
Num++; | |
if(Num > Count) { | |
Num = 0; | |
Value = new_value; | |
} | |
} | |
else | |
Num = 0; | |
return Value; | |
} | |
#endif /* DEBOUNCE */ |
# 限幅消抖滤波法
# A、方法:
- 相当于 “限幅滤波法” + “消抖滤波法”
- 先限幅,后消抖
# B、优点:
- 继承了 “限幅” 和 “消抖” 的优点
- 改进了 “消抖滤波法” 中的某些缺陷,避免将干扰值导入系统
# C、缺点:
- 对于快速变化的参数不宜
# D、代码:
#if LIMITING_DEBOUNCE | |
Data_Typedef Limiter_Debounce_Filter( Data_Typedef Value, int Range, int Count ) | |
{ | |
static int Num = 0; | |
Data_Typedef new_value; | |
new_value = Get_AD(); | |
DUBUG_PRINTF("A%f\r\n", new_value); | |
if((new_value - Value > Range) | |
|| (Value - new_value > Range)) | |
{ | |
new_value = Value; | |
} | |
if(Value != new_value) { | |
Num++; | |
if(Num > Count) { | |
Num = 0; | |
Value = new_value; | |
} | |
} | |
else | |
Num = 0; | |
return Value; | |
} | |
#endif /* LIMITING_DEBOUNCE */ |