Над этим еще поработал. Используя некоторые тесты, проведенные с помощью откалиброванных SPL-метров и смартфонов с разными чистыми частотами, белым шумом и розовым шумом, я теперь знаю, что микрофоны мобильных телефонов нельзя использовать для чего-либо, что должно регистрироваться выше 90–100 дБ (SPL) в зависимости от телефона. .
Предполагая, что 90 дБ (SPL) является максимальным, можно рассчитать, что это будет соответствовать давлению 0,6325 Па на микрофоне. Теперь, предполагая, что p0=0,0002 Па является опорным минимумом, и предполагая, что это будет зарегистрировано как 0 (что никогда не произойдет) из getMaxAmplitude(), мы можем сопоставить значения из функции getMaxAmplitude() с максимальным давлением в микрофоне. Это означает, что результат 16375 от getMaxAmplitude() будет соответствовать максимальному давлению 0,3165 Па. Это, конечно, не очень научно, поскольку максимальные и минимальные значения являются чистой догадкой, но это дает нам отправную точку. Теперь мы можем вычислить p с помощью
p=getMaxAmplitude()/51805.5336
Зная давление в микрофоне, мы можем рассчитать значение дБ(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-секундной выборке и, таким образом, являются более точными. После этого выполняются вышеописанные расчеты. Это даст более реалистичное значение в децибелах. Обратите внимание, что микрофоны мобильных телефонов по-прежнему отстой, и что этот алгоритм не будет давать фактические дБ (SPL), а только немного лучшее приближение, чем предыдущий.
Чтобы добиться производительности некоторых приложений, необходимо сделать еще кое-что. Большинство этих приложений используют скользящие окна, что означает продолжение записи и сдвиг окна на x секунд для непрерывной оценки уровня звука. Также я проведу некоторую оценку того, какое значение дБ лучше всего подходит для использования в качестве максимального, прямо сейчас это 90 дБ (SPL) / 0,6325 Па, что является лишь разумным предположением, вероятно, оно будет немного выше этого.
Как только у меня будет больше, я обновлю информацию.
person
Lukas Ruge
schedule
14.02.2013