Пример #1
0
        public double[] getAnalyzeDataC()
        {
            g_OffSet = 0;//初始化
            //使用互相关算法分析
            int len = 262144;
            double[] A = new double[len];
            double[] B = new double[len];

            for (int i = 0; i < len; i++)
            {
                A[i] = g_DataA[i];
                B[i] = g_DataB[i];
            }

            CrossCorrelation ccorr = new CrossCorrelation();
            double[] R = ccorr.Rxy(A, B);
            int R_length = R.Length;

            Position p = new Position();
            int location = p.max(R);
            int d = location - R_length / 2;

            g_OffSet = d;//偏移值

            return R;//经过互相关计算后的数组
        }
Пример #2
0
        private void crossCorrelateButton_Click(object sender, RoutedEventArgs e)
        {
            List <Match> matches = new List <Match>(matchGrid.SelectedItems.Cast <Match>());

            foreach (Match matchFE in matches)
            {
                Match match = matchFE; // needed as reference for async task
                Task.Factory.StartNew(() => {
                    Match ccm = CrossCorrelation.Adjust(match, progressMonitor);
                    Dispatcher.BeginInvoke((Action) delegate {
                        multiTrackViewer.Matches.Add(ccm);
                        matchGrid.Items.Refresh();
                        multiTrackViewer.RefreshAdornerLayer();
                    });
                });
            }
        }
Пример #3
0
        private void crossCorrelateButton_Click(object sender, RoutedEventArgs e)
        {
            if (ccr == null)
            {
                Task.Factory.StartNew(() => {
                    Match ccm = CrossCorrelation.Adjust(match, progressMonitor, out ccr);
                    Dispatcher.BeginInvoke((Action) delegate {
                        multiTrackViewer1.Matches.Add(ccm);
                        multiTrackViewer1.RefreshAdornerLayer();

                        ShowCCResult(ccr);
                    });
                });
            }
            else
            {
                ShowCCResult(ccr);
            }
        }
Пример #4
0
        /// <summary>
        /// The CORE ANALYSIS METHOD.
        /// </summary>
        public static Tuple <BaseSonogram, double[, ], Plot, List <AcousticEvent>, TimeSpan> Analysis(FileInfo fiSegmentOfSourceFile, Dictionary <string, string> configDict, TimeSpan segmentStartOffset)
        {
            //set default values -
            int frameLength = 1024;

            if (configDict.ContainsKey(AnalysisKeys.FrameLength))
            {
                frameLength = int.Parse(configDict[AnalysisKeys.FrameLength]);
            }

            double windowOverlap              = 0.0;
            int    minHz                      = int.Parse(configDict["MIN_HZ"]);
            int    minFormantgap              = int.Parse(configDict["MIN_FORMANT_GAP"]);
            int    maxFormantgap              = int.Parse(configDict["MAX_FORMANT_GAP"]);
            double decibelThreshold           = double.Parse(configDict["DECIBEL_THRESHOLD"]);   //dB
            double harmonicIntensityThreshold = double.Parse(configDict["INTENSITY_THRESHOLD"]); //in 0-1
            double callDuration               = double.Parse(configDict["CALL_DURATION"]);       // seconds

            AudioRecording recording = new AudioRecording(fiSegmentOfSourceFile.FullName);

            //i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName        = recording.BaseName,
                WindowSize         = frameLength,
                WindowOverlap      = windowOverlap,
                NoiseReductionType = SNR.KeyToNoiseReductionType("STANDARD"),
            }; //default values config

            TimeSpan tsRecordingtDuration = recording.Duration;
            int      sr              = recording.SampleRate;
            double   freqBinWidth    = sr / (double)sonoConfig.WindowSize;
            double   framesPerSecond = freqBinWidth;

            //the Xcorrelation-FFT technique requires number of bins to scan to be power of 2.
            //assuming sr=17640 and window=1024, then  64 bins span 1100 Hz above the min Hz level. i.e. 500 to 1600
            //assuming sr=17640 and window=1024, then 128 bins span 2200 Hz above the min Hz level. i.e. 500 to 2700
            int numberOfBins = 64;
            int minBin       = (int)Math.Round(minHz / freqBinWidth) + 1;
            int maxbin       = minBin + numberOfBins - 1;
            int maxHz        = (int)Math.Round(minHz + (numberOfBins * freqBinWidth));

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);
            int          rowCount = sonogram.Data.GetLength(0);
            int          colCount = sonogram.Data.GetLength(1);

            double[,] subMatrix = MatrixTools.Submatrix(sonogram.Data, 0, minBin, rowCount - 1, maxbin);

            int callSpan = (int)Math.Round(callDuration * framesPerSecond);

            //#############################################################################################################################################
            //ii: DETECT HARMONICS
            var results = CrossCorrelation.DetectHarmonicsInSonogramMatrix(subMatrix, decibelThreshold, callSpan);

            double[] dBArray     = results.Item1;
            double[] intensity   = results.Item2;   //an array of periodicity scores
            double[] periodicity = results.Item3;

            //intensity = DataTools.filterMovingAverage(intensity, 3);
            int noiseBound = (int)(100 / freqBinWidth); //ignore 0-100 hz - too much noise

            double[] scoreArray = new double[intensity.Length];
            for (int r = 0; r < rowCount; r++)
            {
                if (intensity[r] < harmonicIntensityThreshold)
                {
                    continue;
                }

                //ignore locations with incorrect formant gap
                double herzPeriod = periodicity[r] * freqBinWidth;
                if (herzPeriod < minFormantgap || herzPeriod > maxFormantgap)
                {
                    continue;
                }

                //find freq having max power and use info to adjust score.
                //expect humans to have max < 1000 Hz
                double[] spectrum = MatrixTools.GetRow(sonogram.Data, r);
                for (int j = 0; j < noiseBound; j++)
                {
                    spectrum[j] = 0.0;
                }

                int    maxIndex         = DataTools.GetMaxIndex(spectrum);
                int    freqWithMaxPower = (int)Math.Round(maxIndex * freqBinWidth);
                double discount         = 1.0;
                if (freqWithMaxPower < 1200)
                {
                    discount = 0.0;
                }

                if (intensity[r] > harmonicIntensityThreshold)
                {
                    scoreArray[r] = intensity[r] * discount;
                }
            }

            //transfer info to a hits matrix.
            var    hits      = new double[rowCount, colCount];
            double threshold = harmonicIntensityThreshold * 0.75; //reduced threshold for display of hits

            for (int r = 0; r < rowCount; r++)
            {
                if (scoreArray[r] < threshold)
                {
                    continue;
                }

                double herzPeriod = periodicity[r] * freqBinWidth;
                for (int c = minBin; c < maxbin; c++)
                {
                    //hits[r, c] = herzPeriod / (double)380;  //divide by 380 to get a relativePeriod;
                    hits[r, c] = (herzPeriod - minFormantgap) / maxFormantgap;  //to get a relativePeriod;
                }
            }

            //iii: CONVERT TO ACOUSTIC EVENTS
            double maxPossibleScore = 0.5;
            int    halfCallSpan     = callSpan / 2;
            var    predictedEvents  = new List <AcousticEvent>();

            for (int i = 0; i < rowCount; i++)
            {
                //assume one score position per crow call
                if (scoreArray[i] < 0.001)
                {
                    continue;
                }

                double        startTime = (i - halfCallSpan) / framesPerSecond;
                AcousticEvent ev        = new AcousticEvent(segmentStartOffset, startTime, callDuration, minHz, maxHz);
                ev.SetTimeAndFreqScales(framesPerSecond, freqBinWidth);
                ev.Score           = scoreArray[i];
                ev.ScoreNormalised = ev.Score / maxPossibleScore; // normalised to the user supplied threshold

                //ev.Score_MaxPossible = maxPossibleScore;
                predictedEvents.Add(ev);
            } //for loop

            Plot plot = new Plot("CROW", intensity, harmonicIntensityThreshold);

            return(Tuple.Create(sonogram, hits, plot, predictedEvents, tsRecordingtDuration));
        } //Analysis()
