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:
-
I2S Configuration: The data is being read correctly. I can see the 24-bit waveform when I plot the raw values.
-
DC Offset Removal: This is working. The mean of the signal is very close to zero after subtraction.
-
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.
-
RMS Calculation: The calculation appears mathematically correct.
-
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:*
-
Is my fundamental dB SPL calculation formula correct (dB FS - Sensitivity + 94)?
-
Could the issue be with the A-weighting coefficients I'm using? Are there better-suited coefficients for the INMP441's response?
-
[*]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 .*