// #############################################################################################################################
        // ################################# FOUR DIFFERENT METHODS TO CALCULATE THE BACKGROUND NOISE PROFILE
        //
        // (1) MODAL METHOD
        // (2) LOWEST PERCENTILE FRAMES METHOD
        // (3) BIN-WISE LOWEST PERCENTILE CELLS METHOD
        // (4) FIRST N FRAMES
        // ##################

        /// <summary>
        /// (1) MODAL METHOD
        /// Assumes the passed matrix is a spectrogram. i.e. rows=frames, cols=freq bins.
        /// Returns the noise profile over freq bins. i.e. one noise value per freq bin.
        /// </summary>
        /// <param name="matrix">the spectrogram with origin top-left</param>
        /// <param name="sdCount">number of standard deviations</param>
        public static NoiseProfile CalculateModalNoiseProfile(double[,] matrix, double sdCount)
        {
            int colCount = matrix.GetLength(1);

            double[] noiseMode      = new double[colCount];
            double[] noiseSd        = new double[colCount];
            double[] noiseThreshold = new double[colCount];
            double[] minsOfBins     = new double[colCount];
            double[] maxsOfBins     = new double[colCount];
            for (int col = 0; col < colCount; col++)
            {
                double[]            freqBin  = MatrixTools.GetColumn(matrix, col);
                SNR.BackgroundNoise binNoise = SNR.CalculateModalBackgroundNoiseInSignal(freqBin, sdCount);
                noiseMode[col]      = binNoise.NoiseMode;
                noiseSd[col]        = binNoise.NoiseSd;
                noiseThreshold[col] = binNoise.NoiseThreshold;
                minsOfBins[col]     = binNoise.MinDb;
                maxsOfBins[col]     = binNoise.MaxDb;
            }

            var profile = new NoiseProfile()
            {
                NoiseMode       = noiseMode,
                NoiseSd         = noiseSd,
                NoiseThresholds = noiseThreshold,
                MinDb           = minsOfBins,
                MaxDb           = maxsOfBins,
            };

            return(profile);
        }
        /// <summary>
        /// This method normalizes a score array by subtracting the mode rather than the average of the array.
        /// This is because the noise is often not normally distributed but rather skewed.
        /// However, did not work well.
        /// </summary>
        public static List <Plot> SubtractModeAndSd(List <Plot> plots)
        {
            var opPlots = new List <Plot>();

            // subtract average from each plot array
            foreach (var plot in plots)
            {
                var scores = plot.data;
                var bgn    = SNR.CalculateModalBackgroundNoiseInSignal(scores, 1.0);
                var mode   = bgn.NoiseMode;
                var sd     = bgn.NoiseSd;

                // normalize the scores to z-scores
                for (int i = 0; i < scores.Length; i++)
                {
                    // Convert scores to z-scores
                    scores[i] = (scores[i] - mode) / sd;
                    if (scores[i] < 0.0)
                    {
                        scores[i] = 0.0;
                    }

                    if (scores[i] > 4.0)
                    {
                        scores[i] = 4.0;
                    }

                    // normalize full scale to 4 SDs.
                    scores[i] /= 4.0;
                }

                opPlots.Add(plot);
            }

            return(opPlots);
        }