/// <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]);
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        /// <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");
        }
Пример #5
0
        /// <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");
        }
Пример #6
0
        /// <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");
        }
Пример #7
0
        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);
        }
Пример #8
0
        /// <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");
        }
Пример #9
0
        } //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);
        }
Пример #16
0
        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);
        }