/// <summary> /// This method takes an audio recording and returns an octave scale spectrogram. /// At the present time it only works for recordings with 64000 sample rate and returns a 256 bin sonogram. /// TODO: generalise this method for other recordings and octave scales. /// </summary> public static BaseSonogram ConvertRecordingToOctaveScaleSonogram(AudioRecording recording, FreqScaleType fst) { var freqScale = new FrequencyScale(fst); double windowOverlap = 0.75; var sonoConfig = new SonogramConfig { WindowSize = freqScale.WindowSize, WindowOverlap = windowOverlap, SourceFName = recording.BaseName, NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; // Generate amplitude sonogram and then conver to octave scale var sonogram = new AmplitudeSonogram(sonoConfig, recording.WavReader); // THIS IS THE CRITICAL LINE. // TODO: SHOULD DEVELOP A SEPARATE UNIT TEST for this method sonogram.Data = ConvertAmplitudeSpectrogramToDecibelOctaveScale(sonogram.Data, freqScale); // DO NOISE REDUCTION var dataMatrix = SNR.NoiseReduce_Standard(sonogram.Data); sonogram.Data = dataMatrix; int windowSize = freqScale.FinalBinCount * 2; sonogram.Configuration.WindowSize = windowSize; sonogram.Configuration.WindowStep = (int)Math.Round(windowSize * (1 - windowOverlap)); return(sonogram); }
public static void TestOctaveScale(FreqScaleType fst) { var freqScale = new FrequencyScale(fst); var octaveBinBounds = freqScale.BinBounds; // now test the octave scale using a test spectrum int sr = 22050; int frameSize = 8192; // default for sr = 22050 if (fst == FreqScaleType.Octaves24Nyquist32000 || fst == FreqScaleType.Linear125Octaves7Tones28Nyquist32000) { sr = 64000; frameSize = 16384; // default for sr = 64000 } // Get a simple test spectrum var linearSpectrum = GetSimpleTestSpectrum(sr, frameSize); //do the test var octaveSpectrum = OctaveSpectrum(octaveBinBounds, linearSpectrum); // write output int rowCount = octaveBinBounds.GetLength(0); for (int i = 0; i < rowCount; i++) { Console.WriteLine(i + " bin-" + octaveBinBounds[i, 0] + " " + octaveBinBounds[i, 1] + "Hz " + octaveSpectrum[i]); } }
public static void TestMethod_GenerateSignal1() { int sampleRate = 22050; double duration = 20; // signal duration in seconds int[] harmonics = { 500, 1000, 2000, 4000, 8000 }; int windowSize = 512; var freqScale = new FrequencyScale(sampleRate / 2, windowSize, 1000); string path = @"C:\SensorNetworks\Output\Sonograms\UnitTestSonograms\SineSignal1.png"; var recording = GenerateTestRecording(sampleRate, duration, harmonics, WaveType.Cosine); var sonoConfig = new SonogramConfig { WindowSize = freqScale.WindowSize, WindowOverlap = 0.0, SourceFName = "Signal1", NoiseReductionType = NoiseReductionType.Standard, NoiseReductionParameter = 0.12, }; var sonogram = new AmplitudeSonogram(sonoConfig, recording.WavReader); // pick a row, any row var oneSpectrum = MatrixTools.GetRow(sonogram.Data, 40); oneSpectrum = DataTools.normalise(oneSpectrum); var peaks = DataTools.GetPeaks(oneSpectrum, 0.5); for (int i = 2; i < peaks.Length - 2; i++) { if (peaks[i]) { LoggedConsole.WriteLine($"bin ={freqScale.BinBounds[i, 0]}, Herz={freqScale.BinBounds[i, 1]}-{freqScale.BinBounds[i + 1, 1]} "); } } if (peaks[11] && peaks[22] && peaks[45] && peaks[92] && peaks[185]) { LoggedConsole.WriteSuccessLine("Spectral Peaks found at correct places"); } else { LoggedConsole.WriteErrorLine("Spectral Peaks found at INCORRECT places"); } foreach (int h in harmonics) { LoggedConsole.WriteLine($"Harmonic {h}Herz should be in bin {freqScale.GetBinIdForHerzValue(h)}"); } // spectrogram without framing, annotation etc var image = sonogram.GetImage(); string title = $"Spectrogram of Harmonics: {DataTools.Array2String(harmonics)} SR={sampleRate} Window={windowSize}"; image = sonogram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations); image.Save(path); }
/// <summary> /// METHOD TO CHECK IF Octave FREQ SCALE IS WORKING /// Check it on standard one minute recording, SR=22050. /// </summary> public static void TESTMETHOD_OctaveFrequencyScale1() { var recordingPath = @"G:\SensorNetworks\WavFiles\LewinsRail\FromLizZnidersic\Lewinsrail_TasmanIs_Tractor_SM304253_0151119_0640_1minMono.wav"; var outputDir = @"C:\SensorNetworks\Output\LewinsRail\LewinsRail_ThreeCallTypes".ToDirectoryInfo(); //var recordingPath = @"C:\SensorNetworks\SoftwareTests\TestRecordings\BAC\BAC2_20071008-085040.wav"; //var outputDir = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale".ToDirectoryInfo(); //var expectedResultsDir = Path.Combine(outputDir.FullName, TestTools.ExpectedResultsDir).ToDirectoryInfo(); var outputImagePath = Path.Combine(outputDir.FullName, "octaveFrequencyScale1NoNoiseReduciton.png"); //var opFileStem = "Lewinsrail_TasmanIs_Tractor"; var recording = new AudioRecording(recordingPath); // default octave scale var fst = FreqScaleType.Linear125Octaves6Tones30Nyquist11025; var freqScale = new FrequencyScale(fst); var sonoConfig = new SonogramConfig { WindowSize = freqScale.WindowSize, WindowOverlap = 0.75, SourceFName = recording.BaseName, NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; // Generate amplitude sonogram and then conver to octave scale var sonogram = new AmplitudeSonogram(sonoConfig, recording.WavReader); sonogram.Data = OctaveFreqScale.ConvertAmplitudeSpectrogramToDecibelOctaveScale(sonogram.Data, freqScale); // DO NOISE REDUCTION //var dataMatrix = SNR.NoiseReduce_Standard(sonogram.Data); //sonogram.Data = dataMatrix; sonogram.Configuration.WindowSize = freqScale.WindowSize; var image = sonogram.GetImageFullyAnnotated(sonogram.GetImage(), "SPECTROGRAM: " + fst.ToString(), freqScale.GridLineLocations); image.Save(outputImagePath); // DO FILE EQUALITY TEST //string testName = "test1"; //var expectedTestFile = new FileInfo(Path.Combine(expectedResultsDir.FullName, "FrequencyOctaveScaleTest1.EXPECTED.json")); //var resultFile = new FileInfo(Path.Combine(outputDir.FullName, opFileStem + "FrequencyOctaveScaleTest1Results.json")); //Acoustics.Shared.Csv.Csv.WriteMatrixToCsv(resultFile, freqScale.GridLineLocations); //TestTools.FileEqualityTest(testName, resultFile, expectedTestFile); LoggedConsole.WriteLine("Completed Octave Frequency Scale test 1"); Console.WriteLine("\n\n"); }
/// <summary> /// METHOD TO CHECK IF SPECIFIED linear FREQ SCALE IS WORKING /// Check it on standard one minute recording. /// </summary> public static void TESTMETHOD_LinearFrequencyScale() { var recordingPath = @"C:\SensorNetworks\SoftwareTests\TestRecordings\BAC2_20071008-085040.wav"; var outputDir = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale".ToDirectoryInfo(); var expectedResultsDir = Path.Combine(outputDir.FullName, TestTools.ExpectedResultsDir).ToDirectoryInfo(); var outputImagePath = Path.Combine(outputDir.FullName, "linearScaleSonogram.png"); var opFileStem = "BAC2_20071008"; var recording = new AudioRecording(recordingPath); // specfied linear scale int nyquist = 11025; int frameSize = 1024; int hertzInterval = 1000; var freqScale = new FrequencyScale(nyquist, frameSize, hertzInterval); var fst = freqScale.ScaleType; var sonoConfig = new SonogramConfig { WindowSize = freqScale.FinalBinCount * 2, WindowOverlap = 0.2, SourceFName = recording.BaseName, //NoiseReductionType = NoiseReductionType.Standard, NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; var sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader); // DO NOISE REDUCTION var dataMatrix = SNR.NoiseReduce_Standard(sonogram.Data); sonogram.Data = dataMatrix; sonogram.Configuration.WindowSize = freqScale.WindowSize; var image = sonogram.GetImageFullyAnnotated(sonogram.GetImage(), "SPECTROGRAM: " + fst.ToString(), freqScale.GridLineLocations); image.Save(outputImagePath); // DO FILE EQUALITY TEST string testName = "testName"; var expectedTestFile = new FileInfo(Path.Combine(expectedResultsDir.FullName, "FrequencyLinearScaleTest.EXPECTED.json")); var resultFile = new FileInfo(Path.Combine(outputDir.FullName, opFileStem + "FrequencyLinearScaleTestResults.json")); Acoustics.Shared.Csv.Csv.WriteMatrixToCsv(resultFile, freqScale.GridLineLocations); TestTools.FileEqualityTest(testName, resultFile, expectedTestFile); LoggedConsole.WriteLine("Completed Linear Frequency Scale test"); Console.WriteLine("\n\n"); }
/// <summary> /// METHOD TO CHECK IF SPECIFIED MEL FREQ SCALE IS WORKING /// Check it on standard one minute recording. /// </summary> public static void TESTMETHOD_MelFrequencyScale() { var recordingPath = @"C:\SensorNetworks\SoftwareTests\TestRecordings\BAC2_20071008-085040.wav"; var outputDir = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale".ToDirectoryInfo(); var expectedResultsDir = Path.Combine(outputDir.FullName, TestTools.ExpectedResultsDir).ToDirectoryInfo(); var outputImagePath = Path.Combine(outputDir.FullName, "melScaleSonogram.png"); var opFileStem = "BAC2_20071008"; var recording = new AudioRecording(recordingPath); int nyquist = recording.Nyquist; int frameSize = 1024; int finalBinCount = 256; int hertzInterval = 1000; FreqScaleType scaleType = FreqScaleType.Mel; var freqScale = new FrequencyScale(scaleType, nyquist, frameSize, finalBinCount, hertzInterval); var fst = freqScale.ScaleType; var sonoConfig = new SonogramConfig { WindowSize = frameSize, WindowOverlap = 0.2, SourceFName = recording.BaseName, DoMelScale = (scaleType == FreqScaleType.Mel) ? true : false, MelBinCount = (scaleType == FreqScaleType.Mel) ? finalBinCount : frameSize / 2, //NoiseReductionType = NoiseReductionType.Standard, NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; var sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader); // DRAW SPECTROGRAM var image = sonogram.GetImageFullyAnnotated(sonogram.GetImage(), "SPECTROGRAM: " + fst.ToString(), freqScale.GridLineLocations); image.Save(outputImagePath); // DO FILE EQUALITY TEST string testName = "MelTest"; var expectedTestFile = new FileInfo(Path.Combine(expectedResultsDir.FullName, "MelFrequencyScaleTest.EXPECTED.json")); var resultFile = new FileInfo(Path.Combine(outputDir.FullName, opFileStem + "MelFrequencyLinearScaleTestResults.json")); Acoustics.Shared.Csv.Csv.WriteMatrixToCsv(resultFile, freqScale.GridLineLocations); TestTools.FileEqualityTest(testName, resultFile, expectedTestFile); LoggedConsole.WriteLine("Completed Mel Frequency Scale test"); Console.WriteLine("\n\n"); }
public static void TESTMETHOD_DrawFrequencyLinesOnImage() { string filename = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale\Clusters50.bmp"; string outputFile = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale\Clusters50WithGrid.bmp"; var bmp = Image.Load(filename); int nyquist = 11025; int frameSize = 1024; int finalBinCount = 128; int gridInterval = 1000; var freqScale = new FrequencyScale(FreqScaleType.Mel, nyquist, frameSize, finalBinCount, gridInterval); DrawFrequencyLinesOnImage((Image <Rgb24>)bmp, freqScale, includeLabels: false); bmp.Save(outputFile); }
/// <summary> /// METHOD TO CHECK IF Octave FREQ SCALE IS WORKING /// Check it on MARINE RECORDING from JASCO, SR=64000. /// 24 BIT JASCO RECORDINGS from GBR must be converted to 16 bit. /// ffmpeg -i source_file.wav -sample_fmt s16 out_file.wav /// e.g. ". C:\Work\Github\audio-analysis\Extra Assemblies\ffmpeg\ffmpeg.exe" -i "C:\SensorNetworks\WavFiles\MarineRecordings\JascoGBR\AMAR119-00000139.00000139.Chan_1-24bps.1375012796.2013-07-28-11-59-56.wav" -sample_fmt s16 "C:\SensorNetworks\Output\OctaveFreqScale\JascoeMarineGBR116bit.wav" /// ffmpeg binaries are in C:\Work\Github\audio-analysis\Extra Assemblies\ffmpeg /// </summary> public static void TESTMETHOD_OctaveFrequencyScale2() { var recordingPath = @"C:\SensorNetworks\SoftwareTests\TestRecordings\MarineJasco_AMAR119-00000139.00000139.Chan_1-24bps.1375012796.2013-07-28-11-59-56-16bit.wav"; var outputDir = @"C:\SensorNetworks\SoftwareTests\TestFrequencyScale".ToDirectoryInfo(); var expectedResultsDir = Path.Combine(outputDir.FullName, TestTools.ExpectedResultsDir).ToDirectoryInfo(); var outputImagePath = Path.Combine(outputDir.FullName, "JascoMarineGBR1.png"); var opFileStem = "JascoMarineGBR1"; var recording = new AudioRecording(recordingPath); var fst = FreqScaleType.Linear125Octaves7Tones28Nyquist32000; var freqScale = new FrequencyScale(fst); var sonoConfig = new SonogramConfig { WindowSize = freqScale.WindowSize, WindowOverlap = 0.2, SourceFName = recording.BaseName, NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; var sonogram = new AmplitudeSonogram(sonoConfig, recording.WavReader); sonogram.Data = OctaveFreqScale.ConvertAmplitudeSpectrogramToDecibelOctaveScale(sonogram.Data, freqScale); // DO NOISE REDUCTION var dataMatrix = SNR.NoiseReduce_Standard(sonogram.Data); sonogram.Data = dataMatrix; sonogram.Configuration.WindowSize = freqScale.WindowSize; var image = sonogram.GetImageFullyAnnotated(sonogram.GetImage(), "SPECTROGRAM: " + fst.ToString(), freqScale.GridLineLocations); image.Save(outputImagePath); // DO FILE EQUALITY TEST string testName = "test2"; var expectedTestFile = new FileInfo(Path.Combine(expectedResultsDir.FullName, "FrequencyOctaveScaleTest2.EXPECTED.json")); var resultFile = new FileInfo(Path.Combine(outputDir.FullName, opFileStem + "FrequencyOctaveScaleTest2Results.json")); Acoustics.Shared.Csv.Csv.WriteMatrixToCsv(resultFile, freqScale.GridLineLocations); TestTools.FileEqualityTest(testName, resultFile, expectedTestFile); LoggedConsole.WriteLine("Completed Octave Frequency Scale " + testName); Console.WriteLine("\n\n"); }
} //end AddHzGridLines() public static void DrawFrequencyLinesOnImage(Image <Rgb24> bmp, FrequencyScale freqScale, bool includeLabels) { DrawFrequencyLinesOnImage(bmp, freqScale.GridLineLocations, includeLabels); }
/// IMPORTANT NOTE: If you are converting Herz scale from LINEAR to OCTAVE, this conversion MUST be done BEFORE noise reduction /// <summary> /// CONSTRUCTION OF Frequency Scales /// WARNING!: Changing the constants for the octave scales will have undefined effects. /// The options below have been debugged to give what is required. /// However other values have not been debugged - so user should check the output to ensure it is what is required. /// </summary> public static void GetOctaveScale(FrequencyScale scale) { int finalBinCount = 256; int sr, frameSize, octaveDivisions; // NOTE: octaveDivisions = the number of fractional Hz steps within one octave. Piano octave contains 12 steps per octave. FreqScaleType fst = scale.ScaleType; switch (fst) { case FreqScaleType.Linear62Octaves7Tones31Nyquist11025: // constants required for split linear-octave scale when sr = 22050 sr = 22050; frameSize = 8192; scale.OctaveCount = 7; octaveDivisions = 31; // tone steps within one octave. Note: piano = 12 steps per octave. scale.LinearBound = 62; scale.Nyquist = 11025; break; case FreqScaleType.Linear125Octaves6Tones30Nyquist11025: // constants required for split linear-octave scale when sr = 22050 sr = 22050; frameSize = 8192; scale.OctaveCount = 6; octaveDivisions = 32; // tone steps within one octave. Note: piano = 12 steps per octave. scale.LinearBound = 125; scale.Nyquist = 11025; break; case FreqScaleType.Octaves24Nyquist32000: //// constants required for full octave scale when sr = 64000 sr = 64000; frameSize = 16384; scale.OctaveCount = 8; octaveDivisions = 24; // tone steps within one octave. Note: piano = 12 steps per octave. scale.LinearBound = 15; scale.Nyquist = 32000; break; case FreqScaleType.Linear125Octaves7Tones28Nyquist32000: // constants required for split linear-octave scale when sr = 64000 sr = 64000; frameSize = 16384; // = 2*8192 or 4*4096; scale.OctaveCount = 7; octaveDivisions = 28; // tone steps within one octave. Note: piano = 12 steps per octave. scale.LinearBound = 125; scale.Nyquist = 32000; break; default: LoggedConsole.WriteErrorLine("WARNING: UNKNOWN OCTAVE SCALE."); return; } scale.WindowSize = frameSize; // = 2*8192 or 4*4096 scale.FinalBinCount = finalBinCount; scale.ToneCount = octaveDivisions; scale.BinBounds = LinearToSplitLinearOctaveScale(sr, frameSize, finalBinCount, scale.LinearBound, scale.Nyquist, scale.ToneCount); scale.GridLineLocations = GetGridLineLocations(fst, scale.BinBounds); }
/// <summary> /// Converts an amplitude spectrogram to a power spectrogram having an octave frequency scale. /// This method has been copied from a method of same name in the class MFCCStuff.cs and adapted to produce an octave freq scale. /// It transforms the amplitude spectrogram in the following steps: /// (1) It removes the DC row or bin 0 iff there is odd number of spectrogram bins. ASSUMPTION: Bin count should be power of 2 from FFT. /// (1) It converts spectral amplitudes to power, normalising for window power and sample rate. /// The window contributes power to the signal which must subsequently be removed from the spectral power. Calculate power per sample. /// See notes in the MFCCStuff.DecibelSpectra for further exp[lanaitons. These normalisations were adapted from MatLab MFCC code. /// (2) Then reduce the linear scale toan octave scale depending on the sr and required number of bins or filters. /// </summary> /// <param name="amplitudeM"> the amplitude spectra </param> /// <param name="windowPower">value for window power normalisation</param> /// <param name="sampleRate">to NormaliseMatrixValues for the sampling rate</param> /// <param name="epsilon">small value to avoid log of zero.</param> /// <param name="freqScale">the kind of frequency scale</param> public static double[,] PowerSpectra(double[,] amplitudeM, double windowPower, int sampleRate, double epsilon, FrequencyScale freqScale) { int frameCount = amplitudeM.GetLength(0); int binCount = amplitudeM.GetLength(1); double minPow = epsilon * epsilon / windowPower / sampleRate; double minPow2 = epsilon * epsilon * 2 / windowPower / sampleRate; if (binCount.IsOdd()) { // remove the DC freq bin 0. amplitudeM = MatrixTools.Submatrix(amplitudeM, 0, 1, frameCount - 1, binCount - 1); } // init the spectrogram as a matrix of spectra double[,] powerSpectra = new double[frameCount, binCount]; // first square the values to calculate power. // Must multiply by 2 to accomodate two spectral components, ie positive and neg freq. for (int j = 0; j < binCount - 1; j++) { //foreach time step or frame for (int i = 0; i < frameCount; i++) { if (amplitudeM[i, j] < epsilon) { powerSpectra[i, j] = minPow2; } else { powerSpectra[i, j] = amplitudeM[i, j] * amplitudeM[i, j] * 2 / windowPower / sampleRate; } } //end of all frames } //end of all freq bins //calculate power of the Nyquist freq bin - last column of matrix //foreach time step or frame for (int i = 0; i < frameCount; i++) { //calculate power of the DC value if (amplitudeM[i, binCount - 1] < epsilon) { powerSpectra[i, binCount - 1] = minPow; } else { powerSpectra[i, binCount - 1] = amplitudeM[i, binCount - 1] * amplitudeM[i, binCount - 1] / windowPower / sampleRate; } } powerSpectra = ConvertLinearSpectrogramToOctaveFreqScale(powerSpectra, freqScale); return(powerSpectra); }
public static double[,] AmplitudeSpectra(double[,] amplitudeM, double windowPower, int sampleRate, double epsilon, FrequencyScale freqScale) { double[,] powerSpectra = PowerSpectra(amplitudeM, windowPower, sampleRate, epsilon, freqScale); // Convert the power values back to amplitude by taking the square root. var amplitudeSpectra = MatrixTools.SquareRootOfValues(powerSpectra); return(amplitudeSpectra); }
public static double[,] DecibelSpectra(double[,] amplitudeM, double windowPower, int sampleRate, double epsilon, FrequencyScale freqScale) { double[,] powerSpectra = PowerSpectra(amplitudeM, windowPower, sampleRate, epsilon, freqScale); // Convert the power values to log using: dB = 10*log(power) double min, max; var decibelSpectra = MatrixTools.Power2DeciBels(powerSpectra, out min, out max); return(decibelSpectra); }
/// <summary> /// Converts a spectrogram having linear freq scale to one having an Octave freq scale. /// Note that the sample rate (sr) and the frame size both need to be apporpriate to the choice of FreqScaleType. /// TODO: SHOULD DEVELOP A SEPARATE UNIT TEST for this method /// </summary> public static double[,] ConvertLinearSpectrogramToOctaveFreqScale(double[,] inputSpgram, FrequencyScale freqScale) { if (freqScale == null) { throw new ArgumentNullException(nameof(freqScale)); } if (freqScale.ScaleType == FreqScaleType.Linear) { LoggedConsole.WriteLine("Linear Hz Scale is not valid for this Octave method."); throw new ArgumentNullException(nameof(freqScale)); } // get the octave bin bounds for this octave scale type var octaveBinBounds = freqScale.BinBounds; //var octaveBinBounds = GetOctaveScale(freqScale.ScaleType); int newBinCount = octaveBinBounds.GetLength(0); // set up the new octave spectrogram int frameCount = inputSpgram.GetLength(0); //int binCount = inputSpgram.GetLength(1); double[,] octaveSpectrogram = new double[frameCount, newBinCount]; for (int row = 0; row < frameCount; row++) { //get each frame or spectrum in turn var linearSpectrum = MatrixTools.GetRow(inputSpgram, row); // convert the spectrum to its octave form var octaveSpectrum = OctaveSpectrum(octaveBinBounds, linearSpectrum); //return the spectrum to output spectrogram. MatrixTools.SetRow(octaveSpectrogram, row, octaveSpectrum); } return(octaveSpectrogram); }
public static double[,] ConvertAmplitudeSpectrogramToDecibelOctaveScale(double[,] inputSpgram, FrequencyScale freqScale) { //var dataMatrix = MatrixTools.Submatrix(inputSpgram, 0, 1, inputSpgram.GetLength(0) - 1, inputSpgram.GetLength(1) - 1); //square the values to produce power spectrogram var dataMatrix = MatrixTools.SquareValues(inputSpgram); //convert spectrogram to octave scale dataMatrix = ConvertLinearSpectrogramToOctaveFreqScale(dataMatrix, freqScale); double min, max; dataMatrix = MatrixTools.Power2DeciBels(dataMatrix, out min, out max); return(dataMatrix); }
public static void TestMethod_GenerateSignal2() { int sampleRate = 64000; double duration = 30; // signal duration in seconds int[] harmonics = { 500, 1000, 2000, 4000, 8000 }; var freqScale = new FrequencyScale(FreqScaleType.Linear125Octaves7Tones28Nyquist32000); string path = @"C:\SensorNetworks\Output\Sonograms\UnitTestSonograms\SineSignal2.png"; var recording = GenerateTestRecording(sampleRate, duration, harmonics, WaveType.Cosine); // init the default sonogram config var sonoConfig = new SonogramConfig { WindowSize = freqScale.WindowSize, WindowOverlap = 0.2, SourceFName = "Signal2", NoiseReductionType = NoiseReductionType.None, NoiseReductionParameter = 0.0, }; var sonogram = new AmplitudeSonogram(sonoConfig, recording.WavReader); sonogram.Data = OctaveFreqScale.ConvertAmplitudeSpectrogramToDecibelOctaveScale(sonogram.Data, freqScale); // pick a row, any row var oneSpectrum = MatrixTools.GetRow(sonogram.Data, 40); oneSpectrum = DataTools.normalise(oneSpectrum); var peaks = DataTools.GetPeaks(oneSpectrum, 0.5); var peakIds = new List <int>(); for (int i = 5; i < peaks.Length - 5; i++) { if (peaks[i]) { int peakId = freqScale.BinBounds[i, 0]; peakIds.Add(peakId); LoggedConsole.WriteLine($"Spectral peak located in bin {peakId}, Herz={freqScale.BinBounds[i, 1]}"); } } //if (peaks[129] && peaks[257] && peaks[513] && peaks[1025] && peaks[2049]) if (peakIds[0] == 129 && peakIds[1] == 257 && peakIds[2] == 513 && peakIds[3] == 1025 && peakIds[4] == 2049) { LoggedConsole.WriteSuccessLine("Spectral Peaks found at correct places"); } else { LoggedConsole.WriteErrorLine("Spectral Peaks found at INCORRECT places"); } foreach (int h in harmonics) { LoggedConsole.WriteLine($"Harmonic {h}Hertz should be in bin {freqScale.GetBinIdForHerzValue(h)}"); } // spectrogram without framing, annotation etc var image = sonogram.GetImage(); string title = $"Spectrogram of Harmonics: {DataTools.Array2String(harmonics)} SR={sampleRate} Window={freqScale.WindowSize}"; image = sonogram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations); image.Save(path); }