Skip to content

Commit

Permalink
Finished Boobook Owl debug and test
Browse files Browse the repository at this point in the history
Issue #321
  • Loading branch information
towsey authored and atruskie committed Jun 12, 2020
1 parent ea6b336 commit b7f74c4
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
---

# Boobook Owl = Towsey.NinoxBoobook
# Resample rate must be 2 X the desired Nyquist
#ResampleRate: 22050
# SegmentDuration: units=seconds;
SegmentDuration: 60
# SegmentOverlap: units=seconds;
SegmentOverlap: 0

# Preprocessing of the recording segment
IgnoreHighAmplitudeClippedRecordingSegments: true

# Each of these profiles will be analyzed
# This profile is required for the species-specific recogniser and must have the current name.
Profiles:
Expand All @@ -19,7 +17,6 @@ Profiles:
FrameSize: 1024
FrameStep: 256
WindowFunction: HANNING
BgNoiseThreshold: 0.0
# min and max of the freq band to search
MinHertz: 400
MaxHertz: 1100
Expand All @@ -31,49 +28,33 @@ Profiles:

# A: First post-processing steps are to combine overlapping/proximal/sequential events
# 1: Combine overlapping events
#CombineOverlappingEvents: false
CombineOverlappingEvents: true

# 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: 0.6
SyllableHertzGap: 350

# B: Select or remove event types.
# 3: Select wanted event types.
#SelectEventsOfType: !ChirpEvent

# 4: Remove unwanted event types.
#RemoveEventsOfType: !ChirpEvent

# C: Remaining post-processing steps are to filter out over and/or undersized events
# 5: Filter the events for duration in seconds
RemoveEventsHavingWrongDuration: true

# 6: Filter the events for bandwidth in Hertz
RemoveEventsHavingWrongBandwidth: true

# 7: Filter the events for excess activity in upper buffer zone
RemoveEventsHavingExcessActivityInUpperBufferZone: true

# 8: Filter the events for excess activity in lower buffer zone
RemoveEventsHavingExcessActivityInLowerBufferZone: true
# B: Filter the events for excess activity in their upper and lower buffer zones
NeighbourhoodLowerHertzBuffer: 150
NeighbourhoodUpperHertzBuffer: 400
NeighbourhoodDbThreshold: 9.0

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

# 10: Available options for saving
#SaveSonogramImages: True
SaveSonogramImages: WhenEventsDetected
# DisplayCsvImage is obsolete - ensure it remains set to: false

# 5: 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
DisplayCsvImage: false
## End section for AnalyzeLongRecording

# Other config files to reference

HighResolutionIndicesConfig: "../Towsey.Acoustic.HiResIndicesForRecognisers.yml"
...
99 changes: 24 additions & 75 deletions src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,85 +96,17 @@ public override RecognizerResults Recognize(
//var newEvents = spectralEvents.Cast<EventCommon>().ToList();
//var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();

// 1: Pull out the chirp events and calculate their frequency profiles.
var (chirpEvents, others) = combinedResults.NewEvents.FilterForEventType<ChirpEvent, EventCommon>();

// Uncomment the next line when want to obtain the event frequency profiles.
// WriteFrequencyProfiles(chirpEvents);

foreach (var ev in chirpEvents)
{
// Calculate frequency profile score for event
SetFrequencyProfileScore((ChirpEvent)ev);
}

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

// 2: Combine overlapping events. If the dB threshold is set low, may get lots of little events.
combinedResults.NewEvents = CompositeEvent.CombineOverlappingEvents(chirpEvents.Cast<EventCommon>().ToList());
BoobookLog.Debug($"Event count after combining overlaps = {combinedResults.NewEvents.Count}");

// 3: Combine proximal events. 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.
// 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 spectralEvents1 = combinedResults.NewEvents.Cast<SpectralEvent>().ToList();
var startDiff = genericConfig.SyllableStartDifference;
var hertzDiff = genericConfig.SyllableHertzGap;
combinedResults.NewEvents = CompositeEvent.CombineProximalEvents(spectralEvents1, TimeSpan.FromSeconds(startDiff), (int)hertzDiff);
BoobookLog.Debug($"Event count after combining proximals = {combinedResults.NewEvents.Count}");
}

