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)?
Now my GetSample() function returns a signed 18 bit values, a few test samples results in these values, before DB offset adjustment:
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; adjustedSample = fabs(adjustedSample); // 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.