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

Public Chat
Similar projects worth following
The project aim is to design and build simple but relatively accurate 'Sound Level Meter' with Arduino IDE, ESP32, and commonly available I2S digital microphones.

Sampling sound with I2S digital microphone

The good thing about digital microphones is that you don't need to worry about the analog part like pre-amplification, linearity and speed of MCU ADC, etc... And the digital values you receive should be already referenced to sound pressure levels (SPL). Datasheet needs to list the amplitude value for certain SPL, for 1KHz pure sine wave tone (i.e. -26dBFS @ 94dB SPL). This is usually expressed as dBFS  (decibel relative to full-scale), so for i.e. -26dBFS you can convert this to absolute amplitude value based on the maximum value mic can send, and in case of 24bit data, this should be (2^23 − 1) * 10^(−26/20) ~= 420426. This is the amplitude you should expect to receive if you i.e. put the microphone inside 'Sound level calibrator'

The microphone of choice for this project is TDK/InvenSense ICS-43434, or more specifically its breakout board available at Tindie. One good thing about this microphone is that its sensitivity is specified as +/-1dB. This means our measurement of 94dB, 1KHz pure sine wave tone, should be -26dBFS, +/-1dB, without any additional calibration. This is pretty good considering I do not have access to any calibration equipment. You can also use the older INMP441 mic, widely available as cheap breakout board on i.e. Aliexpress, but that one has sensitivity specified as +/-3dB.

The hardware

Breadboard friendly, see the list of components

Equalization and weighting

MEMS microphones are usually not ideal and there should be frequency response plot in the datasheet. If this curve deviates outside from acceptable parameters, first we need to equalize (i.e flatten) the microphone native response in the measurement range (20Hz - 20KHz), before we measure the actual SPL levels (i.e. Z-weighted) and apply any weighting filter. We can do this with digital IIR filter designed to (inverse) match the datasheet frequency plot. See the 'ics43434.m' file for my humble attempt at filter design to equalize the ICS-43434. You can copy/paste the math in Octave Online to calculate the coefficients and display the IIR filter frequency response graphs. TLDR, the 'flattened frequency response should look like this (blue line):

Next step is to apply the frequency weighting, in this case the most common (but probably not the most correct) A-weighting, also implemented as IIR filter. The coefficient for this filter were taken from here, for sampling frequency of 48KHz.

Actual implementation of IIR filters is taken (and slightly modified for single-precision and performance) from the nice Arduino digital filter library, and ESP32 with its FPU has the required grunt to do the math continuously while sampling.

The measurement

And from there it is straight forward. I calculate the RMS of the sampled signal, calculate decibels referenced to datasheet value for 94dB and display the value.
Sound level measurements are only meaningful in context of duration of the sampling (see Wikipedia). The Arduino sketch, by default, displays the LAeq(125ms) measurements as horizontal line on top of the screen and LAeq(1sec) measurements as numeric value. It also prints the measured numeric value on the serial monitor and you can graph it with Arduino's 'Serial plotter'

Source code and IIR filter math are available on Github

sheet - 4.57 MB - 09/08/2019 at 16:12


  • 1 × ESP32 Development board of choice
  • 1 × ICS-43434 breakout Digital I2S MEMS microphone
  • 1 × Small OLED display
  • 1 × Breadboard and jumper wires

  • Comparative measurements with B&K 2250

    Ivan Kostoski09/08/2019 at 16:26 0 comments

    If 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.

View project log

Enjoy this project?



Elliot Williams wrote 08/27/2019 at 07:44 point

Great idea to find a (cheap) calibrated part and fill out the rest yourself.  Very cool.

  Are you sure? yes | no

Ivan Kostoski wrote 08/27/2019 at 08:58 point

Thanks. I am waiting for some comparison results with 'real' SLM. Initial test with Bruel&Kjaer 2250 look very promising...

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates