Close

When signle-precision is just not good enough

A project log for ESP32-I2S-SLM

Sound Level Meter with Arduino IDE, ESP32 and I2S MEMS microphone

ivan-kostoskiIvan Kostoski 09/29/2019 at 07:080 Comments

It turns out that doing single-precision (24 bits mantissa) math on IIR filters may not work well for frequencies below 40Hz (sampling rate 48Khz). The A-weighting filter was not attenuating the signal enough (error in range of >10dB),

Easily fixable by replacing 'float' with 'double'. That however, on ESP32 which only has single-precision hardware FPU, comes with big performance penalty. While using only one 6th order IIR filter was still OK, using 2x 6th order filter needed ~122ms just for filtering 125ms sampled data, i.e. just a bit too slow.

ESP32 silicon should have the 'double precision FP acceleration pkg' (more info here) and 'XCHAL_HAVE_DFP_ACCEL' macro is defined in esp-idf. That would have taken care of the problem. Sadly, it seems GCC doesn't know how to use these instructions on and there is no public record of the accelerated libraries mentioned in the application note. Due to the extra registers involved, I assume this may also have impact on FreeRTOS context switching...

Another way around this is to use fixed-point math, with i.e. .32 precision. Again, GCC doesn't have __int128 implementation on 32bit platforms, so that had to be added as well...

Anyway, I have updated the sources with .32 fixed-point implementation of the IIR filters which is fast enough (2x compared to software emulated double-precision) and good enough so error at low frequencies (down to 10Hz) is <=0.1dB. As we are dealing with 24bit microphone values, there should be low risk of fixed-point overloading. The code is not very well tested, but seems to work for microphone sampled data.

Discussions