/// <summary> /// Use this method when want to match defined shape in target using cross-correlation. /// This was the method used by Stewart Gage. /// First set target and source to same dynamic range. /// Then NormaliseMatrixValues target and source to unit-length. /// </summary> public static Tuple <double[]> Execute_StewartGage(double[,] target, double dynamicRange, SpectrogramStandard sonogram, List <AcousticEvent> segments, int minHz, int maxHz, double minDuration) { Log.WriteLine("SEARCHING FOR EVENTS LIKE TARGET."); if (segments == null) { return(null); } int minBin = (int)(minHz / sonogram.FBinWidth); int maxBin = (int)(maxHz / sonogram.FBinWidth); int targetLength = target.GetLength(0); //adjust target's dynamic range to that set by user target = SNR.SetDynamicRange(target, 0.0, dynamicRange); //set event's dynamic range double[] v1 = DataTools.Matrix2Array(target); v1 = DataTools.normalise2UnitLength(v1); //var image = BaseSonogram.Data2ImageData(target); //ImageTools.DrawMatrix(image, 1, 1, @"C:\SensorNetworks\Output\FELT_Currawong\target.png"); double[] scores = new double[sonogram.FrameCount]; foreach (AcousticEvent av in segments) { Log.WriteLine("SEARCHING SEGMENT."); int startRow = (int)Math.Round(av.TimeStart * sonogram.FramesPerSecond); int endRow = (int)Math.Round(av.TimeEnd * sonogram.FramesPerSecond); if (endRow >= sonogram.FrameCount) { endRow = sonogram.FrameCount; } int stopRow = endRow - targetLength; if (stopRow <= startRow) { stopRow = startRow + 1; //want minimum of one row } int offset = targetLength / 2; for (int r = startRow; r < stopRow; r++) { double[,] matrix = DataTools.Submatrix(sonogram.Data, r, minBin, r + targetLength - 1, maxBin); matrix = SNR.SetDynamicRange(matrix, 0.0, dynamicRange); //set event's dynamic range //var image = BaseSonogram.Data2ImageData(matrix); //ImageTools.DrawMatrix(image, 1, 1, @"C:\SensorNetworks\Output\FELT_CURLEW\compare.png"); double[] v2 = DataTools.Matrix2Array(matrix); v2 = DataTools.normalise2UnitLength(v2); scores[r] = DataTools.DotProduct(v1, v2); //the Cross Correlation } // end of rows in segment } // foreach (AcousticEvent av in segments) var tuple = Tuple.Create(scores); return(tuple); }
public static double[] AnalyseWaveformAtLocation(double[] signal, double amplitudeThreshold, double scoreThreshold) { double[] waveTemplate = { -0.000600653, -0.000451427, -0.000193289, -1.91083E-05, 0.000133366, 0.000256465, 0.000387591, 0.000533758, 0.000645976, 0.000670944, 0.000622045, 0.000569337, 0.000553455, 0.000535552, 0.000448935, 0.000286928, 0.000120322, 2.26704E-05, -1.67728E-05, -9.42369E-05, -0.000289969, -0.000565902, -0.00079103, -0.000883849, -0.000898074, -0.000932191, -0.000985956, -0.00097387, -0.00093, -0.00088, -0.00088, -0.00087, -0.000883903, -0.000831651, -0.000759236, -0.000668421, -0.00052348, -0.000361632, -0.00028245, -0.000292255, -0.00025, -8.71854E-05, 0.00011, 0.00014, 0.00010031, 0.00013, 0.00016, 0.000240405, 0.000332283, 0.000357989, 0.000312231, 0.000222307, 0.000138079, 9.49253E-05, 6.74344E-05, -7.81347E-07, -0.000103014, -0.00014973, }; int templateLength = waveTemplate.Length; double[] normalTemplate = DataTools.normalise2UnitLength(waveTemplate); double[] scores = new double[signal.Length]; for (int i = 2; i < signal.Length - templateLength; i++) { // look for a local minimum if (signal[i] > signal[i - 1] || signal[i] > signal[i - 2] || signal[i] > signal[i + 1] || signal[i] > signal[i + 2]) { continue; } double[] subsampleWav = DataTools.Subarray(signal, i, templateLength); double min, max; DataTools.MinMax(subsampleWav, out min, out max); if (max - min < amplitudeThreshold) { continue; } double[] normalwav = DataTools.normalise2UnitLength(subsampleWav); // calculate cosine angle as similarity score double score = DataTools.DotProduct(normalTemplate, normalwav); if (score > scoreThreshold) { for (int j = 0; j < templateLength; j++) { if (score > scores[i + j]) { scores[i + j] = score; } } } } //scores = DataTools.NormaliseMatrixValues(scores); //scores = DataTools.filterMovingAverageOdd(scores, 3); return(scores); }
/// <summary> /// This done using Cosine similarity. Could also use Euclidian distance. /// </summary> /// <param name=""></param> /// <param name=""></param> public static void CalculateSimilarityScores(Arguments arguments, Output output) { int speciesCount = arguments.SpeciesCount; int instanceCount = arguments.InstanceCount; output.SimilarityScores = new double[instanceCount, speciesCount]; // loop through all instances for (int r = 0; r < instanceCount; r++) { double[] instance = MatrixTools.GetRow(output.InstanceFeatureMatrix, r); for (int s = 0; s < speciesCount; s++) { double[] species = MatrixTools.GetRow(output.SpeciesFeatureMatrix, s); double similarity = DataTools.DotProduct(instance, species); output.SimilarityScores[r, s] = similarity; } } // end for loop r over all instances }
public static Tuple <double[]> Execute_MFCC_XCOR(double[,] target, double dynamicRange, SpectrogramStandard sonogram, List <AcousticEvent> segments, int minHz, int maxHz, double minDuration) { Log.WriteLine("SEARCHING FOR EVENTS LIKE TARGET."); if (segments == null) { return(null); } int minBin = (int)(minHz / sonogram.FBinWidth); int maxBin = (int)(maxHz / sonogram.FBinWidth); int targetLength = target.GetLength(0); //set up the matrix of cosine coefficients int coeffCount = 12; //only use first 12 coefficients. int binCount = target.GetLength(1); //number of filters in filter bank double[,] cosines = MFCCStuff.Cosines(binCount, coeffCount + 1); //set up the cosine coefficients //adjust target's dynamic range to that set by user target = SNR.SetDynamicRange(target, 3.0, dynamicRange); //set event's dynamic range target = MFCCStuff.Cepstra(target, coeffCount, cosines); double[] v1 = DataTools.Matrix2Array(target); v1 = DataTools.normalise2UnitLength(v1); string imagePath2 = @"C:\SensorNetworks\Output\FELT_Currawong\target.png"; var result1 = BaseSonogram.Data2ImageData(target); var image = result1.Item1; ImageTools.DrawMatrix(image, 1, 1, imagePath2); double[] scores = new double[sonogram.FrameCount]; foreach (AcousticEvent av in segments) { Log.WriteLine("SEARCHING SEGMENT."); int startRow = (int)Math.Round(av.TimeStart * sonogram.FramesPerSecond); int endRow = (int)Math.Round(av.TimeEnd * sonogram.FramesPerSecond); if (endRow >= sonogram.FrameCount) { endRow = sonogram.FrameCount - 1; } endRow -= targetLength; if (endRow <= startRow) { endRow = startRow + 1; //want minimum of one row } for (int r = startRow; r < endRow; r++) { double[,] matrix = DataTools.Submatrix(sonogram.Data, r, minBin, r + targetLength - 1, maxBin); matrix = SNR.SetDynamicRange(matrix, 3.0, dynamicRange); //set event's dynamic range //string imagePath2 = @"C:\SensorNetworks\Output\FELT_Gecko\compare.png"; //var image = BaseSonogram.Data2ImageData(matrix); //ImageTools.DrawMatrix(image, 1, 1, imagePath2); matrix = MFCCStuff.Cepstra(matrix, coeffCount, cosines); double[] v2 = DataTools.Matrix2Array(matrix); v2 = DataTools.normalise2UnitLength(v2); double crossCor = DataTools.DotProduct(v1, v2); scores[r] = crossCor; } //end of rows in segment } //foreach (AcousticEvent av in segments) var tuple = Tuple.Create(scores); return(tuple); }