Подтвердить что ты не робот

Рассчитать децибелы

Я записываю микрофонный вход с помощью библиотеки XNA (я не думаю, что это действительно технология, но это никогда не повредит). Каждый раз, когда я получаю образец, я бы хотел рассчитать децибелы. Я сделал много поисков в Интернете и не нашел убедительного примера...

Вот моя попытка вычисления децибел из образца:

        double peak = 0;

        for (var i = 0; i < _buffer.Length; i = i + 2)
        {
            var sample = BitConverter.ToInt16(_buffer, i);
            if (sample > peak)
                peak = sample;
            else if (sample < -peak)
                peak = -sample;
        }

        var decibel = (20 * Math.Log10(peak/32768));

Если я вывешу значение децибела на экран, я вижу, что значения становятся выше, когда я становлюсь все громче и ниже, когда говорю более мягко. Тем не менее, он всегда колеблется около -40, когда я абсолютно спокоен... Я бы предположил, что это будет -90. У меня должно быть неправильное вычисление в блоке выше? из того, что я читал на некоторых сайтах -40, эквивалентно "мягкому разговору"... однако, он абсолютно тихий.

Кроме того, если я отключу микрофон, он будет равен -90.

Я делаю это неправильно?

4b9b3361

Ответ 1

При измерении уровня звукового сигнала вы должны рассчитать дБ от значения RMS. В вашем примере вы смотрите на абсолютный пиковый уровень. Единственное (пиковое) значение выборки определяет ваше значение дБ, даже если все остальные образцы равны 0.

попробуйте следующее:

double sum = 0;
for (var i = 0; i < _buffer.length; i = i + 2)
{
    double sample = BitConverter.ToInt16(_buffer, i) / 32768.0;
    sum += (sample * sample);
}
double rms = Math.Sqrt(sum / (_buffer.length / 2));
var decibel = 20 * Math.Log10(rms);

Для "мгновенных" дБ уровней вы обычно вычисляете RMS в сегменте 20-50 мс. Обратите внимание, что рассчитанное значение дБ относится к полномасштабному. Для звука значение дБ должно быть связано с 20 мкПа, и вам нужно будет откалибровать сигнал, чтобы найти правильное преобразование из цифровых значений в значения давления.

Ответ 2

Я ценю пост Han и написал процедуру, которая может вычислять децибелы в 8 и 16-битных аудиоформатах, используя несколько каналов, используя его пример.

public double MeasureDecibels(byte[] samples, int length, int bitsPerSample,
        int numChannels, params int[] channelsToMeasure)
    {
        if (samples == null || length == 0 || samples.Length == 0)
        {
            throw new ArgumentException("Missing samples to measure.");
        }
        //check bits are 8 or 16.
        if (bitsPerSample != 8 && bitsPerSample != 16)
        {
            throw new ArgumentException("Only 8 and 16 bit samples allowed.");
        }
        //check channels are valid
        if (channelsToMeasure == null || channelsToMeasure.Length == 0)
        {
            throw new ArgumentException("Must have target channels.");
        }
        //check each channel is in proper range.
        foreach (int channel in channelsToMeasure)
        {
            if (channel < 0 || channel >= numChannels)
            {
                throw new ArgumentException("Invalid channel requested.");
            }
        }

        //ensure we have only full blocks. A half a block isn't considered valid.
        int sampleSizeInBytes = bitsPerSample / 8;
        int blockSizeInBytes = sampleSizeInBytes * numChannels;
        if (length % blockSizeInBytes != 0)
        {
            throw new ArgumentException("Non-integral number of bytes passed for given audio format.");
        }

        double sum = 0;
        for (var i = 0; i < length; i = i + blockSizeInBytes)
        {
            double sumOfChannels = 0;
            for (int j = 0; j < channelsToMeasure.Length; j++)
            {
                int channelOffset = channelsToMeasure[j] * sampleSizeInBytes;
                int channelIndex = i + channelOffset;
                if (bitsPerSample == 8)
                {
                    sumOfChannels = (127 - samples[channelIndex]) / byte.MaxValue;
                }
                else
                {
                    double sampleValue = BitConverter.ToInt16(samples, channelIndex);
                    sumOfChannels += (sampleValue / short.MaxValue);
                }
            }
            double averageOfChannels = sumOfChannels / channelsToMeasure.Length;
            sum += (averageOfChannels * averageOfChannels);
        }
        int numberSamples = length / blockSizeInBytes;
        double rootMeanSquared = Math.Sqrt(sum / numberSamples);
        if (rootMeanSquared == 0)
        {
            return 0;
        }
        else
        {
            double logvalue = Math.Log10(rootMeanSquared);
            double decibel = 20 * logvalue;
            return decibel;
        }
    }

Ответ 3

Я думаю, что Янн означает, что децибелы являются относительной шкалой. Если вы пытаетесь измерить фактический уровень звукового давления или SPL, вам нужно будет откалибровать. Я думаю, что вы измеряете dBFS (децибелы полномасштабные). Вы измеряете, сколько децибел тише сигнала, чем самый громкий сигнал, который система может представлять ( "полномасштабный" сигнал, или 32768 для этих 16-битных выборок). Вот почему все значения отрицательные.