Skip to content

Commit

Permalink
Refactor methods for recognition of the main generic acoustic events.
Browse files Browse the repository at this point in the history
Issue #370 Main reason for refactoring is so that the generic component recognizers are able to do multiple passes ofr an array of different decibel threshold values.
  • Loading branch information
towsey authored and atruskie committed Oct 14, 2020
1 parent ee3707f commit e45a575
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/AudioAnalysisTools/HarmonicParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static (List<EventCommon> SpectralEvents, List<Plot> DecibelPlots) GetCom
segmentStartOffset);

// prepare plot of resultant Harmonics decibel array.
var plot = Plot.PreparePlot(decibelMaxArray, $"{profileName} (Harmonics:{threshold:d0}db)", threshold.Value);
var plot = Plot.PreparePlot(decibelMaxArray, $"{profileName} (Harmonics:{threshold:F0}db)", threshold.Value);
plots.Add(plot);
}

Expand Down
2 changes: 1 addition & 1 deletion src/AudioAnalysisTools/Ocillations/Oscillations2012.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static (List<EventCommon> SpectralEvents, List<Plot> DecibelPlots) GetCom
spectralEvents.AddRange(oscillationEvents);

// prepare plot of resultant Harmonics decibel array.
var plot = Plot.PreparePlot(scores, $"{profileName} (Oscillations:{threshold:d0}db)", threshold.Value);
var plot = Plot.PreparePlot(scores, $"{profileName} (Oscillations:{threshold:F0}db)", threshold.Value);
plots.Add(plot);
}

Expand Down
14 changes: 8 additions & 6 deletions src/AudioAnalysisTools/Tracks/ForwardTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static (List<EventCommon> Events, List<Plot> DecibelPlots) GetForwardTrac

spectralEvents.AddRange(events);

var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Chirps:{threshold.Value:d0}dB)", threshold.Value);
var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Chirps:{threshold.Value:F0}dB)", threshold.Value);
plots.Add(plot);
}

Expand Down Expand Up @@ -73,6 +73,10 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetForwardT
double minDuration = parameters.MinDuration.Value;
double maxDuration = parameters.MaxDuration.Value;

// Calculate the max score for normalisation purposes
var maxScore = decibelThreshold * 5;
var scoreRange = new Interval<double>(0, maxScore);

var converter = new UnitConverters(
segmentStartOffset: segmentStartOffset.TotalSeconds,
sampleRate: sonogram.SampleRate,
Expand Down Expand Up @@ -105,7 +109,7 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetForwardT
// Initialise each track as an event and store it in a list of acoustic events
var events = new List<SpectralEvent>();

// Also get the combined decibel array.
// Also get the combined decibel intensity array.
var combinedIntensityArray = new double[frameCount];

// The following lines are used only for debug purposes.
Expand All @@ -131,13 +135,11 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetForwardT

//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",
Name = "Chirp",
};

events.Add(ae);
Expand Down Expand Up @@ -189,7 +191,7 @@ public static List<Track> GetForwardTracks(double[,] peaks, double minDuration,
// Visit each spectral peak in order. Each may be start of possible track
var track = GetForwardTrack(peaks, row, col, threshold, converter);

// a forward track should have length >2
// a track should have length > 2
if (track.PointCount > 2)
{
tracks.Add(track);
Expand Down
30 changes: 19 additions & 11 deletions src/AudioAnalysisTools/Tracks/OnebinTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static (List<EventCommon> Events, List<Plot> DecibelPlots) GetOnebinTrack

spectralEvents.AddRange(events);

var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Whistle:{threshold.Value:d0}dB)", threshold.Value);
var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Whistles:{threshold.Value:F0}dB)", threshold.Value);
plots.Add(plot);
}

Expand Down Expand Up @@ -114,6 +114,22 @@ public static (List<EventCommon> ListOfevents, double[] CombinedIntensityArray)

foreach (var track in tracks)
{
// fill the intensity array with decibel values
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]);
}

// Skip tracks that do not have duration within required duration bounds.
if (track.DurationSeconds < minDuration || track.DurationSeconds > maxDuration)
{
continue;
}

