public static SpectralTrack GetVerticalTrack(double[,] peaks, int startRow, int startBin, int maxBin, double threshold)
        {
            var track = new SpectralTrack(SpectralTrackType.VerticalTrack, startRow, startBin, peaks[startRow, startBin]);

            // set the start point in peaks matrix to zero to prevent return to this point.
            peaks[startRow, startBin] = 0.0;
            int row = startRow;

            for (int bin = startBin; bin < maxBin - 1; bin++)
            {
                // Avoid row edge effects.
                if (row < 2 || row > peaks.GetLength(0) - 3)
                {
                    // arrived back at start of recording or end of recording.
                    // The track has come to end
                    return(track);
                }

                if (bin >= maxBin)
                {
                    // arrived at top of the requested frequency band - track has come to end
                    return(track);
                }

                // explore options for track vertical
                double optionStraight = Math.Max(peaks[row, bin] + peaks[row, bin + 1], peaks[row, bin] + peaks[row - 1, bin + 1]);
                optionStraight = Math.Max(optionStraight, peaks[row, bin] + peaks[row + 1, bin + 1]);

                // option for track with negative slope i.e. return to previous row/frame.
                double optionDown = Math.Max(peaks[row - 1, bin] + peaks[row - 1, bin + 1], peaks[row - 1, bin] + peaks[row - 2, bin + 1]);
                optionDown = Math.Max(optionDown, peaks[row - 1, bin] + peaks[row - 1, bin + 1]);

                // option for track with positive slope
                double optionUp = Math.Max(peaks[row + 1, bin] + peaks[row + 1, bin + 1], peaks[row + 1, bin] + peaks[row + 2, bin + 1]);
                optionUp = Math.Max(optionUp, peaks[row + 1, bin] + peaks[row + 2, bin + 1]);

                // get max of the three next possible steps
                double[] options = { optionStraight, optionDown, optionUp };
                var      maxId   = DataTools.GetMaxIndex(options);

                // Check if track has come to an end - average value of the two values is less than threshold.
                var maxValue = options[maxId] / 2;
                if (maxValue < threshold)
                {
                    return(track);
                }

                // else set visited values to zero so as not to revisit.....
                peaks[row - 1, bin] = 0.0;
                peaks[row, bin]     = 0.0;
                peaks[row + 1, bin] = 0.0;

                // and go to the new time frame
                if (maxId == 1)
                {
                    row--;
                }
                else
                if (maxId == 2)
                {
                    row++;
                }

                track.SetPoint(row, bin, maxValue);
            }

            return(track);
        }
