Skip to content

Commit

Permalink
Attempt to implement pulase train detection
Browse files Browse the repository at this point in the history
Did not work so far.
  • Loading branch information
towsey committed Aug 15, 2019
1 parent 6e6cce8 commit 007d150
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Profiles:
MinHz: 200
MaxHz: 2000
# duration of DCT in seconds
DctDuration: 1.0
DctDuration: 0.8
# minimum acceptable value of a DCT coefficient
DctThreshold: 0.5
# ignore oscillation rates below the min & above the max threshold
Expand All @@ -46,7 +46,7 @@ Profiles:
MinDuration: 1.0
MaxDuration: 10.0
# Event threshold - use this to determine FP / FN trade-off for events.
EventThreshold: 0.50
EventThreshold: 0.60
#Agonist:
# This notation means the Groote profile has all of the settings that the Standard profile has,
# however, the MinHz and MaxHz properties have been overridden.
Expand Down
44 changes: 28 additions & 16 deletions src/AnalysisPrograms/Recognizers/PteropusSpecies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group).
// </copyright>
// <summary>
// This is a template recognizer for the Australian Flying Fox.
// This is a recognizer for the Australian Flying Fox.
// Since there are several species, this project is started using only the generic name for Flying Foxes.

// Proposed algorithm has 8 steps
Expand Down Expand Up @@ -74,7 +74,7 @@ public override void SummariseResults(
/// Do your analysis. This method is called once per segment (typically one-minute segments).
/// </summary>
/// <param name="audioRecording">one minute of audio recording.</param>
/// <param name="configuration">config file.</param>
/// <param name="genericConfig">config file that contains parameters used by all profiles.</param>
/// <param name="segmentStartOffset">when recording starts.</param>
/// <param name="getSpectralIndexes">not sure what this is.</param>
/// <param name="outputDirectory">where the recogniser results can be found.</param>
Expand Down Expand Up @@ -123,18 +123,6 @@ public override RecognizerResults Recognize(AudioRecording audioRecording, Confi
log.Warn("Could not access Wingbeats configuration parameters");
}

//RecognizerResults combinedResults = null;

//// combine the results
//return new RecognizerResults()
//{
// Events = results1.Events.AddRange(results2.Events),
// Hits = null,
// ScoreTrack = null,
// Plots = plots,
// Sonogram = sonogram,
//};

// combine the results
if (results1 != null && results2 != null)
{
Expand Down Expand Up @@ -346,8 +334,6 @@ internal static RecognizerResults WingBeats(AudioRecording audioRecording, Confi
double dctThreshold = profile.GetDoubleOrNull("DctThreshold") ?? 0.5;
double minOscilFreq = profile.GetDoubleOrNull("MinOscilFreq") ?? 4.0;
double maxOscilFreq = profile.GetDoubleOrNull("MaxOscilFreq") ?? 6.0;
//var minTimeSpan = TimeSpan.FromSeconds(minDurationSeconds);
//var maxTimeSpan = TimeSpan.FromSeconds(maxDurationSeconds);
double eventThreshold = profile.GetDoubleOrNull("EventThreshold") ?? 0.3;

//######################
Expand Down Expand Up @@ -385,6 +371,32 @@ internal static RecognizerResults WingBeats(AudioRecording audioRecording, Confi
out var hits,
segmentStartOffset);

/*
// Look for wing beats using pulse train detector
double pulsesPerSecond = 5.1;
var scores = PulseTrain.GetPulseTrainScore(decibelArray, pulsesPerSecond, sonogram.FramesPerSecond, 1.0);
//iii: CONVERT Pulse Train SCORES TO ACOUSTIC EVENTS
double pulseTrainThreshold = 0.5;
var minTimeSpan = TimeSpan.FromSeconds(minDurationSeconds);
var maxTimeSpan = TimeSpan.FromSeconds(maxDurationSeconds);
var acousticEvents = AcousticEvent.GetEventsAroundMaxima(
scores,
segmentStartOffset,
minHz,
maxHz,
pulseTrainThreshold,
minTimeSpan,
maxTimeSpan,
sonogram.FramesPerSecond,
sonogram.FBinWidth
);
double scoreThreshold = 0.5;
var normalisedScoreArray = DataTools.NormaliseInZeroOne(scores, 0, 1.0);
var plot2 = new Plot(speciesName + " Wingbeat Pulse-train Score", normalisedScoreArray, scoreThreshold);
*/

// prepare plots
double decibelThreshold = 12.0;
double intensityNormalisationMax = 3 * decibelThreshold;
Expand Down
161 changes: 161 additions & 0 deletions src/TowseyLibrary/PulseTrain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PulseTrain.cs" company="QutEcoacoustics">
// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group).
// </copyright>
// <summary>
// This class contains methods to recognise pulse trains.
// It is an alternative to using the Oscillations class.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TowseyLibrary
{
using Acoustics.Shared.ConfigFile;
using MathNet.Numerics.LinearAlgebra.Solvers;

public static class PulseTrain
{
/// <summary>
/// This method creates a template to recognise two pulses that are possibly part of a pulse train.
/// The template is designed to detect pulse trains of at least 2 pulses!
/// The template is bounded either end by silence and then a pulse. i.e. .:|:. ... .:|:. where .=zero or a negative residual value, := 0.5 and |= 1.0.
/// Any number of residual values may separate the pulses at either end. In this method, templates are created with 6 non-zero values and the remainder are negative.
/// The sum of the positive values = 4.0.
/// The sum of the values in the template should = zero.
/// Designed this way, the minimum pulse length is about 4 or 5 and the minimum template length is about 10;
/// </summary>
/// <param name="pulseLength">length or number of frames between two pulses.</param>
/// <returns>the template.</returns>
public static double[] GetPulseTrainTemplate(int pulseLength)
{
int templateLength = pulseLength + 5;
double residual = 4 / (double)(templateLength - 6);

var template = new double[templateLength];
template[0] = -residual;
template[1] = 0.5;
template[2] = 1.0;
template[3] = 0.5;
for (int i = 4; i < templateLength - 4; i++)
{
template[i] = -residual;
}

template[templateLength - 4] = 0.5;
template[templateLength - 3] = 1.0;
template[templateLength - 2] = 0.5;
template[templateLength - 1] = -residual;
template = DataTools.normalise2UnitLength(template);
return template;
}

/// <summary>
/// Only three pulses included in the single template output by this method.
/// Will generalise if it seems worthwhile.
/// </summary>
public static double[] GetPulseTrainTemplate(int pulseLength, int pulseCount)
{
int templateLength = (pulseLength * pulseCount) + 5;
var template = new double[templateLength];
int templateHalfLength = templateLength / 2;

for (int i = 0; i < templateLength; i++)
{
template[i] = -1.0;
}

template[1] = 0.3;
template[2] = 1.0;
template[3] = 0.3;

template[templateHalfLength - 1] = 0.3;
template[templateHalfLength] = 1.0;
template[templateHalfLength + 1] = 0.3;

template[templateLength - 4] = 0.3;
template[templateLength - 3] = 1.0;
template[templateLength - 2] = 0.3;
//template = DataTools.normalise2UnitLength(template);
return template;
}

/// <summary>
/// returns the length of a pulse interval in frames given pulses and frame rates in seconds.
/// </summary>
/// <param name="pulsesPerSecond">number of pulses per second.</param>
/// <param name="framesPerSecond">frames per second - i.e. assuming the application is applied to a sequence of spectral frames.</param>
/// <returns>the template.</returns>
public static double[] GetPulseTrainTemplate(double pulsesPerSecond, double framesPerSecond)
{
int frameCount = (int)Math.Round(framesPerSecond / pulsesPerSecond);
return GetPulseTrainTemplate(frameCount);
}

public static double[] GetPulseTrainScore(double[] signal, double pulsesPerSecond, double framesPerSecond, double thresholdValue)
{
int pulseCount = 2;
int frameCount = (int)Math.Round(framesPerSecond / pulsesPerSecond);
var templates = new List<double[]>
{
GetPulseTrainTemplate(frameCount, pulseCount),
GetPulseTrainTemplate(frameCount - 1, pulseCount),
GetPulseTrainTemplate(frameCount + 1, pulseCount),
};
int signalLength = signal.Length;

var scores = new double[signalLength];

for (int i = 2; i < signalLength - templates[2].Length; i++)
{
// skip if value is below threshold
if (signal[i] < thresholdValue)
{
continue;
}

// skip if value is not maximum
if (signal[i] < signal[i - 1] || signal[i] < signal[i + 1])
{
continue;
}

// get Cosine similarity for each of three templates.
var templateScores = new double[3];

// get the local nh of signal for template 0 and get score
var nh = DataTools.Subarray(signal, i, templates[0].Length);
nh = DataTools.normalise2UnitLength(nh);
templateScores[0] = DataTools.DotProduct(nh, templates[0]);

// get the local nh of signal for template 1
nh = DataTools.Subarray(signal, i, templates[1].Length);
nh = DataTools.normalise2UnitLength(nh);
templateScores[1] = DataTools.DotProduct(nh, templates[1]);

// get the local nh of signal for template 2
nh = DataTools.Subarray(signal, i, templates[2].Length);
nh = DataTools.normalise2UnitLength(nh);
templateScores[2] = DataTools.DotProduct(nh, templates[2]);

double maxScore = templateScores.Max();
if (maxScore > 0.0)
{
for (int j = 0; j < templates[0].Length - 1; j++)
{
if (maxScore > scores[i + j])
{
scores[i + j] = maxScore;
}
}
}
}

return scores;
}
}
}
1 change: 1 addition & 0 deletions src/TowseyLibrary/TowseyLibrary.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
<Compile Include="HoughTransform.cs" />
<Compile Include="Matrix3D.cs" />
<Compile Include="OtsuThresholder.cs" />
<Compile Include="PulseTrain.cs" />
<Compile Include="StructureTensor.cs" />
<Compile Include="TemporalMatrix.cs" />
<Compile Include="TernaryPlots.cs" />
Expand Down

0 comments on commit 007d150

Please sign in to comment.