thermferm/thermferm.c

changeset 312
7b0f819a3805
parent 311
f3b0e9ac9bcb
child 313
8448fcf3d799
equal deleted inserted replaced
311:f3b0e9ac9bcb 312:7b0f819a3805
832 char use_heater[40], use_cooler[40], use_fan[40]; 832 char use_heater[40], use_cooler[40], use_fan[40];
833 time_t now, last = (time_t)0; 833 time_t now, last = (time_t)0;
834 units_list *unit; 834 units_list *unit;
835 profiles_list *profile; 835 profiles_list *profile;
836 prof_step *step; 836 prof_step *step;
837 int rc, run = 1, seconds = 0, minutes = 0, piddelay = 0, temp, deviation; 837 int rc, run = 1, seconds = 0, minutes = 0, temp, deviation;
838 int run_seconds, run_minutes, run_hours, tot_minutes; 838 int run_seconds, run_minutes, run_hours, tot_minutes;
839 float sp, pv, P_err = 0.0, D_err, Out; 839 float sp, pv, P_err = 0.0, Out;
840 #ifdef HAVE_WIRINGPI_H 840 #ifdef HAVE_WIRINGPI_H
841 struct tm *tm; 841 struct tm *tm;
842 int row, key; 842 int row, key;
843 #else 843 #else
844 long t = 0; 844 long t = 0;
1300 piUnlock(LOCK_LCD); 1300 piUnlock(LOCK_LCD);
1301 } 1301 }
1302 #endif 1302 #endif
1303 } 1303 }
1304 1304
1305 piddelay++; 1305 /*
1306 if (piddelay == 5) { 1306 * PID controller per unit, each second
1307 piddelay = 0; 1307 */
1308 1308 for (unit = Config.units; unit; unit = unit->next) {
1309 for (unit = Config.units; unit; unit = unit->next) { 1309 if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER) || (unit->mode == UNITMODE_PROFILE)) {
1310 if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER) || (unit->mode == UNITMODE_PROFILE)) { 1310 double pTerm, dTerm, iTerm;
1311 /* 1311
1312 * PID controller 1312 sp = unit->beer_set;
1313 */ 1313 pv = unit->beer_temperature / 1000.0;
1314 sp = unit->beer_set; 1314 if (unit->mode == UNITMODE_FRIDGE) {
1315 pv = unit->beer_temperature / 1000.0; 1315 sp = unit->fridge_set;
1316 if (unit->mode == UNITMODE_FRIDGE) { 1316 pv = unit->air_temperature / 1000.0;
1317 sp = unit->fridge_set; 1317 } else if (unit->mode == UNITMODE_PROFILE) {
1318 pv = unit->air_temperature / 1000.0; 1318 sp = unit->prof_target;
1319 } else if (unit->mode == UNITMODE_PROFILE) { 1319 }
1320 sp = unit->prof_target; 1320
1321 } 1321 /*
1322 1322 * PID controller compute
1323 P_err = sp - pv; 1323 */
1324 if (P_err < unit->idle_rangeH && P_err > unit->idle_rangeL) { 1324 P_err = sp - pv;
1325 P_err = 0.0; 1325 // if (P_err < unit->idle_rangeH && P_err > unit->idle_rangeL) {
1326 } 1326 // P_err = 0.0;
1327 unit->PID_I_err += (unit->PID_Ki * P_err); 1327 // }
1328 // unit->PID_I_err -= unit->PID_err_old; 1328 pTerm = unit->PID_Kp * P_err;
1329 // } else { 1329
1330 // unit->PID_I_err += unit->PID_err_old; 1330 /*
1331 * Calculate the intergral state with appropriate limiting
1332 */
1333 unit->PID_I_err += P_err;
1334 /* Limit integral error */
1335 if (unit->PID_I_err < -100.0)
1336 unit->PID_I_err = -100.0;
1337 if (unit->PID_I_err > 100.0)
1338 unit->PID_I_err = 100.0;
1339 iTerm = unit->PID_I_err * unit->PID_Ki;
1340 dTerm = unit->PID_err_old * unit->PID_Kd;
1341
1342 /*
1343 * A postive value means heating, a negative value cooling.
1344 * Start with Kp, Kd and Ki set to 0.
1345 * Increase Kp until small oscillation.
1346 * Increase Kd until a little damping.
1347 * Increase Ki after Kp and Kd are set until longterm convergence.
1348 */
1349 Out = pTerm + dTerm + iTerm;
1350 if (Out > 100.0)
1351 Out = 100.0;
1352 if (Out < -100.0)
1353 Out = -100.0;
1354 // if /* (P_err != 0.0) */ (i == 1) {
1355 if (debug)
1356 fprintf(stdout, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f Out=%.2f\n",
1357 sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, Out);
1358 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",
1359 sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, Out, pTerm, iTerm, dTerm, pTerm + dTerm + iTerm);
1331 // } 1360 // }
1332 /* Limit integral error */ 1361 unit->PID_err_old = P_err;
1333 if (unit->PID_I_err < -100.0) 1362
1334 unit->PID_I_err = -100.0; 1363 if (unit->heater_address) {
1335 if (unit->PID_I_err > 100.0)
1336 unit->PID_I_err = 100.0;
1337 D_err = P_err - unit->PID_err_old;
1338
1339 /*
1340 * A postive value means heating, a negative value cooling.
1341 * Start with Kp, Kd and Ki set to 0.
1342 * Increase Kp until small oscillation.
1343 * Increase Kd until a little damping.
1344 * Increase Ki after Kp and Kd are set until longterm convergence.
1345 */
1346 Out = (unit->PID_Kp * P_err) + unit->PID_I_err - (unit->PID_Kd * D_err);
1347 if (Out > 100.0)
1348 Out = 100.0;
1349 if (Out < -100.0)
1350 Out = -100.0;
1351 // if (P_err != 0.0) {
1352 if (debug)
1353 fprintf(stdout, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f D_err=%.2f Out=%.2f\n",
1354 sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, D_err, Out);
1355 syslog(LOG_NOTICE, "sp=%.2f pv=%.2f err_old=%.2f P_err=%.2f I_err=%.2f D_err=%.2f Out=%.2f",
1356 sp, pv, unit->PID_err_old, P_err, unit->PID_I_err, D_err, Out);
1357 // }
1358 unit->PID_err_old = P_err;
1359
1360 if (unit->heater_address) {
1361 if (Out >= 1) { 1364 if (Out >= 1) {
1362 if (unit->heater_wait < unit->heater_delay) { 1365 if (unit->heater_wait < unit->heater_delay) {
1363 unit->heater_wait++; 1366 unit->heater_wait++;
1364 syslog(LOG_NOTICE, "heater_wait + %d/%d", unit->heater_wait, unit->heater_delay); 1367 syslog(LOG_NOTICE, "heater_wait + %d/%d", unit->heater_wait, unit->heater_delay);
1365 } else { 1368 } else {
1378 unit->heater_state = 0; 1381 unit->heater_state = 0;
1379 } 1382 }
1380 } 1383 }
1381 } 1384 }
1382 device_out(unit->heater_address, unit->heater_state); 1385 device_out(unit->heater_address, unit->heater_state);
1383 } 1386 }
1384 if (unit->cooler_address) { 1387 if (unit->cooler_address) {
1385 if (Out <= -1) { 1388 if (Out <= -1) {
1386 if (unit->cooler_wait < unit->cooler_delay) { 1389 if (unit->cooler_wait < unit->cooler_delay) {
1387 unit->cooler_wait++; 1390 unit->cooler_wait++;
1388 syslog(LOG_NOTICE, "cooler_wait + %d/%d", unit->cooler_wait, unit->cooler_delay); 1391 syslog(LOG_NOTICE, "cooler_wait + %d/%d", unit->cooler_wait, unit->cooler_delay);
1389 } else { 1392 } else {
1402 unit->cooler_state = 0; 1405 unit->cooler_state = 0;
1403 } 1406 }
1404 } 1407 }
1405 } 1408 }
1406 device_out(unit->cooler_address, unit->cooler_state); 1409 device_out(unit->cooler_address, unit->cooler_state);
1407 } 1410 }
1408 if (unit->heater_address && unit->cooler_address && unit->fan_address) { 1411 if (unit->heater_address && unit->cooler_address && unit->fan_address) {
1409 /* 1412 /*
1410 * If the temperature difference between air and beer is more then 1413 * If the temperature difference between air and beer is more then
1411 * xxx degrees, turn the fan on to make an airflow. 1414 * xxx degrees, turn the fan on to make an airflow.
1412 * Maybe, run the fan too if the heater is on because the heater in 1415 * Maybe, run the fan too if the heater is on because the heater in
1413 * most cases will be some sort of radiating heat device. 1416 * most cases will be some sort of radiating heat device.
1422 if (unit->fan_state) 1425 if (unit->fan_state)
1423 syslog(LOG_NOTICE, "Fan On => Off"); 1426 syslog(LOG_NOTICE, "Fan On => Off");
1424 unit->fan_state = 0; 1427 unit->fan_state = 0;
1425 } 1428 }
1426 device_out(unit->fan_address, unit->fan_state); 1429 device_out(unit->fan_address, unit->fan_state);
1427 } 1430 }
1428 } else { 1431 } else {
1429 P_err = 0.0; 1432 P_err = 0.0;
1430 unit->PID_I_err = 0.0; 1433 unit->PID_I_err = 0.0;
1431 unit->PID_err_old = 0.0; 1434 unit->PID_err_old = 0.0;
1432 }
1433 } 1435 }
1434 } 1436 }
1435 1437
1436 #ifdef HAVE_WIRINGPI_H 1438 #ifdef HAVE_WIRINGPI_H
1437 piLock(LOCK_MENU); 1439 piLock(LOCK_MENU);

mercurial