//Analyze()

        /// <summary>
        /// ################ THE KEY ANALYSIS METHOD
        /// Returns a DataTable
        /// </summary>
        /// <param name="fiSegmentOfSourceFile"></param>
        /// <param name="analysisSettings"></param>
        /// <param name="originalSampleRate"></param>
        /// <param name="segmentStartOffset"></param>
        /// <param name="configDict"></param>
        /// <param name="diOutputDir"></param>
        public static Tuple <BaseSonogram, double[, ], List <Plot>, List <AcousticEvent>, TimeSpan> Analysis(FileInfo fiSegmentOfSourceFile, AnalysisSettings analysisSettings, int originalSampleRate, TimeSpan segmentStartOffset)
        {
            Dictionary <string, string> configDict = analysisSettings.ConfigDict;
            int originalAudioNyquist = originalSampleRate / 2; // original sample rate can be anything 11.0-44.1 kHz.

            //set default values - ignore those set by user
            int    frameSize          = 32;
            double windowOverlap      = 0.3;
            int    xCorrelationLength = 256; //for Xcorrelation   - 256 frames @801 = 320ms, almost 1/3 second.
            //int xCorrelationLength = 128;   //for Xcorrelation   - 128 frames @801 = 160ms, almost 1/6 second.
            //int xCorrelationLength = 64;   //for Xcorrelation   - 64 frames @128 = 232ms, almost 1/4 second.
            //int xCorrelationLength = 16;   //for Xcorrelation   - 16 frames @128 = 232ms, almost 1/4 second.
            double dBThreshold = 12.0;

            // read frog data to datatable
            var dt = CsvTools.ReadCSVToTable(configDict[key_FROG_DATA], true);                     // read file contining parameters of frog calls to a table

            double intensityThreshold = double.Parse(configDict[AnalysisKeys.IntensityThreshold]); //in 0-1
            double minDuration        = double.Parse(configDict[AnalysisKeys.MinDuration]);        // seconds
            double maxDuration        = double.Parse(configDict[AnalysisKeys.MaxDuration]);        // seconds
            double minPeriod          = double.Parse(configDict[AnalysisKeys.MinPeriodicity]);     // seconds
            double maxPeriod          = double.Parse(configDict[AnalysisKeys.MaxPeriodicity]);     // seconds

            AudioRecording recording = new AudioRecording(fiSegmentOfSourceFile.FullName);

            if (recording == null)
            {
                LoggedConsole.WriteLine("AudioRecording == null. Analysis not possible.");
                return(null);
            }

            //i: MAKE SONOGRAM
            SonogramConfig sonoConfig = new SonogramConfig(); //default values config

            sonoConfig.SourceFName   = recording.BaseName;
            sonoConfig.WindowSize    = frameSize;
            sonoConfig.WindowOverlap = windowOverlap;
            //sonoConfig.NoiseReductionType = SNR.Key2NoiseReductionType("NONE");
            sonoConfig.NoiseReductionType = SNR.KeyToNoiseReductionType("STANDARD");   //must do noise removal
            TimeSpan tsRecordingtDuration = recording.Duration;
            int      sr              = recording.SampleRate;
            double   freqBinWidth    = sr / (double)sonoConfig.WindowSize;
            double   frameOffset     = sonoConfig.GetFrameOffset(sr);
            double   framesPerSecond = 1 / frameOffset;

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);

            //iii: GET TRACKS
            int nhLimit      = 3; //limit of neighbourhood around maximum
            var peaks        = DataTools.GetPeakValues(sonogram.DecibelsPerFrame);
            var tuple        = SpectralTrack.GetSpectralMaxima(sonogram.DecibelsPerFrame, sonogram.Data, dBThreshold, nhLimit);
            var maxFreqArray = tuple.Item1; //array (one element per frame) indicating which freq bin has max amplitude.
            var hitsMatrix   = tuple.Item2;
            int herzOffset   = 0;
            int maxFreq      = 6000;
            var tracks       = SpectralTrack.GetSpectralTracks(maxFreqArray, framesPerSecond, freqBinWidth, herzOffset, SpectralTrack.MIN_TRACK_DURATION, SpectralTrack.MAX_INTRASYLLABLE_GAP, maxFreq);

            double severity     = 0.5;
            double dynamicRange = 60; // deciBels above background noise. BG noise has already been removed from each bin.
            // convert sonogram to a list of frequency bin arrays
            var listOfFrequencyBins = SpectrogramTools.Sonogram2ListOfFreqBinArrays(sonogram, dynamicRange);
            int minFrameLength      = SpectralTrack.FrameCountEquivalent(SpectralTrack.MIN_TRACK_DURATION, framesPerSecond);

            for (int i = tracks.Count - 1; i >= 0; i--)
            {
                tracks[i].CropTrack(listOfFrequencyBins, severity);
                if (tracks[i].Length < minFrameLength)
                {
                    tracks.Remove(tracks[i]);
                }
            } // foreach track

            foreach (SpectralTrack track in tracks) // find any periodicity in the track and calculate its score.
            {
                SpectralTrack.DetectTrackPeriodicity(track, xCorrelationLength, listOfFrequencyBins, sonogram.FramesPerSecond);
            } // foreach track

            int rowCount       = sonogram.Data.GetLength(0);
            int MAX_FREQ_BOUND = 6000;
            int topBin         = (int)Math.Round(MAX_FREQ_BOUND / freqBinWidth);
            var plots          = CreateScorePlots(tracks, rowCount, topBin);

            //iv: CONVERT TRACKS TO ACOUSTIC EVENTS
            List <AcousticEvent> frogEvents = SpectralTrack.ConvertTracks2Events(tracks, segmentStartOffset);

            // v: GET FROG IDs
            //var frogEvents = new List<AcousticEvent>();
            foreach (AcousticEvent ae in frogEvents)
            {
                double oscRate = 1 / ae.Periodicity;
                // ae.DominantFreq
                // ae.Score
                // ae.Duration
                //ClassifyFrogEvent(ae);
                string[] names = ClassifyFrogEvent(ae.DominantFreq, oscRate, dt);
                ae.Name  = names[0];
                ae.Name2 = names[1];
            }

            return(Tuple.Create(sonogram, hitsMatrix, plots, frogEvents, tsRecordingtDuration));
        } //Analysis()
