Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting default FFT window to Hanning #349

Merged
merged 5 commits into from
Aug 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AnalysisPrograms/Create4Sonograms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public static void Main(Arguments arguments)

var recording = new AudioRecording(fiOutputSegment.FullName);

// EXTRACT ENVELOPE and SPECTROGRAM
// EXTRACT ENVELOPE and SPECTROGRAM// This call uses the default FFT window.
var dspOutput = DSP_Frames.ExtractEnvelopeAndFfts(recording, frameSize, windowOverlap);

// average absolute value over the minute recording
Expand Down
1 change: 1 addition & 0 deletions src/AnalysisPrograms/SnrAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public static void Execute(Arguments arguments)
int frameCount = signalLength / stepSize;

// (B) ################################## EXTRACT ENVELOPE and SPECTROGRAM ##################################
// Calling this method will set the default FFT window.
var dspOutput = DSP_Frames.ExtractEnvelopeAndFfts(
recording,
sonoConfig.WindowSize,
Expand Down
17 changes: 13 additions & 4 deletions src/AudioAnalysisTools/DSP/DSP_Frames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,22 +133,31 @@ public static int FrameStep(int windowSize, double windowOverlap)
return frames;
}

/// <summary>
/// Calling this method will set default FFT window if windowName is null.
/// Otherwise sets the FFT window specified in the config file.
/// </summary>
public static EnvelopeAndFft ExtractEnvelopeAndFfts(AudioRecording recording, int frameSize, double overlap, string windowName = null)
{
int frameStep = (int)(frameSize * (1 - overlap));
return ExtractEnvelopeAndAmplSpectrogram(recording.WavReader.Samples, recording.SampleRate, recording.Epsilon, frameSize, frameStep, windowName);
}

/// <summary>
/// Calling this method sets the default FFT window, currently HANNING - see FFT.cs line 22.
/// </summary>
public static EnvelopeAndFft ExtractEnvelopeAndFfts(AudioRecording recording, int frameSize, int frameStep)
{
string windowName = FFT.KeyHammingWindow;
return ExtractEnvelopeAndAmplSpectrogram(recording.WavReader.Samples, recording.SampleRate, recording.Epsilon, frameSize, frameStep, windowName);
return ExtractEnvelopeAndAmplSpectrogram(recording.WavReader.Samples, recording.SampleRate, recording.Epsilon, frameSize, frameStep, FFT.DefaultFftWindow);
}

/// <summary>
/// Calling this method sets the default FFT window, currently HANNING - see FFT.cs line 22.
/// </summary>
public static EnvelopeAndFft ExtractEnvelopeAndAmplSpectrogram(double[] signal, int sampleRate, double epsilon, int frameSize, double overlap)
{
int frameStep = (int)(frameSize * (1 - overlap));
return ExtractEnvelopeAndAmplSpectrogram(signal, sampleRate, epsilon, frameSize, frameStep, FFT.KeyHammingWindow);
return ExtractEnvelopeAndAmplSpectrogram(signal, sampleRate, epsilon, frameSize, frameStep, FFT.DefaultFftWindow);
}

