2010-11-11 35 views
21

我使用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。

我做錯了嗎?

+0

有可能是背景噪音? – mauris 2010-11-11 07:42:06

+1

有用的研究人員找到此頁:float rms2db(float value) { return 10 * log10(value); } – 2016-02-28 13:29:07

回答

31

測量聲音信號的電平時,應根據RMS值計算dB。在您的樣本中,您正在查看絕對峯值水平。單(峯值)的採樣值決定了你的分貝值,即使在其他所有樣品都完全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毫秒。 請注意,計算出的dB值是相對於滿量程的。對於聲音,dB值應與20 uPa相關,並且您需要校準信號以找到從數字值到壓力值的正確轉換。

+0

而通過校準,你的意思是說,每個客戶端將不得不找到他們的零...因爲每個設備和環境會不同?例如,我的,似乎是-40,而一切都沉默....我會校準到零? – 2010-11-11 15:58:05

+0

通常你會使用麥克風校準器。校準器輸出的信號具有非常精確的已知電平,例如98 dB。然後測量/記錄該信號並導出一個比例因子(與每個採樣值相乘),使得您計算的分貝值爲98 dB。 – Han 2010-11-11 17:55:50

+3

校準器的98dB相對於20uPa,因此實際有效壓力等級爲20 * 10E-6 * 10 ^(98/20)= 1.59帕。 有時您可以找到麥克風靈敏度,單位爲mV/Pa。那麼您只需要知道ADC輸入端的電壓與ADC輸出的數字值之間的關係。這將允許您使用已知的電壓源(或電壓表)來校準麥克風後面的電路,並使用麥克風靈敏度來獲取校準比例因子。 – Han 2010-11-11 18:09:23

3

我認爲Yann意味着分貝是一個相對的尺度。如果您嘗試測量實際的聲壓級或聲壓級,則需要進行校準。你測量的是dBFS(我認爲是全分貝的分貝)。您正在測量的信號比信號最大的信號(「滿量程」信號或這些16位採樣的32768信號)噪聲有多少分貝更安靜。這就是爲什麼所有的價值都是消極的。

+0

正確,修復排雷:) – 2010-11-11 08:15:10

5

我很欣賞韓的文章,並寫了一個例程,可以計算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; 
     } 
    }