滑动平均值滤波是指先在RAM中建立一个数据缓冲区,依顺序存放N个采样数据,每采进一个新数据,就将最早采集的那个数据丢掉,而后求包括新数据在内的N个数据的算术平均值。这样,每进行一次采样,就可计算出一个新的平均值,从而加快了数据处理的速度。
优点:经过滤波处理后,滤除了噪声干扰,数据波动稳定平滑。
缺点:1、需要在RAM中建立数据缓冲区,浪费RAM。
2、当采样数据越多,数据实时性越差,当数据突然发生较大变化时,不能被立刻检测到,无法及时处理突发事件。
所以需要对传统滑动滤波算法进行改进。
1、不需要建立缓冲区,用一个变量保存所有采样数据的累加和,累加和除以采样个数就是滤波后的平均值。
2、在程序中设定数据波动阈值,超过阈值,立刻更新滤波平均值,提高实时性。
经过改进后,兼顾了数据的稳定性和实时性。
u16 Slide_filter(u16 data,u8 Filter_depth,u16 percent)
{
static u8 B_initial=1;
static u16 average;
static u32 Sum;
static u8 LB1,LB2;
static u16 threshold;
if(data<(average-threshold))
{
if(LB1<3)
LB1++;
else
B_initial=1;
}
else
LB1=0;
if(data>(average+threshold))
{
if(LB2<3)
LB2++;
else
B_initial=1;
}
else
LB2=0;
if(B_initial)
{
B_initial--;
average=data;
Sum=average*Filter_depth;
LB1=0;LB2=0;
}
Sum=Sum-average+data;
average=Sum/Filter_depth;
threshold=(average/100)*percent;
return average;
}
时隔半年,发现上面的滤波函数需要进一步优化,下面是优化的原因
由于产品的功率大,di/dt较大,对ADC采样值造成干扰,ADC采样值有很多毛刺,为了使所有参数平滑变化,需要对所有参数进行滤波,例如温度,电流,电压,功率等等。
如果采用上述的函数,那么需要定义很多相同功能的函数,代码行数多,不方便阅读。
所以我采用结构体的方法,定义函数
filter.c文件
type_WSF ACV_Filter,ACI_Filter,ACW_Filter,ACI_disp_Filter,ACIl_disp_Filter;
type_WMF MT20BR5_REF_Filter,ACI_REF_Filter,ACV_REF_Filter;
u16 Sliding_filter(type_WSF *WSF,u16 data,u8 depth,u16 percent)
{
if(data<(WSF->average-WSF->threshold))
{
if(WSF->LB1<d_LB_MAX)
WSF->LB1++;
else
WSF->B_init=1;
}
else
WSF->LB1=0;
if(data>(WSF->average+WSF->threshold))
{
if(WSF->LB2<d_LB_MAX)
WSF->LB2++;
else
WSF->B_init=1;
}
else
WSF->LB2=0;
if(WSF->B_init)
{
WSF->B_init--;
WSF->average=data;
WSF->Sum=WSF->average*depth;
WSF->LB1=0;
WSF->LB2=0;
}
WSF->Sum=WSF->Sum-WSF->average+data;
WSF->average=WSF->Sum/depth;
WSF->threshold=(WSF->average*percent)/100;
return WSF->average;
}
void WSF_int(type_WSF *WSF)
{
WSF->B_init=1;
WSF->LB1=0;
WSF->LB2=0;
WSF->average=0;
WSF->threshold=0;
WSF->Sum=0;
WSF->Sliding_filter=Sliding_filter;
}
/*************************************************************************************/
u16 Mean_filter(type_WMF *WMF,u16 data,u8 size)
{
if(WMF->cnt<size)
{
WMF->cnt++;
WMF->Sum+=data;
}
else
{
WMF->average=WMF->Sum/WMF->cnt;
WMF->Sum=0;
WMF->cnt=0;
}
return WMF->average;
}
void WMF_init(type_WMF *WMF)
{
WMF->cnt=0;
WMF->average=0;
WMF->Sum=0;
WMF->Mean_filter=Mean_filter;
}
filter.h
#ifndef FILTER_H
#define FILTER_H
#include "user_define.h"
#define d_LB_MAX 3
typedef struct Window_Sliding_Filter
{
u8 B_init;
u8 LB1;
u8 LB2;
u16 average;
u16 threshold;
u32 Sum;
u16 (*Sliding_filter)(struct Window_Sliding_Filter *WSF,u16 data,u8 depth,u16 percent);
}type_WSF;
typedef struct Window_Mean_Filter
{
u8 cnt;
u16 average;
u32 Sum;
u16 (*Mean_filter)(struct Window_Mean_Filter *WMF,u16 data,u8 size);
}type_WMF;
extern type_WSF ACV_Filter,ACI_Filter,ACW_Filter,ACI_disp_Filter,ACIl_disp_Filter;
extern type_WMF MT20BR5_REF_Filter,ACI_REF_Filter,ACV_REF_Filter;
extern void WSF_int(type_WSF *WSF);
extern void WMF_init(type_WMF *WMF);
#endif
main.c
void main(void)
{
system_init();
WMF_init(&MT20BR5_REF_Filter);
WMF_init(&ACI_REF_Filter);
WMF_init(&ACV_REF_Filter);
WSF_int(&ACV_Filter);
WSF_int(&ACI_Filter);
WSF_int(&ACW_Filter);
WSF_int(&ACI_disp_Filter);
WSF_int(&ACIl_disp_Filter);
while(1)
{
R_IAC_ADC_REF=ACI_REF_Filter.Mean_filter(&ACI_REF_Filter,R_Iac_rms,200);
ADC_Calculation.V_LN=ACV_Filter.Sliding_filter(&ACV_Filter,V_LN,6,5);
}
}