Exemplo n.º 1
0
        /// <summary>
        /// returns an oscillation array for a single frequency bin.
        /// </summary>
        /// <param name="xCorrByTimeMatrix">derived from single frequency bin.</param>
        /// <param name="sensitivity">a threshold used to ignore low ascillation intensities.</param>
        /// <returns>vector of oscillation values.</returns>
        public static double[] GetOscillationArrayUsingFft(double[,] xCorrByTimeMatrix, double sensitivity)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);
            int sampleCount = xCorrByTimeMatrix.GetLength(1);

            // set up vector to contain fft output
            var oscillationsVector = new double[xCorrLength / 2];

            // loop over all the Auto-correlation vectors and do FFT
            for (int e = 0; e < sampleCount; e++)
            {
                double[] autocor = MatrixTools.GetColumn(xCorrByTimeMatrix, e);

                // zero mean the auto-correlation vector before doing FFT
                autocor = DataTools.DiffFromMean(autocor);
                FFT.WindowFunc wf       = FFT.Hamming;
                var            fft      = new FFT(autocor.Length, wf);
                var            spectrum = fft.Invoke(autocor);

                // skip spectrum[0] because it is DC or zero oscillations/sec
                spectrum = DataTools.Subarray(spectrum, 1, spectrum.Length - 2);

                // reduce the power in the low coeff because these can dominate.
                // This is a hack!
                spectrum[0] *= 0.33;

                // convert to energy and calculate total power in spectrum
                spectrum = DataTools.SquareValues(spectrum);
                double sumOfSquares = spectrum.Sum();

                // get combined relative power in the three bins centred on max.
                int    maxIndex   = DataTools.GetMaxIndex(spectrum);
                double powerAtMax = spectrum[maxIndex];

                if (maxIndex == 0)
                {
                    powerAtMax += spectrum[1] + spectrum[2];
                }
                else if (maxIndex >= spectrum.Length - 1)
                {
                    powerAtMax += spectrum[maxIndex - 1] + spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex - 1] + spectrum[maxIndex + 1];
                }

                double relativePower = powerAtMax / sumOfSquares;

                // if the relative power of the max oscillation is large enough,
                // then accumulate its power into the oscillations Vector
                if (relativePower > sensitivity)
                {
                    oscillationsVector[maxIndex] += powerAtMax;
                }
            }

            return(LogTransformOscillationVector(oscillationsVector, sampleCount));
        }
