在这方面又做了一些工作。使用经过校准的 SPL 计和具有不同纯频率、白噪声和粉红噪声的智能手机进行的一些测试,我现在知道手机麦克风不适用于任何应在 90 到 100 dB(SPL)以上的地方注册的任何东西,具体取决于手机.
假设 90 dB(SPL) 是最大值,可以计算出这将对应于麦克风处 0.6325 Pa 的压力。现在假设 p0=0.0002 Pa 是参考最小值,并假设这将在 getMaxAmplitude() 中注册为 0(实际上永远不会发生),我们可以将 getMaxAmplitude() 函数的值与麦克风的最大压力相关联。这意味着来自 getMaxAmplitude() 的 16375 的结果将对应于 0.3165 Pa 的最大压力。这当然不是很科学,因为最大值和最小值纯属猜想,但它为我们提供了一个起点。我们现在可以计算 p
p=getMaxAmplitude()/51805.5336
知道麦克风的压力后,我们可以使用众所周知的公式计算 dB(SPL) 值
X = 20 log_10 (p/p0)
这仍然会给出一个很高的值,因为在计算中只使用了最大幅度。要解决这个问题,一定不要使用 getMaxAmplitude() ,虽然这稍微超出了这个问题的重点,但无论如何我都会把代码放进去,希望它会有所帮助
public class NoiseRecorder
{
private final String TAG = SoundOfTheCityConstants.TAG;
public static double REFERENCE = 0.00002;
public double getNoiseLevel() throws NoValidNoiseLevelException
{
Logging.e(TAG, "start new recording process");
int bufferSize = AudioRecord.getMinBufferSize(44100,AudioFormat.CHANNEL_IN_DEFAULT,AudioFormat.ENCODING_PCM_16BIT);
//making the buffer bigger....
bufferSize=bufferSize*4;
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
44100, AudioFormat.CHANNEL_IN_DEFAULT, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
short data [] = new short[bufferSize];
double average = 0.0;
recorder.startRecording();
//recording data;
recorder.read(data, 0, bufferSize);
recorder.stop();
Logging.e(TAG, "stop");
for (short s : data)
{
if(s>0)
{
average += Math.abs(s);
}
else
{
bufferSize--;
}
}
//x=max;
double x = average/bufferSize;
Logging.e(TAG, ""+x);
recorder.release();
Logging.d(TAG, "getNoiseLevel() ");
double db=0;
if (x==0){
NoValidNoiseLevelException e = new NoValidNoiseLevelException(x);
throw e;
}
// calculating the pascal pressure based on the idea that the max amplitude (between 0 and 32767) is
// relative to the pressure
double pressure = x/51805.5336; //the value 51805.5336 can be derived from asuming that x=32767=0.6325 Pa and x=1 = 0.00002 Pa (the reference value)
Logging.d(TAG, "x="+pressure +" Pa");
db = (20 * Math.log10(pressure/REFERENCE));
Logging.d(TAG, "db="+db);
if(db>0)
{
return db;
}
NoValidNoiseLevelException e = new NoValidNoiseLevelException(x);
throw e;
}
}
这些值现在来自 4 秒样本中所有幅度的平均值,因此更准确。之后完成上述计算。这将给出更现实的分贝值。请注意,手机麦克风仍然很糟糕,并且该算法不会产生实际的 dB(SPL),而只会产生比之前更好的近似值。
要获得某些应用程序的性能,还需要做更多工作。这些应用程序中的大多数都使用滑动窗口,这意味着持续录制并滑动 x 秒的窗口以持续评估声音级别。此外,我将进行一些评估,什么 db Value 最适合用作最大值,现在它是 90 dB(SPL)/0.6325 Pa,这只是一个合理的猜测,它可能会略高于该值。
一旦我有更多我会更新信息。