/// <summary> /// Implements the "Adaptive Level Equalisatsion" algorithm of Lamel et al, 1981 - with modifications for our signals. /// Units are assumed to be decibels. /// Returns the min and max frame dB AND the estimate MODAL or BACKGROUND noise for the signal array /// IF This modal noise is subtracted from each frame dB, the effect is to set set average background noise level = 0 dB. /// The algorithm is described in Lamel et al, 1981. /// USED TO SEGMENT A RECORDING INTO SILENCE AND VOCALISATION /// NOTE: noiseThreshold is passed as decibels. Original Lamel algorithm ONLY SEARCHES in range min to 10dB above min. /// /// This method debugged on 7 Aug 2018 using following command line arguments: /// audio2csv Y:\TheNatureConservency\Myanmar\20180517\site112\2018_02_14_Bar5\20180214_Bar5\20180214_101121_Bar5.wav Towsey.Acoustic.yml C:\Temp... -m True /// </summary> /// <param name="dBarray">signal in decibel values</param> /// <param name="minDb">minimum value in the passed array of decibel values</param> /// <param name="maxDb">maximum value in the passed array of decibel values</param> /// <param name="modeNoise">modal or background noise in decibels</param> /// <param name="sdNoise">estimated sd of the noies - assuming noise to be guassian</param> public static void CalculateNoiseUsingLamelsAlgorithm( double[] dBarray, out double minDb, out double maxDb, out double modeNoise, out double sdNoise) { // set constants double noiseThreshold_DB = 10.0; // dB var binCount = 100; // number of bins for histogram is FIXED double histogramBinWidth = noiseThreshold_DB / binCount; //ignore first N and last N frames when calculating background noise level because // sometimes these frames have atypically low signal values int buffer = 20; //ignore first N and last N frames when calculating background noise level //HOWEVER do not ignore them for short recordings! int arrayLength = dBarray.Length; if (arrayLength < 1000) { buffer = 0; //ie recording is < approx 11 seconds long } double min = double.MaxValue; double max = -double.MaxValue; for (int i = buffer; i < arrayLength - buffer; i++) { if (dBarray[i] < min) { min = dBarray[i]; } else if (dBarray[i] > max) { max = dBarray[i]; } } if (min <= SNR.MinimumDbBoundForEnvironmentalNoise) { min = SNR.MinimumDbBoundForEnvironmentalNoise; } // return the outs! minDb = min; maxDb = max; var histo = new int[binCount]; var absThreshold = minDb + noiseThreshold_DB; for (var i = 0; i < arrayLength; i++) { if (dBarray[i] <= absThreshold) { var id = (int)((dBarray[i] - minDb) / histogramBinWidth); if (id >= binCount) { id = binCount - 1; } else if (id < 0) { id = 0; } histo[id]++; } } var smoothHisto = DataTools.filterMovingAverage(histo, 3); //DataTools.writeBarGraph(histo); // find peak of lowBins histogram SNR.GetModeAndOneStandardDeviation(smoothHisto, out var indexOfMode, out var indexOfOneSd); // return remaining outs! modeNoise = min + ((indexOfMode + 1) * histogramBinWidth); // modal noise level sdNoise = (indexOfMode - indexOfOneSd) * histogramBinWidth; // SD of the noise }