// ############################################################################################################################# // ################################# FOUR DIFFERENT METHODS TO CALCULATE THE BACKGROUND NOISE PROFILE // // (1) MODAL METHOD // (2) LOWEST PERCENTILE FRAMES METHOD // (3) BIN-WISE LOWEST PERCENTILE CELLS METHOD // (4) FIRST N FRAMES // ################## /// <summary> /// (1) MODAL METHOD /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins. /// Returns the noise profile over freq bins. i.e. one noise value per freq bin. /// </summary> /// <param name="matrix">the spectrogram with origin top-left</param> /// <param name="sdCount">number of standard deviations</param> public static NoiseProfile CalculateModalNoiseProfile(double[,] matrix, double sdCount) { int colCount = matrix.GetLength(1); double[] noiseMode = new double[colCount]; double[] noiseSd = new double[colCount]; double[] noiseThreshold = new double[colCount]; double[] minsOfBins = new double[colCount]; double[] maxsOfBins = new double[colCount]; for (int col = 0; col < colCount; col++) { double[] freqBin = MatrixTools.GetColumn(matrix, col); SNR.BackgroundNoise binNoise = SNR.CalculateModalBackgroundNoiseInSignal(freqBin, sdCount); noiseMode[col] = binNoise.NoiseMode; noiseSd[col] = binNoise.NoiseSd; noiseThreshold[col] = binNoise.NoiseThreshold; minsOfBins[col] = binNoise.MinDb; maxsOfBins[col] = binNoise.MaxDb; } var profile = new NoiseProfile() { NoiseMode = noiseMode, NoiseSd = noiseSd, NoiseThresholds = noiseThreshold, MinDb = minsOfBins, MaxDb = maxsOfBins, }; return(profile); }
} //Analysis() public static Tuple <List <Dictionary <string, double> >, double[]> DetectGratingEvents(double[,] matrix, int colStep, double intensityThreshold) { bool doNoiseremoval = true; int minPeriod = 2; //both period values must be even numbers int maxPeriod = 20; //Note: 17.2 frames per second i.e. period=20 is just over 1s. int numberOfCycles = 4; int step = 1; int rowCount = matrix.GetLength(0); int colCount = matrix.GetLength(1); int numberOfColSteps = colCount / colStep; var events2return = new List <Dictionary <string, double> >(); double[] array2return = null; for (int b = 0; b < numberOfColSteps; b++) { int minCol = (b * colStep); int maxCol = minCol + colStep - 1; double[,] subMatrix = MatrixTools.Submatrix(matrix, 0, minCol, (rowCount - 1), maxCol); double[] amplitudeArray = MatrixTools.GetRowAverages(subMatrix); if (doNoiseremoval) { double StandardDeviationCount = 0.1; // number of noise SDs to calculate noise threshold - determines severity of noise reduction SNR.BackgroundNoise bgn = SNR.SubtractBackgroundNoiseFromSignal(amplitudeArray, StandardDeviationCount); amplitudeArray = bgn.NoiseReducedSignal; } //var events = CrossCorrelation.DetectBarsEventsBySegmentationAndXcorrelation(amplitudeArray, intensityThreshold); var scores = Gratings.ScanArrayForGratingPattern(amplitudeArray, minPeriod, maxPeriod, numberOfCycles, step); var mergedOutput = Gratings.MergePeriodicScoreArrays(scores, minPeriod, maxPeriod); double[] intensity = mergedOutput.Item1; double[] periodicity = mergedOutput.Item2; var events = Gratings.ExtractPeriodicEvents(intensity, periodicity, intensityThreshold); foreach (Dictionary <string, double> item in events) { item[key_MIN_FREQBIN] = minCol; item[key_MAX_FREQBIN] = maxCol; events2return.Add(item); } if (b == 3) { array2return = amplitudeArray; //returned for debugging purposes only } } //for loop over bands of columns return(Tuple.Create(events2return, array2return)); }//end DetectGratingEvents()
//public const string key_COUNT = "count"; public static Tuple <double[, ], double[, ], double[, ], double[]> DetectBarsUsingXcorrelation(double[,] m, int rowStep, int rowWidth, int colStep, int colWidth, double intensityThreshold, int zeroBinCount) { bool doNoiseremoval = true; //intensityThreshold = 0.3; int rowCount = m.GetLength(0); int colCount = m.GetLength(1); int numberOfColSteps = colCount / colStep; int numberOfRowSteps = rowCount / rowStep; var intensityMatrix = new double[numberOfRowSteps, numberOfColSteps]; var periodicityMatrix = new double[numberOfRowSteps, numberOfColSteps]; var hitsMatrix = new double[rowCount, colCount]; double[] array2return = null; for (int b = 0; b < numberOfColSteps; b++) { int minCol = b * colStep; int maxCol = minCol + colWidth - 1; double[,] subMatrix = MatrixTools.Submatrix(m, 0, minCol, rowCount - 1, maxCol); double[] amplitudeArray = MatrixTools.GetRowAverages(subMatrix); if (doNoiseremoval) { double StandardDeviationCount = 0.1; // number of noise SDs to calculate noise threshold - determines severity of noise reduction SNR.BackgroundNoise bgn = SNR.SubtractBackgroundNoiseFromSignal(amplitudeArray, StandardDeviationCount); amplitudeArray = bgn.NoiseReducedSignal; } //double noiseThreshold = 0.005; //for (int i = 1; i < amplitudeArray.Length - 1; i++) //{ // if ((amplitudeArray[i - 1] < noiseThreshold) && (amplitudeArray[i + 1] < noiseThreshold)) amplitudeArray[i] = 0.0; //} //DataTools.writeBarGraph(amplitudeArray); if (b == 2) { array2return = amplitudeArray; //returned for debugging purposes only } //ii: DETECT HARMONICS var results = AutoAndCrossCorrelation.DetectPeriodicityInLongArray(amplitudeArray, rowStep, rowWidth, zeroBinCount); double[] intensity = results.Item1; //an array of periodicity scores double[] periodicity = results.Item2; //transfer periodicity info to a matrices. for (int rs = 0; rs < numberOfRowSteps; rs++) { intensityMatrix[rs, b] = intensity[rs]; periodicityMatrix[rs, b] = periodicity[rs]; //mark up the hits matrix //double relativePeriod = periodicity[rs] / rowWidth / 2; if (intensity[rs] > intensityThreshold) { int minRow = rs * rowStep; int maxRow = minRow + rowStep - 1; for (int r = minRow; r < maxRow; r++) { for (int c = minCol; c < maxCol; c++) { //hitsMatrix[r, c] = relativePeriod; hitsMatrix[r, c] = periodicity[rs]; } } } // if() } // for loop over numberOfRowSteps } // for loop over numberOfColSteps return(Tuple.Create(intensityMatrix, periodicityMatrix, hitsMatrix, array2return)); }
} //DetectBarsInTheRowsOfaMatrix() /// A METHOD TO DETECT HARMONICS IN THE ROWS of the passed portion of a sonogram. /// This method assume the matrix is derived from a spectrogram rotated so that the matrix rows are spectral columns of sonogram. /// Was first developed for crow calls. /// First looks for a decibel profile that matches the passed call duration and decibel loudness /// Then samples the centre portion for the correct harmonic period. /// </summary> /// <param name="m"></param> /// <param name="amplitudeThreshold"></param> /// <returns></returns> public static Tuple <double[], double[], double[]> DetectHarmonicsInSonogramMatrix(double[,] m, double dBThreshold, int callSpan) { int zeroBinCount = 3; //to remove low freq content which dominates the spectrum int halfspan = callSpan / 2; double[] dBArray = MatrixTools.GetRowAverages(m); dBArray = DataTools.filterMovingAverage(dBArray, 3); bool doNoiseRemoval = true; if (doNoiseRemoval) { double StandardDeviationCount = 0.1; // number of noise SDs to calculate noise threshold - determines severity of noise reduction SNR.BackgroundNoise bgn = SNR.SubtractBackgroundNoiseFromSignal(dBArray, StandardDeviationCount); dBArray = bgn.NoiseReducedSignal; } bool[] peaks = DataTools.GetPeaks(dBArray); int rowCount = m.GetLength(0); int colCount = m.GetLength(1); var intensity = new double[rowCount]; //an array of period intensity var periodicity = new double[rowCount]; //an array of the periodicity values for (int r = halfspan; r < rowCount - halfspan; r++) { //APPLY A FILTER: must satisfy the following conditions for a call. if (!peaks[r]) { continue; } if (dBArray[r] < dBThreshold) { continue; } double lowerDiff = dBArray[r] - dBArray[r - halfspan]; double upperDiff = dBArray[r] - dBArray[r + halfspan]; if (lowerDiff < dBThreshold || upperDiff < dBThreshold) { continue; } double[] prevRow = DataTools.DiffFromMean(MatrixTools.GetRow(m, r - 1)); double[] thisRow = DataTools.DiffFromMean(MatrixTools.GetRow(m, r)); var spectrum = AutoAndCrossCorrelation.CrossCorr(prevRow, thisRow); for (int s = 0; s < zeroBinCount; s++) { spectrum[s] = 0.0; //in real data these bins are dominant and hide other frequency content } spectrum = DataTools.NormaliseArea(spectrum); int maxId = DataTools.GetMaxIndex(spectrum); double intensityValue = spectrum[maxId]; intensity[r] = intensityValue; double period = 0.0; if (maxId != 0) { period = 2 * colCount / (double)maxId; } periodicity[r] = period; prevRow = thisRow; } // rows return(Tuple.Create(dBArray, intensity, periodicity)); } //DetectHarmonicsInSonogramMatrix()