feat: added deadband for pid

This commit is contained in:
Yurii
2025-01-24 01:43:52 +03:00
parent afe710abd3
commit 8475833dce
9 changed files with 201 additions and 16 deletions

View File

@@ -1062,7 +1062,10 @@ protected:
);
} else {
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set max heating temp"));
Log.swarningln(
FPSTR(L_OT_HEATING), F("Failed set max heating temp: %.2f (converted: %.2f)"),
vars.master.heating.setpointTemp, convertedTemp
);
}
}

View File

@@ -196,6 +196,7 @@ protected:
//if (vars.parameters.heatingEnabled) {
if (settings.heating.enabled && this->indoorSensorsConnected) {
pidRegulator.Kp = settings.heating.turbo ? 0.0f : settings.pid.p_factor;
pidRegulator.Ki = settings.pid.i_factor;
pidRegulator.Kd = settings.pid.d_factor;
pidRegulator.setLimits(settings.pid.minTemp, settings.pid.maxTemp);
@@ -203,12 +204,22 @@ protected:
pidRegulator.input = vars.master.heating.indoorTemp;
pidRegulator.setpoint = settings.heating.target;
if (fabsf(pidRegulator.Ki - settings.pid.i_factor) >= 0.0001f) {
/*if (fabsf(pidRegulator.Ki - settings.pid.i_factor) >= 0.0001f) {
pidRegulator.Ki = settings.pid.i_factor;
pidRegulator.integral = 0.0f;
pidRegulator.getResultNow();
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
}*/
float error = pidRegulator.setpoint - pidRegulator.input;
bool hasDeadband = (error > -(settings.pid.deadband.thresholdHigh))
&& (error < settings.pid.deadband.thresholdLow);
if (hasDeadband) {
pidRegulator.Kp *= settings.pid.deadband.p_multiplier;
pidRegulator.Ki *= settings.pid.deadband.i_multiplier;
pidRegulator.Kd *= settings.pid.deadband.d_multiplier;
}
float pidResult = pidRegulator.getResultTimer();

View File

@@ -115,6 +115,15 @@ struct Settings {
unsigned short dt = 180;
short minTemp = 0;
short maxTemp = DEFAULT_HEATING_MAX_TEMP;
struct {
bool enabled = false;
float p_multiplier = 1.0f;
float i_multiplier = 0.05f;
float d_multiplier = 0.0f;
float thresholdHigh = 0.5f;
float thresholdLow = 1.0f;
} deadband;
} pid;
struct {

View File

@@ -63,6 +63,7 @@ const char S_CRASH[] PROGMEM = "crash";
const char S_CURRENT_TEMP[] PROGMEM = "currentTemp";
const char S_DATA[] PROGMEM = "data";
const char S_DATE[] PROGMEM = "date";
const char S_DEADBAND[] PROGMEM = "deadband";
const char S_DHW[] PROGMEM = "dhw";
const char S_DHW_BLOCKING[] PROGMEM = "dhwBlocking";
const char S_DHW_SUPPORT[] PROGMEM = "dhwSupport";
@@ -71,6 +72,7 @@ const char S_DIAG[] PROGMEM = "diag";
const char S_DNS[] PROGMEM = "dns";
const char S_DT[] PROGMEM = "dt";
const char S_D_FACTOR[] PROGMEM = "d_factor";
const char S_D_MULTIPLIER[] PROGMEM = "d_multiplier";
const char S_EMERGENCY[] PROGMEM = "emergency";
const char S_ENABLED[] PROGMEM = "enabled";
const char S_ENV[] PROGMEM = "env";
@@ -108,6 +110,7 @@ const char S_INTERVAL[] PROGMEM = "interval";
const char S_INVERT_STATE[] PROGMEM = "invertState";
const char S_IP[] PROGMEM = "ip";
const char S_I_FACTOR[] PROGMEM = "i_factor";
const char S_I_MULTIPLIER[] PROGMEM = "i_multiplier";
const char S_K_FACTOR[] PROGMEM = "k_factor";
const char S_LOGIN[] PROGMEM = "login";
const char S_LOG_LEVEL[] PROGMEM = "logLevel";
@@ -152,6 +155,7 @@ const char S_PREFIX[] PROGMEM = "prefix";
const char S_PROTOCOL_VERSION[] PROGMEM = "protocolVersion";
const char S_PURPOSE[] PROGMEM = "purpose";
const char S_P_FACTOR[] PROGMEM = "p_factor";
const char S_P_MULTIPLIER[] PROGMEM = "p_multiplier";
const char S_REAL_SIZE[] PROGMEM = "realSize";
const char S_REASON[] PROGMEM = "reason";
const char S_RESET_DIAGNOSTIC[] PROGMEM = "resetDiagnostic";
@@ -183,6 +187,8 @@ const char S_TARGET[] PROGMEM = "target";
const char S_TARGET_TEMP[] PROGMEM = "targetTemp";
const char S_TELNET[] PROGMEM = "telnet";
const char S_TEMPERATURE[] PROGMEM = "temperature";
const char S_THRESHOLD_HIGH[] PROGMEM = "thresholdHigh";
const char S_THRESHOLD_LOW[] PROGMEM = "thresholdLow";
const char S_THRESHOLD_TIME[] PROGMEM = "thresholdTime";
const char S_TOTAL[] PROGMEM = "total";
const char S_TRESHOLD_TIME[] PROGMEM = "tresholdTime";

View File

@@ -438,6 +438,14 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
pid[FPSTR(S_MIN_TEMP)] = src.pid.minTemp;
pid[FPSTR(S_MAX_TEMP)] = src.pid.maxTemp;
auto pidDeadband = pid[FPSTR(S_DEADBAND)].to<JsonObject>();
pidDeadband[FPSTR(S_ENABLED)] = src.pid.deadband.enabled;
pidDeadband[FPSTR(S_P_MULTIPLIER)] = src.pid.deadband.p_multiplier;
pidDeadband[FPSTR(S_I_MULTIPLIER)] = src.pid.deadband.i_multiplier;
pidDeadband[FPSTR(S_D_MULTIPLIER)] = src.pid.deadband.d_multiplier;
pidDeadband[FPSTR(S_THRESHOLD_HIGH)] = src.pid.deadband.thresholdHigh;
pidDeadband[FPSTR(S_THRESHOLD_LOW)] = src.pid.deadband.thresholdLow;
if (!safe) {
auto externalPump = dst[FPSTR(S_EXTERNAL_PUMP)].to<JsonObject>();
externalPump[FPSTR(S_USE)] = src.externalPump.use;
@@ -1075,6 +1083,60 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
changed = true;
}
if (src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_ENABLED)].is<bool>()) {
bool value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_ENABLED)].as<bool>();
if (value != dst.pid.deadband.enabled) {
dst.pid.deadband.enabled = value;
changed = true;
}
}
if (!src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_P_MULTIPLIER)].isNull()) {
float value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_P_MULTIPLIER)].as<float>();
if (value >= 0 && value <= 1 && fabsf(value - dst.pid.deadband.p_multiplier) > 0.0001f) {
dst.pid.deadband.p_multiplier = roundf(value, 3);
changed = true;
}
}
if (!src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_I_MULTIPLIER)].isNull()) {
float value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_I_MULTIPLIER)].as<float>();
if (value >= 0 && value <= 1 && fabsf(value - dst.pid.deadband.i_multiplier) > 0.0001f) {
dst.pid.deadband.i_multiplier = roundf(value, 3);
changed = true;
}
}
if (!src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_D_MULTIPLIER)].isNull()) {
float value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_D_MULTIPLIER)].as<float>();
if (value >= 0 && value <= 1 && fabsf(value - dst.pid.deadband.d_multiplier) > 0.0001f) {
dst.pid.deadband.d_multiplier = roundf(value, 3);
changed = true;
}
}
if (!src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_THRESHOLD_HIGH)].isNull()) {
float value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_THRESHOLD_HIGH)].as<float>();
if (value >= 0.0f && value <= 5.0f && fabsf(value - dst.pid.deadband.thresholdHigh) > 0.0001f) {
dst.pid.deadband.thresholdHigh = roundf(value, 2);
changed = true;
}
}
if (!src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_THRESHOLD_LOW)].isNull()) {
float value = src[FPSTR(S_PID)][FPSTR(S_DEADBAND)][FPSTR(S_THRESHOLD_LOW)].as<float>();
if (value >= 0.0f && value <= 5.0f && fabsf(value - dst.pid.deadband.thresholdLow) > 0.0001f) {
dst.pid.deadband.thresholdLow = roundf(value, 2);
changed = true;
}
}
// heating
if (src[FPSTR(S_HEATING)][FPSTR(S_ENABLED)].is<bool>()) {