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:
- 78528
- 77376
- 73472
- 80384
- 79872
- 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;
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.
10*log10(p^2)
, which translates to20*log10(p)
. In your case you are doing both:20*log10(p^2)
. So I guess this explains why you get double the value. $\endgroup$sqrt(pow())
which translates toabs()
, so20*log10()
is correct. $\endgroup$