1、创作灵感
最近在做一个电机项目,需要采集电机的运行电流,用来判断电机的运行状态。经过硬件电路转换后可以将电机的运行电流转化为电压,用单片机的ADC进行采集,即可获取电机的运行状态。
在项目过程中,由于ADC采样速度过快,使得采集到的电机ADC不稳定(启动瞬间ADC过高),加入滤波算法后可以大幅度降低误报风险,本次采取的算法是递推平均值滤波算法。
2、思路分析
电机ADC持续采样,将采集到的ADC值存到一个数组中(这里对20个数据进行运算。PS:太少容易不稳定,太多容易浪费CPU资源),用新数据不断覆盖老数据,最后将数据进行平均处理,可以得到稳定的ADC值。
3、代码实现
定义一个结构体:
struct average
{
unsigned char new_data;//输入的数据
unsigned char data_num;//替换哪一位的数据
unsigned char data[20];//存放数据,最多放20个
unsigned int sum;//总和
unsigned char average_value;//平均值
};
平均值运算程序:
unsigned char average_run(struct average *object)
{
object -> data[object -> data_num] = object -> new_data;//将新值覆盖掉数组中的一个数据
if(object -> data_num >= 0 && object -> data_num < 19) object -> data_num++;
else object -> data_num = 0;
//计算平均值
object -> sum = 0;//清空总和
for(unsigned char loop = 0; loop < 20; loop++)
{
object -> sum += object -> data[loop];//计算总和
}
object -> average_value = (object -> sum / 20);//取平均值
return (object -> average_value);
}
使用示范:
定义一个结构体对象:
struct average adc;
将采集到的数据给到结构体:
(说明:这里是测试代码,在while中不断让num自增,不断更新num的值,对其进行平均值运算。)
adc.new_data = ++num;//将取到的值赋给结构体
adc_average = average_run(&adc);//得到平均值
4、测试结果:
5、总结:
本次的算法只对最近采集到的20个数据进行平均处理,通过数据覆盖使数据不易进行突变而造成干扰,为了节约CPU资源,所以不进行浮点数的运算(浮点数运算更加准确,需要精确数据的可以进行程序修改)。
注意要点:由于电机采集到的ADC值一般不会超过255,所以采集的值用unsigned char类型的变量进行保存,如果单次输入的值大于255,则要将结构体中的 new_data 、 data[20] 、average_value三个变量的数据类型改成unsigned int。运算函数返回类型也要修改成unsigned int。