MCU移动平均的集中算法

1. 最原始的算法:

u16 moving_average(u16 in) 
{
	static u16 d[16] = {0,0};
	u32 sum = 0;

	for(u8 i = 15; i > 0; i--)
	{
		d[i] = d[i-1];
		sum += d[i];
	}
	d[0] = in;
	sum += d[0];

	return sum >> 4;  // 1/16
}

2. 优化的: 使用当前需要替换的元素index来更换新的数据, 避免耗时的逐次移动

#define MG_LEN        64
typedef struct 
{
    u16 d[MG_LEN];
    u8 seq;
}MAG;
MAG mag;

void mov_avg_rst(void)
{
    u8 i;
    mag.seq = 0;
    for(i = 0; i < MG_LEN; i++)
        mag.d[i] = 0;    
}

u16 move_avg64(u16 in)
{
    u8 i;
    u32 sum;

    mag.d[mag.seq] = in;    //new data in
    sum = 0;
    for(i = 0; i < MG_LEN; i++)
        sum += mag.d[i];
        
    mag.seq++;
    if(mag.seq >= MG_LEN)
    {
        mag.seq = 0;
    }
        
    return     (u16)(sum >> 6);    //div 64
}

3. 不需要数组来存放历史数据, 用一个总和sum来存储. 很次用时先减去sum/64, 然后加入新的数据到sum, 返回新的sum/64

u16 moveAverage(u16 in) 
{
	static u32 sum = 0;

	sum = sum + in - (sum >> 6);
	return sum >> 6;  // 1/64
}

4. 趋势判断法, 适合趋势明显的曲线变化, 比如充电的电流是稳定下降的, 先获取到13个连续的数值, 得到平均值和平均变化趋势值(两点间差值), 然后推算出接下一点会是什么数值, 达到过滤出不符合趋势变化的噪声的目的

#define TREAND_LEN		12   //must be an even number
u16 trend(u16 new)
{
	static u16 d[TREAND_LEN] = {0,0};
	s32 sum = 0;
	s32 delta = 0;

	for(u8 i = (TREAND_LEN-1); i > 0; i--)
    {
        sum += d[i];
		delta += (d[i] - d[i-1]);
		d[i] = d[i-1];
    }
	sum += (d[0] + new);
	sum /= (TREAND_LEN+1);

	delta += (d[0] - new);
	d[0] = new;

	delta = ((TREAND_LEN+2)/2 * delta) / TREAND_LEN;
    // delta = (7 * delta) / 12;
	if(sum > delta)
		return sum - delta;
	else
		return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值