Exemplo n.º 2
0
        public static double[] GetOscillationArrayUsingWpd(double[,] xCorrByTimeMatrix, double sensitivity, int binNumber)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);
            int sampleCount = xCorrByTimeMatrix.GetLength(1);

            double[] oscillationsVector = new double[xCorrLength / 2];

            for (int e = 0; e < sampleCount; e++)
            {
                var autocor = MatrixTools.GetColumn(xCorrByTimeMatrix, e);
                autocor = DataTools.DiffFromMean(autocor);
                var      wpd      = new WaveletPacketDecomposition(autocor);
                double[] spectrum = wpd.GetWPDEnergySpectrumWithoutDC();

                // reduce the power in first coeff because it can dominate - this is a hack!
                spectrum[0] *= 0.5;

                spectrum = DataTools.SquareValues(spectrum);

                // get relative power in the three bins around max.
                double sumOfSquares = spectrum.Sum();

                //double avPower = spectrum.Sum() / spectrum.Length;
                int    maxIndex   = DataTools.GetMaxIndex(spectrum);
                double powerAtMax = spectrum[maxIndex];
                if (maxIndex == 0)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex - 1];
                }

                if (maxIndex >= spectrum.Length - 1)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex + 1];
                }

                double relativePower1 = powerAtMax / sumOfSquares;

                if (relativePower1 > sensitivity)
                {
                    // check for boundary overrun
                    if (maxIndex < oscillationsVector.Length)
                    {
                        // add in a new oscillation
                        oscillationsVector[maxIndex] += powerAtMax;
                    }
                }
            }

            return(LogTransformOscillationVector(oscillationsVector, sampleCount));
        }
        /// <summary>
        /// returns the fft spectrum of a cross-correlation function.
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static double[] CrossCorr(double[] v1, double[] v2)
        {
            int n = v1.Length; // assume both vectors of same length

            double[] r;
            alglib.corrr1d(v1, n, v2, n, out r);

            // alglib.complex[] f;
            // alglib.fftr1d(newOp, out f);
            // System.LoggedConsole.WriteLine("{0}", alglib.ap.format(f, 3));
            // for (int i = 0; i < op.Length; i++) LoggedConsole.WriteLine("{0}   {1:f2}", i, op[i]);

            // rearrange corr output and NormaliseMatrixValues
            int xcorrLength = 2 * n;

            double[] xCorr = new double[xcorrLength];

            // for (int i = 0; i < n - 1; i++) newOp[i] = r[i + n];   //rearrange corr output
            // for (int i = n - 1; i < opLength-1; i++) newOp[i] = r[i - n + 1];
            for (int i = 0; i < n - 1; i++)
            {
                xCorr[i] = r[i + n] / (i + 1);  // rearrange and NormaliseMatrixValues
            }

            for (int i = n - 1; i < xcorrLength - 1; i++)
            {
                xCorr[i] = r[i - n + 1] / (xcorrLength - i - 1);
            }

            // add extra value at end so have length = power of 2 for FFT
            // xCorr[xCorr.Length - 1] = xCorr[xCorr.Length - 2];
            // LoggedConsole.WriteLine("xCorr length = " + xCorr.Length);
            // for (int i = 0; i < xCorr.Length; i++) LoggedConsole.WriteLine("{0}   {1:f2}", i, xCorr[i]);
            // DataTools.writeBarGraph(xCorr);

            xCorr = DataTools.DiffFromMean(xCorr);
            FFT.WindowFunc wf  = FFT.Hamming;
            var            fft = new FFT(xCorr.Length, wf);

            var spectrum = fft.Invoke(xCorr);

            return(spectrum);
        }// CrossCorrelation()
        /// <summary>
        /// This method assume the matrix is derived from a spectrogram rotated so that the matrix rows are spectral columns of sonogram.
        ///
        /// </summary>
        /// <param name="m"></param>
        /// <param name="amplitudeThreshold"></param>
        /// <returns></returns>
        public static Tuple <double[], double[]> DetectBarsInTheRowsOfaMatrix(double[,] m, double threshold, int zeroBinCount)
        {
            int rowCount    = m.GetLength(0);
            int colCount    = m.GetLength(1);
            var intensity   = new double[rowCount];   //an array of period intensity
            var periodicity = new double[rowCount];   //an array of the periodicity values

            double[] prevRow = MatrixTools.GetRow(m, 0);
            prevRow = DataTools.DiffFromMean(prevRow);

            for (int r = 1; r < rowCount; r++)
            {
                double[] thisRow = MatrixTools.GetRow(m, r);
                thisRow = DataTools.DiffFromMean(thisRow);

                var spectrum = AutoAndCrossCorrelation.CrossCorr(prevRow, thisRow);

                for (int s = 0; s < zeroBinCount; s++)
                {
                    spectrum[s] = 0.0;  //in real data these bins are dominant and hide other frequency content
                }

                spectrum = DataTools.NormaliseArea(spectrum);
                int    maxId          = DataTools.GetMaxIndex(spectrum);
                double intensityValue = spectrum[maxId];
                intensity[r] = intensityValue;

                double period = 0.0;
                if (maxId != 0)
                {
                    period = 2 * colCount / (double)maxId;
                }

                periodicity[r] = period;

                prevRow = thisRow;
            }// rows

            return(Tuple.Create(intensity, periodicity));
        } //DetectBarsInTheRowsOfaMatrix()
        } //DetectBarsInTheRowsOfaMatrix()

        /// A METHOD TO DETECT HARMONICS IN THE ROWS of the passed portion of a sonogram.
        /// This method assume the matrix is derived from a spectrogram rotated so that the matrix rows are spectral columns of sonogram.
        /// Was first developed for crow calls.
        /// First looks for a decibel profile that matches the passed call duration and decibel loudness
        /// Then samples the centre portion for the correct harmonic period.
        /// </summary>
        /// <param name="m"></param>
        /// <param name="amplitudeThreshold"></param>
        /// <returns></returns>
        public static Tuple <double[], double[], double[]> DetectHarmonicsInSonogramMatrix(double[,] m, double dBThreshold, int callSpan)
        {
            int zeroBinCount = 3;  //to remove low freq content which dominates the spectrum
            int halfspan     = callSpan / 2;

            double[] dBArray = MatrixTools.GetRowAverages(m);
            dBArray = DataTools.filterMovingAverage(dBArray, 3);

            bool doNoiseRemoval = true;

            if (doNoiseRemoval)
            {
                double StandardDeviationCount = 0.1;  // number of noise SDs to calculate noise threshold - determines severity of noise reduction
                SNR.BackgroundNoise bgn       = SNR.SubtractBackgroundNoiseFromSignal(dBArray, StandardDeviationCount);
                dBArray = bgn.NoiseReducedSignal;
            }

            bool[] peaks = DataTools.GetPeaks(dBArray);

            int rowCount    = m.GetLength(0);
            int colCount    = m.GetLength(1);
            var intensity   = new double[rowCount];    //an array of period intensity
            var periodicity = new double[rowCount];    //an array of the periodicity values

            for (int r = halfspan; r < rowCount - halfspan; r++)
            {
                //APPLY A FILTER: must satisfy the following conditions for a call.
                if (!peaks[r])
                {
                    continue;
                }

                if (dBArray[r] < dBThreshold)
                {
                    continue;
                }

                double lowerDiff = dBArray[r] - dBArray[r - halfspan];
                double upperDiff = dBArray[r] - dBArray[r + halfspan];
                if (lowerDiff < dBThreshold || upperDiff < dBThreshold)
                {
                    continue;
                }

                double[] prevRow  = DataTools.DiffFromMean(MatrixTools.GetRow(m, r - 1));
                double[] thisRow  = DataTools.DiffFromMean(MatrixTools.GetRow(m, r));
                var      spectrum = AutoAndCrossCorrelation.CrossCorr(prevRow, thisRow);

                for (int s = 0; s < zeroBinCount; s++)
                {
                    spectrum[s] = 0.0;  //in real data these bins are dominant and hide other frequency content
                }

                spectrum = DataTools.NormaliseArea(spectrum);
                int    maxId          = DataTools.GetMaxIndex(spectrum);
                double intensityValue = spectrum[maxId];
                intensity[r] = intensityValue;

                double period = 0.0;
                if (maxId != 0)
                {
                    period = 2 * colCount / (double)maxId;
                }

                periodicity[r] = period;

                prevRow = thisRow;
            } // rows

            return(Tuple.Create(dBArray, intensity, periodicity));
        } //DetectHarmonicsInSonogramMatrix()
