Skip to content

Commit

Permalink
Refactor code for filtering on sideband activity.
Browse files Browse the repository at this point in the history
Issue #390 Separate out the lower and upper side band activity so as to filter on the two separately rather than combined as previously.
  • Loading branch information
towsey authored and atruskie committed Nov 1, 2020
1 parent 109921d commit 5d0a3bd
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 15 deletions.
18 changes: 15 additions & 3 deletions src/AnalysisPrograms/Recognizers/GenericRecognizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,18 +358,30 @@ public override RecognizerResults Recognize(
var sidebandActivity = postprocessingConfig.SidebandActivity;
if (sidebandActivity != null)
{
if (sidebandActivity.UpperHertzBuffer > 0 || sidebandActivity.LowerHertzBuffer > 0)
if (sidebandActivity.LowerHertzBuffer > 0)
{
var spectralEvents2 = allResults.NewEvents.Cast<SpectralEvent>().ToList();
allResults.NewEvents = EventFilters.FilterEventsOnSidebandActivity(
allResults.NewEvents = EventFilters.FilterEventsOnLowerSidebandActivity(
spectralEvents2,
allResults.Sonogram,
sidebandActivity.LowerHertzBuffer,
segmentStartOffset,
sidebandActivity.DecibelBuffer);

Log.Debug($"Event count after filtering on acoustic activity in lower sideband = {allResults.NewEvents.Count}");
}

if (sidebandActivity.UpperHertzBuffer > 0)
{
var spectralEvents3 = allResults.NewEvents.Cast<SpectralEvent>().ToList();
allResults.NewEvents = EventFilters.FilterEventsOnUpperSidebandActivity(
spectralEvents3,
allResults.Sonogram,
sidebandActivity.UpperHertzBuffer,
segmentStartOffset,
sidebandActivity.DecibelBuffer);

Log.Debug($"Event count after filtering on acoustic activity in upper/lower sidebands = {allResults.NewEvents.Count}");
Log.Debug($"Event count after filtering on acoustic activity in upper sideband = {allResults.NewEvents.Count}");
}
}

Expand Down
74 changes: 64 additions & 10 deletions src/AudioAnalysisTools/Events/EventFilters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,26 +330,28 @@ public static List<EventCommon> FilterEventsOnNeighbourhoodAverage(
}

/// <summary>
/// Removes events from a list of events that contain excessive noise in the event side bands; i.e. thhe upper and/or lower neighbouring frequency bands.
/// Removes events from a list of events that contain excessive noise in the lower event side band.
/// Excess noise can indicate that this is not a legitimate event.
/// This method counts the bins and frames containing above threshold activity (decibel value) in the buffer zones above and below the events.
/// This method counts the bins and frames containing above threshold activity (decibel value) in the buffer zone below the events.
/// </summary>
/// <param name="events">A list of spectral events.</param>
/// <param name="spectrogram">The decibel spectrogram in which the events occurs.</param>
/// <param name="lowerHertzBuffer">The band width of the required lower buffer. 100-200Hz is often appropriate.</param>
/// <param name="upperHertzBuffer">The band width of the required upper buffer. 300-500Hz is often appropriate.</param>
/// <param name="decibelBuffer">Minimum required decibel difference between event activity and neighbourhood activity.</param>
/// <returns>A list of filtered events.</returns>
public static List<EventCommon> FilterEventsOnSidebandActivity(
public static List<EventCommon> FilterEventsOnLowerSidebandActivity(
List<SpectralEvent> events,
BaseSonogram spectrogram,
int lowerHertzBuffer,
int upperHertzBuffer,
TimeSpan segmentStartOffset,
double decibelBuffer)
{
// allow bin gaps above and below the event.
int upperBinGap = 4;
if (lowerHertzBuffer == 0)
{
return null;
}

// allow bin gaps below the event.
int lowerBinGap = 2;

var converter = new UnitConverters(
Expand All @@ -362,11 +364,63 @@ public static List<EventCommon> FilterEventsOnSidebandActivity(
foreach (var ev in events)
{
var eventDecibels = EventExtentions.GetAverageDecibelsInEvent(ev, spectrogram.Data, converter);
var sidebandMatrix = GetNeighbourhoodAsOneMatrix(ev, spectrogram.Data, lowerHertzBuffer, lowerBinGap, upperHertzBuffer, upperBinGap, converter);
var sidebandThreshold = eventDecibels - decibelBuffer;

var sidebandMatrix = GetLowerNeighbourhood(ev, spectrogram.Data, lowerHertzBuffer, lowerBinGap, converter);

var averageRowDecibels = MatrixTools.GetRowAverages(sidebandMatrix);
var averageColDecibels = MatrixTools.GetColumnAverages(sidebandMatrix);
int noisyRowCount = averageRowDecibels.Count(x => x > sidebandThreshold);
int noisyColCount = averageColDecibels.Count(x => x > sidebandThreshold);

// Require that there be at most one buffer bin and one buffer frame containing excessive acoustic activity.
if (noisyRowCount <= 1 && noisyColCount <= 1)
{
// There is reduced acoustic activity in the upper and lower buffer zones. It is likely to be a discrete event.
filteredEvents.Add(ev);
}
}

return filteredEvents;
}

/// <summary>
/// Removes events from a list of events that contain excessive noise in the upper event side band.
/// Excess noise can indicate that this is not a legitimate event.
/// This method counts the bins and frames containing above threshold activity (decibel value) in the buffer zone above the events.
/// </summary>
/// <param name="events">A list of spectral events.</param>
/// <param name="spectrogram">The decibel spectrogram in which the events occurs.</param>
/// <param name="upperHertzBuffer">The band width of the required upper buffer. 300-500Hz is often appropriate.</param>
/// <param name="decibelBuffer">Minimum required decibel difference between event activity and neighbourhood activity.</param>
/// <returns>A list of filtered events.</returns>
public static List<EventCommon> FilterEventsOnUpperSidebandActivity(
List<SpectralEvent> events,
BaseSonogram spectrogram,
int upperHertzBuffer,
TimeSpan segmentStartOffset,
double decibelBuffer)
{
// allow bin gaps above the event.
int upperBinGap = 3;

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

var filteredEvents = new List<EventCommon>();
foreach (var ev in events)
{
var eventDecibels = EventExtentions.GetAverageDecibelsInEvent(ev, spectrogram.Data, converter);
var sidebandThreshold = eventDecibels - decibelBuffer;

var sidebandMatrix = GetUpperNeighbourhood(ev, spectrogram.Data, upperHertzBuffer, upperBinGap, converter);
var averageRowDecibels = MatrixTools.GetRowAverages(sidebandMatrix);
var averageColDecibels = MatrixTools.GetColumnAverages(sidebandMatrix);
int noisyRowCount = averageRowDecibels.Count(x => x > (eventDecibels - decibelBuffer));
int noisyColCount = averageColDecibels.Count(x => x > (eventDecibels - decibelBuffer));
int noisyRowCount = averageRowDecibels.Count(x => x > sidebandThreshold);
int noisyColCount = averageColDecibels.Count(x => x > sidebandThreshold);

// Require that there be at most one buffer bin and one buffer frame containing excessive acoustic activity.
if (noisyRowCount <= 1 && noisyColCount <= 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ public class AustBitternTests : OutputDirectoryTest
/// <summary>
/// The canonical recording used for this recognizer is a 30 second recording made by Liz Znidersic at Medeas Cove, St Helens, 2016-12-17.
/// </summary>
private static readonly FileInfo TestAsset = PathHelper.ResolveAsset("Recordings", "medeas_cove_2-2_1831_471228_20161217_232352_30_0.wav");
private static readonly FileInfo ConfigFile = PathHelper.ResolveConfigFile("RecognizerConfigFiles", "Towsey.BotaurusPoiciloptilus.yml");
//private static readonly FileInfo TestAsset = PathHelper.ResolveAsset("Recordings", "medeas_cove_2-2_1831_471228_20161217_232352_30_0.wav");
private static readonly FileInfo TestAsset = new FileInfo(@"C:\Ecoacoustics\WavFiles\TestNoiseRecordings\Cotton_BBN1_20170406_202404_Truck.wav");
//private static readonly FileInfo ConfigFile = PathHelper.ResolveConfigFile("RecognizerConfigFiles", "Towsey.BotaurusPoiciloptilus.yml");
private static readonly FileInfo ConfigFile = PathHelper.ResolveConfigFile(@"C:\Ecoacoustics\ConfigFiles\Towsey.BotaurusPoiciloptilus.yml");
private static readonly BotaurusPoiciloptilus Recognizer = new BotaurusPoiciloptilus();

//NOTE: If testing recording at its original sample-rate, then use line below.
Expand Down

0 comments on commit 5d0a3bd

Please sign in to comment.