/// <summary>
Expand Down Expand Up @@ -196,7 +205,7 @@ public static EnvelopeAndFft ExtractEnvelopeAndAmplSpectrogram(
// set up the FFT parameters
if (windowName == null)
{
windowName = FFT.KeyHammingWindow;
windowName = FFT.DefaultFftWindow;
}

FFT.WindowFunc w = FFT.GetWindowFunction(windowName);
Expand Down
7 changes: 6 additions & 1 deletion src/TowseyLibrary/FFT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public sealed class FFT
public const string KeyNoWindow = "NONE";
public const string KeyHammingWindow = "HAMMING";
public const string KeyHanningWindow = "HANNING";
public const string DefaultFftWindow = KeyHanningWindow;

public delegate double WindowFunc(int n, int N);

Expand Down Expand Up @@ -338,9 +339,13 @@ private static double lrw(double a0, double a1, double a2, double a3, int n, int
return 1.0 - (1.93 * c1) + (1.29 * c2) - (0.388 * c3) + (0.032 * c4);
};

/// <summary>
/// Returns an FFT window function given the name of the window type.
/// </summary>
/// <param name="name">FFT window name.</param>
/// <returns>FFT.WindowFunc.</returns>
public static WindowFunc GetWindowFunction(string name)
{
//FFT.WindowFunc windowFnc;
if (name.StartsWith(KeyHammingWindow))
{
return Hamming;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public void TestCalculateEventStatistics()
LoggedConsole.WriteLine($"Stats: DominantFrequency= {stats.DominantFrequency}");

Assert.AreEqual(0.0, stats.TemporalEnergyDistribution, 1E-4);
Assert.AreEqual(0.6062, stats.SpectralEnergyDistribution, 1E-4);
Assert.AreEqual(6687, stats.SpectralCentroid);
Assert.AreEqual(8003, stats.DominantFrequency);
Assert.AreEqual(0.61647, stats.SpectralEnergyDistribution, 1E-4);
Assert.AreEqual(6011, stats.SpectralCentroid);
Assert.AreEqual(3998, stats.DominantFrequency);

Assert.AreEqual(1500, stats.LowFrequencyHertz);
Assert.AreEqual(8500, stats.HighFrequencyHertz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ public void TestBinaryClusteringOfSpectra()
var clusterSpectrum = SpectralClustering.RestoreFullLengthSpectrum(clusterInfo.ClusterSpectrum, freqBinCount, lowerBinBound);

// test the cluster count - also called spectral diversity in some papers
Assert.AreEqual(clusterInfo.ClusterCount, 17);
Assert.AreEqual(clusterInfo.ClusterCount, 19);

// test the trigram count - another way of thinking about spectral change
Assert.AreEqual(clusterInfo.TriGramUniqueCount, 342);
Assert.AreEqual(clusterInfo.TriGramUniqueCount, 436);

// test what used to be the CLS spectral index. Sum of the rows of the weight vectors.
var expectedSpectrumFile = PathHelper.ResolveAsset("BinaryClustering", "clusterSpectrum.bin");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,27 @@ public void TestOfSummaryIndices()

var summaryIndices = results.SummaryIndexValues;

Assert.AreEqual(0.6793287, summaryIndices.AcousticComplexity, AllowedDelta);
Assert.AreEqual(0.689085, summaryIndices.AcousticComplexity, AllowedDelta);
Assert.AreEqual(0.484520, summaryIndices.Activity, AllowedDelta);
Assert.AreEqual(-30.946519, summaryIndices.AvgSignalAmplitude, AllowedDelta);
Assert.AreEqual(11.533420, summaryIndices.AvgSnrOfActiveFrames, AllowedDelta);
Assert.AreEqual(-39.740775, summaryIndices.BackgroundNoise, AllowedDelta);
Assert.AreEqual(21, summaryIndices.ClusterCount);
Assert.AreEqual(0.153191, summaryIndices.EntropyOfAverageSpectrum, AllowedDelta);
Assert.AreEqual(0.301929, summaryIndices.EntropyOfCoVSpectrum, AllowedDelta);
Assert.AreEqual(0.260999, summaryIndices.EntropyOfPeaksSpectrum, AllowedDelta);
Assert.AreEqual(0.522080, summaryIndices.EntropyOfVarianceSpectrum, AllowedDelta);
Assert.AreEqual(23, summaryIndices.ClusterCount);
Assert.AreEqual(0.153642, summaryIndices.EntropyOfAverageSpectrum, AllowedDelta);
Assert.AreEqual(0.299602, summaryIndices.EntropyOfCoVSpectrum, AllowedDelta);
Assert.AreEqual(0.264981, summaryIndices.EntropyOfPeaksSpectrum, AllowedDelta);
Assert.AreEqual(0.522530, summaryIndices.EntropyOfVarianceSpectrum, AllowedDelta);
Assert.AreEqual(2.0, summaryIndices.EventsPerSecond, AllowedDelta);
Assert.AreEqual(0.467151, summaryIndices.SpectralCentroid, AllowedDelta);
Assert.AreEqual(0.140306, summaryIndices.HighFreqCover, AllowedDelta);
Assert.AreEqual(0.137873, summaryIndices.MidFreqCover, AllowedDelta);
Assert.AreEqual(0.055341, summaryIndices.LowFreqCover, AllowedDelta);
Assert.AreEqual(0.957433, summaryIndices.Ndsi, AllowedDelta);
Assert.AreEqual(0.462917, summaryIndices.SpectralCentroid, AllowedDelta);
Assert.AreEqual(0.148697, summaryIndices.HighFreqCover, AllowedDelta);
Assert.AreEqual(0.139938, summaryIndices.MidFreqCover, AllowedDelta);
Assert.AreEqual(0.048843, summaryIndices.LowFreqCover, AllowedDelta);
Assert.AreEqual(0.957532, summaryIndices.Ndsi, AllowedDelta);
Assert.AreEqual(27.877206, summaryIndices.Snr, AllowedDelta);
Assert.AreEqual(6.240310, summaryIndices.SptDensity, AllowedDelta);
Assert.AreEqual(6.257752, summaryIndices.SptDensity, AllowedDelta);
Assert.AreEqual(0, summaryIndices.ResultStartSeconds);
Assert.AreEqual(0.162216, summaryIndices.TemporalEntropy, AllowedDelta);
Assert.AreEqual(401, summaryIndices.ThreeGramCount, AllowedDelta);
Assert.AreEqual(487, summaryIndices.ThreeGramCount, AllowedDelta);
}

/// <summary>
Expand Down Expand Up @@ -139,7 +139,7 @@ public void TestOfSpectralIndices()
// 1:ACI
var expectedSpectrumFile = PathHelper.ResolveAsset("Indices", "ACI.bin");

//Binary.Serialize(expectedSpectrumFile, spectralIndices.ACI);
// Binary.Serialize(expectedSpectrumFile, spectralIndices.ACI);
var expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.ACI, AllowedDelta);

Expand Down Expand Up @@ -174,7 +174,7 @@ public void TestOfSpectralIndices()
// 6:OSC
expectedSpectrumFile = PathHelper.ResolveAsset("Indices", "OSC.bin");

//Binary.Serialize(expectedSpectrumFile, spectralIndices.OSC);
// Binary.Serialize(expectedSpectrumFile, spectralIndices.OSC);
expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.OSC, AllowedDelta);

Expand Down Expand Up @@ -263,13 +263,13 @@ public void TestOfSpectralIndices_ICD20()
var resourcesDir = PathHelper.ResolveAssetPath("Indices");
var expectedSpectrumFile = PathHelper.ResolveAsset("Indices", "BGN_ICD20.bin");

//Binary.Serialize(expectedSpectrumFile, spectralIndices.BGN);
// Binary.Serialize(expectedSpectrumFile, spectralIndices.BGN);
var expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.BGN, AllowedDelta);

