Что на самом деле дает мне функция Android getMaxAmplitude() для MediaRecorder?

The Android MediaRecorder has a function

.getMaxAmplitude();
which, as the API tells me, "Returns the maximum absolute amplitude that was sampled since the last call to this method." but I can't find what amplitude this is? Is it in pascal or watts?

Я нашел на нескольких страницах в Интернете, что вы можете рассчитать значение, тесно связанное с децибелами, используя (как было предложено здесь).

double db = (20 * Math.log10(amplitude / REFERENCE)); 

что позволило бы мне предположить, что возвращаемое значение находится в некоторой линейной шкале (возможно, что-то вроде миллипаскаля...)

REFERENCE=0,1 (я знаю, что это должно быть что-то вроде 2*10^(-5) Паскалей ((20 мкПаскалей)), но это возвращает странные значения... 0,1, как ни странно, работает лучше.)

Right now I measure the MaxAmplitude() using the

getMaxAmplitude()
and put this into the variable amplitude.

Это метод:

public double getNoiseLevel() 
{
    //Log.d("SPLService", "getNoiseLevel() ");
    int x = mRecorder.getMaxAmplitude();
    double x2 = x;
    Log.d("SPLService", "x="+x);
    double db = (20 * Math.log10(x2 / REFERENCE));
    //Log.d("SPLService", "db="+db);
    if(db>0)
    {
        return db;
    }
    else
    {
        return 0;
    }
}

Это делается 5 раз за полсекунды, что является средним значением.

for(int i=0; i<5; i++)
{
    try 
    {
            Thread.sleep(100);
    } 
    catch (InterruptedException e) 
    {
            e.printStackTrace();
            return 0;
    }
    level = level+getNoiseLevel();
    if(level>0)
    {
        counter++;
    }
}
level=level/counter;
Log.d(LOG_TAG, "level="+level);

Я получаю что-то похожее на децибел, но я вообще не уверен, что это децибел...

Итак, может ли кто-нибудь помочь мне в этом? Кажется очень странным, что API вообще не указывает, что возвращается...


person Lukas Ruge    schedule 18.05.2012    source источник
comment
Это сработало, спасибо за объяснение того, что делает getMaxAmplitude. Но я не уверен, что это точные значения дБ. Когда я тестирую в некоторых случаях и пытаюсь сравнить значения с этим: newton. dep.anl.gov/askasci/phy99/phy99405.htm не хватает 30 дБ. У вас есть идеи, почему?   -  person Wissem    schedule 12.09.2012
comment
Причин может быть несколько: 1. Этот алгоритм использует getMaxAmplitude в качестве основы для расчета, что означает, что все менее громкие события в периоде игнорируются. Это приводит к результатам, которые могут быть выше фактического уровня дБ (и обычно в естественных условиях они таковы) 2. Микрофоны телефонов разные. Некоторые более разумны, чем другие. Этот алгоритм не учитывает это, делая одинаковые вычисления на любом телефоне. Из-за этих различий некоторые телефоны могут давать значительно более высокие или более низкие значения.   -  person Lukas Ruge    schedule 13.09.2012
comment
Кроме того, из-за ограничивающего фактора (значение достигает только 32767) очень громкие шумы не обнаруживаются точно. Обычно отсечка будет около 100 дБ.   -  person Lukas Ruge    schedule 13.09.2012
comment
Хорошо, тогда есть ли лучшие решения? Чтобы получить точное значение дБ от микрофона? На рынке есть несколько приложений (например, шумомер), которые отлично справляются с этой задачей.   -  person Wissem    schedule 13.09.2012
comment
Явно есть. Если вы храните исходные данные с аудиомагнитофона, вы можете провести их комплексный анализ, в том числе с использованием фильтрации/частотного анализа для компенсации недостатков микрофона. Например, вы можете использовать FFT-Packed из Стэнфорда и, возможно, рассчитать лучшее значение из выборки вместо дискретных значений maxAmplitude. Однако все это выходит за рамки первоначального вопроса и, вероятно, обсуждалось в другом месте.   -  person Lukas Ruge    schedule 13.09.2012
comment
Прости, но я тебя не понимаю. Что вы подразумеваете под использованием FFT-Packed? Кроме того, я нашел этот код code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/ выглядит немного точным (если добавить значение +30 дБ) Кажется, они делят max getMaxAmplitude на 2700,0 (строка 51). Знаете, почему они так сделали?   -  person Wissem    schedule 20.09.2012
comment
дополнительную информацию о fft можно найти по адресу en.wikipedia.org/wiki/Fast_Fourier_transform. a href="http://introcs.cs.princeton.edu/java/97data/FFT.java.html" rel="nofollow noreferrer">introcs.cs.princeton.edu/java/97data/FFT.java.html . На 2700.0 понятия не имею. Вместо значения от 0 до 32768 теперь они получают значение примерно до 12, может быть, это более удобно для них. Они ни в коем случае фактически не вычисляют дБ.   -  person Lukas Ruge    schedule 21.09.2012
comment
Спасибо, я посмотрю на эти!   -  person Wissem    schedule 21.09.2012
comment
@Lukas Вы должны поместить ответ не как редактирование, а как .. ответ! :) Таким образом, люди могут отдать вам должное за то, что вы узнали. И нет ничего странного в том, чтобы ответить на свой вопрос ;)   -  person Marcin Koziński    schedule 17.10.2012


