30

Android MediaRecorder には関数があります

.getMaxAmplitude();
これは、APIが教えてくれるように、「このメソッドへの最後の呼び出し以降にサンプリングされた最大絶対振幅を返します」。しかし、私はこれがどの振幅であるかを見つけることができませんか? パスカルですか、それともワットですか。

Web 上のいくつかのページで、デシベルに密接に関連する値を計算できることを発見しました (ここで提案されているように)。

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

これにより、戻り値が線形スケールであると仮定できます(おそらくミリパスカルのようなものです...)

REFERENCE=0.1 (これは 2*10^(-5) Pascal ((20 uPascal)) のようなものであるべきだと認識していますが、それは奇妙な値を返します... 0.1 は奇妙にうまく機能します。)

今、私は MaxAmplitude() を使用して測定します

getMaxAmplitude()
これを可変振幅に入れます。

これは方法です:

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;
    }
}

これは 0.5 秒間に 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が返されるものをまったく指定しないのは非常に奇妙に思えます...

4

2 に答える 2

24

この質問に対する答えを見つけることができたので、気になる人のためにここで共有します。このMediaRecorder.getMaxAmplitude()関数は、符号なし16ビット整数値(0-32767)を返します。これはおそらく、-32768〜32767の範囲のCD品質のサンプル値のabs()にすぎません。これは、マイクビルドの最大電圧範囲0〜100%の電気出力の16ビットデジタル化を表している可能性があることを意味します。その携帯電話に。あるブランドの携帯電話でも、これらのマイクは正確な範囲が異なる場合があるため、同じ音源まで同じ距離を指定しても、同じような電話でも同じ値を返すとは限りません。

ただし、この値はPascalの音圧と相関関係があります。これは、特定のマイクで音を測定できる領域(電話の制限により、スペクトル全体をカバーできない領域)での音圧の線形定量化でもあるためです。

于 2012-10-17T10:28:41.260 に答える
23

これにもう少し取り組みました。キャリブレーション済みの 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 値を評価します。現時点では 90 dB(SPL)/0.6325 Pa であり、これは妥当な推測にすぎません。おそらくそれよりわずかに高いでしょう。

また情報が入り次第、更新します。

于 2013-02-14T08:16:28.793 に答える