expectedSpectrumFile = PathHelper.ResolveAsset("Indices", "CVR_ICD20.bin");

//Binary.Serialize(expectedSpectrumFile, spectralIndices.CVR);
// Binary.Serialize(expectedSpectrumFile, spectralIndices.CVR);
expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.CVR, AllowedDelta);

Expand Down Expand Up @@ -333,12 +333,16 @@ public void TestOfSpectralIndices_Octave()
// TEST the BGN SPECTRAL INDEX
Assert.AreEqual(256, spectralIndices.BGN.Length);

//Binary.Serialize(expectedSpectrumFile, spectralIndices.BGN);
var expectedVector = Binary.Deserialize<double[]>(PathHelper.ResolveAsset("Indices", "BGN_OctaveScale.bin"));
var expectedSpectrumFile1 = PathHelper.ResolveAsset("Indices", "BGN_OctaveScale.bin");

// Binary.Serialize(expectedSpectrumFile1, spectralIndices.BGN);
var expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile1);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.BGN, AllowedDelta);

//Binary.Serialize(expectedSpectrumFile, spectralIndices.CVR);
expectedVector = Binary.Deserialize<double[]>(PathHelper.ResolveAsset("Indices", "CVR_OctaveScale.bin"));
var expectedSpectrumFile2 = PathHelper.ResolveAsset("Indices", "CVR_OctaveScale.bin");

// Binary.Serialize(expectedSpectrumFile2, spectralIndices.CVR);
expectedVector = Binary.Deserialize<double[]>(expectedSpectrumFile2);
CollectionAssert.That.AreEqual(expectedVector, spectralIndices.CVR, AllowedDelta);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,13 @@ public void TwoOscillationTests()
// construct name of expected matrix osc spectrogram to save file
var expectedMatrixFile = PathHelper.ResolveAsset("Oscillations2014", stem + ".Matrix.EXPECTED.csv");

