Оптимизировать взвешенное скользящее среднее
Среда: STM32H7 и GCC
Работа с потоком данных: 1 образец, полученный от SPI каждые 250 мкс.
Я использую "треугольное" взвешенное скользящее среднее с 256 образцами, как это, но средний образец имеет вес 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 мкс, но я измерил с помощью вывода GPIO отладки, что "моя" часть занимает 252 мкс. Здесь
смоделирован код. Интересный факт: если я удалю
(uint32_t)
бросить ближе к концу требуется 274 нас вместо 252 нас
Как мне сделать это быстрее?
Я думал использовать вместо
float
за
coef
(например, умножить на 1000), но мой
uint32
переполнится
1 ответ
Это, безусловно, должно быть целым числом. Это будет и быстрее, и точнее.
Этот процессор может выполнять умножение 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;