# dB SPL readings differ from external sound level meter?

I'm trying to write a program that takes values from a MEMS microphone and calculates the dB of the incoming audio data.

The microphone i'm using is this: https://www.mouser.es/datasheet/2/218/ph0645lm4h-b-datasheet-rev-c-1525723.pdf using the I2S protocol, 24 bits signed integers.

The problem i have is that my dB SPL calculations are reading at 80 dB SPL at silence whereas my sound level meter reads around 30/40 dB(A).

Here is how i'm calculating the db SPL of the microphone input:

#define DC_OFFSET 419430

// this int32_t contains a 24 bit signed integer
int32_t sample = GetSample();

// Remove the DC offset.
sample = sample + DC_OFFSET;

sample = sqrt(pow(sample, 2));
double sampleNormalized = ((double)(sample) / 8388607);

// Convert the normalized samples to dB FS
double dbFS = 20.0 * log10(sampleNormalized);
double dbSPL = dbFS + 120.0;


Why do my readings read from 80 dB SPL whereas my sound level meter reads from 30/40 dB(A)?

## UPDATE

Now my GetSample() function returns a signed 18 bit values, a few test samples results in these values, before DB offset adjustment:

1. 78528
2. 77376
3. 73472
4. 80384
5. 79872
6. 83648

DC offset defined as (+-100 5%), max value of 18 bits is 131071, therefore DC offset is (131071 * 0.05) = 6553.0.

When i pass it through this algorithm to convert it to dBSPL, the values now come out even higher than before, but the value responds how it should.

double ref = 131071.0;
double dc_offset = ref * 0.05;

// read 18 bit signed value
int32_t sample = GetSample(); // 18 bits wide.

// remove the dc offset.
double adjustedSample = sample - dc_offset;

// normalize. the sample to the range 0.0 to 1.0.
double sampleNormalized = ((double)(adjustedSample) / ref);

// map the range from 0.0->1.0 to -1.0->1.0.
sampleNormalized -= 0.5;

sampleNormalized = abs(sampleNormalized);

// convert the normalized samples to dB FS
double dbFS = 20.0 * log10(sampleNormalized);
double dbSPL = dbFS + 120.0;


I'm still calculating db SPL values that are 88 dB SPL at quiet background, but the value actually responds correctly, i will apply the A filter as @Max posted and return the results afterwards.

• What kind of values the GetSample returns? Why is it only a 24-bit integer? The I2S protocol uses 32 bits per sample, and microphone will only send highest 18 bits and set the LSBs to zero. Mar 20 '20 at 9:15
• "sample = sample + DC_OFFSET" you are adding or removing DC_OFFSET?. Also, "sample = sqrt(pow(sample, 2));" you are just raising to power of 2 and taking its square-root. Shouldn't you divide by 2 before taking sqrt? Mar 20 '20 at 9:28
• The equation for SPL is 10*log10(p^2), which translates to 20*log10(p). In your case you are doing both: 20*log10(p^2). So I guess this explains why you get double the value.
– jojek
Mar 20 '20 at 9:41
• No, he is not doing both. He is doing sqrt(pow())which translates to abs(), so 20*log10() is correct.
– Max
Mar 20 '20 at 9:48
• @justme you are absolutely correct, i thougt the numbers were 24 bits wide. Mar 20 '20 at 11:34