Пример #5
0
        private void button3_Click(object sender, EventArgs e)
        {
            EraseGraph();

            CreateGraph();

            panel3.Controls.Clear();

            /*Label label13 = new Label();
             * Label label14 = new Label();
             * label13.Font = label14.Font = new System.Drawing.Font("宋体", 15.75F, System.Drawing.FontStyle.Bold);
             * label13.ForeColor = label14.ForeColor = Color.Red;
             * label13.Location = new System.Drawing.Point(100, 30);
             * label14.Location = new System.Drawing.Point(900, 30);
             * label13.AutoSize = label14.AutoSize = true;
             * panel3.Controls.Add(label13);
             * panel3.Controls.Add(label14);*/

            ZedGraphControl zed3 = new ZedGraphControl();

            zed3.Width  = panel3.Width;
            zed3.Height = panel3.Height;

            //读取数据
            int datalength = WaterLeak.get_DataLength();

            double[] dataA     = WaterLeak.get_DataA();
            double[] dataB     = WaterLeak.get_DataB();
            double   dataA_avg = WaterLeak.get_DataA_Avg();
            double   dataB_avg = WaterLeak.get_DataB_Avg();


            if (比较ToolStripMenuItem.Checked == true)
            {
                byte[] A = data_A;
                byte[] B = data_B;

                int[] m = new int[2 * datalength];
                int   j;
                int   k = 0;
                for (int i = 0; i < 2 * datalength; i++)
                {
                    if (A[i] != B[i])
                    {
                        j    = i;
                        m[k] = j;
                        k++;
                    }
                }

                int index = 0;
                for (int i = 0; i < 2 * datalength; i++)
                {
                    if (m[i] == 0)
                    {
                        index = i;
                    }
                }
                int[] n = new int[index];
                for (int i = 0; i < index; i++)
                {
                    n[i] = m[i];
                }
                MessageBox.Show("" + index);
            }


            //处理数据,采用均方差算法
            if (算术平均ToolStripMenuItem.Checked == true)
            {
                progressBar1.Value = 0;

                int      j    = 0;
                double   MINC = 0;
                int      bias = 5000;
                int      w    = 5000;
                double[] C    = new double[2 * bias];
                for (int i = -bias; i < bias; i++)
                {
                    C[i + bias] = 0;
                    for (int k = w; k < datalength - w; k++)
                    {
                        C[i + bias] += Math.Abs(dataA[k + i] - dataB[k]);  //曼哈顿距离
                    }
                    if (i == -bias)
                    {
                        MINC = C[0];
                    }
                    else if (C[bias + i] < MINC)
                    {
                        j    = i;
                        MINC = C[bias + i];
                    }
                    Application.DoEvents();
                    progressBar1.Value = (i + bias) * 50 / bias;
                }
                progressBar1.Value += 1;  //进度条

                double w_avg;
                w_avg = 0;
                for (int i = 0; i < 2 * bias; i++)
                {
                    w_avg += C[i] / (2 * bias);
                }

                for (int i = 0; i < 2 * bias; i++)
                {
                    C[i] = (C[i] - w_avg) / w_avg;
                }

                panel3.Controls.Add(zed3);
                GraphPane Pane = zed3.GraphPane;

                /*Pane.Title = "偏差结果";
                 * Pane.XAxis.Title = "";
                 * Pane.YAxis.Title = "";*/

                PointPairList list1 = new PointPairList();
                for (int i = 0; i < 2 * bias; i++)
                {
                    list1.Add(i, C[i]);
                }

                LineItem myCurve1 = Pane.AddCurve("Porsche", list1, Color.Blue, SymbolType.None);
                zed3.AxisChange();

                //计算漏水点位置
                double positon = (WaterLeak.get_PipelineLength() + WaterLeak.get_WaveNumber() * j / (1000 * WaterLeak.get_CaptureRate())) / 2;

                /*label14.Text = "漏水点距离A探头" + positon.ToString() + "米!";
                 *
                 * //显示标注数据
                 * if (j > 0)
                 *  label13.Text = "A探头滞后B探头" + j.ToString("G") + "个基点!";
                 * if (j < 0)
                 *  label13.Text = "A探头超前B探头" + (-j).ToString() + "个基点!";
                 * if (j == 0)
                 *  label13.Text = "A探头与B探头无偏移!";*/

                //显示基点
                textBoxOffSet.Text = j.ToString();

                //保存参数
                WaterLeak.set_dataC_factor(500);
                WaterLeak.set_dataC_shift(100);
                WaterLeak.set_Bias(bias);
                WaterLeak.set_Min_Position(j);
                WaterLeak.set_Min_Value(MINC);
                WaterLeak.set_DataC(C);
            }

            //if (LMSToolStripMenuItem.Checked == true)
            //{
            //    progressBar1.Value = 0;


            //    MatlabClass mat = new MatlabClass();
            //    MWNumericArray dataA_m = new MWNumericArray(1, datalength, dataA);
            //    MWNumericArray dataB_m = new MWNumericArray(1, datalength, dataB);
            //    MWArray M_m = 100;
            //    MWArray mu_m = 0.00001;
            //    MWArray W_m = mat.my_LMS(dataA_m, dataB_m, M_m, mu_m);
            //    Array W = ((MWNumericArray)W_m).ToArray();
            //    int M = ((MWNumericArray)M_m).ToScalarInteger();
            //    int W_length = W.Length;
            //    int d = 0;
            //    double temp = Convert.ToDouble(W.GetValue(0, 0));

            //    for (int i = 1; i < W_length; i++)
            //    {
            //        if (temp < Convert.ToDouble(W.GetValue(i, 0)))
            //        {
            //            temp = Convert.ToDouble(W.GetValue(i, 0));
            //            d = i - 2 * M;
            //        }
            //    }

            //    panel3.Controls.Add(zed3);
            //    GraphPane Pane = zed3.GraphPane;
            //    Pane.Title = "偏差结果";
            //    Pane.XAxis.Title = "";
            //    Pane.YAxis.Title = "";

            //    PointPairList list = new PointPairList();
            //    for (int i = 0; i < W_length; i++)
            //    {
            //        list.Add(i - 2 * M, Convert.ToDouble(W.GetValue(i, 0)));
            //    }

            //    LineItem myCurve = Pane.AddCurve("Porsche", list, Color.Blue, SymbolType.None);
            //    zed3.AxisChange();

            //    //计算漏水点位置
            //    double positon = (WaterLeak.get_PipelineLength() + WaterLeak.get_WaveNumber() * d / (1000 * WaterLeak.get_CaptureRate())) / 2;
            //    label14.Text = "漏水点距离A探头" + positon.ToString() + "米!";

            //    //显示标注数据
            //    if (d > 0)
            //        label13.Text = "A探头滞后B探头" + d.ToString("G") + "个基点!";
            //    if (d < 0)
            //        label13.Text = "A探头超前B探头" + (-d).ToString() + "个基点!";
            //    if (d == 0)
            //        label13.Text = "A探头与B探头无偏移!";
            //}

            if (广义互相关ToolStripMenuItem.Checked == true)
            {
                DateTime startDT = System.DateTime.Now;
                progressBar1.Value = 0;
                int len = 262144;


                double[] A = new double[len];
                double[] B = new double[len];

                for (int i = 0; i < len; i++)
                {
                    A[i] = dataA[i];
                    B[i] = dataB[i];
                }

                CrossCorrelation ccorr = new CrossCorrelation();
                double[]         R     = ccorr.Rxy(A, B);
                int R_length           = R.Length;

                Position p        = new Position();
                int      location = p.max(R);
                int      d        = location - R_length / 2;

                panel3.Controls.Add(zed3);
                GraphPane Pane = zed3.GraphPane;


                /*Pane.Title = "互相关系数";
                 * Pane.XAxis.Title = "";
                 * Pane.YAxis.Title = "";*/

                PointPairList list = new PointPairList();
                for (int i = 0; i < R_length; i++)
                {
                    list.Add(i, R[i]);
                }

                LineItem myCurve = Pane.AddCurve("Porsche", list, Color.Blue, SymbolType.None);
                zed3.AxisChange();

                //计算漏水点位置
                double positon = (WaterLeak.get_PipelineLength() + WaterLeak.get_WaveNumber() * d / (1000 * WaterLeak.get_CaptureRate())) / 2;

                /*label14.Text = "漏水点距离A探头" + positon.ToString() + "米!";
                 * //显示标注数据
                 * if (d > 0)
                 *  label13.Text = "A探头滞后B探头" + d.ToString("G") + "个基点!";
                 * if (d < 0)
                 *  label13.Text = "A探头超前B探头" + (-d).ToString() + "个基点!";
                 * if (d == 0)
                 *  label13.Text = "A探头与B探头无偏移!";*/

                //显示基点
                textBoxOffSet.Text = d.ToString();

                DateTime endDT = System.DateTime.Now;
                TimeSpan time  = endDT.Subtract(startDT);
                //MessageBox.Show(time.TotalMilliseconds.ToString() + "ms");
            }

            //if (互功率谱ToolStripMenuItem.Checked == true)
            //{
            //    progressBar1.Value = 0;


            //    MatlabClass mat = new MatlabClass();
            //    MWNumericArray dataA_m = new MWNumericArray(1, datalength, dataA);
            //    MWNumericArray dataB_m = new MWNumericArray(1, datalength, dataB);
            //    MWArray datalength_m = datalength;
            //    MWArray R_m = mat.my_xcorrPow(dataA_m, dataB_m);
            //    Array R = ((MWNumericArray)R_m).ToArray();
            //    int R_length = R.Length;

            //    int d = 0;
            //    double temp = Convert.ToDouble(R.GetValue(0, 0));

            //    for (int i = 1; i < R_length; i++)
            //    {
            //        if (temp < Convert.ToDouble(R.GetValue(0, i)))
            //        {
            //            temp = Convert.ToDouble(R.GetValue(0, i));
            //            d = i - datalength + 1;
            //        }
            //    }

            //    panel3.Controls.Add(zed3);
            //    GraphPane Pane = zed3.GraphPane;
            //    Pane.Title = "偏差结果";
            //    Pane.XAxis.Title = "";
            //    Pane.YAxis.Title = "";

            //    PointPairList list = new PointPairList();
            //    for (int i = 0; i < R_length; i++)
            //    {
            //        list.Add(i - datalength + 1, Convert.ToDouble(R.GetValue(0, i)));
            //    }

            //    LineItem myCurve = Pane.AddCurve("Porsche", list, Color.Blue, SymbolType.None);
            //    zed3.AxisChange();

            //    //计算漏水点位置
            //    double positon = (WaterLeak.get_PipelineLength() + WaterLeak.get_WaveNumber() * d / (1000 * WaterLeak.get_CaptureRate())) / 2;
            //    label14.Text = "漏水点距离A探头" + positon.ToString() + "米!";

            //    //显示标注数据
            //    if (d > 0)
            //        label13.Text = "A探头滞后B探头" + d.ToString("G") + "个基点!";
            //    if (d < 0)
            //        label13.Text = "A探头超前B探头" + (-d).ToString() + "个基点!";
            //    if (d == 0)
            //        label13.Text = "A探头与B探头无偏移!";
            //}
            //int bias = 5000;
            //int w = 2500;
            //double[] C = new double[bias];
            //double minc = 0;
            //int d = 0;
            //int n = 5;//计算次数
            //int sp = datalength / n;//每次计算的间隔
            //int[] T = new int[n];//时延点数
            //double[] S = new double[n];//离A点距离
            //DataTable dt = new DataTable();
            //dt.Columns.Add("A探头超前点数", typeof(int));
            //dt.Columns.Add("漏水点离A探头距离", typeof(double));
            //for (int m = 0; m < n; m++)
            //{
            //    for (int i = 0 + m * sp; i < bias + m * sp; i++)
            //    {
            //        C[i - m * sp] = 0;
            //        for (int j = w + m * sp; j < w + bias + m * sp; j++)
            //        {
            //            C[i - m * sp] += Math.Abs(dataA[i + j - w - m * sp] - dataB[j]);
            //        }
            //        if (i == 0) minc = C[0];
            //        else if (C[i - m * sp] < minc)
            //        {
            //            d = i - m * sp;
            //            minc = C[i - m * sp];
            //        }
            //    }
            //    T[m] = w - d;
            //    S[m] = 500 - (double)T[m] / 10;
            //    DataRow dr = dt.NewRow();
            //    dr[0] = T[m].ToString();
            //    dr[1] = S[m].ToString();
            //    dt.Rows.Add(dr);
            //    Application.DoEvents();
            //    progressBar1.Value = (m - 1) * 100 / n;
            //}
            //dataGridView1.DataSource = dt;
            //dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            /*
             *
             * //处理数据,采用LMS算法
             * //初始化
             * int M=1000;
             * float mu = (float)0.1;
             * float[] en = new float[datalength];
             * for (int i = 0; i < datalength; i++)
             *  en[i] = 0;
             * double[] w = new double[M];
             * for (int i = 0; i < M; i++)
             *  w[i] = 0;
             * float y;
             * //迭代运算
             * for (int k = M - 1; k < datalength; k++)
             * {
             *  y=0;
             *  for (int i = 0; i < M; i++)
             *      y += (float)(w[i]) * dataB[k - i];
             *  if (double.IsNaN(y)) y = 0;
             *  en[k] =dataA[k] - y;
             *
             *  for (int i = 0; i < M; i++)
             *  {
             *      w[i] = w[i] + 2 * mu * en[k] * dataB[k - i];
             *      if (double.IsNaN(w[i])) w[i] = 0;
             *      // w[i] = Math.Round(w[i], 6);
             *  }
             *
             *  progressBar1.Value = (k-M) * 100 / (datalength - M-1);
             *
             *  Application.DoEvents();
             *
             * }
             *
             *
             * float w_avg;
             * w_avg = 0;
             * for (int i = 0; i < M; i++)
             * w_avg += (float)w[i];
             *
             * w_avg /= M;
             * // w_avg = Math.Round(w_avg, 6);
             *
             * // w[0] = Math.Round(w[0], 10);
             * textBox1.Text = w[0].ToString("G");
             */
        }