Exemplo n.º 6
0
        public static double[] GetOscillationArrayUsingCwt(double[,] xCorrByTimeMatrix, double framesPerSecond, int binNumber)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);

            //int sampleCount = xCorrByTimeMatrix.GetLength(1);

            // loop over the singular values and
            // transfer data from SVD.UMatrix to a single vector of oscilation values
            var oscillationsVector = new double[xCorrLength / 2];

            for (int e = 0; e < 10; e++)
            {
                var autocor = new double[xCorrLength];

                // the sign of the left singular vectors are usually negative.
                if (autocor[0] < 0)
                {
                    for (int i = 0; i < autocor.Length; i++)
                    {
                        autocor[i] *= -1.0;
                    }
                }

                // ##########################################################\
                autocor = DataTools.DiffFromMean(autocor);
                FFT.WindowFunc wf       = FFT.Hamming;
                var            fft      = new FFT(autocor.Length, wf);
                var            spectrum = fft.Invoke(autocor);

                // skip spectrum[0] because it is DC or zero oscillations/sec
                spectrum = DataTools.Subarray(spectrum, 1, spectrum.Length - 2);

                // reduce the power in first coeff because it can dominate - this is a hack!
                spectrum[0] *= 0.5;

                spectrum = DataTools.SquareValues(spectrum);
                double avPower    = spectrum.Sum() / spectrum.Length;
                int    maxIndex   = DataTools.GetMaxIndex(spectrum);
                double powerAtMax = spectrum[maxIndex];

                //double relativePower1 = powerAtMax / sumOfSquares;
                double relativePower2 = powerAtMax / avPower;

                //if (relativePower1 > 0.05)
                if (relativePower2 > 10.0)
                {
                    // check for boundary overrun
                    if (maxIndex < oscillationsVector.Length)
                    {
                        // add in a new oscillation
                        //oscillationsVector[maxIndex] += powerAtMax;
                        oscillationsVector[maxIndex] += relativePower2;
                    }
                }
            }

            for (int i = 0; i < oscillationsVector.Length; i++)
            {
                // NormaliseMatrixValues by sample count
                //oscillationsVector[i] /= sampleCount;
                // do log transform
                if (oscillationsVector[i] < 1.0)
                {
                    oscillationsVector[i] = 0.0;
                }
                else
                {
                    oscillationsVector[i] = Math.Log10(1 + oscillationsVector[i]);
                }
            }

            return(oscillationsVector);
        }
