diff --git a/src/AnalysisPrograms/Sandpit.cs b/src/AnalysisPrograms/Sandpit.cs index cee166718..768161b53 100644 --- a/src/AnalysisPrograms/Sandpit.cs +++ b/src/AnalysisPrograms/Sandpit.cs @@ -120,20 +120,73 @@ public override Task Execute(CommandLineApplication app) public static void ContentDescriptionDev() { - //var dir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez02\Towsey.Acoustic"); - DirectoryInfo[] directories = { new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez01\Towsey.Acoustic"), new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez02\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez03\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez04\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez05\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez06\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez07\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez08\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez09\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez10\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez11\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez12\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez13\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez14\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez15\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez16\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez17\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez18\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez19\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez20\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez21\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez22\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez23\Towsey.Acoustic"), + new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez24\Towsey.Acoustic"), }; - string[] baseNames = { "SM304256_0+1_20151114_001652", "SM304256_0+1_20151114_011652" }; + string[] baseNames = { "SM304256_0+1_20151114_001652", + "SM304256_0+1_20151114_011652", + "SM304256_0+1_20151114_021652", + "SM304256_0+1_20151114_031652", + "SM304256_0+1_20151114_041652", + "SM304256_0+1_20151114_051652", + "SM304256_0+1_20151114_061652", + "SM304256_0+1_20151114_071652", + "SM304256_0+1_20151114_081652", + "SM304256_0+1_20151114_091652", + "SM304256_0+1_20151114_101652", + "SM304256_0+1_20151114_111652", + "SM304256_0+1_20151114_121652", + "SM304256_0+1_20151114_131652", + "SM304256_0+1_20151114_141652", + "SM304256_0+1_20151114_151652", + "SM304256_0+1_20151114_161652", + "SM304256_0+1_20151114_171652", + "SM304256_0+1_20151114_181652", + "SM304256_0+1_20151114_191652", + "SM304256_0+1_20151114_201652", + "SM304256_0+1_20151114_211652", + "SM304256_0+1_20151114_221652", + "SM304256_0+1_20151114_231652", +}; //PREPARE STRONG WIND TEMPLATE - //var path2 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "StrongWindTemplate.csv"); + //var dir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez02\Towsey.Acoustic"); + //string baseName = "SM304256_0+1_20151114_011652"; + //var path2 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "StrongWindTemplate1.csv"); //WindContent.WriteStrongWindTemplateToFile(dictionary, path2); + //PREPARE LIGHT RAIN TEMPLATE + //var dir = new DirectoryInfo(@"C:\Ecoacoustics\Output\Test\Test24HourRecording\TasmanIslandMez\Mez08\Towsey.Acoustic"); + //string baseName = "SM304256_0+1_20151114_071652"; + //var dictionary = ContentDescription.ReadIndexMatrices(dir, baseName); + //var path2 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "LightRainTemplate1.csv"); + //RainContent.WriteLightRainTemplateToFile(dictionary, path2); + var contentPlots = ContentDescription.ContentDescriptionOfMultipleRecordingFiles(directories, baseNames); // Attach content description plots to LDFC spectrogram @@ -146,7 +199,7 @@ public static void ContentDescriptionDev() //}; var image = ContentDescription.DrawLdfcSpectrogramWithContentScoreTracks(ldfcSpectrogram, contentPlots); - var path1 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "Testing__2Maps.CONTENT2.png"); + var path1 = Path.Combine(@"C:\Ecoacoustics\Output\ContentDescription", "Testing__2Maps.CONTENT3.png"); image.Save(path1); } diff --git a/src/AudioAnalysisTools/ContentDescriptionTools/ContentDescription.cs b/src/AudioAnalysisTools/ContentDescriptionTools/ContentDescription.cs index 984595167..1be53a6fd 100644 --- a/src/AudioAnalysisTools/ContentDescriptionTools/ContentDescription.cs +++ b/src/AudioAnalysisTools/ContentDescriptionTools/ContentDescription.cs @@ -39,6 +39,7 @@ public static List ContentDescriptionOfMultipleRecordingFiles(DirectoryInf var completeListOfResults = new List(); // cycle through the directories + // WARNING: Assume one-hour duration for each recording for (int i = 0; i < directories.Length; i++) { // read the spectral indices for the current file @@ -55,6 +56,7 @@ public static List ContentDescriptionOfMultipleRecordingFiles(DirectoryInf var plotDict = ContentDescription.ConvertResultsToPlots(completeListOfResults, 1440, 0); var contentPlots = ContentDescription.ConvertPlotDictionaryToPlotList(plotDict); + contentPlots = SubtractMeanPlusSd(contentPlots); return contentPlots; } @@ -324,6 +326,41 @@ public static Dictionary ConvertResultsToPlots(List SubtractMeanPlusSd(List plots) + { + var opPlots = new List(); + + // subtract average from each plot array + foreach (Plot plot in plots) + { + var scores = plot.data; + NormalDist.AverageAndSD(scores, out double average, out double sd); + + // normalise the scores to z-scores + for (int i = 0; i < scores.Length; i++) + { + // Convert scores to z-scores + scores[i] = (scores[i] - average) / sd; + if (scores[i] < 0.0) + { + scores[i] = 0.0; + } + + if (scores[i] > 4.0) + { + scores[i] = 4.0; + } + + // normalise full scale to 4 SDs. + scores[i] /= 4.0; + } + + opPlots.Add(plot); + } + + return opPlots; + } + public static List ConvertPlotDictionaryToPlotList(Dictionary dict) { var list = new List(); diff --git a/src/AudioAnalysisTools/ContentDescriptionTools/RainContent.cs b/src/AudioAnalysisTools/ContentDescriptionTools/RainContent.cs index 557a84763..48381336a 100644 --- a/src/AudioAnalysisTools/ContentDescriptionTools/RainContent.cs +++ b/src/AudioAnalysisTools/ContentDescriptionTools/RainContent.cs @@ -1,29 +1,89 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// 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). +// namespace AudioAnalysisTools.ContentDescriptionTools { + using System; + using System.Collections.Generic; using TowseyLibrary; public static class RainContent { + private const int ReductionFactor = 16; + + private static Dictionary StrongRainTemplate = new Dictionary + { + ["ACI"] = new[] { 0.076, 0.046, 0.167, 0.360, 0.426, 0.443, 0.545, 0.595, 0.564, 0.612, 0.659, 0.570, 0.542, 0.520, 0.485, 0.485 }, + ["ENT"] = new[] { 0.065, 0.061, 0.176, 0.289, 0.249, 0.255, 0.296, 0.292, 0.262, 0.386, 0.462, 0.262, 0.222, 0.243, 0.217, 0.205 }, + ["EVN"] = new[] { 0.136, 0.009, 0.022, 0.051, 0.072, 0.092, 0.109, 0.150, 0.175, 0.176, 0.193, 0.155, 0.171, 0.135, 0.109, 0.133 }, + ["BGN"] = new[] { 0.366, 0.249, 0.181, 0.148, 0.122, 0.111, 0.106, 0.105, 0.104, 0.111, 0.111, 0.111, 0.105, 0.100, 0.090, 0.048 }, + ["PMN"] = new[] { 0.182, 0.076, 0.243, 0.459, 0.470, 0.501, 0.592, 0.651, 0.625, 0.699, 0.792, 0.599, 0.572, 0.550, 0.490, 0.488 }, + }; + public static KeyValuePair GetStrongRainContent(Dictionary oneMinuteOfIndices) { const string name = "StrongRain1"; - var rn = new RandomNumber((int)DateTime.Now.Ticks + 27); - var score = rn.GetDouble(); - return new KeyValuePair(name, score); + + var reducedIndices = ContentDescription.ReduceIndicesByFactor(oneMinuteOfIndices, ReductionFactor); + var oneMinuteVector = ContentDescription.ConvertDictionaryToVector(reducedIndices); + var templateVector = ContentDescription.ConvertDictionaryToVector(StrongRainTemplate); + + //Get Euclidian distance and normalise the distance + var distance = DataTools.EuclidianDistance(templateVector, oneMinuteVector); + distance /= Math.Sqrt(templateVector.Length); + + // get dummy data + //var rn = new RandomNumber(DateTime.Now.Second + (int)DateTime.Now.Ticks + 333); + //var distance = rn.GetDouble(); + + return new KeyValuePair(name, 1 - distance); } + // ####################################################################################################################### + + private static Dictionary LightRainTemplate = new Dictionary + { + ["ACI"] = new[] { 0.076, 0.046, 0.167, 0.360, 0.426, 0.443, 0.545, 0.595, 0.564, 0.612, 0.659, 0.570, 0.542, 0.520, 0.485, 0.485 }, + ["ENT"] = new[] { 0.065, 0.061, 0.176, 0.289, 0.249, 0.255, 0.296, 0.292, 0.262, 0.386, 0.462, 0.262, 0.222, 0.243, 0.217, 0.205 }, + ["EVN"] = new[] { 0.136, 0.009, 0.022, 0.051, 0.072, 0.092, 0.109, 0.150, 0.175, 0.176, 0.193, 0.155, 0.171, 0.135, 0.109, 0.133 }, + ["BGN"] = new[] { 0.366, 0.249, 0.181, 0.148, 0.122, 0.111, 0.106, 0.105, 0.104, 0.111, 0.111, 0.111, 0.105, 0.100, 0.090, 0.048 }, + ["PMN"] = new[] { 0.182, 0.076, 0.243, 0.459, 0.470, 0.501, 0.592, 0.651, 0.625, 0.699, 0.792, 0.599, 0.572, 0.550, 0.490, 0.488 }, + }; + + public static KeyValuePair GetLightRainContent(Dictionary oneMinuteOfIndices) { const string name = "LightRain1"; - var rn = new RandomNumber(DateTime.Now.Millisecond + 9); - var score = rn.GetDouble(); - return new KeyValuePair(name, score); + var reducedIndices = ContentDescription.ReduceIndicesByFactor(oneMinuteOfIndices, ReductionFactor); + var oneMinuteVector = ContentDescription.ConvertDictionaryToVector(reducedIndices); + var templateVector = ContentDescription.ConvertDictionaryToVector(LightRainTemplate); + + //Get Euclidian distance and normalise the distance + var distance = DataTools.EuclidianDistance(templateVector, oneMinuteVector); + distance /= Math.Sqrt(templateVector.Length); + + // get dummy data + //var rn = new RandomNumber(DateTime.Now.Second + (int)DateTime.Now.Ticks + 333); + //var distance = rn.GetDouble(); + + return new KeyValuePair(name, 1 - distance); + } + + /// + /// string baseName = "SM304256_0+1_20151114_071652". + /// + public static Dictionary GetLightRainTemplate(Dictionary dictionaryOfIndices) + { + var windIndices = ContentDescription.AverageIndicesOverMinutes(dictionaryOfIndices, 32, 36); + var reducedIndices = ContentDescription.ReduceIndicesByFactor(windIndices, ReductionFactor); + return reducedIndices; + } + + public static void WriteLightRainTemplateToFile(Dictionary dictionaryOfIndices, string path) + { + var template = GetLightRainTemplate(dictionaryOfIndices); + FileTools.WriteDictionaryToFile(template, path); } } } diff --git a/src/AudioAnalysisTools/ContentDescriptionTools/WindContent.cs b/src/AudioAnalysisTools/ContentDescriptionTools/WindContent.cs index 2258b9605..7b15997bc 100644 --- a/src/AudioAnalysisTools/ContentDescriptionTools/WindContent.cs +++ b/src/AudioAnalysisTools/ContentDescriptionTools/WindContent.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// 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). +// namespace AudioAnalysisTools.ContentDescriptionTools { - using System.IO; + using System; + using System.Collections.Generic; using TowseyLibrary; public static class WindContent @@ -51,7 +50,7 @@ public static Dictionary GetStrongWindTemplate(Dictionary dictionaryOfIndices, string path) { - var template = WindContent.GetStrongWindTemplate(dictionaryOfIndices); + var template = GetStrongWindTemplate(dictionaryOfIndices); FileTools.WriteDictionaryToFile(template, path); }