Пример #6
0
        public void Test(double[] recorded)
        {
            // 動作テスト

            int N = mOrder;
            int P = (1 << N) - 1;

            var from = new double[P + 1];

            {
                int copySize = recorded.Length;
                if (from.Length < copySize)
                {
                    copySize = from.Length;
                }
                Array.Copy(recorded, from, copySize);
            }

            byte[] mlsSeq;
            {
                var mls = new MaximumLengthSequence(N);
                mlsSeq = mls.Sequence();
                for (int i = 0; i < mlsSeq.Length; ++i)
                {
                    Console.Write("{0} ", mlsSeq[i]);
                }
                Console.WriteLine("");
            }

            {
                var mlsD = new double[mlsSeq.Length];
                for (int i = 0; i < mlsD.Length; ++i)
                {
                    mlsD[i] = mlsSeq[i] * 2.0 - 1.0;
                }
                var ccc = CrossCorrelation.CalcCircularCrossCorrelation(mlsD, mlsD);
                for (int i = 0; i < ccc.Length; ++i)
                {
                    Console.Write("{0:g2} ", ccc[i]);
                }
                Console.WriteLine("");
            }

            var mlsMat = new MatrixGF2(P, P);

            {
                for (int y = 0; y < P; ++y)
                {
                    for (int x = 0; x < P; ++x)
                    {
                        mlsMat.Set(y, x, (0 != mlsSeq[(x + y) % P]) ? GF2.One : GF2.Zero);
                    }
                }
            }
            mlsMat.Print("MLS matrix");

            // σ: mlsMatの左上N*N要素
            var σ = mlsMat.Subset(0, 0, N, N);

            σ.Print("σ");

            var σInv = σ.Inverse();

            σInv.Print("σ^-1");

            // S: MLS行列の上N行。
            var S = mlsMat.Subset(0, 0, N, P);

            S.Print("S");

            // Sの転置S^T
            S.Transpose().Print("S^T");

            // L: Sの転置 x σInv
            var L = S.Transpose().Mul(σInv);

            L.Print("L");

            // L x S == MLS行列
            var LS = L.Mul(S);

            LS.Print("L x S");

            int diff = LS.CompareTo(mlsMat);

            System.Diagnostics.Debug.Assert(diff == 0);

            // 2進で0~P-1までの値が入っている行列
            var B  = new MatrixGF2(P + 1, N);
            var Bt = new MatrixGF2(N, P + 1);

            for (int r = 0; r < P + 1; ++r)
            {
                for (int c = 0; c < N; ++c)
                {
                    int v = r & (1 << (N - 1 - c));
                    var b = (v == 0) ? GF2.Zero : GF2.One;
                    B.Set(r, c, b);
                    Bt.Set(c, r, b);
                }
            }

            B.Print("B");
            Bt.Print("Bt");

            // アダマール行列H8
            var H8 = MatrixGF2.Mul(B, Bt);

            H8.Print("H8");

            var vTest = new double[P + 1];

            for (int i = 0; i < P + 1; ++i)
            {
                vTest[i] = i;
            }

            var r1 = H8.ToMatrix().Mul(vTest);

            Print(r1, "R1");

            var r2 = FastWalshHadamardTransform.Transform(vTest);

            Print(r2, "R2");

            // Ps: S行列の列の値を2進数として、順番入れ替え行列を作る
            var Ps        = new MatrixGF2(P + 1, P + 1);
            var PsReorder = new List <int>();

            PsReorder.Add(0);
            for (int c = 0; c < P; ++c)
            {
                int sum = 0;
                for (int r = 0; r < N; ++r)
                {
                    sum += (1 << (N - 1 - r)) * S.At(r, c).Val;
                }
                Console.WriteLine("Ps: c={0} sum={1}", c, sum);
                Ps.Set(sum, c + 1, GF2.One);
                PsReorder.Add(sum);
            }
            Ps.Print("Ps");

            {
                var testMat = new WWMatrix(P + 1, 1);
                for (int r = 0; r < P + 1; ++r)
                {
                    testMat.Set(r, 0, PsReorder[r]);
                }

                var PsTest = Ps.ToMatrix().Mul(testMat);
                PsTest.Print("Ps x n");
            }

            // Pl: L行列の列の値を2進数として、順番入れ替え行列を作る
            var Pl        = new MatrixGF2(P + 1, P + 1);
            var PlReorder = new List <int>();

            PlReorder.Add(0);
            for (int r = 0; r < P; ++r)
            {
                int sum = 0;
                for (int c = 0; c < N; ++c)
                {
                    sum += (1 << (N - 1 - c)) * L.At(r, c).Val;
                }
                Console.WriteLine("Pl: r={0} sum={1}", r, sum);
                Pl.Set(r + 1, sum, GF2.One);
                PlReorder.Add(sum);
            }
            Pl.Print("Pl");

            S.Print("S");
            var BtPs = Bt.Mul(Ps);

            BtPs.Print("BtPs");

            L.Print("L");
            var PlB = Pl.Mul(B);

            PlB.Print("PlB");

            {
                var test2Mat = new WWMatrix(P + 1, 1);
                for (int r = 0; r < P + 1; ++r)
                {
                    test2Mat.Set(r, 0, r);
                }

                var PlTest = Pl.ToMatrix().Mul(test2Mat);
                PlTest.Print("Pl x n");
            }

            mlsMat.Print("MLS mat");
            var Mhat = Pl.Mul(H8).Mul(Ps);

            Mhat.Print("Mhat");

            // MLS deconvolution
            var decon = Mhat.ToMatrix().Mul(from);

            Print(decon, "decon");

            // 同じ処理をWalsh-Hadamard変換を使って行う。
            var reorderedFrom = new double[P + 1];

            for (int i = 0; i < P + 1; ++i)
            {
                reorderedFrom[PsReorder[i]] = from[i];
            }

#if true
            var hR = FastWalshHadamardTransform.Transform(reorderedFrom);
#else
            var hR = H8.ToMatrix().Mul(reorderedFrom);
#endif

            var hTo = new double[P + 1];
            for (int i = 0; i < P + 1; ++i)
            {
                hTo[i] = hR[PlReorder[i]];
            }
            Print(hTo, "hTo");
        }
