I'm working with STM32F4, MAX4466 amplifier and a condenser microphone. In other words, Adafruit 1063. I want to get the sound level in dB unit. I know:
- Microphone sensitivity: 0.0063096 V/Pa
- Amplifier gain: 41dB
- Amplifier voltage bias: Vcc/2
STM32F4 ADC resolution is setted to 12 bit, so the max value is 4095. Vcc = 3.3V. To reach the goal, I collect 800 samples (with a sample frequency equals to 8kHz) and make the RMS in this way:
\$V_{RMS} = \sqrt{\frac{1}{N}\sum_{i=1}^{N} \left(\frac{x_i}{4096} V_{cc} - V_{bias}\right)^2}\$
where \$x_i\$ is the ADC input value. Now, to find the sound level, I'm using the following equation
\$L_{p} = 20\;\log_{10}\left(\frac{p}{p_0}\right) - gain\$
where \$p = \frac{V_{RMS}}{S}\$, \$S\$ is the microphone sensitivity, \$p_0\$ is the sound reference pressure (0,00002 Pa) and gain is the amplifier gain (41dB).
Here is my problem. The value I get, seems to be different from the sound level measured with other tools for at least 20dB. Unfortunately, it is not only a shift, because this value changes when the sound level changes.
Exploiting the properties of logarithms, is possibile to write \$L_p \$ in a different way.
\$L_{p} = 20\;\log_{10}\left(V_{RMS}\right) - S_{dB} - p_{0_{dB}} - gain \$
where \$S_{dB}\$ microphone sensitivity in dB (-44 dB) and \$p_{0_{dB}}\$ is the sound reference pressure in dB unit (-94 dB).
Both equations return the same wrong result.
Now, if I try to multiply the log function by 30 instead of 20 in the second form, the final value is correct and very accurate. In order to understand more, I tried to use another microphone with a different sensitivity, and another amplifier (MAX9814) with differerent gain. Same result. My question is, why? Maybe something is wrong somewhere else?
Edit
Here's my code:
#define AMPLIFIER_GAIN 41.727F // dB
#define MICROPHONE_SENSITIVITY -44.0F // dB
#define AMP_BIAS 1.65F // Volts
#define SM_ADC_MAX_VALUE 4096.0F
#define SM_VOLTAGE_REFERENCE 3.3F // V
#define SM_REFERENCE_SOUND_PRESSURE -93.979F // dB
float SM_Get_Sound_Level(sound_meter_t* sound_meter, float *input, size_t n)
{
float amp_out_rms = 0.0;
for (size_t i = 0; i<n; i++)
{
float amp_out = ((input[i]/sound_meter->adc_max_value)*sound_meter->voltage_reference - sound_meter->amp_bias);
// Calculate the average for RMS
amp_out_rms += (amp_out * amp_out);
}
// Get the RMS value
amp_out_rms = sqrtf(amp_out_rms/((float)n));
// Avoid to compute log(0)
if (amp_out_rms != 0.0F)
{
return 30.0F * log10f(amp_out_rms) - sound_meter->microphone_sensitivity - sound_meter->p0 - sound_meter->amp_gain;
}
else {
return 0.01F;
}
}
void SM_Init(sound_meter_t *sound_meter, float microphone_sensitivity, float amp_gain, float amp_bias)
{
sound_meter->microphone_sensitivity = microphone_sensitivity;
sound_meter->amp_gain = amp_gain;
sound_meter->amp_bias = amp_bias;
sound_meter->adc_max_value = SM_ADC_MAX_VALUE;
sound_meter->voltage_reference = SM_VOLTAGE_REFERENCE;
sound_meter->p0 = SM_REFERENCE_SOUND_PRESSURE;
}
...
SM_Init(&sound_meter, MICROPHONE_SENSITIVITY, AMPLIFIER_GAIN, AMP_BIAS);