// SAVE THE OUTPUT if true
// SAVE THE image of oscillation spectrogram if true.
// WARNING: this will overwrite fixtures
if (false)
{
// 1: save image of oscillation spectrogram
string imageName = stem + ".EXPECTED.png";
string imagePath = Path.Combine(PathHelper.ResolveAssetPath("Oscillations2014"), imageName);
tuple.Item1.Save(imagePath);

// 2: Save matrix of oscillation data stored in freqOscilMatrix1
//Csv.WriteMatrixToCsv(expectedMatrixFile, tuple.Item2);
Binary.Serialize(expectedMatrixFile, tuple.Item2);
}

// Run two tests. Have to deserialise the expected data files
Expand All @@ -105,6 +100,8 @@ public void TwoOscillationTests()
Assert.AreEqual(675, tuple.Item1.Height);

// 2. Compare matrix data
// Save matrix in expectedMatrixFile
// Binary.Serialize(expectedMatrixFile, tuple.Item2);
var expectedMatrix = Binary.Deserialize<double[,]>(expectedMatrixFile);

//TODO Following test fails when using CSV reader because the reader cuts out first line of the matrix
Expand Down Expand Up @@ -132,35 +129,31 @@ public void SpectralIndexOsc_Test()
var threshold = Oscillations2014.DefaultSensitivityThreshold;
var spectralIndex = Oscillations2014.GetSpectralIndex_Osc(recordingSegment, frameLength, sampleLength, threshold);

// 3. construct name of spectral index vector
// SAVE THE OUTPUT if true
// 3. construct name of spectral index vector and save as image file
// No need to do tests on this image but it is useful to visualise output
// WARNING: this will overwrite fixtures
var sourceName = Path.GetFileNameWithoutExtension(sourceRecording.Name);
var stem = sourceName + ".SpectralIndex.OSC";
var expectedIndexPath = PathHelper.ResolveAsset("Oscillations2014", stem + ".EXPECTED.csv");
if (false)
{
// 4. Save spectral index vector to file
//Csv.WriteToCsv(expectedIndexPath, spectralIndex);
//Json.Serialise(expectedIndexPath, spectralIndex);
Binary.Serialize(expectedIndexPath, spectralIndex);

// 5. Get the vector as image and save as image file
// no need to do tests on this image but it is useful to visualise output
var expectedVectorImage = ImageTools.DrawVectorInColour(DataTools.reverseArray(spectralIndex), cellWidth: 10);
var expectedImagePath = PathHelper.ResolveAsset("Oscillations2014", stem + ".png");
var expectedImagePath = PathHelper.ResolveAsset("Oscillations2014", sourceName + ".SpectralIndex.OSC.png");
expectedVectorImage.Save(expectedImagePath.FullName);
}

// 6. Get the vector as image and save as image file
// no need to do tests on this image but it is useful to compare with expected visual output
var currentVectorImage = ImageTools.DrawVectorInColour(DataTools.reverseArray(spectralIndex), cellWidth: 10);
var currentImagePath = Path.Combine(this.outputDirectory.FullName, stem + ".png");
var currentImagePath = Path.Combine(this.outputDirectory.FullName, sourceName + ".SpectralIndex.OSC.png");
currentVectorImage.Save(currentImagePath);

// 7. Run test. Compare vectors
// TODO this test fails when using CSV reader because the reader cuts out first element/line of the vector
//var expectedVector = (double[])Csv.ReadFromCsv<double>(expectedIndexPath);
var expectedIndexPath = PathHelper.ResolveAsset("Oscillations2014", sourceName + ".SpectralIndex.OSC.EXPECTED.csv");

//comment the following line once fixture is saved.
// Binary.Serialize(expectedIndexPath, spectralIndex);

var expectedVector = Binary.Deserialize<double[]>(expectedIndexPath);
CollectionAssert.That.AreEqual(expectedVector, spectralIndex, 0.000001);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/BinaryClustering/clusterSpectrum.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/ACI.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/BGN.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/BGN_ICD20.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/BGN_OctaveScale.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/CVR.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/CVR_ICD20.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/ENT.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/EVN.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/OSC.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/PMN.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/RHZ.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/RNG.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/RPS.bin
Git LFS file not shown
2 changes: 1 addition & 1 deletion tests/Fixtures/Indices/RVT.bin
Git LFS file not shown
Loading