优化加权移动平均线

Optimize a weighted moving average

环境:STM32H7 和 GCC
使用数据流:每 250 us
从 SPI 接收 1 个样本 我用 256 个样本做了一个“三角形”加权移动平均值,比如 this 但中间样本的权重为 1,它在它周围形成一个三角形
我的样本存储在 uint32_t val[256] 循环缓冲区中,它与 uint8_t write_index
一起使用 样本为24位,一个样本的最大值为0x00FFFFFF

uint8_t write_idx =0;
uint32_t val[256];
float coef[256];

void init(void)
{
  uint8_t counter=0;
  // I calculate my triangle coefs
  for(uint16_t c=0;c<256;c++) 
  {
    coef[c]=(c>127)?--counter:++counter;
    coef[c]/=128;
  }
}

void ACQ_Complete(void)
{
  uint32_t moy=0;
  // write_idx is meant to wrap
  val[write_idx++]= new_sample;
  // calc moving average (uint8_t)(c-write_idx) is meant to wrap
  for(uint16_t c=0;c<256;c++)
    moy += (uint32_t)(val[c]*coef[(uint8_t)(c-write_idx)]);
  moy/=128;
}

我必须在 250 us 时间跨度 内进行计算,但我使用调试 GPIO 引脚测量“moy”部分需要 252 us
代码被模拟here
有趣的事实:如果我在接近尾声时删除 (uint32_t) 强制转换,则需要 274 us 而不是 252 us

我怎样才能更快地完成它?

我正在考虑对 coef 使用 uint32 而不是 float(例如乘以 1000),但我的 uint32 会溢出

毫无疑问,这应该以整数形式完成。它会更快更准确。

这个处理器单周期可以做32x32+64=64次乘加!

将所有系数乘以 2 的幂(不是评论中提到的 1000),然后在最后向下移动而不是相除。

uint32_t coef[256];

uint64_t moy = 0;

for(unsigned int c = 0; c < 256; c++)
{
   moy += (val[c] * (uint64_t)coef[(c - write_idx) & 0xFFu]);
}

moy >>= N;