Exemplo n.º 7
0
        /// <summary>
        ///  reduces the sequence of Xcorrelation vectors to a single summary vector.
        ///  Does this by:
        ///  (1) do SVD on the collection of XCORRELATION vectors
        ///  (2) select the dominant ones based on the eigen values - 90% threshold
        ///      Typically there are 1 to 10 eigen values depending on how busy the bin is.
        ///  (3) Do an FFT on each of the returned SVD vectors to pick the dominant oscillation rate.
        ///  (4) Accumulate the oscillations in a freq by oscillation rate matrix.
        ///      The amplitude value for the oscillation is the eigenvalue.
        /// #
        ///  NOTE: There should only be one dominant oscillation in any one freq band at one time.
        ///        Birds with oscillating calls do call simultaneously, but this technique will only pick up the dominant call.
        /// #.
        /// </summary>
        /// <param name="xCorrByTimeMatrix">double[,] xCorrelationsByTime = new double[sampleLength, sampleCount]. </param>
        /// <param name="sensitivity">can't remember what this does.</param>
        /// <param name="binNumber">only used when debugging.</param>
        public static double[] GetOscillationArrayUsingSvdAndFft(double[,] xCorrByTimeMatrix, double sensitivity, int binNumber)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);

            // int sampleCount = xCorrByTimeMatrix.GetLength(1);

            // do singular value decomp on the xcorrelation vectors.
            // we want to compute the U and V matrices of singular vectors.
            //var svd = DenseMatrix.OfArray(xCorrByTimeMatrix).Svd(true);
            var svd = DenseMatrix.OfArray(xCorrByTimeMatrix).Svd();

            // svd.S returns the singular values in a vector
            Vector <double> singularValues = svd.S;

            // get total energy in first singular values
            double energySum = 0.0;

            foreach (double v in singularValues)
            {
                energySum += v * v;
            }

            // get the 90% most significant ####### THis is a significant parameter but not critical. 90% is OK
            double significanceThreshold = 0.9;
            double energy = 0.0;
            int    countOfSignificantSingularValues = 0;

            for (int n = 0; n < singularValues.Count; n++)
            {
                energy += singularValues[n] * singularValues[n];
                double fraction = energy / energySum;
                if (fraction > significanceThreshold)
                {
                    countOfSignificantSingularValues = n + 1;
                    break;
                }
            }

            //foreach (double d in singularValues)
            //    Console.WriteLine("singular value = {0}", d);
            //Console.WriteLine("Freq bin:{0}  Count Of Significant SingularValues = {1}", binNumber, countOfSignificantSingularValues);

            // svd.U returns the LEFT singular vectors in matrix
            Matrix <double> uMatrix = svd.U;

            //Matrix<double> relevantU = UMatrix.SubMatrix(0, UMatrix.RowCount-1, 0, eigenVectorCount);

            //Console.WriteLine("\n\n");
            //MatrixTools.writeMatrix(UMatrix.ToArray());
            //string pathUmatrix1 = @"C:\SensorNetworks\Output\Sonograms\testMatrixSVD_U1.png";
            //ImageTools.DrawReversedMDNMatrix(UMatrix, pathUmatrix1);
            //string pathUmatrix2 = @"C:\SensorNetworks\Output\Sonograms\testMatrixSVD_U2.png";
            //ImageTools.DrawReversedMDNMatrix(relevantU, pathUmatrix2);

            // loop over the singular values and
            // transfer data from SVD.UMatrix to a single vector of oscilation values
            double[] oscillationsVector = new double[xCorrLength / 2];

            for (int e = 0; e < countOfSignificantSingularValues; e++)
            {
                double[] autocor = uMatrix.Column(e).ToArray();

                // the sign of the left singular vectors are usually negative.
                if (autocor[0] < 0)
                {
                    for (int i = 0; i < autocor.Length; i++)
                    {
                        autocor[i] *= -1.0;
                    }
                }

                // ##########################################################\
                autocor = DataTools.DiffFromMean(autocor);
                FFT.WindowFunc wf       = FFT.Hamming;
                var            fft      = new FFT(autocor.Length, wf);
                var            spectrum = fft.Invoke(autocor);

                // skip spectrum[0] because it is DC or zero oscillations/sec
                spectrum = DataTools.Subarray(spectrum, 1, spectrum.Length - 2);

                // reduce the power in first coeff because it can dominate - this is a hack!
                spectrum[0] *= 0.5;

                spectrum = DataTools.SquareValues(spectrum);

                // get relative power in the three bins around max.
                double sumOfSquares = spectrum.Sum();
                int    maxIndex     = DataTools.GetMaxIndex(spectrum);
                double powerAtMax   = spectrum[maxIndex];

                if (maxIndex == 0)
                {
                    powerAtMax += spectrum[1] + spectrum[2];
                }
                else if (maxIndex >= spectrum.Length - 1)
                {
                    powerAtMax += spectrum[maxIndex - 1] + spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex - 1] + spectrum[maxIndex + 1];
                }

                double relativePower = powerAtMax / sumOfSquares;

                // if the relative power of the max oscillation is large enough,
                // then accumulate its power into the oscillationsVector
                if (relativePower > sensitivity)
                {
                    oscillationsVector[maxIndex] += powerAtMax;
                }
            }

            return(LogTransformOscillationVector(oscillationsVector, countOfSignificantSingularValues));
        }
        public static double[] GetOscillationArrayUsingWpd(double[,] xCorrByTimeMatrix, double sensitivity, int binNumber)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);
            int sampleCount = xCorrByTimeMatrix.GetLength(1);

            double[] oscillationsVector = new double[xCorrLength / 2];

            for (int e = 0; e < sampleCount; e++)
            {
                double[] autocor = MatrixTools.GetColumn(xCorrByTimeMatrix, e);

                // ##########################################################\
                autocor = DataTools.DiffFromMean(autocor);
                WaveletPacketDecomposition wpd = new WaveletPacketDecomposition(autocor);
                double[] spectrum = wpd.GetWPDEnergySpectrumWithoutDC();

                // reduce the power in first coeff because it can dominate - this is a hack!
                spectrum[0] *= 0.66;

                spectrum = DataTools.SquareValues(spectrum);

                // get relative power in the three bins around max.
                double sumOfSquares = spectrum.Sum();

                //double avPower = spectrum.Sum() / spectrum.Length;
                int    maxIndex   = DataTools.GetMaxIndex(spectrum);
                double powerAtMax = spectrum[maxIndex];
                if (maxIndex == 0)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex - 1];
                }

                if (maxIndex >= spectrum.Length - 1)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex + 1];
                }

                double relativePower1 = powerAtMax / sumOfSquares;

                //double relativePower2 = powerAtMax / avPower;

                if (relativePower1 > sensitivity)

                //if (relativePower2 > 10.0)
                {
                    // check for boundary overrun
                    if (maxIndex < oscillationsVector.Length)
                    {
                        // add in a new oscillation
                        oscillationsVector[maxIndex] += powerAtMax;

                        //oscillationsVector[maxIndex] += relativePower;
                    }
                }
            }

            for (int i = 0; i < oscillationsVector.Length; i++)
            {
                // NormaliseMatrixValues by sample count
                oscillationsVector[i] /= sampleCount;

                // do log transform
                if (oscillationsVector[i] < 1.0)
                {
                    oscillationsVector[i] = 0.0;
                }
                else
                {
                    oscillationsVector[i] = Math.Log10(1 + oscillationsVector[i]);
                }
            }

            return(oscillationsVector);
        }
        public static double[] GetOscillationArrayUsingFft(double[,] xCorrByTimeMatrix, double sensitivity, int binNumber)
        {
            int xCorrLength = xCorrByTimeMatrix.GetLength(0);
            int sampleCount = xCorrByTimeMatrix.GetLength(1);

            // loop over the Auto-correlation vectors and do FFT
            double[] oscillationsVector = new double[xCorrLength / 2];

            for (int e = 0; e < sampleCount; e++)
            {
                double[] autocor = MatrixTools.GetColumn(xCorrByTimeMatrix, e);

                //DataTools.writeBarGraph(autocor);

                // ##########################################################\
                autocor = DataTools.DiffFromMean(autocor);
                FFT.WindowFunc wf       = FFT.Hamming;
                var            fft      = new FFT(autocor.Length, wf);
                var            spectrum = fft.Invoke(autocor);

                // skip spectrum[0] because it is DC or zero oscillations/sec
                spectrum = DataTools.Subarray(spectrum, 1, spectrum.Length - 2);

                // reduce the power in first coeff because it can dominate - this is a hack!
                spectrum[0] *= 0.66;

                spectrum = DataTools.SquareValues(spectrum);

                // get relative power in the three bins around max.
                double sumOfSquares = spectrum.Sum();

                //double avPower = spectrum.Sum() / spectrum.Length;
                int    maxIndex   = DataTools.GetMaxIndex(spectrum);
                double powerAtMax = spectrum[maxIndex];
                if (maxIndex == 0)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex - 1];
                }

                if (maxIndex >= spectrum.Length - 1)
                {
                    powerAtMax += spectrum[maxIndex];
                }
                else
                {
                    powerAtMax += spectrum[maxIndex + 1];
                }

                double relativePower1 = powerAtMax / sumOfSquares;

                //double relativePower2 = powerAtMax / avPower;

                if (relativePower1 > sensitivity)

                //if (relativePower2 > 10.0)
                {
                    // check for boundary overrun
                    if (maxIndex < oscillationsVector.Length)
                    {
                        // add in a new oscillation
                        oscillationsVector[maxIndex] += powerAtMax;

                        //oscillationsVector[maxIndex] += relativePower;
                    }
                }
            }

            for (int i = 0; i < oscillationsVector.Length; i++)
            {
                // NormaliseMatrixValues by sample count
                oscillationsVector[i] /= sampleCount;

                // do log transform
                if (oscillationsVector[i] < 1.0)
                {
                    oscillationsVector[i] = 0.0;
                }
                else
                {
                    oscillationsVector[i] = Math.Log10(1 + oscillationsVector[i]);
                }
            }

            return(oscillationsVector);
        }