Пример #7
0
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Title = Title + (Environment.Is64BitProcess ? " (x64)" : " (x86)");

            multiTrackViewer1.ItemsSource = trackList;

            // INIT COMMAND BINDINGS
            CommandBinding playBinding = new CommandBinding(MediaCommands.Play);

            CommandBindings.Add(playBinding);
            playBinding.CanExecute += new CanExecuteRoutedEventHandler(playCommandBinding_CanExecute);
            playBinding.Executed   += new ExecutedRoutedEventHandler(playCommandBinding_Executed);

            CommandBinding pauseBinding = new CommandBinding(MediaCommands.Pause);

            CommandBindings.Add(pauseBinding);
            pauseBinding.CanExecute += new CanExecuteRoutedEventHandler(pauseCommandBinding_CanExecute);
            pauseBinding.Executed   += new ExecutedRoutedEventHandler(pauseCommandBinding_Executed);

            CommandBinding playToggleBinding = new CommandBinding(Commands.PlayToggle);

            CommandBindings.Add(playToggleBinding);
            playToggleBinding.Executed += new ExecutedRoutedEventHandler(playToggleBinding_Executed);


            //// INIT TRACKLIST STUFF
            //trackList.PropertyChanged += delegate(object sender2, PropertyChangedEventArgs e2) {
            //    if (e2.PropertyName == "TotalLength") {
            //        multiTrackViewer1.VirtualViewportMaxWidth = trackList.TotalLength.Ticks;
            //    }
            //};


            // INIT PLAYER
            player = new MultitrackPlayer(trackList);
            player.VolumeAnnounced += Player_VolumeAnnounced_VolumeMeter;

            player.CurrentTimeChanged += new EventHandler <ValueEventArgs <TimeSpan> >(
                delegate(object sender2, ValueEventArgs <TimeSpan> e2) {
                multiTrackViewer1.Dispatcher.BeginInvoke((Action) delegate {
                    multiTrackViewer1.VirtualCaretOffset = e2.Value.Ticks;
                    // autoscroll
                    if (multiTrackViewer1.VirtualViewportInterval.To <= multiTrackViewer1.VirtualCaretOffset)
                    {
                        multiTrackViewer1.VirtualViewportOffset = multiTrackViewer1.VirtualCaretOffset;
                    }
                });
            });

            player.PlaybackStateChanged += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                multiTrackViewer1.Dispatcher.BeginInvoke((Action) delegate {
                    // CommandManager must be called on the GUI-thread, else it won't do anything
                    CommandManager.InvalidateRequerySuggested();
                });
            });

            volumeSlider.ValueChanged += new RoutedPropertyChangedEventHandler <double>(
                delegate(object sender2, RoutedPropertyChangedEventArgs <double> e2) {
                player.Volume = (float)e2.NewValue;
            });


            // INIT PROGRESSBAR
            progressBar1.IsEnabled = false;
            ProgressMonitor.GlobalInstance.ProcessingStarted += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.IsEnabled    = true;
                    progressBar1Label.Text    = ProgressMonitor.GlobalInstance.StatusMessage;
                    win7TaskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
                    win7TaskBar.ProgressValue = 0;
                });
            });

            ProgressMonitor.GlobalInstance.ProcessingProgressChanged += new EventHandler <ValueEventArgs <float> >(
                delegate(object sender2, ValueEventArgs <float> e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.Value        = e2.Value;
                    win7TaskBar.ProgressValue = e2.Value / 100;
                    progressBar1Label.Text    = ProgressMonitor.GlobalInstance.StatusMessage;
                });
            });

            ProgressMonitor.GlobalInstance.ProcessingFinished += new EventHandler(
                delegate(object sender2, EventArgs e2) {
                progressBar1.Dispatcher.BeginInvoke((Action) delegate {
                    progressBar1.Value        = 0;
                    progressBar1.IsEnabled    = false;
                    progressBar1Label.Text    = "";
                    win7TaskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
                });
            });


            // INIT RANDOM STUFF
            multiTrackViewer1.KeyUp += new KeyEventHandler(delegate(object sender2, KeyEventArgs e2) {
                if (e2.Key == Key.Delete)
                {
                    // create temporary list to avoid concurrent modification exception
                    var selectedAudioTracks = new List <AudioTrack>(multiTrackViewer1.SelectedItems.Cast <AudioTrack>());

                    // delete tracks
                    foreach (AudioTrack audioTrack in selectedAudioTracks)
                    {
                        if (audioTrack != null)
                        {
                            // 1. delete all related matches
                            List <Match> deleteList = new List <Match>();
                            // 1a find all related matches
                            foreach (Match m in multiTrackViewer1.Matches)
                            {
                                if (m.Track1 == audioTrack || m.Track2 == audioTrack)
                                {
                                    deleteList.Add(m);
                                }
                            }
                            // 1b delete
                            foreach (Match m in deleteList)
                            {
                                multiTrackViewer1.Matches.Remove(m);
                            }
                            // 2. delete track
                            trackList.Remove(audioTrack);
                        }
                    }
                    e2.Handled = true;
                }
            });


            // INIT FFT
            int    fftSize     = 1024;
            double correlation = 0;

            fftAnalyzer         = new FFTAnalyzer(fftSize);
            fftAnalyzerConsumer = 2;
            correlationConsumer = 1;
            WindowFunction fftWindow = WindowUtil.GetFunction(WindowType.BlackmanHarris, fftSize);

            fftAnalyzer.WindowFunction  = fftWindow;
            fftAnalyzer.WindowAnalyzed += FftAnalyzer_WindowAnalyzed_FrequencyGraph;
            fftAnalyzer.WindowAnalyzed += FftAnalyzer_WindowAnalyzed_Spectrogram;
            player.SamplesMonitored    += new EventHandler <StreamDataMonitorEventArgs>(delegate(object sender2, StreamDataMonitorEventArgs e2) {
                if (fftAnalyzerConsumer > 0 || correlationConsumer > 0)
                {
                    float[][] uninterleaved = AudioUtil.Uninterleave(e2.Properties, e2.Buffer, e2.Offset, e2.Length, true);
                    if (fftAnalyzerConsumer > 0)
                    {
                        fftAnalyzer.PutSamples(uninterleaved[0]); // put the summed up mono samples into the analyzer
                    }
                    if (correlationConsumer > 0)
                    {
                        correlation = CrossCorrelation.Correlate(uninterleaved[1], uninterleaved[2]);
                        Dispatcher.BeginInvoke((Action) delegate {
                            correlationMeter.Value = correlation;
                        });
                    }
                }
            });
            spectrogram.SpectrogramSize = fftSize / 2;
        }
        } //Analysis()

        public static Tuple <BaseSonogram, double[, ], double[], List <AcousticEvent> > DetectHarmonics(
            AudioRecording recording,
            double intensityThreshold,
            int minHz,
            int minFormantgap,
            int maxFormantgap,
            double minDuration,
            int windowSize,
            double windowOverlap,
            TimeSpan segmentStartOffset)
        {
            //i: MAKE SONOGRAM
            int    numberOfBins    = 32;
            double binWidth        = recording.SampleRate / (double)windowSize;
            int    sr              = recording.SampleRate;
            double frameDuration   = windowSize / (double)sr;             // Duration of full frame or window in seconds
            double frameOffset     = frameDuration * (1 - windowOverlap); //seconds between starts of consecutive frames
            double framesPerSecond = 1 / frameOffset;

            //double framesPerSecond = sr / (double)windowSize;
            //int frameOffset = (int)(windowSize * (1 - overlap));
            //int frameCount = (length - windowSize + frameOffset) / frameOffset;

            double epsilon  = Math.Pow(0.5, recording.BitsPerSample - 1);
            var    results2 = DSP_Frames.ExtractEnvelopeAndAmplSpectrogram(
                recording.WavReader.Samples,
                sr,
                epsilon,
                windowSize,
                windowOverlap);

            double[] avAbsolute = results2.Average; //average absolute value over the minute recording

            //double[] envelope = results2.Item2;
            double[,]
            matrix = results2
                     .AmplitudeSpectrogram; //amplitude spectrogram. Note that column zero is the DC or average energy value and can be ignored.
            double windowPower = results2.WindowPower;

            //window    sr          frameDuration   frames/sec  hz/bin  64frameDuration hz/64bins       hz/128bins
            // 1024     22050       46.4ms          21.5        21.5    2944ms          1376hz          2752hz
            // 1024     17640       58.0ms          17.2        17.2    3715ms          1100hz          2200hz
            // 2048     17640       116.1ms          8.6         8.6    7430ms           551hz          1100hz

            //the Xcorrelation-FFT technique requires number of bins to scan to be power of 2.
            //assuming sr=17640 and window=1024, then  64 bins span 1100 Hz above the min Hz level. i.e. 500 to 1600
            //assuming sr=17640 and window=1024, then 128 bins span 2200 Hz above the min Hz level. i.e. 500 to 2700
            int minBin = (int)Math.Round(minHz / binWidth);
            int maxHz  = (int)Math.Round(minHz + (numberOfBins * binWidth));

            int rowCount = matrix.GetLength(0);
            int colCount = matrix.GetLength(1);
            int maxbin   = minBin + numberOfBins;

            double[,] subMatrix = MatrixTools.Submatrix(matrix, 0, minBin + 1, rowCount - 1, maxbin);

            //ii: DETECT HARMONICS
            int zeroBinCount = 5; //to remove low freq content which dominates the spectrum
            var results      = CrossCorrelation.DetectBarsInTheRowsOfaMatrix(subMatrix, intensityThreshold, zeroBinCount);

            double[] intensity   = results.Item1; //an array of periodicity scores
            double[] periodicity = results.Item2;

            //transfer periodicity info to a hits matrix.
            //intensity = DataTools.filterMovingAverage(intensity, 3);
            double[] scoreArray = new double[intensity.Length];
            var      hits       = new double[rowCount, colCount];

            for (int r = 0; r < rowCount; r++)
            {
                double relativePeriod = periodicity[r] / numberOfBins / 2;
                if (intensity[r] > intensityThreshold)
                {
                    for (int c = minBin; c < maxbin; c++)
                    {
                        hits[r, c] = relativePeriod;
                    }
                }

                double herzPeriod = periodicity[r] * binWidth;
                if (herzPeriod > minFormantgap && herzPeriod < maxFormantgap)
                {
                    scoreArray[r] = 2 * intensity[r] * intensity[r]; //enhance high score wrt low score.
                }
            }

            scoreArray = DataTools.filterMovingAverage(scoreArray, 11);

            //iii: CONVERT TO ACOUSTIC EVENTS
            double maxDuration = 100000.0; //abitrary long number - do not want to restrict duration of machine noise
            List <AcousticEvent> predictedEvents = AcousticEvent.ConvertScoreArray2Events(
                scoreArray,
                minHz,
                maxHz,
                framesPerSecond,
                binWidth,
                intensityThreshold,
                minDuration,
                maxDuration,
                segmentStartOffset);

            hits = null;

            //set up the songogram to return. Use the existing amplitude sonogram
            int                bitsPerSample = recording.WavReader.BitsPerSample;
            TimeSpan           duration      = recording.Duration;
            NoiseReductionType nrt           = SNR.KeyToNoiseReductionType("STANDARD");

            var sonogram = (BaseSonogram)SpectrogramStandard.GetSpectralSonogram(
                recording.BaseName,
                windowSize,
                windowOverlap,
                bitsPerSample,
                windowPower,
                sr,
                duration,
                nrt,
                matrix);

            sonogram.DecibelsNormalised = new double[rowCount];

            //foreach frame or time step
            for (int i = 0; i < rowCount; i++)
            {
                sonogram.DecibelsNormalised[i] = 2 * Math.Log10(avAbsolute[i]);
            }

            sonogram.DecibelsNormalised = DataTools.normalise(sonogram.DecibelsNormalised);
            return(Tuple.Create(sonogram, hits, scoreArray, predictedEvents));
        } //end Execute_HDDetect
