diff --git a/README.md b/README.md index 2b6276b..9460d88 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ void loop() { ## Версии - v2.1 - исправлена getResultTimer +- v2.2 - улучшен и упрощён алгоритм ## Баги и обратная связь diff --git a/examples/relay_simulation/relay_simulation.ino b/examples/relay_simulation/relay_simulation.ino index ac39b83..1aa7ef9 100644 --- a/examples/relay_simulation/relay_simulation.ino +++ b/examples/relay_simulation/relay_simulation.ino @@ -10,7 +10,7 @@ void setup() { Serial.begin(9600); regulator.setpoint = 40; regulator.hysteresis = 5; - regulator.k = 0.5; + regulator.k = 0.6; } boolean state = 0; @@ -23,9 +23,9 @@ void loop() { Serial.print(value); Serial.print(' '); - Serial.print(regulator.setpoint - 5 / 2); + Serial.print(regulator.setpoint - regulator.hysteresis / 2); Serial.print(' '); - Serial.print(regulator.setpoint + 5 / 2); + Serial.print(regulator.setpoint + regulator.hysteresis / 2); Serial.print(' '); Serial.println(regulator.setpoint); delay(100); @@ -34,7 +34,6 @@ void loop() { void process() { static float coef = 0; coef += state ? 0.3 : -0.6; - if (coef > 2.0) coef = 2.0; - if (coef < -3.0) coef = -3; + coef = constrain(coef, -3, 2); value += coef; } diff --git a/library.properties b/library.properties index ea32345..97ef06b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=GyverRelay -version=2.1 +version=2.2 author=AlexGyver maintainer=AlexGyver sentence=Library for relay regulation algorithm diff --git a/src/GyverRelay.cpp b/src/GyverRelay.cpp index 0aedb9b..a98c41e 100644 --- a/src/GyverRelay.cpp +++ b/src/GyverRelay.cpp @@ -1,47 +1,37 @@ #include "GyverRelay.h" -GyverRelay::GyverRelay(boolean direction) { - _direction = direction; - output = !_direction; // выключить реле сразу +GyverRelay::GyverRelay(GR_dir dir = REVERSE) { + _dir = dir; + output = !_dir; // выключить реле сразу } -void GyverRelay::setDirection(boolean dir) { - _direction = dir; -} - -int signum(float val) { - return ((val > 0) ? 1 : ((val < 0) ? -1 : 0)); +void GyverRelay::setDirection(GR_dir dir) { + _dir = dir; } // вернёт выход, принимает время итерации в секундах -boolean GyverRelay::compute(float dt) { +bool GyverRelay::compute(float dt) { float signal; - if (dt > 0) { - float rate = (input - prevInput) / dt; // производная от величины (величина/секунду) + if (dt != 0 && k != 0) { + signal = input + (input - prevInput) * k / dt; prevInput = input; - signal = input + rate * k; - } else { - signal = input; - } - - // жуткая функция реле из лекций по ТАУ - int8_t F = (signum(signal - setpoint - hysteresis / 2) + signum(signal - setpoint + hysteresis / 2)) / 2; - - if (F == 1) output = !_direction; - else if (F == -1) output = _direction; + } else signal = input; + + if (signal < (setpoint - hysteresis / 2)) output = _dir; + else if (signal > (setpoint + hysteresis / 2)) output = !_dir; return output; } -boolean GyverRelay::getResult() { - GyverRelay::compute((millis() - prevTime) / 1000.0f); +bool GyverRelay::getResult() { + compute((millis() - prevTime) / 1000.0f); prevTime = millis(); return output; } -boolean GyverRelay::getResultTimer() { +bool GyverRelay::getResultTimer() { if (millis() - prevTime > dT) { prevTime = millis(); - GyverRelay::compute((float)dT / 1000); + compute(dT / 1000.0); } return output; } \ No newline at end of file diff --git a/src/GyverRelay.h b/src/GyverRelay.h index 1778ce3..a9e6939 100644 --- a/src/GyverRelay.h +++ b/src/GyverRelay.h @@ -13,32 +13,35 @@ Версии: v2.1 - исправлена getResultTimer + v2.2 - улучшен и упрощён алгоритм */ -#ifndef GyverRelay_h -#define GyverRelay_h +#ifndef _GyverRelay_h +#define _GyverRelay_h #include -#define NORMAL 0 -#define REVERSE 1 +enum GR_dir { + NORMAL, + REVERSE, +}; class GyverRelay { public: // принимает установку, ширину гистерезиса, направление (NORMAL, REVERSE) // NORMAL - включаем нагрузку при переходе через значение снизу (пример: охлаждение) // REVERSE - включаем нагрузку при переходе через значение сверху (пример: нагрев) - GyverRelay(boolean direction = REVERSE); + GyverRelay(GR_dir dir); // расчёт возвращает состояние для управляющего устройства (реле, транзистор) (1 вкл, 0 выкл) - boolean compute(float dt = 0); // моментальный расчёт. Принимает dt в секундах для режима с ОС - boolean getResult(); // моментальный расчёт. Встроенный таймер для режима с ОС - boolean getResultTimer(); // расчёт по встроенному таймеру + bool compute(float dt = 0); // моментальный расчёт. Принимает dt в секундах для режима с ОС + bool getResult(); // моментальный расчёт. Встроенный таймер для режима с ОС + bool getResultTimer(); // расчёт по встроенному таймеру - void setDirection(boolean dir); // направление регулирования (NORMAL, REVERSE) + void setDirection(GR_dir dir); // направление регулирования (NORMAL, REVERSE) float input = 0; // сигнал с датчика (например температура, которую мы регулируем) float setpoint = 0; // заданная величина, которую должен поддерживать регулятор (температура) - boolean output = 0; // выход регулятора (0 или 1) + bool output = 0; // выход регулятора (0 или 1) float hysteresis = 0; // ширина окна гистерезиса float k = 0; // коэффициент усиления по скорости (по умолч. 0) @@ -47,6 +50,6 @@ class GyverRelay { private: uint32_t prevTime = 0; float prevInput = 0.0; - boolean _direction = false; + GR_dir _dir = REVERSE; }; #endif \ No newline at end of file