Получить время между достижением цели (вверху) и выходом из цели (внизу) на графике - PullRequest
0 голосов
/ 27 февраля 2019

Следующая таблица обновляет свои значения, используя таймер winforms каждую секунду.Красная линия представляет постоянное целевое испытательное давление, синяя линия - фактическое давление, считываемое с объекта ПЛК.

Ось Y = Испытательное давление, Ось X = Текущее время, график обновляется с помощью таймера winforms с интервалом = 1000 (каждую секунду)

Требование показывает, сколькоПрошло несколько секунд между синей линией, достигающей постоянного необходимого испытательного давления (красная линия) и опускающейся ниже постоянного значения
требуемого испытательного давления

Блок, который устанавливает постоянное требуемое испытательное давление:

...
        chart1.ChartAreas[0].CursorY.Position = d;
        chart1.ChartAreas[0].CursorY.LineWidth = 1;
        chart1.ChartAreas[0].CursorY.LineColor = System.Drawing.Color.Red;

Часть, в которой я застрял (этот блок находится внутри метода, который обновляет диаграмму каждую секунду):

                                                                        double plcTestpressure = ((uint)plc.Read("MD220")).ConvertToDouble();
                    double reqTestPressure = Convert.ToDouble(txtTestingPressure.Text);

                    if (plcTestpressure > reqTestPressure && !isAboveReq)
                    {
                        DateTime aboveReq = new DateTime();
                        aboveReq = DateTime.Now;
                        isAboveReq = true;
                        //this is for checking the plc read pressure
                        string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString();
                    }
                    //check if current pressure is below required and that pressure WAS above required a second ago...
                    if(plcTestpressure < reqTestPressure && isAboveReq)
                    {
                        DateTime belowReq = new DateTime();
                        belowReq = DateTime.Now;                    
                        tickCounter = (belowReq - aboveReq).TotalSeconds;
                        isAboveReq = false;
                    }

Я пробовал и прошел этот блок, но он дает мне вводящий в заблуждение ответ в tickCounter (33 секунды, когда вы можете визуально увидеть на графике, что прошло 5 секунд) и после того, как в первый раз назначен tickCounter,метка даты и времени вышеReq не хочет меняться.

Есть ли лучший способ достичь этой цели?Я поступаю неправильно?Должен ли я предоставить более подробную информацию?

1 Ответ

0 голосов
/ 27 февраля 2019

Я должен был бы предположить, что у вас есть несколько переменных с именем "aboveReq", поскольку переменные, объявленные в блоке "if", являются локальными для блока.Это означает, что когда вы обращаетесь к переменной "aboveReq" во втором блоке "if", вы не получаете доступ к той же переменной.

Также действительно ли string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString(); должно находиться в блоке if (только отслеживаниетекущее давление, пока оно выше целевого значения)?

//Outside of method, top of class
private DateTime? _startTime = null;
private DateTime? _endTime = null;

//In method
 string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString();

 bool breachPressure = plcTestpressure > reqTestPressure;

 if (breachPressure && _startTime == null)
 {
    _startTime = DateTime.Now;
 }
 else if(!breachPressure && _startTime != null)
 {
    _endTime = new DateTime();
    var tickCounter = _endTime.Value.Subtract(_startTime.Value).TotalSeconds;
 }

----------------------------- Edit ---------------------------------------

Я ошибаюсь?

Было бы лучше, если бы вы переместили логику контроля давления в отдельный класс, тем самым придерживаясь принципа единой ответственности.

Вы можете сделать это, применив давлениекласс мониторинга, который будет вызывать события при нарушении порога - что-то вроде -

        public class PressureObserver
        {
            public event EventHandler<double> OnRaisedAboveThreshhold;
            public event EventHandler<double> OnFellBelowThreshhold;

            public double ThresholdPressure{ get; }

            private double _lastMeasured = 0; //Initial Pressure

            public PressureObserver(double thresholdPressure)
            {
                ThresholdPressure = thresholdPressure;
            }

            public void Observe(double plcTestpressure)
            {
                double pressureDelta = plcTestpressure - _lastMeasured;

                if (pressureDelta > 0) //Pressure climbed
                {
                    if(_lastMeasured < ThresholdPressure &&  //Last measurement was below threshold
                        plcTestpressure > ThresholdPressure) //This one is above, cross made
                    {
                        OnRaisedAboveThreshhold?.Invoke(this, plcTestpressure);
                    }
                }
                else if(pressureDelta < 0) //Pressure declined
                {
                    if (_lastMeasured > ThresholdPressure &&  //Last measurement was above threshold
                        plcTestpressure < ThresholdPressure) //This one is below, cross made
                    {
                        OnFellBelowThreshhold?.Invoke(this, plcTestpressure);
                    }
                }

                _lastMeasured = plcTestpressure;
            }
        }

Тогда в вашем основном классе вы будете иметь поля

        private PressureObserver _pressureObserver;
        private DateTime _raisedAboveTime;
        private DateTime _fellBelowTime;
        private double _overpressureDuration;

, вы будете определять два методачтобы реагировать на изменения порогов

        private void Obs_OnRaisedAboveTreshhold(object sender, double e)
        {
            //Code to do on raised above
            _raisedAboveTime = DateTime.Now;
        }

        private void Obs_OnFellBelowTreshhold(object sender, double e)
        {
            //Code to do on fell below
            _fellBelowTime = DateTime.Now;
            _overpressureDuration = _fellBelowTime.Subtract(_raisedAboveTime).TotalSeconds;
        }

, и в конструкторе вы подписываетесь на класс наблюдателя

       _pressureObserver = new PressureObserver(60); //replace 60 with threshold

       _pressureObserver.OnRaisedAboveThreshhold += Obs_OnRaisedAboveTreshhold;
       _pressureObserver.OnFellBelowThreshhold += Obs_OnFellBelowTreshhold;

, а в своем таймере тиков вы просто добавляете

_pressureObserver.Observe(plcTestpressure);
...