-
Back to single-precision with ‘Second-Order Sections’
11/22/2019 at 16:13 • 0 commentsIt turns out that if you 'breakup' the higher order IIR filters into series of Second-Order Sections (i.e. biquads), the filtering error does not accumulate as much. With 24-bit data, broken down filters and single-precision, the error induced by the A-weighting filter should be less than 0.5dB in worst case (20Hz). The monolithic 6th order ‘B/A’ transfer function had >7dB error at 20Hz with single-precision.
As we are here to hack stuff, It is more likely that parts of this project will be integrated into other more complex projects, with many more sensors and functionality, instead of being used as standalone SLM, so I set my (over)optimization goal to leave as much as possible CPU time for other tasks. And instead of fighting with GCC to produce the code that I know is possible, the end result is going all the way to ESP32/Xtensa assembler...
Well, now you can lower the frequency of ESP32 down to 80MHz (i.e. for battery operation) and filtering and summation of I2S data will still take less than 15% of single core processing time. At 240MHz, filtering 1/8sec worth of samples with 2 x 6th-order IIR filters takes less than 5ms. The ESP32/GCC assembler implementation is in ‘sos-iir-filter.h’ and in the comments you can find more or less equivalent C code. The sources from esp-dsp were quite helpful. The CPU ISAs these days… let’s just say that my beginnings involved writing 6502 assembler…
Support for Knowles SPH0645LM4H-B
I received a sample of this microphone so I decided to try it out. First, it is not quite compatible with ESP32 I2S peripheral and you need to apply ‘dirty hack’ (directly manipulating ESP32 registers, see the code) to even receive the MSB of I2S data. Additionally, the received values have ‘DC bias’ (or offset) so calculating SPL RMS directly is not possible. If you apply DC-blocker filter (or more specifically, DC-Blocker SOS section), this bias can be filtered out.
While it finally works, in my humble opinion, this microphone is not very well suited for sound level measurement, mostly due to its limited dynamic range (18 valid bits in I2S data) and the errors that will be added by any IIR filters at lower amplitudes, no matter what kind of arithmetic precision you use.
-
When signle-precision is just not good enough
09/29/2019 at 07:08 • 0 commentsIt 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.
-
Comparative measurements with B&K 2250
09/08/2019 at 16:26 • 0 commentsIf you are wondering if the theoretic accuracy of this simple and cheap SLM has any practical meaning, here are some measurements in comparison with IEC-61672-1, class 1, Brüel&Kjær 2250 sound level meter, courtesy of D-r Enrico Armelloni.
The MEMS microphone used in the test is ICS-42432 (slightly older, and perhaps more accurate model), in protective shell which also acts as 1.27mm adapter, connected to ESP32 running the GitHub sketch. D-r Armelloni went to great length testing the MEMS+ESP32 setup, including various sound amplitudes, frequencies, pink and white noise, etc...
The detailed calibrated results so far are in the excel file in the ‘Files’ section.Please have in mind that this is probably the best-case scenario, i.e. it is not expected that every single piece of MEMS microphone will produce such close results. And if you wish to be confident in the measurements, you will need to do similar calibration on your setup. Also note that the range of the used MEMS microphones is about 35dB to 116dB and not suitable for i.e. low noise measurements.
What test does validate is the principle of how noise is calculated based on sampled sound from I2S microphone. On D-r Armelloni's advice, I also removed all misleading references to 'Fast' and 'Slow' in the project description, as the code never did any time-weighting on the sampled values. It only calculates LAeq values for various periods, which I believe is currently the most useful metric.