//Following line used only for debug purposes. Can save as image.
//spectrogram.Mutate(x => track.Draw(x, options));
var ae = new WhistleEvent(track, scoreRange)
{
SegmentStartSeconds = segmentStartOffset.TotalSeconds,
Expand All @@ -122,14 +138,6 @@ public static (List<EventCommon> ListOfevents, double[] CombinedIntensityArray)
};

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]);
}
}

// This algorithm tends to produce temporally overlapped whistle events in adjacent channels.
Expand Down Expand Up @@ -171,8 +179,8 @@ public static List<Track> GetOnebinTracks(double[,] peaks, double minDuration, d
// Visit each spectral peak in order. Each may be start of possible whistle track
var track = GetOnebinTrack(peaks, row, col, threshold, converter);

//If track has length within duration bounds, then add the track to list.
if (track.DurationSeconds >= minDuration && track.DurationSeconds <= maxDuration)
// a track should have length > 2
if (track.PointCount > 2)
{
tracks.Add(track);
}
Expand Down
53 changes: 35 additions & 18 deletions src/AudioAnalysisTools/Tracks/OneframeTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace AudioAnalysisTools.Tracks
{
using System;
using System.Collections.Generic;
using System.Linq;
using AnalysisPrograms.Recognizers.Base;
using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Tracks;
Expand Down Expand Up @@ -38,7 +39,7 @@ public static (List<EventCommon> Events, List<Plot> DecibelPlots) GetOneFrameTra

spectralEvents.AddRange(events);

var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Clicks:{threshold.Value:d0}dB)", threshold.Value);
var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Clicks:{threshold.Value:F0}dB)", threshold.Value);
plots.Add(plot);
}

Expand Down Expand Up @@ -68,6 +69,9 @@ public static (List<EventCommon> Events, double[] Intensity) GetOneFrameTracks(
var minBandwidthHertz = parameters.MinBandwidthHertz.Value;
var maxBandwidthHertz = parameters.MaxBandwidthHertz.Value;

// Calculate the max score for normalisation purposes
var maxScore = decibelThreshold * 5;

var converter = new UnitConverters(
segmentStartOffset: segmentStartOffset.TotalSeconds,
sampleRate: sonogram.SampleRate,
Expand Down Expand Up @@ -100,34 +104,46 @@ public static (List<EventCommon> Events, double[] Intensity) GetOneFrameTracks(
}
}

//NOTE: the Peaks matrix is same size as the sonogram.
// Get a list of tracks
// NOTE: the Peaks matrix is same size as the sonogram.
var tracks = GetOneFrameTracks(peaks, minBin, maxBin, minBandwidthHertz, maxBandwidthHertz, decibelThreshold, converter);

// initialise tracks as events and get the combined intensity array.
var events = new List<EventCommon>();
// Initialise each track as an event and store it in a list of acoustic events
var events = new List<SpectralEvent>();

// Also get the combined decibel intensity array.
var temporalIntensityArray = new double[frameCount];
var maxScore = decibelThreshold * 5;

// Initialise events with tracks.
foreach (var track in tracks)
{
// fill the intensity array with decibel values
var startRow = converter.FrameFromStartTime(track.StartTimeSeconds);
var amplitudeTrack = track.GetAmplitudeOverTimeFrames();
for (int i = 0; i < amplitudeTrack.Length; i++)
{
temporalIntensityArray[startRow + i] += amplitudeTrack[i];
}

// Skip tracks that do not have duration within required duration bounds.
if (track.TrackBandWidthHertz < minBandwidthHertz || track.TrackBandWidthHertz > maxBandwidthHertz)
{
continue;
}

//Following line used only for debug purposes. Can save as image.
//spectrogram.Mutate(x => track.Draw(x, options));
var ae = new ClickEvent(track, maxScore)
{
SegmentStartSeconds = segmentStartOffset.TotalSeconds,
SegmentDurationSeconds = frameCount * converter.SecondsPerFrameStep,
Name = "noName",
Name = "Click",
};

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++)
{
temporalIntensityArray[startRow + i] += amplitudeTrack[i];
}
}

// MAY NOT WANT TO Do THIS FOR ONE-FRAME tracks
// MAY NOT WANT TO Do THIS FOR ONE-FRAME tracks (clicks)
// combine proximal events that occupy similar frequency band
//if (combineProximalSimilarEvents)
//{
Expand All @@ -137,7 +153,8 @@ public static (List<EventCommon> Events, double[] Intensity) GetOneFrameTracks(
// //events = AcousticEvent.CombineSimilarProximalEvents(events, startDifference, hertzDifference);
//}

return (events, temporalIntensityArray);
List<EventCommon> returnEvents = events.Cast<EventCommon>().ToList();
return (returnEvents, temporalIntensityArray);
}