Пример #9
0
        } //Analysis()

        public static System.Tuple <List <double[]>, double[, ], List <AcousticEvent> > DetectKiwi(BaseSonogram sonogram, int minHz, int maxHz,
                                                                                                   /* double dctDuration, double dctThreshold, */ double minPeriod, double maxPeriod, double eventThreshold, double minDuration, double maxDuration)
        {
            int step         = (int)Math.Round(sonogram.FramesPerSecond); //take one second steps
            int sampleLength = 32;                                        //32 frames = 1.85 seconds.   64 frames (i.e. 3.7 seconds) is to long a sample - require stationarity.

            int    rowCount       = sonogram.Data.GetLength(0);
            int    colCount       = sonogram.Data.GetLength(1);
            double minFramePeriod = minPeriod * sonogram.FramesPerSecond;
            double maxFramePeriod = maxPeriod * sonogram.FramesPerSecond;

            int minBin = (int)(minHz / sonogram.FBinWidth);
            int maxBin = (int)(maxHz / sonogram.FBinWidth);


            //#############################################################################################################################################
            //window    sr          frameDuration   frames/sec  hz/bin  64frameDuration hz/64bins       hz/128bins
            // 1024     22050       46.4ms          21.5        21.5    2944ms          1376hz          2752hz
            // 1024     17640       58.0ms          17.2        17.2    3715ms          1100hz          2200hz
            // 2048     17640       116.1ms          8.6         8.6    7430ms           551hz          1100hz
            double[] fullArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, minBin, (rowCount - 1), minBin + 130);
            var      result1   = CrossCorrelation.DetectXcorrelationInTwoArrays(fullArray, fullArray, step, sampleLength, minFramePeriod, maxFramePeriod);

            double[] intensity1   = result1.Item1;
            double[] periodicity1 = result1.Item2;
            intensity1 = DataTools.filterMovingAverage(intensity1, 11);

            //#############################################################################################################################################
            //double[] lowerArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, minBin, (rowCount - 1), minBin + 65);
            //double[] upperArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, minBin+66, (rowCount - 1), minBin+130);
            //int actualMaxHz     = (int)Math.Round((minBin+130) * sonogram.FBinWidth);
            //var result2 = CrossCorrelation.DetectXcorrelationInTwoArrays(lowerArray, upperArray, step, sampleLength, minFramePeriod, maxFramePeriod);
            //double[] intensity2   = result2.Item1;
            //double[] periodicity2 = result2.Item2;
            //intensity2 = DataTools.filterMovingAverage(intensity2, 5);

            //#############################################################################################################################################
            //minFramePeriod = 4;
            //maxFramePeriod = 14;
            //var return3 = Gratings.ScanArrayForGratingPattern(fullArray, (int)minFramePeriod, (int)maxFramePeriod, 4, step);
            //var return3 = Gratings.ScanArrayForGratingPattern(fullArray, step, 4, 4);
            //var return4 = Gratings.ScanArrayForGratingPattern(fullArray, step, 4, 5);
            //var return5 = Gratings.ScanArrayForGratingPattern(fullArray, step, 4, 8);
            //var return6 = Gratings.ScanArrayForGratingPattern(fullArray, step, 4, 10);
            //var return7 = Gratings.ScanArrayForGratingPattern(fullArray, step, 4, 12);

            //#############################################################################################################################################
            //bool normaliseDCT = true;
            //Double[,] maleHits;                       //predefinition of hits matrix - to superimpose on sonogram image
            //double[] maleScores;                      //predefinition of score array
            //double[] maleOscRate;
            //List<AcousticEvent> predictedMaleEvents;
            //double minOscilFreq = 1 / maxPeriod;  //convert max period (seconds) to oscilation rate (Herz).
            //double maxOscilFreq = 1 / minPeriod;  //convert min period (seconds) to oscilation rate (Herz).
            //OscillationAnalysis.Execute((SpectralSonogram)sonogram, minHz, maxHz, dctDuration, dctThreshold, normaliseDCT,
            //                             minOscilFreq, maxOscilFreq, eventThreshold, minDuration, maxDuration,
            //                             out maleScores, out predictedMaleEvents, out maleHits, out maleOscRate);

            //iii: CONVERT SCORES TO ACOUSTIC EVENTS
            List <AcousticEvent> events = AcousticEvent.ConvertScoreArray2Events(intensity1, minHz, maxHz, sonogram.FramesPerSecond, sonogram.FBinWidth,
                                                                                 eventThreshold, minDuration, maxDuration);

            CropEvents(events, fullArray, minDuration);
            CalculateAvIntensityScore(events, intensity1);
            CalculateDeltaPeriodScore(events, periodicity1, minFramePeriod, maxFramePeriod);
            CalculateBandWidthScore(events, sonogram.Data);
            CalculatePeaksScore(events, fullArray);
            //FilterEvents(events);
            CalculateWeightedEventScore(events);

            // PREPARE HITS MATRIX
            var    hits  = new double[rowCount, colCount];
            double range = maxFramePeriod - minFramePeriod;

            for (int r = 0; r < rowCount; r++)
            {
                if (intensity1[r] > eventThreshold)
                {
                    for (int c = minBin; c < maxBin; c++)
                    {
                        hits[r, c] = (periodicity1[r] - minFramePeriod) / range; //normalisation
                    }
                }
            }

            periodicity1 = CropArrayToEvents(events, periodicity1); //for display only

            var scores = new List <double[]>();

            scores.Add(DataTools.normalise(fullArray));
            //scores.Add(DataTools.normalise(upperArray));
            //scores.Add(DataTools.normalise(lowerArray));
            scores.Add(DataTools.normalise(intensity1));
            scores.Add(DataTools.normalise(periodicity1));
            //scores.Add(DataTools.normalise(intensity2));
            //scores.Add(DataTools.normalise(return3));
            //scores.Add(DataTools.normalise(return4));
            //scores.Add(DataTools.normalise(return5));
            //scores.Add(DataTools.normalise(return6));
            //scores.Add(DataTools.normalise(return7));
            //scores.Add(DataTools.normalise(maleScores));
            //scores.Add(DataTools.normalise(maleOscRate));
            return(System.Tuple.Create(scores, hits, events));
        }
