Files
@ 752fd27f607a
Branch filter:
Location: therm-ng/src/pid.c
752fd27f607a
2.8 KiB
text/plain
Basic code cleanup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | //
// PID: proportional/integral/derivative controller
//
#include "pid.h"
#include "flash.h"
// Private variables
static pid_state_t state;
// Initialize PID loop
void pid_init()
{
state.i_state = 0;
state.last_pid_temp = 0;
state.last_pid_temp_frac = 0;
}
// Apply PID output values
float pid_process(void)
{
// #ifdef MAX31865_RTD_SENSOR
// max31865_readtemp(spi_get(), &set, &status);
// #else
// max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
// #endif
float ssr_output = 0;
if(runtime_status()->pid_enabled)
{
// Get ssr output for next time
int16_t power_percent = pid_update();
if(flash_getsettings()->val.plant_type == PLANT_COOLER)
power_percent *= -1;
//power-percent is 0-1000?
ssr_output = power_percent; //(((uint32_t)SSR_PERIOD * (uint32_t)10 * (uint32_t)100) * power_percent) / (uint32_t)1000000;
// put ssr output on display
ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
char tempstr[8];
snprintf(tempstr, 8, "%4.1f%%", ssr_output/10.0);
ssd1306_drawstring(tempstr, 0, 85);
}
else
{
ssr_output = 0.0;
}
return ssr_output; //ssr_output;
}
// Calculate new PID values
int16_t pid_update(void)
{
therm_status_t* status = runtime_status();
therm_settings_t* set = flash_getsettings();
// Convert temperature to fixed point number with 1/10th resolution
float temp = status->temp;
// Calculate instantaneous error
// EMZ FIXME: was regulating to 1 degree below the setpoint! +1 accomadates for this
int16_t error = (status->setpoint+1) - temp;
// Proportional component
int32_t p_term = set->val.k_p * error;
// Error accumulator (integrator)
state.i_state += error;
// to prevent the iTerm getting huge from lots of
// error, we use a "windup guard"
// (this happens when the machine is first turned on and
// it cant help be cold despite its best efforts)
// not necessary, but this makes windup guard values
// relative to the current iGain
int32_t windup_guard_res = (set->val.windup_guard * 10) / set->val.k_i;
// Calculate integral term with windup guard
if (state.i_state > windup_guard_res)
state.i_state = windup_guard_res;
else if (state.i_state < -windup_guard_res)
state.i_state = -windup_guard_res;
// Discard I if we've achieved the setpoint (TODO: add setting disable/enable)
if(error <= 0)
state.i_state = 0;
int32_t i_term = set->val.k_i * state.i_state;
// Calculate differential term (slope since last iteration)
int32_t d_term = (set->val.k_d * (temp - state.last_pid_temp));
// Save temperature for next iteration
state.last_pid_temp = temp;
int16_t result = (p_term + i_term - d_term) / 10;
// Put out tenths of percent, 0-1000.
if(result > 1000)
result = 1000;
else if(result < -1000)
result = -1000;
// Return feedback
return result;
}
|