/// <summary>
Expand Down Expand Up @@ -172,8 +189,8 @@ public static List<Track> GetOneFrameTracks(double[,] peaks, int minBin, int max
// Visit each spectral peak in order. Each may be start of possible track
var track = GetOneFrameTrack(peaks, row, col, maxBin, threshold, converter);

//If track lies within the correct bandWidth range, then return as track.
if (track.TrackBandWidthHertz >= minBandwidthHertz && track.TrackBandWidthHertz <= maxBandwidthHertz)
// a track should have length > 2
if (track.PointCount > 2)
{
tracks.Add(track);
}
Expand Down
37 changes: 24 additions & 13 deletions src/AudioAnalysisTools/Tracks/UpwardTrackAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static (List<EventCommon> Events, List<Plot> DecibelPlots) GetUpwardTrack

spectralEvents.AddRange(events);

var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Clicks:{threshold.Value:d0}dB)", threshold.Value);
var plot = Plot.PreparePlot(decibelArray, $"{profileName} (Whips:{threshold.Value:F0}dB)", threshold.Value);
plots.Add(plot);
}

Expand Down Expand Up @@ -77,6 +77,10 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetUpwardTr
var minBandwidthHertz = parameters.MinBandwidthHertz.Value;
var maxBandwidthHertz = parameters.MaxBandwidthHertz.Value;

// Calculate the max score for normalisation purposes
var maxScore = decibelThreshold * 5;
var scoreRange = new Interval<double>(0, maxScore);

var converter = new UnitConverters(
segmentStartOffset: segmentStartOffset.TotalSeconds,
sampleRate: sonogram.SampleRate,
Expand Down Expand Up @@ -110,19 +114,9 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetUpwardTr
// initialise tracks as events and get the combined intensity array.
var events = new List<SpectralEvent>();
var temporalIntensityArray = new double[frameCount];
var scoreRange = new Interval<double>(0.0, decibelThreshold * 5);

foreach (var track in tracks)
{
var ae = new WhipEvent(track, scoreRange)
{
SegmentStartSeconds = segmentStartOffset.TotalSeconds,
SegmentDurationSeconds = frameCount * converter.SecondsPerFrameStep,
Name = "Whip",
};

events.Add(ae);

// fill the intensity array
//var startRow = (int)converter.TemporalScale.To(track.StartTimeSeconds);
var startRow = converter.FrameFromStartTime(track.StartTimeSeconds);
Expand All @@ -131,6 +125,23 @@ public static (List<EventCommon> Events, double[] CombinedIntensity) GetUpwardTr
{
temporalIntensityArray[startRow + i] += amplitudeTrack[i];
}

//Skip tracks that do not sit within the correct bandWidth range.
if (track.TrackBandWidthHertz < minBandwidthHertz || track.TrackBandWidthHertz > maxBandwidthHertz)
{
continue;
}

//Following line used only for debug purposes. Can save as image.
//spectrogram.Mutate(x => track.Draw(x, options));
var ae = new WhipEvent(track, scoreRange)
{
SegmentStartSeconds = segmentStartOffset.TotalSeconds,
SegmentDurationSeconds = frameCount * converter.SecondsPerFrameStep,
Name = "Whip",
};

events.Add(ae);
}

List<EventCommon> returnEvents = events.Cast<EventCommon>().ToList();
Expand Down Expand Up @@ -164,8 +175,8 @@ public static List<Track> GetUpwardTracks(double[,] peaks, int minBin, int maxBi
// Visit each spectral peak in order. Each may be start of possible track
var track = GetUpwardTrack(peaks, row, col, maxBin, threshold, converter);

//If track lies within the correct bandWidth range, then return as track.
if (track.TrackBandWidthHertz >= minBandwidthHertz && track.TrackBandWidthHertz <= maxBandwidthHertz)
// a track should have length > 2
if (track.PointCount > 2)
{
tracks.Add(track);
}
Expand Down

0 comments on commit e45a575

Please sign in to comment.