Пример #10
0
        //#IntensityThreshold: 0.15
        //# Event threshold - Determines FP / FN trade-off for events.
        //EventThreshold: 0.2

        public static (List <AcousticEvent>, double[]) GetComponentsWithHarmonics(
            SpectrogramStandard sonogram,
            int minHz,
            int maxHz,
            int nyquist,
            double decibelThreshold,
            double dctThreshold,
            double minDuration,
            double maxDuration,
            int minFormantGap,
            int maxFormantGap,
            TimeSpan segmentStartOffset)
        {
            // Event threshold - Determines FP / FN trade-off for events.
            //double eventThreshold = 0.2;

            var sonogramData = sonogram.Data;
            int frameCount   = sonogramData.GetLength(0);
            int binCount     = sonogramData.GetLength(1);

            double freqBinWidth  = nyquist / (double)binCount;
            int    minBin        = (int)Math.Round(minHz / freqBinWidth);
            int    maxBin        = (int)Math.Round(maxHz / freqBinWidth);
            int    bandWidthBins = maxBin - minBin + 1;

            // extract the sub-band
            double[,] subMatrix = MatrixTools.Submatrix(sonogram.Data, 0, minBin, frameCount - 1, maxBin);

            //ii: DETECT HARMONICS
            // now look for harmonics in search band using the Xcorrelation-DCT method.
            var results = CrossCorrelation.DetectHarmonicsInSonogramMatrix(subMatrix, decibelThreshold);

            // set up score arrays
            double[] dBArray = results.Item1;
            double[] harmonicIntensityScores = results.Item2; //an array of formant intesnity
            int[]    maxIndexArray           = results.Item3;

            for (int r = 0; r < frameCount; r++)
            {
                if (harmonicIntensityScores[r] < dctThreshold)
                {
                    continue;
                }

                //ignore locations with incorrect formant gap
                int    maxId      = maxIndexArray[r];
                double freqBinGap = 2 * bandWidthBins / (double)maxId;
                double formantGap = freqBinGap * freqBinWidth;
                if (formantGap < minFormantGap || formantGap > maxFormantGap)
                {
                    harmonicIntensityScores[r] = 0.0;
                }
            }

            // smooth the harmonicIntensityScores array to allow for brief gaps.
            harmonicIntensityScores = DataTools.filterMovingAverageOdd(harmonicIntensityScores, 5);

            //extract the events based on length and threshhold.
            // Note: This method does NOT do prior smoothing of the score array.
            var acousticEvents = AcousticEvent.ConvertScoreArray2Events(
                harmonicIntensityScores,
                minHz,
                maxHz,
                sonogram.FramesPerSecond,
                sonogram.FBinWidth,
                decibelThreshold,
                minDuration,
                maxDuration,
                segmentStartOffset);

            return(acousticEvents, harmonicIntensityScores);
        }
Пример #11
0
        private void correlationButton_Click(object sender, RoutedEventArgs e)
        {
            List <MatchGroup> trackGroups = DetermineMatchGroups();

            foreach (MatchGroup trackGroup in trackGroups)
            {
                foreach (MatchPair trackPair in trackGroup.MatchPairs)
                {
                    MatchPair localMP = trackPair;
                    Task.Factory.StartNew(() => {
                        TimeSpan t1Offset;
                        TimeSpan t2Offset;
                        if (localMP.Track1.Offset < localMP.Track2.Offset)
                        {
                            t1Offset = localMP.Track2.Offset - localMP.Track1.Offset;
                            t2Offset = TimeSpan.Zero;
                        }
                        else
                        {
                            t1Offset = TimeSpan.Zero;
                            t2Offset = localMP.Track1.Offset - localMP.Track2.Offset;
                        }
                        TimeSpan length;
                        if (localMP.Track1.Length > localMP.Track2.Length)
                        {
                            length = localMP.Track2.Length;
                        }
                        else
                        {
                            length = localMP.Track1.Length;
                        }
                        TimeSpan interval = CorrelationIntervalSize;
                        TimeSpan window   = CorrelationWindowSize;

                        List <Match> computedMatches = new List <Match>();
                        for (TimeSpan position = TimeSpan.Zero; position < length; position += interval)
                        {
                            Interval t1Interval = new Interval((t1Offset + position).Ticks, (t1Offset + position + window).Ticks);
                            Interval t2Interval = new Interval((t2Offset + position).Ticks, (t2Offset + position + window).Ticks);

                            if (t1Interval.TimeTo >= localMP.Track1.Length || t2Interval.TimeTo >= localMP.Track2.Length)
                            {
                                // not enough samples remaining to compute the correlation (end of track reached)
                                break;
                            }

                            CrossCorrelation.Result ccr;
                            IAudioStream s1 = localMP.Track1.CreateAudioStream();
                            IAudioStream s2 = localMP.Track2.CreateAudioStream();
                            TimeSpan offset = CrossCorrelation.Calculate(s1, t1Interval, s2, t2Interval, progressMonitor, out ccr);
                            s1.Close();
                            s2.Close();
                            // always apply a positive offset that moves the match position inside the corelation interval,
                            // else it can happen that a negative offset is applied to a match at the beginning of the stream
                            // which means that the matching point would be at a negative position in the audio stream
                            computedMatches.Add(new Match {
                                Track1     = localMP.Track1, Track1Time = t1Offset + position + (offset < TimeSpan.Zero ? -offset : TimeSpan.Zero),
                                Track2     = localMP.Track2, Track2Time = t2Offset + position + (offset >= TimeSpan.Zero ? offset : TimeSpan.Zero),
                                Similarity = ccr.AbsoluteMaxValue,
                                Source     = "CC"
                            });
                        }

                        Dispatcher.BeginInvoke((Action) delegate {
                            foreach (Match match in computedMatches)
                            {
                                multiTrackViewer.Matches.Add(match);
                            }
                        });
                    });
                }
            }
        }
