コード例 #1
0
        public void Test_Dispersion_Of_Constant()
        {
            SeriesStatisticsCollector ssc = new SeriesStatisticsCollector(size);

            for (int i = 0; i < size; ++i)
            {
                ssc.AddValue(constantValue);
            }

            ssc.AddValue(constantValue);

            NUnit.Framework.Assert.AreEqual(0, ssc.GetDX(0));
            NUnit.Framework.Assert.AreEqual(constantValue, ssc.GetMX(0));
        }
コード例 #2
0
        /// <summary>
        /// Обрабатываем следующий отсчет АЦП
        /// </summary>
        /// <param name="stab_val"></param>
        /// <param name="timestamp"></param>
        /// <param name="timestamp_data_count"></param>
        private void ProcessNextSample(int stab_val, long timestamp, long timestamp_data_count)
        {
            double RezD1 = -500;
            double RezT  = -1000;
            double RezD2 = -2000;

            try
            {
                // запоминаем историю стабилизированного сигнала
                this.m_Y.AddValue(stab_val);

                // посчитаем новое среднее значение сигнала, в текущий момент
                this.m_SumY -= m_Y.GetOldestValue();
                this.m_SumY += stab_val;

                // запоминаем историю сумм (а значит, и средних значений)
                this.m_History_SumY.AddValue((long)this.m_SumY);

                // запоминаем историю стабилизированных значений
                this.m_SumY_front_history.AddValue(this.m_SumY);

                // считаем производную в текущий момент
                double Y_0 = this.m_History_SumY.GetValue(0);
                double Y_1 = this.m_History_SumY.GetValue(2);

                RezD1 = (1 * (Y_0 - Y_1) * 76800) / KD1;

                double Rez = RezD1;
                if (Rez < 0)
                {
                    Rez = 0;
                }

                // Собираем статистику по фильтрованному сигналу
                m_Signal_Statistics.AddValue(this.m_SumY / ((double)this.m_Y.GetSize()));

                // Собираем статистику по значениям первой производной, большей 0
                m_DY_Statistics.AddValue(Rez);

                if (0 == Rez)
                {
                    // оцениваем пороговое значение для первой производной
                    // обновляем его только до тех пор, пока не начнется фронт
                    // полагаем его равным СКО производной стабилизированного сигнала
                    // с некоторым подстраиваемым коэффициентом
                    int sigma_DY = (int)(dY_Threshold_Factor * System.Math.Sqrt(m_DY_Statistics.GetDX(0)));
                    m_Threshold_DY = System.Math.Max(sigma_DY, this.MinThreshold);
                }

                // первая производная с учетом порога
                RezT = Rez - m_Threshold_DY;

                if (RezT < 0)
                {
                    RezT = 0;
                }

                this.m_SumDY -= this.m_DY.GetOldestValue();
                this.m_SumDY += (long)RezT;

                // запоминаем историю значений первой производной, большей 0 с учетом порога
                this.m_DY.AddValue((int)RezT);

                // запоминаем историю суммы последних значений первой производной, больших чем 0 с учетом порога
                this.m_History_SumDY.AddValue((long)this.m_SumDY);

                // вычисляем вторую производную
                double MDY_0 = this.m_History_SumDY.GetValue(0);
                double MDY_1 = this.m_History_SumDY.GetValue(2);

                // вычисляем 2 производную
                RezD2 = (1 * (MDY_0 - MDY_1) * 3880) / KD2;

                // запоминаем историю производной
                this.m_History_D2Y.AddValue((int)RezD2);

                // проверяем пересечение нуля второй производной сверху вниз
                double D2Y_0 = this.m_History_D2Y.GetValue(0);

                System.Diagnostics.Debug.Assert(((int)RezD2) == ((int)D2Y_0));

                //if( this.bFrontAlreadyDetected && ( ! zero_crossing_detector.AddValue(D2Y_0)) )
                //{
                //  this.m_SumY_front_history.GetLastRisingFrontAmplitude()
                //}

                if (zero_crossing_detector.AddValue(D2Y_0))
                {
                    // Теперь надо ждать конца фронта, а потом оценить его высоту...

                    // В момент пересечения нуля второй производной сверху вниз
                    // мы знаем высоту примерно половины фронта!
                    // Пока удовольствуемся этим -- так проще.

                    double sumY_front_amplitude     = this.m_SumY_front_history.GetLastRisingFrontAmplitude();
                    double detected_front_amplitude = sumY_front_amplitude / ((double)this.BY);
                    double detected_front_duration  = this.m_SumY_front_history.GetLastRisingFrontDuration();

                    // Момент фронта
                    double front_sample_count = ((double)this.m_TotalCounter) - zero_crossing_detector.GetLastZeroCrossingPoint();

                    double delta_samples      = ((double)timestamp_data_count) - front_sample_count;
                    double delta_time_seconds = delta_samples / this.m_SamplingRate;
                    double delta_timestamp    = 1.0e6 * delta_time_seconds;
                    long   front_timestamp    = timestamp - ((long)delta_timestamp);


                    log.DebugFormat(
                        "front: time {0} ms, duration {1} ms, amplitude {2}, raw amplitude is {3}",
                        (int)(front_sample_count / this.m_SamplingRate * 1000.0),
                        (int)(detected_front_duration / this.m_SamplingRate * 1000.0),
                        (int)detected_front_amplitude,
                        (int)sumY_front_amplitude
                        );


                    if (detected_front_duration > 0)
                    {
                        double front_duration_ms = ((double)detected_front_duration * 1000.0 / this.m_SamplingRate);
                        double front_duration_min_threshold_ms = 2;
                        double front_duration_max_threshold_ms = 1000;

                        // оценим высоту предшествующего фронта...
                        double front_height = detected_front_amplitude;

                        // адаптивный порог высоты фронта
                        double front_height_threshold = this.front_amplitude_threshold_factor * System.Math.Sqrt(this.m_Signal_Statistics.GetDX(1));

                        // учитываем абсолютный порог минимально допустимой высоты фронта
                        front_height_threshold = System.Math.Max(front_height_threshold, 10);

                        if ((front_duration_ms > front_duration_min_threshold_ms))
                        {
                            if ((front_duration_ms < front_duration_max_threshold_ms))
                            {
                                if (
                                    (System.Math.Abs(front_height) > front_height_threshold)
                                    )
                                {
                                    log.DebugFormat(".NORMAL FRONT ({0} steps), threshold is {1}",
                                                    (int)front_height,
                                                    (int)front_height_threshold
                                                    );
                                    // поставить метку "хорошего" фронта
                                    // Debug_AddMark(front_sample_count / this.m_SamplingRate, System.Drawing.Color.Green);

                                    // this function checks fronts and rejects those
                                    // that may have been detected due to various interferences
                                    this.OnFrontFound(front_sample_count, front_timestamp);

                                    return;
                                }
                                else
                                {
                                    this.log.DebugFormat(
                                        "....front too low ({0} steps), threshold is {1}",
                                        (int)front_height,
                                        (int)front_height_threshold
                                        );
                                }
                            }
                            else
                            {
                                this.log.DebugFormat(
                                    "....front too long ({0} ms), max. allowed is {1} ms",
                                    (int)front_duration_ms,
                                    (int)front_duration_max_threshold_ms
                                    );
                            }
                        }
                        else
                        {
                            this.log.DebugFormat(
                                "....front too short ({0} ms), min. allowed is {1} ms",
                                (int)front_duration_ms,
                                (int)front_duration_min_threshold_ms
                                );
                        }
                    }
                    else
                    {
                        this.log.Debug(
                            "....front too short (1 sampling period)"
                            );
                    }

                    //Debug_AddMark(front_sample_count / this.m_SamplingRate, System.Drawing.Color.Red);
                }
            }
            catch (Exception ex)
            {
                this.log.Error(ex);
            }
            finally
            {
                Dump();

#if ENABLE_DEBUG_MONITOR
                // отладка: показываем нефильтрованное значение
                // стабилизированного сигнала в текущий момент
                this.Debug_AddData(this.channelY_Crimson, stab_val);

                // отладка: показываем среднее значение
                // стабилизированного сигнала в текущий момент
                // (сглаженный сигнал перед дифференцированием)
                this.Debug_AddData(this.channelMY_Red, this.m_SumY / ((double)this.m_Y.GetSize()));

                // показываем производную, не обрезанную ниже уровня "0"
                this.Debug_AddData(this.channelDY_LightGreen, RezD1);

                // отладка: показываем производную, обрезанную ниже уровня порога
                this.Debug_AddData(this.channelDY_T_Brown, RezT);

                // отладка: показываем уровень порога
                this.Debug_AddData(this.channelT_Maroon, m_Threshold_DY);

                // отладка: показываем сглаженное значение первой производной
                this.Debug_AddData(this.channelMDY_Blue, this.m_SumDY / ((double)this.m_DY.GetSize()));

                // отладка: показываем вторую производную
                this.Debug_AddData(this.channelD2Y_Orange, RezD2);
#endif
            }
        }