I'm developing an embedded system which takes in digital audio from an ICS43432 MEMS-microphone via the I2S-bus to compute the sound pressure level over variable time. No $A$ or $C$-weightings are applied (yet).

The signal flow is supposed to work like this: enter image description here

Where $N_S = 1000$ and $N_B=48$, since the sampling rate $f_s=48kHz$. Resolution is 24bit, $S$ and $L_{94}$ are derived from the datasheet. If working, $N_B$ should be configurable to produce $L_{ZEQ1''}$, $L_{ZEQ5''}$ or even $L_{ZEQ1'}$.

I now would expect values of around $30dB_{SPL}$ in a quiet room, which stands contrary to the $-50dB_{SPL}$ which I currently receive...

Am I doing a physically impossible conversion somewhere?


1 Answer 1


Hard to say without looking at your actual code, the devil is always in the details. Nothing is obviously wrong as far as I can tell.

There are a few potential problems

  1. Fixed point processing is hard. Doing this in floating point would me much easier.
  2. Taking the square of an int32 results in an int64. You need to make sure you are not clipping.
  3. There is some superfluous stuff in there. Instead of taking the root and doing $20 \cdot \log()$ you can just leave it squared an do $10 \cdot \log(\frac{x_{RMS}^2}{2^{46}})$
  4. The last step is clearly wrong. You need to average in energy not in dB. However that should result in such large an error if your test signal is reasonably stationary.

The buffering scheme seems awkward. I would just get a sample, square it and apply a low-pass filter for whatever time constant you want your $L_{EQ}$ to have. Turn this into to dB only when you need an output reading. But this depends a bit on what exactly you want to do with the $L_{EQ}$. For example, if you want this as a "dosimeter" you would need a star and a stop button as well.

General debugging rules apply (as they always). Start with a known test signal with known answer. Verify each block using one or more test signals. Don't both writing the next block before all previous blocks have been verified and unit tested.

In your case you can simply start with a 1kHz sine wave at 94 dB, (or if you can't isolate the setup yourself, use a lower level).

  1. Put your mems mic next to a speaker and play a 1kHz sine wave.
  2. Use a known good SPL meter to adjust the level to 94 dB SPL next to the mems
  3. verify your algorithm step by step. For example, your input should be a sine wave with an amplitude of of 420000 or thereabouts and the RMS should be around 300000.

Once you have this up and running, try different frequencies, amplitudes, signal types, etc. Always verify against a good meter.

  • $\begingroup$ Ad 1.: The first thing I could do ist normalize every incoming sample by INT24_MAX. But by doing that I will always obtain a value smaller than 1, which squared is even less. That sounds counter-intuitive to me. Ad 3.: I use the ARM CMSIS DSP-lib, which has an rms()-function optimized for speed, so I took that one instad of a "manual" mean-square. Ad 4.: "Energy" in this case is always in the form of a mean-square, right? $\endgroup$ Mar 20, 2022 at 11:38
  • 1
    $\begingroup$ Start with a sine wave. Do a manual calculation of each step. Verify each step of your code against your manual calculation. That will tell you what part isn't working as expected. $\endgroup$
    – Hilmar
    Mar 20, 2022 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.