Пример #12
0
        private void TimeWarp(TimeWarpType type, AudioTrack t1, TimeSpan t1From, TimeSpan t1To, AudioTrack t2, TimeSpan t2From, TimeSpan t2To, bool calculateSimilarity, bool normalizeSimilarity, bool cueIn, bool cueOut)
        {
            IAudioStream s1 = t1.CreateAudioStream();
            IAudioStream s2 = t2.CreateAudioStream();

            s1 = new CropStream(s1, TimeUtil.TimeSpanToBytes(t1From, s1.Properties), TimeUtil.TimeSpanToBytes(t1To, s1.Properties));
            s2 = new CropStream(s2, TimeUtil.TimeSpanToBytes(t2From, s2.Properties), TimeUtil.TimeSpanToBytes(t2To, s2.Properties));

            List <Tuple <TimeSpan, TimeSpan> > path = null;
            DTW dtw = null;

            // execute time warping
            if (type == TimeWarpType.DTW)
            {
                dtw = new DTW(TimeWarpSearchWidth, progressMonitor);
            }
            else if (type == TimeWarpType.OLTW)
            {
                dtw = new OLTW2(TimeWarpSearchWidth, progressMonitor);
            }

            if (TimeWarpDisplay)
            {
                this.Dispatcher.BeginInvoke((Action) delegate {
                    dtwPathViewer = new DtwPathViewer();
                    dtwPathViewer.Show();
                });

                dtw.OltwInit += new DTW.OltwInitDelegate(delegate(int windowSize, IMatrix <double> cellCostMatrix, IMatrix <double> totalCostMatrix) {
                    dtwPathViewer.Dispatcher.BeginInvoke((Action) delegate {
                        dtwPathViewer.DtwPath.Init(windowSize, cellCostMatrix, totalCostMatrix);
                    });
                });
                bool drawing = false;
                dtw.OltwProgress += new DTW.OltwProgressDelegate(delegate(int i, int j, int minI, int minJ, bool force) {
                    if (!drawing || force)
                    {
                        dtwPathViewer.Dispatcher.BeginInvoke((Action) delegate {
                            drawing = true;
                            dtwPathViewer.DtwPath.Refresh(i, j, minI, minJ);
                            drawing = false;
                        });
                    }
                });
            }

            path = dtw.Execute(s1, s2);

            if (path == null)
            {
                return;
            }

            // convert resulting path to matches and filter them
            int               filterSize       = TimeWarpFilterSize; // take every n-th match and drop the rest
            bool              smoothing        = TimeWarpSmoothing;
            int               smoothingWidth   = Math.Max(1, Math.Min(filterSize / 10, filterSize));
            bool              inOutCue         = TimeWarpInOutCue;
            TimeSpan          inOutCueSpan     = TimeWarpSearchWidth;
            List <Match>      matches          = new List <Match>();
            float             maxSimilarity    = 0; // needed for normalization
            IProgressReporter progressReporter = progressMonitor.BeginTask("post-process resulting path...", true);
            double            totalProgress    = path.Count;
            double            progress         = 0;

            /* Leave out matches in the in/out cue areas...
             * The matches in the interval at the beginning and end of the calculated time warping path with a width
             * equal to the search width should be left out because they might not be correct - since the time warp
             * path needs to start at (0,0) in the matrix and end at (m,n), they would only be correct if the path gets
             * calculated between two synchronization points. Paths calculated from the start of a track to the first
             * sync point, or from the last sync point to end of the track are probably wrong in this interval since
             * the start and end points don't match if there is time drift so it is better to leave them out in those
             * areas... in those short a few second long intervals the drict actually will never be that extreme that
             * someone would notice it anyway. */
            if (inOutCue)
            {
                int startIndex = 0;
                int endIndex   = path.Count;

                // this needs a temporally ordered mapping path (no matter if ascending or descending)
                foreach (Tuple <TimeSpan, TimeSpan> mapping in path)
                {
                    if (cueIn && (mapping.Item1 < inOutCueSpan || mapping.Item2 < inOutCueSpan))
                    {
                        startIndex++;
                    }
                    if (cueOut && (mapping.Item1 > (t1To - t1From - inOutCueSpan) || mapping.Item2 > (t2To - t2From - inOutCueSpan)))
                    {
                        endIndex--;
                    }
                }
                path = path.GetRange(startIndex, endIndex - startIndex);
            }

            for (int i = 0; i < path.Count; i += filterSize)
            {
                //List<Tuple<TimeSpan, TimeSpan>> section = path.GetRange(i, Math.Min(path.Count - i, filterSize));
                List <Tuple <TimeSpan, TimeSpan> > smoothingSection = path.GetRange(
                    Math.Max(0, i - smoothingWidth / 2), Math.Min(path.Count - i, smoothingWidth));
                Tuple <TimeSpan, TimeSpan> match = path[i];

                if (smoothingSection.Count == 0)
                {
                    throw new InvalidOperationException("must not happen");
                }
                else if (smoothingSection.Count == 1 || !smoothing || i == 0)
                {
                    // do nothing, match doesn't need any processing
                    // the first and last match must not be smoothed since they must sit at the bounds
                }
                else
                {
                    List <TimeSpan> offsets = new List <TimeSpan>(smoothingSection.Select(t => t.Item2 - t.Item1).OrderBy(t => t));
                    int             middle  = offsets.Count / 2;

                    // calculate median
                    // http://en.wikiversity.org/wiki/Primary_mathematics/Average,_median,_and_mode#Median
                    TimeSpan smoothedDriftTime = new TimeSpan((offsets[middle - 1] + offsets[middle]).Ticks / 2);
                    match = new Tuple <TimeSpan, TimeSpan>(match.Item1, match.Item1 + smoothedDriftTime);
                }

                float similarity = calculateSimilarity ? (float)Math.Abs(CrossCorrelation.Correlate(
                                                                             s1, new Interval(match.Item1.Ticks, match.Item1.Ticks + TimeUtil.SECS_TO_TICKS),
                                                                             s2, new Interval(match.Item2.Ticks, match.Item2.Ticks + TimeUtil.SECS_TO_TICKS))) : 1;

                if (similarity > maxSimilarity)
                {
                    maxSimilarity = similarity;
                }

                matches.Add(new Match()
                {
                    Track1     = t1,
                    Track1Time = match.Item1 + t1From,
                    Track2     = t2,
                    Track2Time = match.Item2 + t2From,
                    Similarity = similarity,
                    Source     = type.ToString()
                });

                progressReporter.ReportProgress(progress / totalProgress * 100);
                progress += filterSize;
            }

            // add last match if it hasn't been added
            if (path.Count > 0 && path.Count % filterSize != 1)
            {
                Tuple <TimeSpan, TimeSpan> lastMatch = path[path.Count - 1];
                matches.Add(new Match()
                {
                    Track1     = t1,
                    Track1Time = lastMatch.Item1 + t1From,
                    Track2     = t2,
                    Track2Time = lastMatch.Item2 + t2From,
                    Similarity = 1,
                    Source     = type.ToString()
                });
            }
            progressReporter.Finish();

            multiTrackViewer.Dispatcher.BeginInvoke((Action) delegate {
                foreach (Match match in matches)
                {
                    if (normalizeSimilarity)
                    {
                        match.Similarity /= maxSimilarity; // normalize to 1
                    }
                    multiTrackViewer.Matches.Add(match);
                }
            });

            s1.Close();
            s2.Close();
        }
