Skip to content

Commit

Permalink
Issue#297 Tweak the spectral peak track recognizer
Browse files Browse the repository at this point in the history
Issue #297  Tweak the spectral peak track recognizer to get it workin on unit test spectrogram, boobook owl and the stone curlew.
  • Loading branch information
towsey committed Mar 26, 2020
1 parent 7ea052d commit b603703
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static (List<AcousticEvent>, double[]) GetSpectralPeakTracks(
int bandWidth = maxBin - minBin + 1;
var frameDuration = sonogram.FrameDuration;
var frameStep = sonogram.FrameStep;
var frameOverStep = frameDuration - frameStep;

// list of accumulated acoustic events
var events = new List<AcousticEvent>();
Expand Down Expand Up @@ -72,38 +73,34 @@ public static (List<AcousticEvent>, double[]) GetSpectralPeakTracks(
//Look for track starts and initialise them as events.
// Cannot used edge rows & columns because of edge effects.
var combinedIntensityArray = new double[frameCount];
for (int row = 1; row < frameCount; row++)
for (int row = 0; row < frameCount; row++)
{
for (int col = 3; col < bandWidth - 3; col++)
{
// if this spectral peak is possible start of a track
if (peaks[row, col] >= decibelThreshold
&& peaks[row - 1, col] <= decibelThreshold
&& peaks[row - 1, col - 1] <= decibelThreshold
&& peaks[row - 1, col + 1] <= decibelThreshold)
if (peaks[row, col] >= decibelThreshold)
{
//have the beginning of a potential track
(int[] BinIds, double[] Amplitude) track = GetTrack(peaks, row, col, decibelThreshold);

// calculate max and min bin IDs in the original spectrogram
int trackMinBin = track.BinIds.Min() + minBin;
int trackMaxBin = track.BinIds.Max() + minBin;
double trackDuration = track.BinIds.Length * frameDuration;

//Ignore short tracks.
if (trackDuration < minDuration || trackDuration > maxDuration)
{
break;
}
double trackDuration = (track.BinIds.Length * frameStep) + frameOverStep;

for (int i = 0; i < track.Amplitude.Length; i++)
//If track has length within duration bounds, then create an event
if (trackDuration >= minDuration && trackDuration <= maxDuration)
{
combinedIntensityArray[row + i] += track.Amplitude[i];
var oblong = new Oblong(row, trackMinBin - 1, row + track.BinIds.Length - 1, trackMaxBin + 1);
var ae = new AcousticEvent(segmentStartOffset, oblong, nyquist, binCount, frameDuration, frameStep, frameCount);
events.Add(ae);

// fill the intensity array
for (int i = 0; i < track.Amplitude.Length; i++)
{
combinedIntensityArray[row + i] += track.Amplitude[i];
}
}

var oblong = new Oblong(row, trackMinBin - 1, row + track.BinIds.Length, trackMaxBin + 1);
var ae = new AcousticEvent(segmentStartOffset, oblong, nyquist, binCount, frameDuration, frameStep, frameCount);
events.Add(ae);
}
}
}
Expand All @@ -126,14 +123,19 @@ public static (int[] BinIds, double[] Amplitude) GetTrack(double[,] peaks, int s
peaks[startRow, startCol] = 0.0;

int bin = startCol;
for (int row = startRow + 2; row < peaks.GetLength(0) - 2; row++)
for (int row = startRow + 1; row < peaks.GetLength(0) - 2; row++)
{
//cannot take bin value less than 3 because of edge effects.
if (bin < 3)
{
bin = 3;
}

if (bin > peaks.GetLength(1) - 4)
{
bin = peaks.GetLength(1) - 4;
}

// explore options for track ahead
double optionStraight = Math.Max(peaks[row, bin] + peaks[row + 1, bin], peaks[row, bin] + peaks[row + 1, bin - 1]);
optionStraight = Math.Max(optionStraight, peaks[row, bin] + peaks[row + 1, bin + 1]);
Expand Down
3 changes: 3 additions & 0 deletions src/AnalysisPrograms/Recognizers/GenericRecognizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ public override RecognizerResults Recognize(
//SaveDebugSpectrogram(allResults, genericConfig, outputDirectory, "name");
}

// combine adjacent acoustic events
//allResults.Events = AcousticEvent.CombineOverlappingEvents(allResults.Events, segmentStartOffset);

return allResults;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void TestOscillationAlgorithm()
};

var results = recognizer.Recognize(recording, config, 100.Seconds(), null, this.TestOutputDirectory, null);
//results.Plots.

//results.Sonogram.GetImage().Save(this.outputDirectory + "\\debug.png");

Assert.AreEqual(1, results.Events.Count);
Expand Down Expand Up @@ -211,7 +211,6 @@ public void TestHarmonicsAlgorithm()
var dctThreshold = 0.15;
var minFormantGap = 400;
var maxFormantGap = 1200;
//var minDuration = 0.35;
var minDuration = 0.2;
var maxDuration = 1.1;
var decibelThreshold = 2.0;
Expand All @@ -233,8 +232,10 @@ public void TestHarmonicsAlgorithm()
SampleRate = samplerate,
};

var spectrogram = this.CreateArtificialSpectrogramContainingHarmonics(sonoConfig);
var spectrogram = this.CreateArtificialSpectrogramToTestTracksAndHarmonics(sonoConfig);

//var image1 = SpectrogramTools.GetSonogramPlusCharts(spectrogram, null, null, null);
//results.Sonogram.GetImage().Save(this.outputDirectory + "\\debug.png");

//var results = recognizer.Recognize(recording, sonoConfig, 100.Seconds(), null, this.TestOutputDirectory, null);
//get the array of intensity values minus intensity in side/buffer bands.
Expand Down Expand Up @@ -342,8 +343,10 @@ public void TestSpectralPeakTracksAlgorithm()
SampleRate = samplerate,
};

var spectrogram = this.CreateArtificialSpectrogramContainingHarmonics(sonoConfig);
var spectrogram = this.CreateArtificialSpectrogramToTestTracksAndHarmonics(sonoConfig);

//var image1 = SpectrogramTools.GetSonogramPlusCharts(spectrogram, null, null, null);
//results.Sonogram.GetImage().Save(this.outputDirectory + "\\debug.png");

var segmentStartOffset = TimeSpan.Zero;
var plots = new List<Plot>();
Expand Down Expand Up @@ -386,23 +389,22 @@ public void TestSpectralPeakTracksAlgorithm()
var outputDirectory = new DirectoryInfo("C:\\temp");
GenericRecognizer.SaveDebugSpectrogram(allResults, null, outputDirectory, "track");

Assert.AreEqual(21, allResults.Events.Count);
Assert.AreEqual(23, allResults.Events.Count);

var @event = allResults.Events[3];
var @event = allResults.Events[4];
Assert.AreEqual(2.0, @event.EventStartSeconds, 0.1);
Assert.AreEqual(2.5, @event.EventEndSeconds, 0.1);
Assert.AreEqual(1680, @event.LowFrequencyHertz);
Assert.AreEqual(2110, @event.HighFrequencyHertz);

@event = allResults.Events[10];
@event = allResults.Events[11];
Assert.AreEqual(6.0, @event.EventStartSeconds, 0.1);
Assert.AreEqual(6.6, @event.EventEndSeconds, 0.1);
Assert.AreEqual(2110, @event.LowFrequencyHertz);
Assert.AreEqual(2584, @event.HighFrequencyHertz);

}

