You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升STM32 ADC指数移动平均的整数运算精度?

STM32 16位ADC整数EMA平滑的偏差修正方案

你的问题核心是整数EMA的截断误差累积导致的系统性向下偏差:原始代码用右移实现整数除法时,会直接截断小数部分,每次更新的向下误差被指数加权后长期累积,最终让稳定值低于真实均值。以下是几种高效的整数运算修正方案,适配中断服务程序的快速执行要求:

偏差根源解析

你用的EMA公式本质是:

ema_new = ema_old * (2^factor - 1)/2^factor + adc * 1/2^factor

整数右移相当于截断除法,每次计算会丢弃(ema_old*(2^factor-1) + adc) % 2^factor的小数部分,平均每次引入-0.5的误差。当factor越大(新值权重越小),误差累积越明显,最终稳定值偏离真实均值。


优化方案

方案1:64位中间运算实现精确四舍五入

STM32 Cortex-M3及以上MCU支持32×32位乘法得到64位结果,利用这一点可以避免截断误差:

uint32_t ema = 0;
const unsigned factor = 8;
const uint64_t m = (1ULL << factor) - 1;
const uint64_t round_offset = 1ULL << (factor - 1);

// 中断内更新逻辑
uint64_t temp = (uint64_t)ema * m + adc[0];
temp += round_offset; // 四舍五入偏移
ema = (uint32_t)(temp >> factor);

这个方法通过64位中间值完整保留乘法结果,加偏移后再右移实现真正的四舍五入,每次更新的误差控制在±0.5,长期累积的期望偏差为0,稳定值会贴合真实均值。

方案2:轻量偏差补偿(无需64位运算)

如果MCU资源受限,可通过添加固定补偿项抵消截断误差:

uint32_t ema = 0;
const unsigned factor = 8;
const unsigned m = (1 << factor) - 1;
const unsigned bias = 1; // 补偿截断的向下误差

// 中断内更新逻辑
ema = (ema * m + adc[0] + bias) >> factor;

原理是主动给每次计算加1,抵消平均-0.5的截断误差。若factor较小(如≤4),可适当增大bias(比如设为2),能快速让稳定值回归真实均值区间。

方案3:高精度定点数存储

用64位变量存储EMA的整数+小数部分,彻底避免精度丢失:

uint64_t ema = 0; // 高32位为整数部分,低factor位为小数部分
const unsigned factor = 8;
const uint64_t m = (1ULL << factor) - 1;

// 中断内更新逻辑
ema = (ema * m + (uint64_t)adc[0] << factor) >> factor;

// 读取整数结果
uint32_t ema_result = (uint32_t)(ema >> factor);

该方法把ADC值左移factor位后参与运算,保留了EMA的小数精度,读取时仅需右移取整数部分,稳定后结果会精确贴合真实均值(若均值为整数),无系统性偏差。


方案选择建议

  • 优先选方案1:实现简单,偏差最小,适配绝大多数STM32 MCU;
  • 资源极度受限选方案2:代码量最小,运算最快;
  • 追求最高精度选方案3:完全消除截断误差,适合对读数精度要求极高的场景。

内容的提问来源于stack exchange,提问作者Stefan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:13:14