// 1: Filter the events for duration in seconds
// Get the BoobookSyllable config.
const string profileName = "BoobookSyllable";
var configuration = (NinoxBoobookConfig)genericConfig;
var chirpConfig = (ForwardTrackParameters)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 = chirpConfig.DecibelThreshold.Value * 0.8333;

if (upperHertzBuffer > 0 || lowerHertzBuffer > 0)
{
var spectralEvents2 = combinedResults.NewEvents.Cast<SpectralEvent>().ToList();
combinedResults.NewEvents = EventExtentions.FilterEventsOnNeighbourhood(
spectralEvents2,
combinedResults.Sonogram,
lowerHertzBuffer,
upperHertzBuffer,
segmentStartOffset,
neighbourhoodDbThreshold);

BoobookLog.Debug($"Event count after filtering on neighbourhood = {combinedResults.NewEvents.Count}");
}

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

// 5: Filter on COMPONENT COUNT in Composite events.
int maxComponentCount = 2;
combinedResults.NewEvents = EventExtentions.FilterEventsOnCompositeContent(combinedResults.NewEvents, maxComponentCount);
BoobookLog.Debug($"Event count after filtering on component count = {combinedResults.NewEvents.Count}");

// 6: Filter the events for duration in seconds
var minimumEventDuration = chirpConfig.MinDuration;
var maximumEventDuration = chirpConfig.MaxDuration;
if (genericConfig.CombinePossibleSyllableSequence)
Expand All @@ -186,13 +118,35 @@ public override RecognizerResults Recognize(
combinedResults.NewEvents = EventExtentions.FilterOnDuration(combinedResults.NewEvents, minimumEventDuration.Value, maximumEventDuration.Value);
BoobookLog.Debug($"Event count after filtering on duration = {combinedResults.NewEvents.Count}");

// 7: Filter the events for bandwidth in Hertz
// 2: Filter the events for bandwidth in Hertz
double average = 280;
double sd = 40;
double sigmaThreshold = 3.0;
combinedResults.NewEvents = EventExtentions.FilterOnBandwidth(combinedResults.NewEvents, average, sd, sigmaThreshold);
BoobookLog.Debug($"Event count after filtering on bandwidth = {combinedResults.NewEvents.Count}");

// 3: Filter on COMPONENT COUNT in Composite events.
int maxComponentCount = 2;
combinedResults.NewEvents = EventExtentions.FilterEventsOnCompositeContent(combinedResults.NewEvents, maxComponentCount);
BoobookLog.Debug($"Event count after filtering on component count = {combinedResults.NewEvents.Count}");

// 4: Pull out the chirp events and calculate their frequency profiles.
var (chirpEvents, others) = combinedResults.NewEvents.FilterForEventType<ChirpEvent, EventCommon>();

// Uncomment the next line when want to obtain the event frequency profiles.
// WriteFrequencyProfiles(chirpEvents);
foreach (var ev in chirpEvents)
{
// Calculate frequency profile score for event
SetFrequencyProfileScore((ChirpEvent)ev);
}

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

//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.
//GenericRecognizer.SaveDebugSpectrogram(territorialResults, genericConfig, outputDirectory, audioRecording.BaseName);
Expand Down Expand Up @@ -315,11 +269,6 @@ public override void SummariseResults(
/// <inheritdoc cref="NinoxBoobookConfig"/> />
public class NinoxBoobookConfig : GenericRecognizerConfig, INamedProfiles<object>
{
public bool CombinePossibleSyllableSequence { get; set; } = false;

public double SyllableStartDifference { get; set; } = 0.5;

public double SyllableHertzGap { get; set; } = 200;
}
}
}

0 comments on commit b7f74c4

Please sign in to comment.