# HG changeset patch # User Michiel Broek # Date 1424112762 -3600 # Node ID 7b0f819a3805aa4accf585a4c0e3ec616f6e8799 # Parent f3b0e9ac9bcbe79819f8557aed99fe1e78bc6022 Added more precision to the unit low and high black window margins. Switched to PID routine from Pid without a PhD. The PID compute routine is now in the one second loop. The switch delay times are now in seconds, 0..720. diff -r f3b0e9ac9bcb -r 7b0f819a3805 thermferm/rdconfig.c --- a/thermferm/rdconfig.c Sun Feb 15 23:09:00 2015 +0100 +++ b/thermferm/rdconfig.c Mon Feb 16 19:52:42 2015 +0100 @@ -461,11 +461,11 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IDLE_RANGE_L", "%.1f", tmp3->idle_rangeL)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IDLE_RANGE_L", "%.2f", tmp3->idle_rangeL)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IDLE_RANGE_H", "%.1f", tmp3->idle_rangeH)) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IDLE_RANGE_H", "%.2f", tmp3->idle_rangeH)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } diff -r f3b0e9ac9bcb -r 7b0f819a3805 thermferm/server.c --- a/thermferm/server.c Sun Feb 15 23:09:00 2015 +0100 +++ b/thermferm/server.c Mon Feb 16 19:52:42 2015 +0100 @@ -1613,8 +1613,8 @@ srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done); srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min); srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max); - srv_send((char *)"IDLE_RANGE_L,%.1f", unit->idle_rangeL); - srv_send((char *)"IDLE_RANGE_H,%.1f", unit->idle_rangeH); + srv_send((char *)"IDLE_RANGE_L,%.2f", unit->idle_rangeL); + srv_send((char *)"IDLE_RANGE_H,%.2f", unit->idle_rangeH); srv_send((char *)"PID_KP,%.2f", unit->PID_Kp); srv_send((char *)"PID_KI,%.2f", unit->PID_Ki); srv_send((char *)"PID_KD,%.2f", unit->PID_Kd); @@ -1984,14 +1984,14 @@ } else if (val && (strcmp(kwd, (char *)"IDLE_RANGE_L") == 0)) { if (sscanf(val, "%f", &fval) == 1) { if (unit->idle_rangeL != fval) - syslog(LOG_NOTICE, "Fermenter unit %s idle range low %.1f to %.1f", unit->uuid, unit->idle_rangeL, fval); + syslog(LOG_NOTICE, "Fermenter unit %s idle range low %.2f to %.2f", unit->uuid, unit->idle_rangeL, fval); unit->idle_rangeL = fval; } } else if (val && (strcmp(kwd, (char *)"IDLE_RANGE_H") == 0)) { if (sscanf(val, "%f", &fval) == 1) { if (unit->idle_rangeH != fval) - syslog(LOG_NOTICE, "Fermenter unit %s idle range high %.1f to %.1f", unit->uuid, unit->idle_rangeH, fval); + syslog(LOG_NOTICE, "Fermenter unit %s idle range high %.2f to %.2f", unit->uuid, unit->idle_rangeH, fval); unit->idle_rangeH = fval; } diff -r f3b0e9ac9bcb -r 7b0f819a3805 thermferm/thermferm.c --- a/thermferm/thermferm.c Sun Feb 15 23:09:00 2015 +0100 +++ b/thermferm/thermferm.c Mon Feb 16 19:52:42 2015 +0100 @@ -834,9 +834,9 @@ units_list *unit; profiles_list *profile; prof_step *step; - int rc, run = 1, seconds = 0, minutes = 0, piddelay = 0, temp, deviation; + int rc, run = 1, seconds = 0, minutes = 0, temp, deviation; int run_seconds, run_minutes, run_hours, tot_minutes; - float sp, pv, P_err = 0.0, D_err, Out; + float sp, pv, P_err = 0.0, Out; #ifdef HAVE_WIRINGPI_H struct tm *tm; int row, key; @@ -1302,62 +1302,65 @@ #endif } - piddelay++; - if (piddelay == 5) { - piddelay = 0; + /* + * PID controller per unit, each second + */ + for (unit = Config.units; unit; unit = unit->next) { + if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER) || (unit->mode == UNITMODE_PROFILE)) { + double pTerm, dTerm, iTerm; + + sp = unit->beer_set; + pv = unit->beer_temperature / 1000.0; + if (unit->mode == UNITMODE_FRIDGE) { + sp = unit->fridge_set; + pv = unit->air_temperature / 1000.0; + } else if (unit->mode == UNITMODE_PROFILE) { + sp = unit->prof_target; + } + + /* + * PID controller compute + */ + P_err = sp - pv; +// if (P_err < unit->idle_rangeH && P_err > unit->idle_rangeL) { +// P_err = 0.0; +// } + pTerm = unit->PID_Kp * P_err; - for (unit = Config.units; unit; unit = unit->next) { - if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER) || (unit->mode == UNITMODE_PROFILE)) { - /* - * PID controller - */ - sp = unit->beer_set; - pv = unit->beer_temperature / 1000.0; - if (unit->mode == UNITMODE_FRIDGE) { - sp = unit->fridge_set; - pv = unit->air_temperature / 1000.0; - } else if (unit->mode == UNITMODE_PROFILE) { - sp = unit->prof_target; - } + /* + * Calculate the intergral state with appropriate limiting + */ + unit->PID_I_err += P_err; + /* Limit integral error */ + if (unit->PID_I_err < -100.0) + unit->PID_I_err = -100.0; + if (unit->PID_I_err > 100.0) + unit->PID_I_err = 100.0; + iTerm = unit->PID_I_err * unit->PID_Ki; + dTerm = unit->PID_err_old * unit->PID_Kd; - P_err = sp - pv; - if (P_err < unit->idle_rangeH && P_err > unit->idle_rangeL) { - P_err = 0.0; - } - unit->PID_I_err += (unit->PID_Ki * P_err); -// unit->PID_I_err -= unit->PID_err_old; -// } else { -// unit->PID_I_err += unit->PID_err_old; + /* + * A postive value means heating, a negative value cooling. + * Start with Kp, Kd and Ki set to 0. + * Increase Kp until small oscillation. + * Increase Kd until a little damping. + * Increase Ki after Kp and Kd are set until longterm convergence. + */ + Out = pTerm + dTerm + iTerm; + if (Out > 100.0) + Out = 100.0; + if (Out < -100.0) + Out = -100.0; +// if /* (P_err != 0.0) */ (i == 1) { + if (debug) + fprintf(stdout, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f Out=%.2f\n", + sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, Out); + syslog(LOG_NOTICE, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f Out=%.2f pTerm=%.2f iTerm=%.2f dTerm=%.2f, N=%.2f", + sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, Out, pTerm, iTerm, dTerm, pTerm + dTerm + iTerm); // } - /* Limit integral error */ - if (unit->PID_I_err < -100.0) - unit->PID_I_err = -100.0; - if (unit->PID_I_err > 100.0) - unit->PID_I_err = 100.0; - D_err = P_err - unit->PID_err_old; + unit->PID_err_old = P_err; - /* - * A postive value means heating, a negative value cooling. - * Start with Kp, Kd and Ki set to 0. - * Increase Kp until small oscillation. - * Increase Kd until a little damping. - * Increase Ki after Kp and Kd are set until longterm convergence. - */ - Out = (unit->PID_Kp * P_err) + unit->PID_I_err - (unit->PID_Kd * D_err); - if (Out > 100.0) - Out = 100.0; - if (Out < -100.0) - Out = -100.0; -// if (P_err != 0.0) { - if (debug) - fprintf(stdout, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f D_err=%.2f Out=%.2f\n", - sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, D_err, Out); - syslog(LOG_NOTICE, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f D_err=%.2f Out=%.2f", - sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, D_err, Out); -// } - unit->PID_err_old = P_err; - - if (unit->heater_address) { + if (unit->heater_address) { if (Out >= 1) { if (unit->heater_wait < unit->heater_delay) { unit->heater_wait++; @@ -1380,8 +1383,8 @@ } } device_out(unit->heater_address, unit->heater_state); - } - if (unit->cooler_address) { + } + if (unit->cooler_address) { if (Out <= -1) { if (unit->cooler_wait < unit->cooler_delay) { unit->cooler_wait++; @@ -1404,8 +1407,8 @@ } } device_out(unit->cooler_address, unit->cooler_state); - } - if (unit->heater_address && unit->cooler_address && unit->fan_address) { + } + if (unit->heater_address && unit->cooler_address && unit->fan_address) { /* * If the temperature difference between air and beer is more then * xxx degrees, turn the fan on to make an airflow. @@ -1424,12 +1427,11 @@ unit->fan_state = 0; } device_out(unit->fan_address, unit->fan_state); - } - } else { + } + } else { P_err = 0.0; unit->PID_I_err = 0.0; unit->PID_err_old = 0.0; - } } } diff -r f3b0e9ac9bcb -r 7b0f819a3805 www-thermferm/units.php --- a/www-thermferm/units.php Sun Feb 15 23:09:00 2015 +0100 +++ b/www-thermferm/units.php Mon Feb 16 19:52:42 2015 +0100 @@ -203,10 +203,10 @@ if (($_POST['TempSetMin'] < -5) || ($_POST['TempSetMin'] > 15)) return 6; - if (($_POST['HeaterDelay'] < 0) || ($_POST['HeaterDelay'] > 45)) + if (($_POST['HeaterDelay'] < 0) || ($_POST['HeaterDelay'] > 720)) return 7; - if (($_POST['CoolerDelay'] < 0) || ($_POST['CoolerDelay'] > 45)) + if (($_POST['CoolerDelay'] < 0) || ($_POST['CoolerDelay'] > 720)) return 8; if (($_POST['IdleRangeL'] > 0) || ($_POST['IdleRangeL'] < -5)) @@ -215,7 +215,7 @@ if (($_POST['IdleRangeH'] < 0) || ($_POST['IdleRangeH'] > 5)) return 10; - if (($_POST['LightDelay'] < 0) || ($_POST['LightDelay'] > 45)) + if (($_POST['LightDelay'] < 0) || ($_POST['LightDelay'] > 720)) return 11; } else { @@ -256,15 +256,15 @@ break; case 6: $error = 'Temperature Minimum must be between -5 and 15 °C'; break; - case 7: $error = 'Heater Delay must be bewteen 0 and 45'; + case 7: $error = 'Heater Delay must be bewteen 0 and 720 seconds'; break; - case 8: $error = 'Cooler Delay must be bewteen 0 and 45'; + case 8: $error = 'Cooler Delay must be bewteen 0 and 720 seconds'; break; case 9: $error = 'Idle Range Low must be between -5 en 0'; break; case 10: $error = 'Idle Range High must be between 0 and 5'; break; - case 11: $error = 'Light Delay must be bewteen 0 and 45'; + case 11: $error = 'Light Delay must be bewteen 0 and 720 seconds'; break; case 99: load('units.php'); @@ -397,7 +397,7 @@ if ($f[0] == "HEATER_DELAY") { $outstr .= ' '.PHP_EOL; $outstr .= ' Heater Switch Delay'.PHP_EOL; - $outstr .= ' * 15 seconds'.PHP_EOL; + $outstr .= ' seconds (0..720)'.PHP_EOL; $outstr .= ' '.PHP_EOL; } if ($f[0] == "COOLER_ADDRESS") { @@ -424,7 +424,7 @@ if ($f[0] == "COOLER_DELAY") { $outstr .= ' '.PHP_EOL; $outstr .= ' Cooler Switch Delay'.PHP_EOL; - $outstr .= ' * 15 seconds'.PHP_EOL; + $outstr .= ' seconds (0..720)'.PHP_EOL; $outstr .= ' '.PHP_EOL; } if ($f[0] == "FAN_ADDRESS") { @@ -472,7 +472,7 @@ if ($f[0] == "LIGHT_DELAY") { $outstr .= ' '.PHP_EOL; $outstr .= ' Lights Delay'.PHP_EOL; - $outstr .= ' * 15 seconds'.PHP_EOL; + $outstr .= ' seconds (0..720)'.PHP_EOL; $outstr .= ' '.PHP_EOL; } if ($f[0] == "DOOR_ADDRESS") { @@ -532,13 +532,13 @@ if ($f[0] == "IDLE_RANGE_L") { $outstr .= ' '.PHP_EOL; $outstr .= ' Idle Range Low'.PHP_EOL; - $outstr .= ' °C (Cooler margin)'.PHP_EOL; + $outstr .= ' °C (Cooler margin)'.PHP_EOL; $outstr .= ' '.PHP_EOL; } if ($f[0] == "IDLE_RANGE_H") { $outstr .= ' '.PHP_EOL; $outstr .= ' Idle Range High'.PHP_EOL; - $outstr .= ' °C (Heater margin)'.PHP_EOL; + $outstr .= ' °C (Heater margin)'.PHP_EOL; $outstr .= ' '.PHP_EOL; } if ($f[0] == "PID_KP") { @@ -663,9 +663,9 @@ $outstr .= ''; $outstr .= ''; $outstr .= ''; - $outstr .= ''; - $outstr .= ''; - $outstr .= ''; + $outstr .= ''; + $outstr .= ''; + $outstr .= ''; $outstr .= ''; $outstr .= ''; $outstr .= '';