Ответы (2)


Я мог бы найти ответ на этот вопрос и поделюсь им со всеми, кому это интересно: Функция MediaRecorder.getMaxAmplitude() возвращает 16-битные целые числа без знака (0-32767). Вероятно, это всего лишь abs() выборочных значений качества компакт-диска, которые варьируются от -32768 до 32767. Это означает, что они, вероятно, представляют собой 16-битную оцифровку электрического выхода от 0 до 100% диапазона максимального напряжения сборки микрофона. в этот мобильный телефон. Поскольку даже в мобильных телефонах одной марки эти микрофоны иногда различаются по своему точному диапазону, даже аналогичные телефоны не обязательно будут давать одинаковое значение при одинаковом расстоянии до одного и того же источника звука.

Это значение, однако, коррелирует со звуковым давлением в Паскалях, так как это также линейное квантование звукового давления в области, где звук может быть измерен с помощью данного микрофона (который не будет охватывать весь спектр из-за ограничений телефона).

person Lukas Ruge    schedule 17.10.2012
comment
Беззнаковые 16-битные целые числа на самом деле 0-65536, а не 0-32767, поэтому я предполагаю, что значение сдвинуто так, что оно положительное - person mcont; 25.08.2019
comment
@mcont В ответе говорится, что, вероятно, берется абсолютное значение 16-битного значения в диапазоне от -32768 до 32768. Таким образом, вывод будет между 0 и 32768. - person Kathir; 25.09.2020

Над этим еще поработал. Используя некоторые тесты, проведенные с помощью откалиброванных 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
comment
Большое спасибо - это очень полезно - person Kylie Moden; 28.06.2013
comment
Знаете ли вы, если при вызове метода recorder.read(data, 0, bufferSize); записывающее устройство получает амплитуды и сохраняет их в массиве коротких данных? Я не совсем уверен, понимаю ли я, что делает метод. - person Kylie Moden; 01.08.2013
comment
Это сэмплированные значения с микрофона, которые сохраняются. Они будут (как и давление на микрофон) колебаться между положительными и отрицательными значениями. Таким образом, чтобы получить амплитуду, вам придется использовать какой-то медианный или взвешенный расчет. - person Lukas Ruge; 01.08.2013
comment
Так что же представляют собой эти выборочные значения и в чем они измеряются? (т.е. что хранится в массиве данных) - еще раз спасибо, я очень ценю это - person Kylie Moden; 01.08.2013
comment
Когда давление воздуха от звуковых волн достигает микрофона, давление преобразуется в электрический ток. Нормальное атмосферное давление равняется значению 0. Поскольку звук представляет собой волну, ток колеблется ниже и выше нуля в зависимости от осцилляции. Этот ток измеряется 44 100 раз в секунду. Эти значения преобразуются в короткие значения и сохраняются в этом массиве (это результат квантования). - person Lukas Ruge; 01.08.2013
comment
Кроме того, извините, что я продолжаю задавать вопросы - я очень ценю, что вы нашли время, чтобы ответить, какую формулу вы используете, чтобы получить 51805,5336? Я полностью понимаю, как вы получили 0,6325 Па (поскольку 90 дБ - это заявленный максимум микрофона, и вы преобразовали значение), но откуда взялось это число 51805,5336? Еще раз спасибо - person Kylie Moden; 02.08.2013
comment
На самом деле, ничего, я понял! Это просто коэффициент пересчета (32767/0,6325) - еще раз спасибо - person Kylie Moden; 02.08.2013
comment
В чем смысл «Math.abs(s)», если перед ним стоит «if(s›0)»? Действительно, нужен ли оператор if? - person Hardell; 20.08.2014
comment
Как бы вы представили возвращаемое значение из getNoiseLevel()? Например. используя традиционную полосу громкости? - person l33t; 07.01.2017