The idea of including real-time decibel measurement in this project started as a stretch goal. Audio samples are already continuously written to a WAV file on an external SD Card. The plan is to analyse these recorded audio samples at a later time. But, it would be a lot more interesting if the Street Sense unit could show a real-time value of the audible noise on the local display. There are two challenges I faced:
- Calculate a decibel measurement without stealing away too many processing resources such as CPU cycles and RAM.
- What algorithm to use?
Like all technical endeavors I started with a Google search: "ESP32 noise measurement". On top of the search results is an Arduino project. That looked hopeful as I can often adapt these type of projects into MicroPython. But, two lines down I hit the jackpot. Here is a project that "checks all of the boxes"
Decibel Meter- yes. ESP32-yes. I2S-yes
The ESP-I2S-SLM Hackaday project provides all the resources on implementing a real-time decibel meter using an ESP32 microcontroller and an I2S microphone. The author, Ivan Kostoski, does an excellent job describing the digital filters that are needed to make an accurate decibel reading from microphone audio samples. The project also shares working C++ code to implement the infinite impulse response (IIR) filters needed in the dB(A) calculation.
Much gratitude to Ivan Kostoski for publishing this work !
The Street Sense project is based on MicroPython not C++ so I reworked the C++ code into a MicroPython C module that calculates dBA. The MicroPython/C implementation is here: MicroPython dBA module in github.
In the Street Sense MicroPython code the dBA calculation is included in the microphone co-routine, in a loop that is used to read audio samples from the I2S microphone and stream the samples to a SD Card. The dBA module calculates dBA incrementally, 256 audio samples at a time. When one second of samples has been processed the final dBA calculation is returned. Performance is excellent. Each incremental calculation of 256 samples takes about 0.25ms and the final calculation takes about 0.6ms. The loop that contains the dBA calculation has constraints based on the 10kHz sample frequency used. The constraint is 25.6ms - on average the loop cannot run longer than this amount of time. So, the dBA calculation only uses 1%-2% of this time allowance.
In stress tests, I found that it is possible to make a continuous dBA calculation while sampling the I2S microphone at 44.1kHz.
I chose to implement the IIR filter and RMS arithmetic using 32-bit floating point precision. The calculations seemed to yield accurate and stable results.
Moving onto some hardware and testing results ...
The I2S microphone is located on the bottom of the prototype case, shown by the blue arrow in the photo below.
An Extech digital sound level meter is used as the "golden measurement reference". The datasheet of the Extech device indicates an accuracy of +-2dB. The metal wand of the sound meter is placed into the microphone cut-out, almost touching the I2S microphone. With this arrangement both devices receive the same sounds.
An online tone generation tool is used to create pure tone frequencies. The tones are played through a pair of PC speakers.
Using the littleVGL graphics library I made a dedicated graphics display that updates the decibel measurement every second. The short video below shows the decibel meter feature being tested with 3 pure audio tones: 500 Hz, 1000 Hz, and 3000 Hz. Note: even though the generated tones were perceived as close in volume by the human ear, the recording camera gives extra emphasis to the final 3000 Hz tone (i.e. recommend to turn down your speakers for this tone)
The video shows that the Street Sense decibel meter prototype follows the Extech meter readings fairly closely, typically within 1 dBA. These results exceed my expectations. The INMP441 MEMS microphone used in this project indicates an accuracy of +-3dB. Perhaps I got lucky and both the I2S microphone and the Extech device are operating the same end of the accuracy spectrum (and making the prototype look more accurate than it really is?)
This result gives me confidence that the Street Sense decibel meter can be trusted.
Integrating the dBA measurement
The real-time dBA measurement gets used 3 ways:
- shown on the TFT display
- published to the Adafruit IO cloud database using WiFI+MQTT protocol
- recorded to SD Card
The photo below is a dashboard capture from Adafruit IO showing dBA measurements taken in our kitchen during the night. The time-span is about 8 hrs and shows the sounds coming from the kitchen refrigerator as it cycles on and off.
The unit also proved to be a competent "scream meter" with one family member claiming the top scream at 119 dBA :)
Revisiting problems with the SPH0645LM4H microphone
In an earlier project log I described the problems using a SPH0645LM4H microphone with the ESP32. This microphone is used in the popular Adafruit I2S microphone breakout board. In the project log I show how every audio sample is left shifted by one bit.
I wondered how the dBA calculations would be affected by this L shift.
I used two I2S breakout boards (INMP441 and SPH0645LM4H ) and wired them to an ESP32 (Lolin D32 Pro) and modified some MicroPython code to simultaneously read audio samples from both I2S devices and calculate dBA. The ESP32 has two I2S peripherals.
The results are interesting... and expected. Here is one result from both microphones.
INMP441 result = 73.0 dBA
SPH0645 result = 79.5 dBA
The SPH0645LM4H microphone on the Adafruit breakout board consistently delivers a 6dB higher result than the INMP441 microphone.
This makes sense. A single bit L shift in the SPH0645LM4H audio samples is a doubling of value. And a doubling of sample values results in a 6dB increase in sound level value.
If you use the SPH0645LM4H for decibel calculations it is best to shift samples R by one bit before performing the dBA calculation.