Skip to content

Commit

Permalink
Fix unit test for Australasian Pipit.
Browse files Browse the repository at this point in the history
Issue #370 Adjust test for changes to generic algorith, The recognizer is now more accurate.
  • Loading branch information
towsey authored and atruskie committed Oct 14, 2020
1 parent dee47b7 commit 53e9c4d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,55 @@ Profiles:
MinHertz: 2000
MaxHertz: 7000
MinBandwidthHertz: 500
MaxBandwidthHertz: 5000
DecibelThreshold: 9.0
MaxBandwidthHertz: 6000
DecibelThresholds:
- 6.0
- 9.0
- 12.0

#################### POST-PROCESSING of EVENTS ###################

# A: First post-processing steps are to combine overlapping/proximal/sequential events
# 1: Combine overlapping events
CombineOverlappingEvents: true
PostProcessing:
# The following generic post-processing steps are determined by config settings.
# Step 1: Combine overlapping events - events derived from all profiles.
# Step 2: Combine possible syllable sequences and filter on excess syllable count.
# Step 3: Remove events whose bandwidth is too small or large.
# Step 4: Remove events that have excessive noise in their side-bands.

# 2: Combine syllables that possibly belong to the same strophe.
# Can also use this to "mop up" events in neighbourhood - these can be removed later.
CombinePossibleSyllableSequence: true
SyllableStartDifference: 0.25
SyllableHertzGap: 3000
# 1: Combine overlapping events
CombineOverlappingEvents: true

# B: Filter the events for excess activity in their upper and lower buffer zones
NeighbourhoodLowerHertzBuffer: 200
NeighbourhoodUpperHertzBuffer: 0
NeighbourhoodDbThreshold: 9.0
# 2: Combine possible syllable sequences
SyllableSequence:
CombinePossibleSyllableSequence: false
SyllableStartDifference: 0.25
SyllableHertzGap: 3000
FilterSyllableSequence: false
SyllableMaxCount: 0
ExpectedPeriod: 0

# C: Options to save results files
# 4: Available options for saving spectrograms (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
# 3: Remove events whose bandwidth lies outside 3 SDs of an expected value.
Bandwidth:
ExpectedBandwidth: 4000
BandwidthStandardDeviation: 400

# 4: Filter the events for excess activity in their sidebands, i.e. upper and lower buffer zones
SidebandActivity:
LowerHertzBuffer: 0 #200
UpperHertzBuffer: 0
DecibelBuffer: 0.0 #9.0

# Options to save results files
# 1: Available options for saving spectrograms (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
# "True" is useful when debugging but "WhenEventsDetected" is required for operational use.
#SaveSonogramImages: True
SaveSonogramImages: WhenEventsDetected

# 5: Available options for saving data files (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
# 2: Available options for saving data files (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
SaveIntermediateWavFiles: Never
SaveIntermediateCsvFiles: false

# 6: DisplayCsvImage is obsolete - ensure it remains set to: false
# 3: DisplayCsvImage is obsolete - ensure it remains set to: false
DisplayCsvImage: false
## End section for AnalyzeLongRecording

Expand Down
88 changes: 1 addition & 87 deletions src/AnalysisPrograms/Recognizers/Birds/AnthusNovaeseelandiae.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,97 +92,11 @@ public override RecognizerResults Recognize(
outputDirectory,
imageWidth);

// ################### POST-PROCESSING of EVENTS ###################

if (combinedResults.NewEvents.Count == 0)
{
PipitLog.Debug($"Return zero events.");
return combinedResults;
}

// 1: Filter the events for duration in seconds
var minimumEventDuration = 0.1;
var maximumEventDuration = 0.4;
combinedResults.NewEvents = EventFilters.FilterOnDuration(combinedResults.NewEvents, minimumEventDuration, maximumEventDuration);
PipitLog.Debug($"Event count after filtering on duration = {combinedResults.NewEvents.Count}");

// 2: Filter the events for bandwidth in Hertz
double average = 3500;
double sd = 600;
double sigmaThreshold = 3.0;
combinedResults.NewEvents = EventFilters.FilterOnBandwidth(combinedResults.NewEvents, average, sd, sigmaThreshold);
PipitLog.Debug($"Event count after filtering on bandwidth = {combinedResults.NewEvents.Count}");

combinedResults.NewEvents = FilterEventsOnFrequencyProfile(combinedResults.NewEvents);
// ################### YOU CAN PUT ADDITIONAL POST-PROCESSING CODE HERE ###################

