When you need to get faster on an processor that lacks an FPU, your best
bet is to replace floating point calculations with fixed point. Combine
this with joop's suggestion (a one Newton-Raphson sqrt) and you get
something like this:
#define INITIAL 512 /* Initial value of the filter memory. */
#define SAMPLES 512
uint16_t rms_filter(uint16_t sample)
{
static uint16_t rms = INITIAL;
static uint32_t sum_squares = 1UL * SAMPLES * INITIAL * INITIAL;
sum_squares -= sum_squares / SAMPLES;
sum_squares += (uint32_t) sample * sample;
if (rms == 0) rms = 1; /* do not divide by zero */
rms = (rms + sum_squares / SAMPLES / rms) / 2;
return rms;
}
Just run your raw ADC samples through this filter. You may add a few
bit-shifts here and there to get more resolution, but you have to be
careful not to overflow your variables. And I doubt you really need the
extra resolution.
The output of the filter is in the same unit as its input. In this case,
it is the unit of your ADC:
2.5 V / 1024 ≈ 2.44 mV. If you can keep
this unit in subsequent calculations, you will save cycles by avoiding
unnecessary conversions. If you really need the value to be in volts (it
may be an I/O requirement), then you will have to convert to floating
point. If you want millivolts, you can stay in the integer realm:
uint16_t rms_in_mV = rms_filter(raw_sample) * 160000UL >> 16;
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…