Ejemplo n.º 3
0
        public static SpectralTrack GetTrack(double[,] peaks, int startRow, int startBin, double threshold)
        {
            var track = new SpectralTrack(SpectralTrackType.HorizontalTrack, startRow, startBin, peaks[startRow, startBin]);

            // set the start point in peaks matrix to zero to prevent return to this point.
            peaks[startRow, startBin] = 0.0;

            int bin = startBin;

            for (int row = startRow + 1; row < peaks.GetLength(0) - 2; row++)
            {
                //cannot take bin value less than 3 because of edge effects.
                if (bin < 3)
                {
                    bin = 3;
                }

                if (bin > peaks.GetLength(1) - 4)
                {
                    bin = peaks.GetLength(1) - 4;
                }

                // explore options for track ahead
                double optionStraight = Math.Max(peaks[row, bin] + peaks[row + 1, bin], peaks[row, bin] + peaks[row + 1, bin - 1]);
                optionStraight = Math.Max(optionStraight, peaks[row, bin] + peaks[row + 1, bin + 1]);

                // option for track descent
                double optionDown = Math.Max(peaks[row, bin - 1] + peaks[row + 1, bin - 1], peaks[row, bin - 1] + peaks[row + 1, bin - 2]);
                optionDown = Math.Max(optionDown, peaks[row, bin - 1] + peaks[row + 1, bin]);

                // need this option for a steep track descent
                double optionTwoDown = Math.Max(peaks[row, bin - 2] + peaks[row + 1, bin - 2], peaks[row, bin - 2] + peaks[row + 1, bin - 1]);
                optionTwoDown = Math.Max(optionTwoDown, peaks[row, bin - 2] + peaks[row + 1, bin - 3]);

                // option for track asscent
                double optionUp = Math.Max(peaks[row, bin + 1] + peaks[row + 1, bin + 1], peaks[row, bin + 1] + peaks[row + 1, bin]);
                optionUp = Math.Max(optionUp, peaks[row, bin + 1] + peaks[row + 1, bin + 2]);

                // need this option for a steep track asscent
                double optionTwoUp = Math.Max(peaks[row, bin + 2] + peaks[row + 1, bin + 2], peaks[row, bin + 2] + peaks[row + 1, bin + 1]);
                optionTwoUp = Math.Max(optionTwoUp, peaks[row, bin + 2] + peaks[row + 1, bin + 3]);

                // get max of the five next possible steps
                double[] options = { optionStraight, optionDown, optionUp, optionTwoDown, optionTwoUp };
                //double[] options = { optionStraight, optionDown, optionUp, 0.0, 0.0 };
                var maxId = DataTools.GetMaxIndex(options);

                // if track has come to an end
                var maxValue = options[maxId] / 2;
                if (maxValue < threshold)
                {
                    break;
                }

                // else set bins to zero so as not to revisit.....
                for (int col = -2; col <= 2; col++)
                {
                    peaks[row, bin + col] = 0.0;
                }

                // and go to the new frequency bin
                if (maxId == 1)
                {
                    bin--;
                }
                else
                if (maxId == 2)
                {
                    bin++;
                }
                else
                if (maxId == 3)
                {
                    bin -= 2;
                }
                else
                if (maxId == 4)
                {
                    bin += 2;
                }

                track.SetPoint(row, bin, maxValue);
            }

            return(track);
        }