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%.

Fri, 11 Mar 2016 20:27:02 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 11 Mar 2016 20:27:02 +0100
changeset 492
750f2468dec5
parent 491
31b14c9ac625
child 493
04d726035afe

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) {
 			/*

mercurial