Индикация при стабилизации параметров

Тема в разделе "Arduino & Shields", создана пользователем SDV, 8 ноя 2018.

  1. SDV

    SDV Нерд

    Подскажите пожалуйста. Имеется контроллер UNO, светодиод, и датчик температуры.
    Датчик температуры замеряет температуру нагревающейся воды. Температура плавно растет, ее рост заканчивается допустим на 55 С, далее она стабильно держится на этом уровне - 55 С.
    Мне нужно, чтобы загорелся светодиод как только температура стабилизируется и перестанет расти.
    Подскажите как это реализовать на программном уровне в скетче.
    Спасибо!
     
  2. DIYMan

    DIYMan Гуру

    Примерно вот так:
    Код (C++):

    uint32_t timer = 0;
    int lastTemp = 0;

    void loop()
    {
        int temp = getTemp();
       
        if(lastTemp == temp)
        {
            if(temp >= 55)
            {
                if(!timer)
                    timer = millis();
               
                if(millis() - timer > 10000)
                {
                    // стабилизировалась, больше либо равна 55, не растёт 10 секунд
                   
                    timer = millis();
                }
            }
        }
        else
        {
            lastTemp = temp;
            if(temp < 55)
                timer = 0;
        }
       
    }
     
     
  3. SDV

    SDV Нерд

    Нет. Я наверно не совсем понятно объяснил. Температура может быть и больше 55 или меньше. Необходимо, чтобы индикатор загорелся как температура перестанет расти и остановится на каком-нибудь значении.
     
  4. DIYMan

    DIYMan Гуру

    Что в моём примере непонятно? Куда вставить зажигание светодиода, что ли? Там комментарии есть.
     
  5. SDV

    SDV Нерд

    Вы в скетче прописали 55 С. А мне нужна индикация при любой стабильной температуре.
     
  6. DIYMan

    DIYMan Гуру

    Как запрошено - так и написано ;) Из кода можно понять, как выкинуть проверку на 55 и понять, что температура стабилизировалась и не меняется. Что именно вам непонятно в примере?
     
  7. DIYMan

    DIYMan Гуру

    Вот псевдокод:
    Код (C++):

    T lastTemp = 0;
    Timer t = 0;

    void loop()
    {
       T current = getTemp();

       if(current != lastTemp)
       {
          t = 0;
          echo "ИЗМЕНИЛАСЬ!!!";
       }
       else
       {
          if(!t)
             t = millis();

          if(millis() - t > 5000)
          {
                 echo "СТАБИЛИЗИРОВАЛАСЬ И НЕ МЕНЯЕТСЯ 5 СЕКУНД!!!";
                 t = 0;
          }
       }

      lastTemp = current;
    }
     
    Какие части приведённого псевдокода вызывают у вас вопросы?
     
  8. Daniil

    Daniil Гик

    Я думаю, что стабилизацию надо проверять не равенством точному значению, а производной, которая должна в идеальном случае стремиться к нулю.
    Из-за неидеальности(?) нашего мира там должен быть допуск, т.е. производная должна быть в интервале dTпороговое, которое определяет пользователь.
    Код (C++):
    if ( abs(Tcur - Tneed) < dT) и (!t)
    {засечь время}
     
    arkadyf нравится это.
  9. b707

    b707 Гуру

    Недавно решал похожую задачку - строил по последним 10 замерам линию тренда методом МНК и анализировал ее наклон. Если меньше данного значения - значит параметр стабилен.
     
    arkadyf нравится это.
  10. DIYMan

    DIYMan Гуру

    Это понятно, но, судя по всему, ТС мало знаком с программированием, поэтому не стал его путать ещё и допуском.
     
  11. b707

    b707 Гуру

    У вас в формуле опять считается разница между текущей и какой-то заданной температурой Tneed.
    ТС вроде уже уточнил, что его интересует сам факт стабидизации, безотносительно абсолютного значения T
     
  12. DIYMan

    DIYMan Гуру

    Всё правильно: факт стабилизации - это когда значение за N времени укладывается в гистерезис. Достаточно чуть допилить мой пример, получая разницу последнего и текущего значения, и если она больше гистерезиса, то в данный текущий момент времени - показания не стабилизировались ещё. Примерно так:
    Код (C++):
    T lastTemp = 0, histeresis = 0.2;
    Timer t = 0;

    void loop()
    {
       T current = getTemp();
       T diff = abs(current - lastTemp);

       if(diff > histeresis)
       {
          t = 0;
          echo "ИЗМЕНИЛАСЬ!!!";
       }
       else
       {
          if(!t)
             t = millis();

          if(millis() - t > 5000)
          {
                 echo "СТАБИЛИЗИРОВАЛАСЬ И НЕ МЕНЯЕТСЯ 5 СЕКУНД!!!";
                 t = 0;
          }
       }

      lastTemp = current;
    }
     
  13. Daniil

    Daniil Гик

    ну так, это уже мина с моей стороны;) я хотел добавить шепотку реализма не уходя далеко от уже написанного примера.
     
  14. b707

    b707 Гуру

    ну не совсем так. Для такого расчета надо заранее выбрать удачный гистерезис.
    С точки зрения математики правильнее все же брать производную, как советовал Daniil.. Ну или наклон линии МНК. Тогда и гистерезис можно заранее не подбирать.
     
  15. DIYMan

    DIYMan Гуру

    Всё зависит от задачи, скажем так ;) Вполне возможно, что достаточно простого решения "в лоб", так сказать. А вы сразу - про МНК ;)
     
  16. Daniil

    Daniil Гик

    В моем случае нет усреднения, в мнк есть. Надо бы добавить, а то у порога будет мерцать светодиод.
    Готовимся к худшему, надеемся на лучшее. Надо быть готовым к новым хотелкам ТС.
     
  17. b707

    b707 Гуру

    ну на самом деле в МНК математика простая, у меня ардуина при частоте отсчета 100Гц вполне успевала и данные собирать и скользящий МНК делать. Надо только сумму квадратов заранее посчитать.
    Код (C++):
    #define BUF_SIZE 16 //размер буфера - степень двойки
    #define BUF_MASK (BUF_SIZE-1)
    const uint8_t sum_of_numbers[] = {0,1,3,6,10,15,21,28,36,45,55};
    const uint16_t sum_of_squares[] = {0,1,5,14,30,55,91,140,204,285,385};

    uint8_t count;          // текущее число отсчетов в буфере
    uint16_t buffer [BUF_SIZE];
    uint8_t idxOUT;         //указатель на последний элемент в буфере

    // расчет тренда методом МНК по <norm> точкам
    // где  4 <= norm <= 10
    float trend(uint8_t norm) {
         long sum =0;
         if (norm > count) norm = count;
         if (norm > 10) norm = 10;
         if ( norm <4 ) return -9999;
       
         for (int i = norm-1; i>0; i--) {
           sum += buffer[idxOUT--] * i;
               idxOUT &= BUF_MASK;
          }
         return ((float)(sum - sum_of_numbers[norm-1] * buffer[idxOUT])) / sum_of_squares[norm-1];
    }
    Вот, вытащил из проекта, чуть пришлось подправить, надеюсь нигде не испортил...
     
    DetSimen и DIYMan нравится это.
  18. parovoZZ

    parovoZZ Гуру

    Самое простое - загнать значения в кольцевой буфер. Не надо никаких миллисов, нужен только анализ на каком-то отрезке.
     
  19. SDV

    SDV Нерд

    Все, разобрался. Спасибо! Очень помогли.