return combinedResults;
}

/// <summary>
/// This method assumes that the only events of interest are composite events.
/// </summary>
/// <param name="events">THe current list of events.</param>
/// <returns>A list of composite events.</returns>
public static List<EventCommon> FilterEventsOnFrequencyProfile(List<EventCommon> events)
{
if (events.Count == 0)
{
return events;
}

// select only the composite events.
//var compositeEvents = events.Select(x => (CompositeEvent)x).ToList();
var (compositeEvents, others) = events.FilterForEventType<CompositeEvent, EventCommon>();

if (compositeEvents == null || compositeEvents.Count == 0)
{
return events;
}

// get the composite track for each composite event.
var returnEvents = new List<EventCommon>();
foreach (var ev in compositeEvents)
{
var componentEvents = ev.ComponentEvents.Cast<WhipEvent>();
var points = EventExtentions.GetCompositeTrack(componentEvents).ToArray();

// Uncomment this line when want to see the composite track profile.
//WriteFrequencyProfile(points);

// For Pipit require minimum of four frames duration.
var length = points.Length;
if (length < 4)
{
continue;
}

// Only select events having strong downward slope in spectrogram.
var avFirstTwoEvents = (points[0].Hertz.Minimum + points[0].Hertz.Minimum) / 2;
var avLastTwoEvents = (points[length - 1].Hertz.Minimum + points[length - 2].Hertz.Minimum) / 2;
if (avFirstTwoEvents - avLastTwoEvents > 500)
{
returnEvents.Add(ev);
}
}

return returnEvents;
}

public static void WriteFrequencyProfile(ISpectralPoint[] points)
{
if (points != null)
{
var str = $"Track({points[0].Seconds.Minimum:F2}):";

foreach (var point in points)
{
str += $" {point.Hertz.Minimum},";
}

Console.WriteLine(str);
}
}

/*
/// <summary>
/// Summarize your results. This method is invoked exactly once per original file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,28 @@ public void TestRecognizer()
this.SaveTestOutput(
outputDirectory => GenericRecognizer.SaveDebugSpectrogram(results, null, outputDirectory, Recognizer.SpeciesName));

//this test returns two false-positives with the current component parameters.
Assert.AreEqual(7, events.Count);
Assert.AreEqual(5, events.Count);
Assert.IsNull(scoreTrack);
Assert.AreEqual(1, plots.Count);
Assert.AreEqual(3, plots.Count);
Assert.AreEqual(1874, sonogram.FrameCount);

Assert.IsInstanceOfType(events[2], typeof(CompositeEvent));
var ev = (CompositeEvent)events[2];

// events[2] should be a composite event.
Assert.AreEqual(16.656, ev.EventStartSeconds);
Assert.AreEqual(17.008, ev.EventEndSeconds);
Assert.AreEqual(3596, ev.BandWidthHertz);
var ev = (CompositeEvent)events[2];
Assert.IsInstanceOfType(events[2], typeof(CompositeEvent));
Assert.AreEqual(22.0000000000000, ev.EventStartSeconds, TestHelper.AllowedDelta);
Assert.AreEqual(22.3680000000000, ev.EventEndSeconds, TestHelper.AllowedDelta);
Assert.AreEqual(4743, ev.BandWidthHertz);

// This event should contain 5 component events
// This event should contain 13 component events
var componentEvents = ev.ComponentEvents;
Assert.AreEqual(5, componentEvents.Count);
Assert.AreEqual(13, componentEvents.Count);

// This tests that the component tracks are correctly combined.
//This can also be tested somewhere else, starting with just the comosite event in json file.
var points = EventExtentions.GetCompositeTrack(componentEvents.Cast<WhipEvent>()).ToArray();
Assert.AreEqual(16.672, points[1].Seconds.Minimum);
Assert.AreEqual(5425, points[1].Hertz.Minimum);
Assert.AreEqual(23.712453258003087, points[1].Value, TestHelper.AllowedDelta);
Assert.AreEqual(22.0160000000000, points[1].Seconds.Minimum, TestHelper.AllowedDelta);
Assert.AreEqual(5456, points[1].Hertz.Minimum);
Assert.AreEqual(23.13758005922, points[1].Value, TestHelper.AllowedDelta);
}
}
}

0 comments on commit 53e9c4d

Please sign in to comment.