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
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.