Fri, 11 Mar 2016 20:27:02 +0100
Changed PID code. PID parameters are now stored 3 digits instead of 2 behind the decimal point. Prevent extreme heating or cooling in Beer mode. Heat and Cool lockdown now allows the lagest value to win instead of zero them both. PID output treshold from 2% to 50%.
thermferm/pid.c | file | annotate | diff | comparison | revisions | |
thermferm/pid.h | file | annotate | diff | comparison | revisions | |
thermferm/rdconfig.c | file | annotate | diff | comparison | revisions | |
thermferm/server.c | file | annotate | diff | comparison | revisions | |
thermferm/thermferm.c | file | annotate | diff | comparison | revisions |
--- a/thermferm/pid.c Sat Mar 05 12:50:23 2016 +0100 +++ b/thermferm/pid.c Fri Mar 11 20:27:02 2016 +0100 @@ -26,7 +26,7 @@ void InitPID(pid_var *pid, int type) { - pid->Err = pid->ErrLast = pid->iState = 0.0; + pid->Err = pid->InputLast = pid->iState = 0.0; pid->Input = pid->OutP = pid->SetP = 0.0; pid->pGain = pid->iGain = pid->dGain = 0.0; pid->idleRange = 0.4; @@ -41,7 +41,7 @@ { if (pid->Mode == PID_MODE_AUTO) { - double pTerm, dTerm, iTerm; + double dTerm; if (pid->Type == PID_TYPE_HEAT) pid->Err = pid->SetP - pid->Input; @@ -52,24 +52,22 @@ * Calculate the integral state with appopriate limiting. * Use ErrLastLast as iState */ - pid->iState += pid->Err; - if (pid->iState > PID_WINDUP_GUARD) - pid->iState = PID_WINDUP_GUARD; - else if (pid->iState < -PID_WINDUP_GUARD) - pid->iState = -PID_WINDUP_GUARD; + pid->iState += (pid->iGain * pid->Err); + if (pid->iState > pid->iMax) + pid->iState = pid->iMax; + else if (pid->iState < 0) + pid->iState = 0; - pTerm = pid->pGain * pid->Err; - iTerm = pid->iGain * pid->iState; - dTerm = pid->dGain * (pid->Err - pid->ErrLast); + dTerm = (pid->Input - pid->InputLast); - pid->OutP = pTerm + dTerm + iTerm; - pid->ErrLast = pid->Err; + pid->OutP = (pid->pGain * pid->Err) + pid->iState - (pid->dGain * dTerm); + pid->InputLast = pid->Input; } else if (pid->Mode == PID_MODE_BOO) { /* * Mode Bang On Off */ - pid->ErrLast = pid->Err; + pid->InputLast = pid->Input; if (pid->Type == PID_TYPE_HEAT) pid->Err = pid->SetP - pid->Input; @@ -88,7 +86,7 @@ * While in manual mode, stay ready for bumpless switch to * auto. */ - pid->ErrLast = pid->Err = 0.0; + pid->InputLast = pid->Input; pid->OutP = pid->iState = 0.0; }
--- a/thermferm/pid.h Sat Mar 05 12:50:23 2016 +0100 +++ b/thermferm/pid.h Fri Mar 11 20:27:02 2016 +0100 @@ -21,7 +21,7 @@ double Input; /* Input value */ double Err; /* Error, diff between input and set point */ - double ErrLast; /* Error from last pass */ + double InputLast; /* Input from last pass */ double iState; /* Error from next last pass */ double SetP; /* Set point */ double OutP; /* Output of PID algorithm */
--- a/thermferm/rdconfig.c Sat Mar 05 12:50:23 2016 +0100 +++ b/thermferm/rdconfig.c Fri Mar 11 20:27:02 2016 +0100 @@ -493,15 +493,15 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IGAIN", "%.2f", tmp3->PID_cool->iGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IGAIN", "%.3f", tmp3->PID_cool->iGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.2f", tmp3->PID_cool->pGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.3f", tmp3->PID_cool->pGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.2f", tmp3->PID_cool->dGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.3f", tmp3->PID_cool->dGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } @@ -517,10 +517,6 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ERRLAST", "%.2f", tmp3->PID_cool->ErrLast)) < 0) { - syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); - return 1; - } if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ISTATE", "%.2f", tmp3->PID_cool->iState)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; @@ -551,15 +547,15 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IGAIN", "%.2f", tmp3->PID_heat->iGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IGAIN", "%.3f", tmp3->PID_heat->iGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.2f", tmp3->PID_heat->pGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.3f", tmp3->PID_heat->pGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.2f", tmp3->PID_heat->dGain)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.3f", tmp3->PID_heat->dGain)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } @@ -571,10 +567,6 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ERRLAST", "%.2f", tmp3->PID_heat->ErrLast)) < 0) { - syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); - return 1; - } if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ISTATE", "%.2f", tmp3->PID_heat->iState)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; @@ -1250,12 +1242,6 @@ unit->PID_cool->Err = val; xmlFree(key); } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_ERRLAST"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%f", &val) == 1) - unit->PID_cool->ErrLast = val; - xmlFree(key); - } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_ISTATE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) @@ -1326,12 +1312,6 @@ unit->PID_heat->Err = val; xmlFree(key); } - if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_ERRLAST"))) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - if (sscanf((const char *)key, "%f", &val) == 1) - unit->PID_heat->ErrLast = val; - xmlFree(key); - } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_ISTATE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1)
--- a/thermferm/server.c Sat Mar 05 12:50:23 2016 +0100 +++ b/thermferm/server.c Fri Mar 11 20:27:02 2016 +0100 @@ -2085,9 +2085,10 @@ if (unit->PID_heat) { srv_send((char *)"PIDH_IMAX,%.1f", unit->PID_heat->iMax); srv_send((char *)"PIDH_IDLERANGE,%.2f", unit->PID_heat->idleRange); - srv_send((char *)"PIDH_PGAIN,%.2f", unit->PID_heat->pGain); - srv_send((char *)"PIDH_IGAIN,%.2f", unit->PID_heat->iGain); - srv_send((char *)"PIDH_DGAIN,%.2f", unit->PID_heat->dGain); + srv_send((char *)"PIDH_PGAIN,%.3f", unit->PID_heat->pGain); + srv_send((char *)"PIDH_IGAIN,%.3f", unit->PID_heat->iGain); + srv_send((char *)"PIDH_DGAIN,%.3f", unit->PID_heat->dGain); + srv_send((char *)"PIDH_SV,%.2f", unit->PID_heat->SetP); } srv_send((char *)"COOLER_ADDRESS,%s", unit->cooler_address); srv_send((char *)"COOLER_STATE,%d", unit->cooler_state); @@ -2096,9 +2097,10 @@ if (unit->PID_cool) { srv_send((char *)"PIDC_IMAX,%.1f", unit->PID_cool->iMax); srv_send((char *)"PIDC_IDLERANGE,%.2f", unit->PID_cool->idleRange); - srv_send((char *)"PIDC_PGAIN,%.2f", unit->PID_cool->pGain); - srv_send((char *)"PIDC_IGAIN,%.2f", unit->PID_cool->iGain); - srv_send((char *)"PIDC_DGAIN,%.2f", unit->PID_cool->dGain); + srv_send((char *)"PIDC_PGAIN,%.3f", unit->PID_cool->pGain); + srv_send((char *)"PIDC_IGAIN,%.3f", unit->PID_cool->iGain); + srv_send((char *)"PIDC_DGAIN,%.3f", unit->PID_cool->dGain); + srv_send((char *)"PIDC_SV,%.2f", unit->PID_cool->SetP); } srv_send((char *)"FAN_ADDRESS,%s", unit->fan_address); srv_send((char *)"FAN_STATE,%d", unit->fan_state);
--- a/thermferm/thermferm.c Sat Mar 05 12:50:23 2016 +0100 +++ b/thermferm/thermferm.c Fri Mar 11 20:27:02 2016 +0100 @@ -1516,15 +1516,15 @@ */ unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE; if (unit->mode == UNITMODE_FRIDGE) { - unit->PID_cool->SetP = unit->fridge_set; - unit->PID_heat->SetP = unit->fridge_set; + unit->PID_cool->SetP = unit->fridge_set + unit->PID_cool->idleRange; + unit->PID_heat->SetP = unit->fridge_set - unit->PID_heat->idleRange; unit->PID_cool->Input = unit->PID_heat->Input = unit->air_temperature / 1000.0; unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO; } else if (unit->mode == UNITMODE_BEER) { unit->PID_cool->SetP = unit->beer_set; unit->PID_heat->SetP = unit->beer_set; unit->PID_cool->Input = unit->PID_heat->Input = unit->beer_temperature / 1000.0; - unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO; + unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_AUTO; } else if (unit->mode == UNITMODE_PROFILE) { double usetemp; unit->PID_cool->SetP = unit->prof_target_hi; @@ -1538,7 +1538,7 @@ fprintf(stdout, " fridge_mode=%d measured=%.3f %.3f => %.3f\n", unit->prof_fridge_mode, unit->air_temperature / 1000.0, unit->beer_temperature / 1000.0, usetemp); unit->PID_cool->Input = unit->PID_heat->Input = usetemp; - unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO; + unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_AUTO; } /* @@ -1551,19 +1551,31 @@ * Logging */ if (unit->heater_address) { + /* + * Prevent extreme heating + */ + if ((unit->mode == UNITMODE_BEER) && ((unit->air_temperature / 1000.0) > (unit->PID_heat->Input + 5.0))) { + unit->PID_heat->OutP = 0.0; + } if (debug) fprintf(stdout, "Heat: sp=%.2f Input=%.2f iState=%.2f Err=%.2f Out=%.2f\n", unit->PID_heat->SetP, unit->PID_heat->Input, unit->PID_heat->iState, unit->PID_heat->Err, unit->PID_heat->OutP); - if (/* ((unit->PID_heat->OutP >= 2) && unit->heater_address) || */ (seconds == 60) /* || unit->heater_state */) { + if (seconds == 60) { syslog(LOG_NOTICE, "Heat: sp=%.2f Input=%.2f iState=%.2f Err=%.2f Out=%.2f", unit->PID_heat->SetP, unit->PID_heat->Input, unit->PID_heat->iState, unit->PID_heat->Err, unit->PID_heat->OutP); } } if (unit->cooler_address) { + /* + * Prevent extreme cooling + */ + if ((unit->mode == UNITMODE_BEER) && ((unit->air_temperature / 1000.0) < (unit->PID_cool->Input - 5.0))) { + unit->PID_cool->OutP = 0.0; + } if (debug) fprintf(stdout, "Cool: sp=%.2f Input=%.2f iState=%.2f Err=%.2f Out=%.2f\n", unit->PID_cool->SetP, unit->PID_cool->Input, unit->PID_cool->iState, unit->PID_cool->Err, unit->PID_cool->OutP); - if (/* ((unit->PID_cool->OutP >= 2) && unit->cooler_address) || */ (seconds == 60) /* || unit->cooler_state*/ ) { + if (seconds == 60) { syslog(LOG_NOTICE, "Cool: sp=%.2f Input=%.2f iState=%.2f Err=%.2f Out=%.2f", unit->PID_cool->SetP, unit->PID_cool->Input, unit->PID_cool->iState, unit->PID_cool->Err, unit->PID_cool->OutP); } @@ -1574,11 +1586,15 @@ */ if (unit->PID_cool->OutP && unit->PID_heat->OutP) { syslog(LOG_NOTICE, "Heat and Cool lockdown"); - unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0; + if (unit->PID_cool->OutP > unit->PID_heat->OutP) + unit->PID_heat->OutP = 0.0; + else + unit->PID_cool->OutP = 0.0; +// unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0; } if (unit->heater_address && ! unit->cooler_state) { - if (unit->PID_heat->OutP >= 2) { + if (unit->PID_heat->OutP >= 50) { if (unit->heater_wait < unit->heater_delay) { unit->heater_wait++; } else { @@ -1605,7 +1621,7 @@ } if (unit->cooler_address && ! unit->heater_state) { - if (unit->PID_cool->OutP >= 2) { + if (unit->PID_cool->OutP >= 50) { if (unit->cooler_wait < unit->cooler_delay) { unit->cooler_wait++; } else { @@ -1630,6 +1646,9 @@ else device_out(unit->cooler_address, 0); } + if (debug) + fprintf(stdout, "Final: PIDheat=%.2f PWRheat=%d PIDcool=%.2f PWRcool=%d\n", + unit->PID_heat->OutP, unit->heater_state, unit->PID_cool->OutP, unit->cooler_state); if ((unit->heater_address || unit->cooler_address) && unit->fan_address) { /*