For now only the proportional (Kp) and derivative (Kd) components are used, the integral term is 0.
65 lines
1.2 KiB
C
65 lines
1.2 KiB
C
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
#include "thermostat.h"
|
|
|
|
#define TEMP_MIN 35.0 /* °C */
|
|
#define DELTA_LOW 1.0
|
|
#define DELTA_HIGH 1.0
|
|
|
|
#define T_ERR_MIN 35.0 /* °C */
|
|
|
|
void
|
|
thermostat_set(struct thermostat *th, float temp_target)
|
|
{
|
|
if (th->st == THERMOSTAT_ON && th->temp_target == temp_target)
|
|
return;
|
|
|
|
th->st = THERMOSTAT_ON;
|
|
th->temp_target = temp_target;
|
|
th->temp_min = temp_target - DELTA_LOW;
|
|
th->temp_max = temp_target + DELTA_HIGH;
|
|
th->on = 1;
|
|
}
|
|
|
|
void
|
|
thermostat_off(struct thermostat *th)
|
|
{
|
|
th->st = THERMOSTAT_OFF;
|
|
th->on = 0;
|
|
}
|
|
|
|
static float
|
|
pid(float T0, float T, float dT_dt)
|
|
{
|
|
float err_min = 2.0;
|
|
|
|
/* The rate of change of error is the same as the temperature, as they
|
|
* are only offset by a mostly constant value */
|
|
float derr_dt = dT_dt;
|
|
|
|
if ((T0 - T) < err_min)
|
|
return 0.0;
|
|
|
|
float Kp = 1.0 / 20.0;
|
|
float Kd = - 1.0 / 3.0;
|
|
float u = Kp * (T0 - T) + Kd * dT_dt;
|
|
|
|
if (u < 0.0)
|
|
u = 0.0;
|
|
else if (u > 1.0)
|
|
u = 1.0;
|
|
|
|
return u;
|
|
}
|
|
|
|
/* Return a value in [0, 1] to set the heater duty cycle */
|
|
float
|
|
thermostat_state(struct thermostat *th, float T, float dT_dt)
|
|
{
|
|
if (th->st == THERMOSTAT_OFF)
|
|
return 0.0;
|
|
|
|
return pid(th->temp_target, T, dT_dt);
|
|
}
|