ESP32 + INMP441 I2S Microphone: ~10 dB SPL Discrepancy vs. Phone App After A-Weighting Implementation

Hello everyone,

I'm working on a sound level meter project using an ESP32 Dev Module and an INMP441 I2S microphone. I've implemented the A-weighting filter and the dB SPL calculation, but I'm consistently getting a reading that is approximately 10 dB lower than several calibrated phone apps (NIOSH SLM, Decibel X) for the same sound source at the same distance.

I've spent a lot of time debugging and would greatly appreciate any insight from this community.

**1. My Hardware Setup:**​

  • MCU: ESP32 Dev Module (WROOM-32)

  • Microphone: TDK/InvenSense INMP441

  • Wiring:

    • INMP441 VDD to ESP32 3.3V

    • INMP441 GND to ESP32 GND

    • INMP441 SCK to ESP32 GPIO32

    • INMP441 WS to ESP32 GPIO25

    • INMP441 SD to ESP32 GPIO33

  • The INMP441 L/R pin is connected to GND to select the left channel.

**2. My Software (Arduino IDE): i can only post bits and pieces:**​

// A-weighting filter coefficients (for INMP441)const float AWEIGHT_GAIN = 1.00197834654696f;const float AWEIGHT_B1 = -1.986920458344451f;const float AWEIGHT_B2 = 0.986963226946616f;const float AWEIGHT_NEG_A1 = 1.995178510504166f;const float AWEIGHT_NEG_A2 = -0.995184322194091f;// Read samples from I2Ssize_t bytes_read = 0;i2s_read(I2S_NUM_0, raw_samples, sizeof(raw_samples), &bytes_read, portMAX_DELAY);int samples_read = bytes_read / sizeof(int32_t);// Convert to floating-point and remove DC offsetfloat sum = 0.0f;float samples[samples_read];for (int i = 0; i < samples_read; i++) {// Extract 24-bit sample (shift right 8 bits)int32_t sample_24bit = raw_samples >> 8;// Convert to normalized float (-1.0 to 1.0)samples = sample_24bit / MAX_24_BIT;sum += samples;}// Calculate DC offset (mean)float mean = sum / samples_read;// Apply A-weighting filter and compute RMSstatic float v1 = 0.0f; // Filter state 1static float v2 = 0.0f; // Filter state 2// Compute RMSfloat sumSquares = 0.0f;for (int i = 0; i < samples_read; i++) {float x = samples - mean; // Remove DC offset//sumSquares += sample * sample;// Apply A-weighting filter (transposed direct form II)float v = x + AWEIGHT_NEG_A1 * v1 + AWEIGHT_NEG_A2 * v2;float y = AWEIGHT_GAIN * (v + AWEIGHT_B1 * v1 + AWEIGHT_B2 * v2);// Update filter statesv2 = v1;v1 = v;// Accumulate squares for RMS calculationsumSquares += y * y;}float rms = sqrt(sumSquares / samples_read);// Convert to dB SPLif (rms < 1e-6) rms = 1e-6; // Avoid log(0)float dbFS = 20.0f * log10(rms); // dB relative to full scalefloat dbSPL = dbFS + MIC_REFERENCE + 94.0f; // INMP441 sensitivity compensation```

***3. The Problem & What I've Tried:*

  • The Problem: For a steady 1 kHz tone and general room noise, my ESP32 code reports a value that is consistently ~10 dB lower than my phone (iPhone with NIOSH SLM app) placed right next to the INMP441.

  • What I've checked:

    1. I2S Configuration: The data is being read correctly. I can see the 24-bit waveform when I plot the raw values.

    2. DC Offset Removal: This is working. The mean of the signal is very close to zero after subtraction.

    3. A-Weighting Filter: I've implemented it as a transposed Direct Form II IIR filter. I reset the filter states (v1, v2) before processing each buffer to prevent drift.

    4. RMS Calculation: The calculation appears mathematically correct.

    5. Physical Setup: I've ensured the microphone's inlet is not obstructed and is facing the sound source, just like the phone's mic.

***4. My Specific Questions:*

  1. Is my fundamental dB SPL calculation formula correct (dB FS - Sensitivity + 94)?

  2. Could the issue be with the A-weighting coefficients I'm using? Are there better-suited coefficients for the INMP441's response?

  3. [*]Has anyone else successfully calibrated an INMP441 to match a known reference and can share their final MIC_REFERENCE or calibration offset value?
    [*]Are there any obvious mistakes in my filter implementation or data handling that would cause a consistent ~10 dB error?

*One last observation is that when i try to compare with the phone app the closer i get the phone and the microphone to the source of the sound the more they have approximatively the same DBSPL value otherweise when they are further at the same distance there is an offset between them

If there are further inquiries just ask me .*

I moved your topic to a more appropriate forum category @nefzaya.

The Nano Family > Nano ESP32 category you chose is only used for discussions directly related to the Arduino Nano ESP32 board.

In the future, when creating a topic please take the time to pick the forum category that best suits the subject of your question. There is an "About the _____ category" topic at the top of each category that explains its purpose.

Thanks in advance for your cooperation.

this works ok for 1khz signals.

phone apps are not calibrated.
no i2s mic is calibrated, and is hard to compensate with a 10th order iir filter.

below 2khz is ok, above is not reliable.

Thank you for the response.

Does that mean i should calibrate the mic and will the output be more accurate after calibration?

for 1 khz is ok.

mems microphones are not made for measurment, just for cellphones and voice recording.

i just have seen one paper with a proper compensation filter and its order is 1024, pretty high for a esp32.