public SpectrogramStandard CreateArtificialSpectrogramContainingHarmonics(SonogramConfig config)
public SpectrogramStandard CreateArtificialSpectrogramToTestTracksAndHarmonics(SonogramConfig config)
{
int samplerate = config.SampleRate;
double signalDuration = config.Duration.TotalSeconds;
Expand Down Expand Up @@ -496,8 +498,18 @@ public SpectrogramStandard CreateArtificialSpectrogramContainingHarmonics(Sonogr
}

// draw a set of sequential tracks
for (int i = 0; i < 15; i++)
{
// track that starts in very first time frame
amplitudeSpectrogram[i, 50] = 6.0;

// track that goes to end of spectrogram
amplitudeSpectrogram[frameCount - 1 - i, 50] = 6.0;
}

//boobook owl look-alike
startframe = (int)Math.Round(framesPerSecond * 2) + 3;
int startBin = 40;
var startBin = 40;
for (int i = 0; i < 9; i++)
{
amplitudeSpectrogram[startframe + i, startBin + i] = 9.0;
Expand All @@ -519,12 +531,12 @@ public SpectrogramStandard CreateArtificialSpectrogramContainingHarmonics(Sonogr
amplitudeSpectrogram[startframe + i, startBin + i] = 9.0;
amplitudeSpectrogram[startframe + 16 - i, startBin + i] = 9.0;
}

amplitudeSpectrogram[startframe + 8, startBin + 8] = 6.0;
amplitudeSpectrogram[startframe + 8, startBin + 7] = 9.0;

var spectrogram = new SpectrogramStandard(config)
{
//FrameCount = amplitudeSpectrogram.GetLength(0),
SampleRate = samplerate,
Data = amplitudeSpectrogram,
};
Expand Down

0 comments on commit b603703

Please sign in to comment.