/// <summary>
        /// generates numbers 1 - 100
        /// </summary>
        public static void GetRandomDistancesInEuclidianSpace(int trialCount, int dimensions)
        {
            double[] distanceArray = new double[trialCount];

            //int seed = 123456;
            int seed = (int)DateTime.Now.Ticks;
            var rn   = new RandomNumber(seed);

            for (int i = 0; i < trialCount; i++)
            {
                double[] v1 = GetRandomVector(dimensions, rn);
                double[] v2 = GetRandomVector(dimensions, rn);
                distanceArray[i] = DataTools.EuclidianDistance(v1, v2);
            }

            double av, sd;

            NormalDist.AverageAndSD(distanceArray, out av, out sd);
            double[] avAndsd = { av, sd };
            Console.WriteLine(NormalDist.formatAvAndSD(avAndsd, 5));
            Console.WriteLine("Min --> Max: {0:f3} --> {1:f3}", distanceArray.Min(), distanceArray.Max());
        } //GetRandomDistancesInEuclidianSpace()
        /// <summary>
        /// Experiments with false colour images - discretising the colours
        /// SEEMED LIKE A GOOD IDEA AT THE TIME!
        /// Not sure it is any use but worthwhile preserving the code.
        /// </summary>
        public static void DiscreteColourSpectrograms()
        {
            Console.WriteLine("Reading image");

            //string wavFilePath = @"C:\SensorNetworks\WavFiles\LewinsRail\BAC2_20071008-085040.wav";
            //string inputPath = @"C:\SensorNetworks\Output\FalseColourSpectrograms\7a667c05-825e-4870-bc4b-9cec98024f5a_101013-0000.colSpectrum.png";
            //string outputPath = @"C:\SensorNetworks\Output\FalseColourSpectrograms\7a667c05-825e-4870-bc4b-9cec98024f5a_101013-0000.discreteColSpectrum.png";

            string inputPath  = @"C:\SensorNetworks\Output\FalseColourSpectrograms\DM420036.colSpectrum.png";
            string outputPath = @"C:\SensorNetworks\Output\FalseColourSpectrograms\DM420036.discreteColSpectrum.png";

            const int R = 0;
            const int G = 1;
            const int B = 2;

            double[,] discreteIndices = new double[12, 3];                                               // Ht, ACI and Ampl values in 0,1
#pragma warning disable SA1107                                                                           // Code should not contain multiple statements on one line
            discreteIndices[0, R] = 0.00; discreteIndices[0, G] = 0.00; discreteIndices[0, B] = 0.00;    // white
            discreteIndices[1, R] = 0.20; discreteIndices[1, G] = 0.00; discreteIndices[1, B] = 0.00;    // pale blue
            discreteIndices[2, R] = 0.60; discreteIndices[2, G] = 0.20; discreteIndices[2, B] = 0.10;    // medium blue

            discreteIndices[3, R] = 0.00; discreteIndices[3, G] = 0.00; discreteIndices[3, B] = 0.40;    // pale yellow
            discreteIndices[4, R] = 0.00; discreteIndices[4, G] = 0.05; discreteIndices[4, B] = 0.70;    // bright yellow
            discreteIndices[5, R] = 0.20; discreteIndices[5, G] = 0.05; discreteIndices[5, B] = 0.80;    // yellow/green
            discreteIndices[6, R] = 0.50; discreteIndices[6, G] = 0.05; discreteIndices[6, B] = 0.50;    // yellow/green
            discreteIndices[7, R] = 0.99; discreteIndices[7, G] = 0.30; discreteIndices[7, B] = 0.70;    // green

            discreteIndices[8, R]  = 0.10; discreteIndices[8, G] = 0.95; discreteIndices[8, B] = 0.10;   // light magenta
            discreteIndices[9, R]  = 0.50; discreteIndices[9, G] = 0.95; discreteIndices[9, B] = 0.50;   // medium magenta
            discreteIndices[10, R] = 0.70; discreteIndices[10, G] = 0.95; discreteIndices[10, B] = 0.70; // dark magenta
            discreteIndices[11, R] = 0.95; discreteIndices[11, G] = 0.95; discreteIndices[11, B] = 0.95; // black
#pragma warning restore SA1107                                                                           // Code should not contain multiple statements on one line

            int N = 12;                                                                                  // number of discrete colours
            byte[,] discreteColourValues = new byte[N, 3];                                               // Ht, ACI and Ampl values in 0,255
            for (int r = 0; r < discreteColourValues.GetLength(0); r++)
            {
                for (int c = 0; c < discreteColourValues.GetLength(1); c++)
                {
                    discreteColourValues[r, c] = (byte)Math.Floor((1 - discreteIndices[r, c]) * 255);
                }
            }

            // set up the colour pallette.
            Color[] colourPalette = new Color[N]; //palette
            for (int c = 0; c < N; c++)
            {
                colourPalette[c] = Color.FromArgb(discreteColourValues[c, R], discreteColourValues[c, G], discreteColourValues[c, B]);
            }

            // read in the image
            Bitmap image = ImageTools.ReadImage2Bitmap(inputPath);
            for (int x = 0; x < image.Width; x++)
            {
                for (int y = 0; y < image.Height; y++)
                {
                    Color  imageCol         = image.GetPixel(x, y);
                    byte[] imageColorVector = new byte[3];
                    imageColorVector[0] = imageCol.R;
                    imageColorVector[1] = imageCol.G;
                    imageColorVector[2] = imageCol.B;

                    // get colour from palette closest to the existing colour
                    double[] distance = new double[N];
                    for (int c = 0; c < N; c++)
                    {
                        byte[] colourVector = new byte[3];
                        colourVector[0] = discreteColourValues[c, 0];
                        colourVector[1] = discreteColourValues[c, 1];
                        colourVector[2] = discreteColourValues[c, 2];
                        distance[c]     = DataTools.EuclidianDistance(imageColorVector, colourVector);
                    }

                    int    minindex, maxindex;
                    double min, max;
                    DataTools.MinMax(distance, out minindex, out maxindex, out min, out max);

                    //if ((col.R > 200) && (col.G > 200) && (col.B > 200))
                    image.SetPixel(x, y, colourPalette[minindex]);
                }
            }

            ImageTools.WriteBitmap2File(image, outputPath);
        }
        public static Image DrawDistanceSpectrogram(LDSpectrogramRGB cs1, LDSpectrogramRGB cs2)
        {
            string[] keys = cs1.ColorMap.Split('-');

            string key = keys[0];

            double[,] m1Red = cs1.GetNormalisedSpectrogramMatrix(key);
            IndexDistributions.SpectralStats stats = IndexDistributions.GetModeAndOneTailedStandardDeviation(m1Red);
            cs1.IndexStats.Add(key, stats);
            m1Red = MatrixTools.Matrix2ZScores(m1Red, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("1.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            key             = keys[1];
            double[,] m1Grn = cs1.GetNormalisedSpectrogramMatrix(key);
            stats           = IndexDistributions.GetModeAndOneTailedStandardDeviation(m1Grn);
            cs1.IndexStats.Add(key, stats);
            m1Grn = MatrixTools.Matrix2ZScores(m1Grn, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("1.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            key             = keys[2];
            double[,] m1Blu = cs1.GetNormalisedSpectrogramMatrix(key);
            stats           = IndexDistributions.GetModeAndOneTailedStandardDeviation(m1Blu);
            cs1.IndexStats.Add(key, stats);
            m1Blu = MatrixTools.Matrix2ZScores(m1Blu, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("1.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            key             = keys[0];
            double[,] m2Red = cs2.GetNormalisedSpectrogramMatrix(key);
            stats           = IndexDistributions.GetModeAndOneTailedStandardDeviation(m2Red);
            cs2.IndexStats.Add(key, stats);
            m2Red = MatrixTools.Matrix2ZScores(m2Red, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("2.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            key             = keys[1];
            double[,] m2Grn = cs2.GetNormalisedSpectrogramMatrix(key);
            stats           = IndexDistributions.GetModeAndOneTailedStandardDeviation(m2Grn);
            cs2.IndexStats.Add(key, stats);
            m2Grn = MatrixTools.Matrix2ZScores(m2Grn, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("2.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            key             = keys[2];
            double[,] m2Blu = cs2.GetNormalisedSpectrogramMatrix(key);
            stats           = IndexDistributions.GetModeAndOneTailedStandardDeviation(m2Blu);
            cs2.IndexStats.Add(key, stats);
            m2Blu = MatrixTools.Matrix2ZScores(m2Blu, stats.Mode, stats.StandardDeviation);

            ////LoggedConsole.WriteLine("2.{0}: Min={1:f2}   Max={2:f2}    Mode={3:f2}+/-{4:f3} (SD=One-tailed)", key, dict["min"], dict["max"], dict["mode"], dict["sd"]);
            var v1 = new double[3];

            double[] mode1 =
            {
                cs1.IndexStats[keys[0]].Mode, cs1.IndexStats[keys[1]].Mode,
                cs1.IndexStats[keys[2]].Mode,
            };
            double[] stDv1 =
            {
                cs1.IndexStats[keys[0]].StandardDeviation, cs1.IndexStats[keys[1]].StandardDeviation,
                cs1.IndexStats[keys[2]].StandardDeviation,
            };
            LoggedConsole.WriteLine(
                "1: avACI={0:f3}+/-{1:f3};   avTEN={2:f3}+/-{3:f3};   avCVR={4:f3}+/-{5:f3}",
                mode1[0],
                stDv1[0],
                mode1[1],
                stDv1[1],
                mode1[2],
                stDv1[2]);

            var v2 = new double[3];

            double[] mode2 =
            {
                cs2.IndexStats[keys[0]].Mode, cs2.IndexStats[keys[1]].Mode,
                cs2.IndexStats[keys[2]].Mode,
            };
            double[] stDv2 =
            {
                cs2.IndexStats[keys[0]].StandardDeviation, cs2.IndexStats[keys[1]].StandardDeviation,
                cs2.IndexStats[keys[2]].StandardDeviation,
            };
            LoggedConsole.WriteLine(
                "2: avACI={0:f3}+/-{1:f3};   avTEN={2:f3}+/-{3:f3};   avCVR={4:f3}+/-{5:f3}",
                mode2[0],
                stDv2[0],
                mode2[1],
                stDv2[1],
                mode2[2],
                stDv2[2]);

            // assume all matricies are normalised and of the same dimensions
            int rows      = m1Red.GetLength(0); // number of rows
            int cols      = m1Red.GetLength(1); // number
            var d12Matrix = new double[rows, cols];
            var d11Matrix = new double[rows, cols];
            var d22Matrix = new double[rows, cols];

            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    v1[0] = m1Red[row, col];
                    v1[1] = m1Grn[row, col];
                    v1[2] = m1Blu[row, col];

                    v2[0] = m2Red[row, col];
                    v2[1] = m2Grn[row, col];
                    v2[2] = m2Blu[row, col];

                    d12Matrix[row, col] = DataTools.EuclidianDistance(v1, v2);
                    d11Matrix[row, col] = (v1[0] + v1[1] + v1[2]) / 3; // get average of the normalised values
                    d22Matrix[row, col] = (v2[0] + v2[1] + v2[2]) / 3;

                    // following lines are for debugging purposes
                    // if ((row == 150) && (col == 1100))
                    // {
                    // LoggedConsole.WriteLine("V1={0:f3}, {1:f3}, {2:f3}", v1[0], v1[1], v1[2]);
                    // LoggedConsole.WriteLine("V2={0:f3}, {1:f3}, {2:f3}", v2[0], v2[1], v2[2]);
                    // LoggedConsole.WriteLine("EDist12={0:f4};   ED11={1:f4};   ED22={2:f4}", d12Matrix[row, col], d11Matrix[row, col], d22Matrix[row, col]);
                    // }
                }
            }

            // rows

            double[] array = DataTools.Matrix2Array(d12Matrix);
            double   avDist, sdDist;

            NormalDist.AverageAndSD(array, out avDist, out sdDist);
            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    d12Matrix[row, col] = (d12Matrix[row, col] - avDist) / sdDist;
                }
            }

            // int MaxRGBValue = 255;
            // int v;
            double zScore;
            Dictionary <string, Color> colourChart = GetDifferenceColourChart();
            Color colour;

            var bmp = new Bitmap(cols, rows, PixelFormat.Format24bppRgb);

            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    zScore = d12Matrix[row, col];

                    if (d11Matrix[row, col] >= d22Matrix[row, col])
                    {
                        if (zScore > 3.08)
                        {
                            colour = colourChart["+99.9%"];
                        }

                        // 99.9% conf
                        else
                        {
                            if (zScore > 2.33)
                            {
                                colour = colourChart["+99.0%"];
                            }

                            // 99.0% conf
                            else
                            {
                                if (zScore > 1.65)
                                {
                                    colour = colourChart["+95.0%"];
                                }

                                // 95% conf
                                else
                                {
                                    if (zScore < 0.0)
                                    {
                                        colour = colourChart["NoValue"];
                                    }
                                    else
                                    {
                                        // v = Convert.ToInt32(zScore * MaxRGBValue);
                                        // colour = Color.FromArgb(v, 0, v);
                                        colour = colourChart["+NotSig"];
                                    }
                                }
                            }
                        }

                        // if() else
                        bmp.SetPixel(col, row, colour);
                    }
                    else
                    {
                        if (zScore > 3.08)
                        {
                            colour = colourChart["-99.9%"];
                        }

                        // 99.9% conf
                        else
                        {
                            if (zScore > 2.33)
                            {
                                colour = colourChart["-99.0%"];
                            }

                            // 99.0% conf
                            else
                            {
                                if (zScore > 1.65)
                                {
                                    colour = colourChart["-95.0%"];
                                }

                                // 95% conf
                                else
                                {
                                    if (zScore < 0.0)
                                    {
                                        colour = colourChart["NoValue"];
                                    }
                                    else
                                    {
                                        // v = Convert.ToInt32(zScore * MaxRGBValue);
                                        // if()
                                        // colour = Color.FromArgb(0, v, v);
                                        colour = colourChart["-NotSig"];
                                    }
                                }
                            }
                        }

                        // if() else
                        bmp.SetPixel(col, row, colour);
                    }
                }

                // all rows
            }

            // all rows

            return(bmp);
        }