背景知识
数字滤波常应用实时低通滤波,硬件滤波常应用于实时高通滤波。
在设计滤波算法时,应考虑采用速度、干扰类型(脉冲干扰、周期性干扰)、采用数据变化特性(如变化速度、变化方向速度)、滞后性等等因素。
数字滤波算法 | 采用输出比 | 抗毛刺干扰能力 | 抗噪声干扰能力 |
---|---|---|---|
限幅滤波 | 1:1 | 强 | 很弱 |
中值滤波 | N:1 | 较强 | 一般 |
算术平均滤波 | N:1 | 较弱 | 较强 |
去极值平均滤波 | N:1 | 较强 | 较强 |
滑动平均滤波 | 1:1 | 弱 | 较强 |
滑动加权平均滤波 | 1:1 | 弱 | 较强 |
算法设计
本文滤波算法构成:
1.filter data at power freqency
2.average without min and max val
3.handler with val out of range
4.weighted average
5.set change deadzone
6.set zero zone
注意事项
1.前期设计算法时未考虑到限幅+消抖算法,为一个败笔
2.超限处理(处理3)位置靠前,是为了后面的滤波算法提供一个有效值
3.超限处理算法是否添加计数器,有待商榷
#ifndef __AI_H__
#define __AI_H__
#include "config.h"//类型命名
#define AICHANNUMB 8
#define SAMPLE_TOTAL_NUM 8
#define WEIGHTED_ARR_SIZE 4
typedef signed short sample_t;//采样的数据类型
struct ai_data{
unsigned char type;//通道类型
sample_t up_limit;//上限值
sample_t down_limit;//下限值
sample_t up_exception_val;//输入小于下限值时,显示的值
sample_t down_exception_val;//输入大于上限值时,显示的值
int dead_zone_size;//变化死区大小 防止数据小范围跳动
int zero_val;//输入为0时,对应的值
int zero_zone_size;//零区大小
int sample_num;//去最值平均滤波的采样个数
sample_t sample_data[SAMPLE_TOTAL_NUM];//采样的数据
sample_t power_freq[SAMPLE_TOTAL_NUM/2];//工频滤波后的数据
int first_weighted;//是否为第一次加权递推平均滤波
sample_t weighted_average[WEIGHTED_ARR_SIZE];//存放历史数据
sample_t input;//最终的输入值
};
extern struct ai_data ai_data_buff[AICHANNUMB];
extern void ai_sample_data(int channo);
extern void ai_data_buff_init(void);
extern void init_channel_para(int channo, uint8 type);
#endif
/*AI.c*/
#include "AI.h"
stcAI_DATA AI_DATA_BUF[AICHANNUMB];
struct ai_data ai_data_buff[AICHANNUMB];
static void ai_data_filter(struct ai_data *buff);
static void power_freq_filter(sample_t sample_data[], sample_t power_freq[], int len);
static sample_t average_filter(sample_t sample_data[], int len);
static void weighted_average_filter(sample_t current_data, sample_t history_data[]);
void ai_data_buff_init(void)
{
int i = 0;
memset(&ai_data_buff[0], 0, sizeof(struct ai_data)*AICHANNUMB);
for(i=0; i<AICHANNUMB; i++) {
ai_data_buff[i].first_weighted = 0xff;
}
}
void init_channel_para(int channo, uint8 type)
{
ai_data_buff[channo].type = type;
switch(type) {
case 0:
return;
case 2:
ai_data_buff[channo].dead_zone_size = 5;
ai_data_buff[channo].zero_val = 0;
ai_data_buff[channo].zero_zone_size = 15;
ai_data_buff[channo].down_limit = 0;
ai_data_buff[channo].up_limit = 20000;
ai_data_buff[channo].down_exception_val = 0;
ai_data_buff[channo].up_exception_val = 20000;
break;
case 3:
ai_data_buff[channo].dead_zone_size = 5;
ai_data_buff[channo].zero_val = 0;
ai_data_buff[channo].zero_zone_size = 25;
ai_data_buff[channo].down_limit = 0;
ai_data_buff[channo].up_limit = 20000;
ai_data_buff[channo].down_exception_val = 0;
ai_data_buff[channo].up_exception_val = 20000;
break;
case 4:
ai_data_buff[channo].dead_zone_size = 3;
ai_data_buff[channo].zero_val = 0;
ai_data_buff[channo].zero_zone_size = 5;
ai_data_buff[channo].down_limit = -500;
ai_data_buff[channo].up_limit = 1500;
ai_data_buff[channo].down_exception_val = 32767;
ai_data_buff[channo].up_exception_val = 32767;
break;
default:
break;
}
}
void ai_sample_data(int channo)
{
sample_t sample_data = read_input();
ai_data_buff[channo].sample_data[ai_data_buff[channo].sample_num] = sample_data;
ai_data_buff[channo].sample_num++;
if(ai_data_buff[channo].sample_num >= SAMPLE_TOTAL_NUM) {
ai_data_buff[channo].sample_num = 0;
ai_data_filter(&ai_data_buff[channo]);
}
}
/*
*brief Function: data filter
1.filter data at power freqency
2.average without min and max val
3.handler with val out of range
4.weighted average
5.set change deadzone
6.set zero zone
*/
void ai_data_filter(struct ai_data *buff)
{
int i = 0;
int weighted_arr_len = sizeof(buff->weighted_average)/sizeof(sample_t);
sample_t average = 0;
sample_t curr_input = 0;
sample_t last_input = buff->input;
int dead_zone_size = buff->dead_zone_size;
int zero_zone_size = buff->zero_zone_size;
int zero_val = buff->zero_val;
power_freq_filter(buff->sample_data, buff->power_freq, sizeof(buff->power_freq)/sizeof(sample_t));
average = average_filter(buff->power_freq, sizeof(buff->power_freq)/sizeof(sample_t));
if(average < buff->down_limit) {
buff->input = buff->down_exception_val;
return;
}
if(average > buff->up_limit) {
buff->input = buff->up_exception_val;
return;
}
if(buff->first_weighted != 0) {
buff->first_weighted = 0;
for(i=0; i<weighted_arr_len; i++)
buff->weighted_average[i] = average;
buff->input = average;
return;
}
weighted_average_filter(average, buff->weighted_average);
curr_input = buff->weighted_average[weighted_arr_len -1];
if((curr_input > last_input-dead_zone_size) && (curr_input < last_input+dead_zone_size))
curr_input = last_input;
if((curr_input < zero_val+zero_zone_size) && (curr_input > zero_val - zero_zone_size))
curr_input = buff->zero_val;
buff->weighted_average[weighted_arr_len-1] = curr_input;
buff->input = curr_input;
}
void power_freq_filter(sample_t sample_data[], sample_t power_freq[], int len)
{
int i = 0;
for(i=0; i<len; i++)
power_freq[i] = (sample_data[2*i] + sample_data[2*i+1])/2;
}
sample_t average_filter(sample_t sample_data[], int len)
{
int total = sample_data[0];
int i = 0;
sample_t max = sample_data[0];
sample_t min = sample_data[0];
for(i=1; i < len; i++) {
if(sample_data[i] < min)
min = sample_data[i];
if(sample_data[i] > max)
max = sample_data[i];
total += sample_data[i];
}
return (total-min-max)/(len-2);
}
void weighted_average_filter(sample_t current_data, sample_t history_data[])
{
int i = 0;
int len = WEIGHTED_ARR_SIZE;
int weight[10] = {0};//??
int total_weight = 0;//???
int total_sample_data = 0;
weight[0] = 1;
total_weight += weight[0];
for(i=1; i<len; i++) {
weight[i] = weight[i-1]*2;
total_weight += weight[i];
}
for(i=0; i<len-1; i++)
history_data[i] = history_data[i+1];
for(i=0; i<len-1; i++)
total_sample_data += history_data[i] * weight[i];
total_sample_data += current_data * weight[len-1];
history_data[len-1] = (sample_t)(total_sample_data/total_weight);
}