Подскажите пожалуйста. Имеется контроллер UNO, светодиод, и датчик температуры. Датчик температуры замеряет температуру нагревающейся воды. Температура плавно растет, ее рост заканчивается допустим на 55 С, далее она стабильно держится на этом уровне - 55 С. Мне нужно, чтобы загорелся светодиод как только температура стабилизируется и перестанет расти. Подскажите как это реализовать на программном уровне в скетче. Спасибо!
Примерно вот так: Код (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; } }
Нет. Я наверно не совсем понятно объяснил. Температура может быть и больше 55 или меньше. Необходимо, чтобы индикатор загорелся как температура перестанет расти и остановится на каком-нибудь значении.
Как запрошено - так и написано Из кода можно понять, как выкинуть проверку на 55 и понять, что температура стабилизировалась и не меняется. Что именно вам непонятно в примере?
Вот псевдокод: Код (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; } Какие части приведённого псевдокода вызывают у вас вопросы?
Я думаю, что стабилизацию надо проверять не равенством точному значению, а производной, которая должна в идеальном случае стремиться к нулю. Из-за неидеальности(?) нашего мира там должен быть допуск, т.е. производная должна быть в интервале dTпороговое, которое определяет пользователь. Код (C++): if ( abs(Tcur - Tneed) < dT) и (!t) {засечь время}
Недавно решал похожую задачку - строил по последним 10 замерам линию тренда методом МНК и анализировал ее наклон. Если меньше данного значения - значит параметр стабилен.
Это понятно, но, судя по всему, ТС мало знаком с программированием, поэтому не стал его путать ещё и допуском.
У вас в формуле опять считается разница между текущей и какой-то заданной температурой Tneed. ТС вроде уже уточнил, что его интересует сам факт стабидизации, безотносительно абсолютного значения T
Всё правильно: факт стабилизации - это когда значение за 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; }
ну так, это уже мина с моей стороны я хотел добавить шепотку реализма не уходя далеко от уже написанного примера.
ну не совсем так. Для такого расчета надо заранее выбрать удачный гистерезис. С точки зрения математики правильнее все же брать производную, как советовал Daniil.. Ну или наклон линии МНК. Тогда и гистерезис можно заранее не подбирать.
Всё зависит от задачи, скажем так Вполне возможно, что достаточно простого решения "в лоб", так сказать. А вы сразу - про МНК
В моем случае нет усреднения, в мнк есть. Надо бы добавить, а то у порога будет мерцать светодиод. Готовимся к худшему, надеемся на лучшее. Надо быть готовым к новым хотелкам ТС.
ну на самом деле в МНК математика простая, у меня ардуина при частоте отсчета 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]; } Вот, вытащил из проекта, чуть пришлось подправить, надеюсь нигде не испортил...
Самое простое - загнать значения в кольцевой буфер. Не надо никаких миллисов, нужен только анализ на каком-то отрезке.