diff --git a/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.BotaurusPoiciloptilus.yml b/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.BotaurusPoiciloptilus.yml
index c0bbff784..2f0095f01 100644
--- a/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.BotaurusPoiciloptilus.yml
+++ b/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.BotaurusPoiciloptilus.yml
@@ -9,51 +9,63 @@ SegmentDuration: 60
SegmentOverlap: 0
# Each of these profiles will be analyzed
+# This profile is required for the species-specific recogniser and must have the current name.
Profiles:
- AustBittern: !OnebinTrackParameters
+ BitternSyllable: !OnebinTrackParameters
ComponentName: Whistle
SpeciesName: BotaurusPoiciloptilus
FrameSize: 512
FrameStep: 256
WindowFunction: HANNING
- BgNoiseThreshold: 0.0
+ #BgNoiseThreshold: 0.0
# min and max of the freq band to search
MinHertz: 100
MaxHertz: 200
MinDuration: 0.3
MaxDuration: 1.0
- DecibelThreshold: 3.0
+ DecibelThreshold: 6.0
-#Combine each pair of Boobook syllables as one event
-#CombineProximalSimilarEvents: false
+#################### POST-PROCESSING of EVENTS ###################
+
+# A: First post-processing steps are to combine overlapping/proximal/sequential events
+# 1: Combine overlapping events
+#CombineOverlappingEvents: false
+
+# 2: Combine each pair of Boobook syllables as one event
+# Can also use this to "mop up" events in neighbourhood - these can be removed later.
CombinePossibleSyllableSequence: true
SyllableStartDifference: 3.0
-SyllableHertzGap: 100
+SyllableHertzGap: 35
-# Common settings
-#Standard: &STANDARD
-#EventThreshold: 0.2
-#BgNoiseThreshold: 3.0
+# B: Filter the events for excess activity in their upper and lower buffer zones
+LowerHertzBuffer: 150
+UpperHertzBuffer: 400
-# This notation means the a profile has all of the settings that the Standard profile has,
-# however, the DctDuration parameter has been overridden.
-# <<: *STANDARD
-# DctDuration: 0.3
-
-################################################################################
-# Save intermediate file options (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
+# C: Options to save results files
+# 4: Available options for saving data files (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
SaveIntermediateWavFiles: Never
SaveIntermediateCsvFiles: false
-
-# Save spectrogram images: available options (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
+# Available options (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
# "True" is useful when debugging but "WhenEventsDetected" is required for operational use.
+
+# 5: Available options for saving
#SaveSonogramImages: True
SaveSonogramImages: WhenEventsDetected
-
# DisplayCsvImage is obsolete - ensure it remains set to: false
DisplayCsvImage: false
## End section for AnalyzeLongRecording
# Other config files to reference
HighResolutionIndicesConfig: "../Towsey.Acoustic.HiResIndicesForRecognisers.yml"
+
+################################################################################
+# Common settings
+#Standard: &STANDARD
+#EventThreshold: 0.2
+#BgNoiseThreshold: 3.0
+
+# This notation means the a profile has all of the settings that the Standard profile has,
+# however, the DctDuration parameter has been overridden.
+# <<: *STANDARD
+# DctDuration: 0.3
...
\ No newline at end of file
diff --git a/src/AnalysisPrograms/Recognizers/Birds/BotaurusPoiciloptilus.cs b/src/AnalysisPrograms/Recognizers/Birds/BotaurusPoiciloptilus.cs
index e690a7cf2..c96e8342f 100644
--- a/src/AnalysisPrograms/Recognizers/Birds/BotaurusPoiciloptilus.cs
+++ b/src/AnalysisPrograms/Recognizers/Birds/BotaurusPoiciloptilus.cs
@@ -13,12 +13,9 @@ namespace AnalysisPrograms.Recognizers
using Acoustics.Shared.ConfigFile;
using AnalysisBase;
using AnalysisPrograms.Recognizers.Base;
- using AudioAnalysisTools;
- using AudioAnalysisTools.DSP;
using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Types;
using AudioAnalysisTools.Indices;
- using AudioAnalysisTools.StandardSpectrograms;
using AudioAnalysisTools.WavTools;
using log4net;
using SixLabors.ImageSharp;
@@ -29,7 +26,7 @@ namespace AnalysisPrograms.Recognizers
///
/// A recognizer for the Australasian Bittern, Botaurus poiciloptilus, https://en.wikipedia.org/wiki/Australasian_bittern.
/// The Australasian bittern, also known as the brown bittern or matuku hūrepo, is a large bird in the heron family Ardeidae.
- /// A secretive bird with a distinctive booming call, it is more often heard than seen.
+ /// A secretive bird with a distinctive, low frequency booming call, it is more often heard than seen.
/// Australasian bitterns are endangered in both Australia and New Zealand.
///
internal class BotaurusPoiciloptilus : RecognizerBase
@@ -91,42 +88,102 @@ public override RecognizerResults Recognize(
outputDirectory,
imageWidth);
- // DO POST-PROCESSING of EVENTS
- var events = combinedResults.NewEvents;
-
+ // ################### POST-PROCESSING of EVENTS ###################
// Following two commented lines are different ways of casting lists.
//var newEvents = spectralEvents.Cast().ToList();
//var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();
- List newEvents;
+
+ // Uncomment the next line when want to obtain the event frequency profiles.
+ // WriteFrequencyProfiles(chirpEvents);
+
+ //foreach (var ev in whistleEvents)
+ //{
+ // // Calculate frequency profile score for event
+ // SetFrequencyProfileScore((WhistleEvent)ev);
+ //}
+
+ if (combinedResults.NewEvents.Count == 0)
+ {
+ BitternLog.Debug($"Return zero events.");
+ return combinedResults;
+ }
+
+ var newEvents = combinedResults.NewEvents;
// NOTE: If the dB threshold is set low, may get lots of little events.
if (genericConfig.CombinePossibleSyllableSequence)
{
// Convert events to spectral events for combining of possible sequences.
- var spectralEvents = events.Cast().ToList();
+ // Can also use this parameter to combine events that are in the upper or lower neighbourhood.
+ // Such combinations will increase bandwidth of the event and this property can be used later to weed out unlikely events..
+ var spectralEvents = newEvents.Cast().ToList();
var startDiff = genericConfig.SyllableStartDifference;
var hertzDiff = genericConfig.SyllableHertzGap;
newEvents = CompositeEvent.CombineProximalEvents(spectralEvents, TimeSpan.FromSeconds(startDiff), (int)hertzDiff);
+ BitternLog.Debug($"Event count after combining proximals = {combinedResults.NewEvents.Count}");
+ }
+
+ // Get the Bittern syllable config.
+ const string profileName = "BitternSyllable";
+ var configuration = (BotaurusPoiciloptilusConfig)genericConfig;
+ var whistleConfig = (OnebinTrackParameters)configuration.Profiles[profileName];
+
+ // 4: Filter events on the amount of acoustic activity in their upper and lower neighbourhoods - their buffer zone.
+ // The idea is that an unambiguous event should have some acoustic space above and below.
+ // The filter requires that the average acoustic activity in each frame and bin of the upper and lower buffer zones should not exceed the user specified decibel threshold.
+ // The bandwidth of these two neighbourhoods is determined by the following parameters.
+ // ########## These parameters could be specified by user in config.yml file.
+ var upperHertzBuffer = 400;
+ var lowerHertzBuffer = 150;
+
+ // The decibel threshold is currently set 5/6ths of the user specified threshold.
+ // THIS IS TO BE WATCHED. IT MAY PROVE TO BE INAPPROPRIATE TO HARD-CODE.
+ // Want the activity in buffer zones to be "somewhat" less than the user-defined threshold.
+ var neighbourhoodDbThreshold = whistleConfig.DecibelThreshold.Value * 0.8333;
+
+ if (upperHertzBuffer > 0 || lowerHertzBuffer > 0)
+ {
+ var spectralEvents2 = combinedResults.NewEvents.Cast().ToList();
+ combinedResults.NewEvents = EventExtentions.FilterEventsOnNeighbourhood(
+ spectralEvents2,
+ combinedResults.Sonogram,
+ lowerHertzBuffer,
+ upperHertzBuffer,
+ segmentStartOffset,
+ neighbourhoodDbThreshold);
+
+ BitternLog.Debug($"Event count after filtering on neighbourhood = {combinedResults.NewEvents.Count}");
}
- else
+
+ if (combinedResults.NewEvents.Count == 0)
{
- newEvents = events;
+ BitternLog.Debug($"Return zero events.");
+ return combinedResults;
}
- //filter the events for duration in seconds
+ // 5: Filter on COMPONENT COUNT in Composite events.
+ int maxComponentCount = 6;
+ combinedResults.NewEvents = EventExtentions.FilterEventsOnCompositeContent(combinedResults.NewEvents, maxComponentCount);
+ BitternLog.Debug($"Event count after filtering on component count = {combinedResults.NewEvents.Count}");
+
+ // 6: Filter the events for duration in seconds
var minimumEventDuration = 0.5;
var maximumEventDuration = 2.0;
if (genericConfig.CombinePossibleSyllableSequence)
{
minimumEventDuration = 2.0;
+ maximumEventDuration = 10.0;
}
combinedResults.NewEvents = EventExtentions.FilterOnDuration(newEvents, minimumEventDuration, maximumEventDuration);
+ BitternLog.Debug($"Event count after filtering on duration = {combinedResults.NewEvents.Count}");
- double average = 365;
- double sd = 22;
+ // 7: Filter the events for bandwidth in Hertz
+ double average = 100;
+ double sd = 15;
double sigmaThreshold = 3.0;
combinedResults.NewEvents = EventExtentions.FilterOnBandwidth(combinedResults.NewEvents, average, sd, sigmaThreshold);
+ BitternLog.Debug($"Event count after filtering on bandwidth = {combinedResults.NewEvents.Count}");
//UNCOMMENT following line if you want special debug spectrogram, i.e. with special plots.
// NOTE: Standard spectrograms are produced by setting SaveSonogramImages: "True" or "WhenEventsDetected" in UserName.SpeciesName.yml config file.
diff --git a/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs b/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
index f503610ea..ffe68fa6f 100644
--- a/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
+++ b/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
@@ -17,7 +17,6 @@ namespace AnalysisPrograms.Recognizers
using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Types;
using AudioAnalysisTools.Indices;
- using AudioAnalysisTools.StandardSpectrograms;
using AudioAnalysisTools.WavTools;
using log4net;
using SixLabors.ImageSharp;
@@ -92,7 +91,7 @@ public override RecognizerResults Recognize(
outputDirectory,
imageWidth);
- // ################### DO POST-PROCESSING of EVENTS ###################
+ // ################### POST-PROCESSING of EVENTS ###################
// Following two commented lines are different ways of casting lists.
//var newEvents = spectralEvents.Cast().ToList();
//var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();
diff --git a/tests/Acoustics.Test/AnalysisPrograms/Recognizers/AustBitternTests.cs b/tests/Acoustics.Test/AnalysisPrograms/Recognizers/AustBitternTests.cs
index 841d0f4c7..51d1da256 100644
--- a/tests/Acoustics.Test/AnalysisPrograms/Recognizers/AustBitternTests.cs
+++ b/tests/Acoustics.Test/AnalysisPrograms/Recognizers/AustBitternTests.cs
@@ -67,11 +67,11 @@ public void TestRecognizer()
var onlyEvent = (CompositeEvent)events[0];
Assert.AreEqual(5.12, onlyEvent.EventStartSeconds);
- Assert.AreEqual(12.26, onlyEvent.EventEndSeconds);
+ Assert.AreEqual(12.256, onlyEvent.EventEndSeconds);
Assert.AreEqual(105, onlyEvent.LowFrequencyHertz);
Assert.AreEqual(180, onlyEvent.HighFrequencyHertz);
- Assert.AreEqual(21.7, onlyEvent.Score);
- Assert.AreEqual(0.95, onlyEvent.ScoreNormalized);
+ Assert.AreEqual(21.72, onlyEvent.Score, 0.01);
+ Assert.AreEqual(0.947, onlyEvent.ScoreNormalized, 0.01);
}
}
}
\ No newline at end of file