Пример #13
0
        private void alignTracksButton_Click(object sender, RoutedEventArgs e)
        {
            bool postProcessMatchingPoints  = (bool)postProcessMatchingPointsCheckBox.IsChecked;
            bool removeUnusedMatchingPoints = (bool)removeUnusedMatchingPointsCheckBox.IsChecked;

            List <Match>      matches     = new List <Match>(multiTrackViewer.Matches);
            List <Match>      newMatches  = new List <Match>();
            List <MatchGroup> trackGroups = DetermineMatchGroups();

            try {
                MatchProcessor.ValidateMatches(trackGroups);
            } catch (Exception ex) {
                var message = "Invalid sequence of matches, cannot warp. " +
                              "Please clean up the matches first (e.g. by filtering) to get rid of invalid mappings, e.g. overlapping/crossing matches.";
                MessageBox.Show(this, message, ex.Message, MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            Task.Factory.StartNew(() => {
                Parallel.ForEach(trackGroups, trackGroup => {
                    if (postProcessMatchingPoints)
                    {
                        Parallel.ForEach(trackGroup.MatchPairs, trackPair => {
                            MatchProcessor.ValidatePairOrder(trackPair.Matches);
                            foreach (Match match in trackPair.Matches)
                            {
                                newMatches.Add(CrossCorrelation.Adjust(match, progressMonitor));
                            }
                        });
                    }
                });

                Dispatcher.BeginInvoke((Action) delegate {
                    newMatches.ForEach((m) => multiTrackViewer.Matches.Add(m));

                    if (removeUnusedMatchingPoints)
                    {
                        multiTrackViewer.Matches.Clear();
                    }

                    TrackList <AudioTrack> alignedTracks = new TrackList <AudioTrack>();
                    TimeSpan componentStartTime          = TimeSpan.Zero;

                    string[] colors = { "#00aeef", "#00a651", "#8A2BE2", "#5F9EA0", "#D2691E", "#B8860B", "#483D8B", "#FF69B4", "#B0C4DE", "#6B8E23", "#F4A460" };
                    int colorIndex  = 0;

                    foreach (MatchGroup trackGroup in trackGroups)
                    {
                        if (removeUnusedMatchingPoints)
                        {
                            foreach (MatchPair trackPair in trackGroup.MatchPairs)
                            {
                                foreach (Match match in trackPair.Matches)
                                {
                                    multiTrackViewer.Matches.Add(match);
                                }
                            }
                        }

                        MatchProcessor.FilterCoincidentMatches(trackGroup.MatchPairs);
                        MatchProcessor.AlignTracks(trackGroup.MatchPairs);
                        //MatchProcessor.MoveToStartTime(trackGroup.TrackList, componentStartTime);
                        alignedTracks.Add(trackGroup.TrackList);
                        componentStartTime = trackGroup.TrackList.End;

                        foreach (AudioTrack t in trackGroup.TrackList)
                        {
                            t.Color = colors[colorIndex % colors.Length];
                        }
                        colorIndex++;
                    }

                    // process unaligned tracks (= tracks without matching points)
                    foreach (AudioTrack track in trackList.Except(alignedTracks))
                    {
                        track.Volume = 0;
                    }
                });
            });
        }
Пример #14
0
        /// <summary>
        /// THIS IS THE CORE DETECTION METHOD
        /// Detects the human voice
        /// </summary>
        public static Tuple <BaseSonogram, double[, ], Plot, List <AcousticEvent>, TimeSpan> Analysis(FileInfo fiSegmentOfSourceFile, Dictionary <string, string> configDict, TimeSpan segmentStartOffset)
        {
            //set default values
            int frameLength = 1024;

            if (configDict.ContainsKey(AnalysisKeys.FrameLength))
            {
                frameLength = int.Parse(configDict[AnalysisKeys.FrameLength]);
            }

            double windowOverlap = 0.0;

            int    minHz              = int.Parse(configDict["MIN_HZ"]);
            int    minFormantgap      = int.Parse(configDict["MIN_FORMANT_GAP"]);
            int    maxFormantgap      = int.Parse(configDict["MAX_FORMANT_GAP"]);
            double intensityThreshold = double.Parse(configDict["INTENSITY_THRESHOLD"]); //in 0-1
            double minDuration        = double.Parse(configDict["MIN_DURATION"]);        // seconds
            double maxDuration        = double.Parse(configDict["MAX_DURATION"]);        // seconds

            AudioRecording recording = new AudioRecording(fiSegmentOfSourceFile.FullName);

            //i: MAKE SONOGRAM
            SonogramConfig sonoConfig = new SonogramConfig
            {
                //default values config
                SourceFName        = recording.BaseName,
                WindowSize         = frameLength,
                WindowOverlap      = windowOverlap,
                NoiseReductionType = SNR.KeyToNoiseReductionType("STANDARD"),
            };
            var    tsRecordingtDuration = recording.Duration;
            int    sr           = recording.SampleRate;
            double freqBinWidth = sr / (double)sonoConfig.WindowSize;

            //#############################################################################################################################################
            //window    sr          frameDuration   frames/sec  hz/bin  64frameDuration hz/64bins       hz/128bins
            // 1024     22050       46.4ms          21.5        21.5    2944ms          1376hz          2752hz
            // 1024     17640       58.0ms          17.2        17.2    3715ms          1100hz          2200hz
            // 2048     17640       116.1ms          8.6         8.6    7430ms           551hz          1100hz

            //the Xcorrelation-FFT technique requires number of bins to scan to be power of 2.
            //assuming sr=17640 and window=1024, then  64 bins span 1100 Hz above the min Hz level. i.e. 500 to 1600
            //assuming sr=17640 and window=1024, then 128 bins span 2200 Hz above the min Hz level. i.e. 500 to 2700
            int numberOfBins = 64;
            int minBin       = (int)Math.Round(minHz / freqBinWidth) + 1;
            int maxbin       = minBin + numberOfBins - 1;
            int maxHz        = (int)Math.Round(minHz + (numberOfBins * freqBinWidth));

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);
            int          rowCount = sonogram.Data.GetLength(0);
            int          colCount = sonogram.Data.GetLength(1);

            double[,] subMatrix = MatrixTools.Submatrix(sonogram.Data, 0, minBin, rowCount - 1, maxbin);

            //ii: DETECT HARMONICS
            int zeroBinCount = 4; //to remove low freq content which dominates the spectrum
            var results      = CrossCorrelation.DetectBarsInTheRowsOfaMatrix(subMatrix, intensityThreshold, zeroBinCount);

            double[] intensity   = results.Item1;
            double[] periodicity = results.Item2; //an array of periodicity scores

            //intensity = DataTools.filterMovingAverage(intensity, 3);
            //expect humans to have max power >100 and < 1000 Hz. Set these bounds
            int lowerHumanMaxBound = (int)(100 / freqBinWidth);  //ignore 0-100 hz - too much noise
            int upperHumanMaxBound = (int)(3000 / freqBinWidth); //ignore above 2500 hz

            double[] scoreArray = new double[intensity.Length];
            for (int r = 0; r < rowCount; r++)
            {
                if (intensity[r] < intensityThreshold)
                {
                    continue;
                }

                //ignore locations with incorrect formant gap
                double herzPeriod = periodicity[r] * freqBinWidth;
                if (herzPeriod < minFormantgap || herzPeriod > maxFormantgap)
                {
                    continue;
                }

                //find freq having max power and use info to adjust score.
                double[] spectrum = MatrixTools.GetRow(sonogram.Data, r);
                for (int j = 0; j < lowerHumanMaxBound; j++)
                {
                    spectrum[j] = 0.0;
                }

                for (int j = upperHumanMaxBound; j < spectrum.Length; j++)
                {
                    spectrum[j] = 0.0;
                }

                double[] peakvalues = DataTools.GetPeakValues(spectrum);
                int      maxIndex1  = DataTools.GetMaxIndex(peakvalues);
                peakvalues[maxIndex1] = 0.0;
                int maxIndex2 = DataTools.GetMaxIndex(peakvalues);
                int avMaxBin  = (maxIndex1 + maxIndex2) / 2;

                //int freqWithMaxPower = (int)Math.Round(maxIndex * freqBinWidth);
                int    freqWithMaxPower = (int)Math.Round(avMaxBin * freqBinWidth);
                double discount         = 1.0;
                if (freqWithMaxPower > 1000)
                {
                    discount = 0.0;
                }
                else
                if (freqWithMaxPower < 500)
                {
                    discount = 0.0;
                }

                //set scoreArray[r]  - ignore locations with low intensity
                if (intensity[r] > intensityThreshold)
                {
                    scoreArray[r] = intensity[r] * discount;
                }
            }

            //transfer info to a hits matrix.
            var    hits      = new double[rowCount, colCount];
            double threshold = intensityThreshold * 0.75; //reduced threshold for display of hits

            for (int r = 0; r < rowCount; r++)
            {
                if (scoreArray[r] < threshold)
                {
                    continue;
                }

                double herzPeriod = periodicity[r] * freqBinWidth;
                for (int c = minBin; c < maxbin; c++)
                {
                    //hits[r, c] = herzPeriod / (double)380;  //divide by 380 to get a relativePeriod;
                    hits[r, c] = (herzPeriod - minFormantgap) / maxFormantgap;  //to get a relativePeriod;
                }
            }

            //iii: CONVERT TO ACOUSTIC EVENTS
            List <AcousticEvent> predictedEvents = AcousticEvent.ConvertScoreArray2Events(
                scoreArray,
                minHz,
                maxHz,
                sonogram.FramesPerSecond,
                freqBinWidth,
                intensityThreshold,
                minDuration,
                maxDuration,
                segmentStartOffset);

            //remove isolated speech events - expect humans to talk like politicians
            //predictedEvents = Human2.FilterHumanSpeechEvents(predictedEvents);
            Plot plot = new Plot(AnalysisName, intensity, intensityThreshold);

            return(Tuple.Create(sonogram, hits, plot, predictedEvents, tsRecordingtDuration));
        } //Analysis()