Exemplo n.º 1
0
        /// <summary>
        /// The Boobook call syllable is shaped like an inverted "U". Its total duration is close to 0.15 seconds.
        /// The rising portion lasts for 0.06s, followed by a turning portion, 0.03s, followed by the decending portion of 0.06s.
        /// The constants for this method were obtained from the calls in a Gympie recording obtained by Yvonne Phillips.
        /// </summary>
        /// <param name="ev">An event containing at least one forward track i.e. a chirp.</param>
        public static void SetFrequencyProfileScore(ChirpEvent ev)
        {
            const double risingDuration  = 0.06;
            const double gapDuration     = 0.03;
            const double fallingDuration = 0.06;

            var track   = ev.Tracks.First();
            var profile = track.GetTrackFrequencyProfile().ToArray();

            // get the first point
            var firstPoint        = track.Points.First();
            var frameDuration     = firstPoint.Seconds.Maximum - firstPoint.Seconds.Minimum;
            var risingFrameCount  = (int)Math.Floor(risingDuration / frameDuration);
            var gapFrameCount     = (int)Math.Floor(gapDuration / frameDuration);
            var fallingFrameCount = (int)Math.Floor(fallingDuration / frameDuration);

            var startSum = 0.0;

            if (profile.Length >= risingFrameCount)
            {
                for (var i = 0; i <= risingFrameCount; i++)
                {
                    startSum += profile[i];
                }
            }

            int startFrame = risingFrameCount + gapFrameCount;
            int endFrame   = startFrame + fallingFrameCount;
            var endSum     = 0.0;

            if (profile.Length >= endFrame)
            {
                for (var i = startFrame; i <= endFrame; i++)
                {
                    endSum += profile[i];
                }
            }

            // set score to 1.0 if the profile has inverted U shape.
            double score = 0.0;

            if (startSum > 0.0 && endSum < 0.0)
            {
                score = 1.0;
            }

            ev.FrequencyProfileScore = score;
        }
Exemplo n.º 2
0
        /// <summary>
        /// This method returns foward (spectral peak) tracks enclosed in spectral events.
        /// It averages dB log values incorrectly but it is faster than doing many log conversions.
        /// </summary>
        /// <param name="sonogram">The spectrogram to be searched.</param>
        /// <returns>A list of acoustic events containing foward tracks.</returns>
        public static (List <EventCommon> Events, double[] CombinedIntensity) GetForwardTracks(
            SpectrogramStandard sonogram,
            ForwardTrackParameters parameters,
            TimeSpan segmentStartOffset)
        {
            var    sonogramData     = sonogram.Data;
            int    frameCount       = sonogramData.GetLength(0);
            int    binCount         = sonogramData.GetLength(1);
            int    nyquist          = sonogram.NyquistFrequency;
            double binWidth         = nyquist / (double)binCount;
            int    minBin           = (int)Math.Round(parameters.MinHertz.Value / binWidth);
            int    maxBin           = (int)Math.Round(parameters.MaxHertz.Value / binWidth);
            double minDuration      = parameters.MinDuration.Value;
            double maxDuration      = parameters.MaxDuration.Value;
            double decibelThreshold = parameters.DecibelThreshold.Value;

            var converter = new UnitConverters(
                segmentStartOffset: segmentStartOffset.TotalSeconds,
                sampleRate: sonogram.SampleRate,
                frameSize: sonogram.Configuration.WindowSize,
                frameOverlap: sonogram.Configuration.WindowOverlap);

            //Find all spectral peaks and place in peaks matrix
            var peaks = new double[frameCount, binCount];

            for (int row = 0; row < frameCount; row++)
            {
                for (int col = minBin + 1; col < maxBin - 1; col++)
                {
                    if (sonogramData[row, col] < decibelThreshold)
                    {
                        continue;
                    }

                    // if given matrix element is greater than in freq bin either side
                    bool isPeak = (sonogramData[row, col] > sonogramData[row, col - 1]) && (sonogramData[row, col] > sonogramData[row, col + 1]);
                    if (isPeak)
                    {
                        peaks[row, col] = sonogramData[row, col];
                    }
                }
            }

            var tracks = GetForwardTracks(peaks, minDuration, maxDuration, decibelThreshold, converter);

            // initialise tracks as events and get the combined intensity array.
            // list of accumulated acoustic events
            var events = new List <SpectralEvent>();
            var combinedIntensityArray = new double[frameCount];

            // The following lines are used only for debug purposes.
            //var options = new EventRenderingOptions(new UnitConverters(segmentStartOffset.TotalSeconds, sonogram.Duration.TotalSeconds, nyquist, frameCount, binCount));
            //var spectrogram = sonogram.GetImage(doHighlightSubband: false, add1KHzLines: true, doMelScale: false);

            // Initialise events with tracks.
            foreach (var track in tracks)
            {
                //Following line used only for debug purposes. Can save as image.
                //spectrogram.Mutate(x => track.Draw(x, options));
                var maxScore   = decibelThreshold * 5;
                var scoreRange = new Interval <double>(0, maxScore);
                var ae         = new ChirpEvent(track, scoreRange)
                {
                    SegmentStartSeconds    = segmentStartOffset.TotalSeconds,
                    SegmentDurationSeconds = frameCount * converter.SecondsPerFrameStep,
                    Name = "noName",
                };

                events.Add(ae);

                // fill the intensity array
                var startRow       = converter.FrameFromStartTime(track.StartTimeSeconds);
                var amplitudeTrack = track.GetAmplitudeOverTimeFrames();
                for (int i = 0; i < amplitudeTrack.Length; i++)
                {
                    combinedIntensityArray[startRow + i] = Math.Max(combinedIntensityArray[startRow + i], amplitudeTrack[i]);
                }
            }

            List <EventCommon> returnEvents = events.Cast <EventCommon>().ToList();

            // Combine coincident events that are stacked one above other.
            // This will help in some cases to combine related events.
            if (parameters.CombinePossibleHarmonics)
            {
                returnEvents = CompositeEvent.CombinePotentialStackedTracks(events, parameters.HarmonicsStartDifference, parameters.HarmonicsHertzGap);
            }

            // Combine events that are temporally close and in the same frequency band.
            // This will help in some cases to combine related events.
            if (parameters.CombinePossibleSyllableSequence)
            {
                var timeDiff = TimeSpan.FromSeconds(parameters.SyllableStartDifference);
                returnEvents = CompositeEvent.CombineSimilarProximalEvents(events, timeDiff, parameters.SyllableHertzGap);
            }

            return(returnEvents, combinedIntensityArray);
        }