32#ifndef DETERMINISTICESPASYNCWEBSERVER_CONTROL_H
33#define DETERMINISTICESPASYNCWEBSERVER_CONTROL_H
37#if DETWS_ENABLE_CONTROL
42#define CONTROL_UNBOUNDED 1e30f
47#define CONTROL_LOG_HEADER "t_s,setpoint,measurement,output,dt_s"
56#define PID_LOG_MAGIC "DPID"
57#define PID_LOG_VERSION 1
58#define PID_LOG_HEADER_LEN 36
59#define PID_LOG_RECORD_LEN 16
60#define PID_LOG_STATUS_SATURATED 0x1u
92static inline float control_clamp(
float v,
float lo,
float hi)
94 return v < lo ? lo : (v > hi ? hi : v);
98static inline float control_deadband(
float v,
float band)
108static inline float control_slew(
float target,
float current,
float max_step)
110 float d = target - current;
112 return current + max_step;
114 return current - max_step;
119static inline float control_lpf(
float prev,
float sample,
float alpha)
121 return prev + alpha * (sample - prev);
126void pid_init(Pid *p,
float kp,
float ki,
float kd);
129void pid_set_output_limits(Pid *p,
float lo,
float hi);
132void pid_set_integral_limits(Pid *p,
float lo,
float hi);
135void pid_set_derivative_filter(Pid *p,
float alpha);
138void pid_set_feedforward(Pid *p,
float kff);
142void pid_set_rate(Pid *p,
float dt);
145void pid_reset(Pid *p);
150static inline float pid_step_(Pid *p,
float setpoint,
float measurement,
float dt,
float inv_dt)
152 float error = setpoint - measurement;
159 deriv = -(measurement - p->prev_meas) * inv_dt;
160 p->d_filt = (p->d_alpha > 0.0f) ? p->d_filt + p->d_alpha * (deriv - p->d_filt) : deriv;
162 p->prev_meas = measurement;
166 float integ_next = control_clamp(p->integ + p->ki * error * dt, p->integ_min, p->integ_max);
169 float unclamped = p->kp * error + integ_next + p->kd * p->d_filt + p->kff * setpoint;
170 float out = control_clamp(unclamped, p->out_min, p->out_max);
175 bool worsen_high = (unclamped > p->out_max) && (error > 0.0f);
176 bool worsen_low = (unclamped < p->out_min) && (error < 0.0f);
177 if (!worsen_high && !worsen_low)
178 p->integ = integ_next;
190static inline float pid_update(Pid *p,
float setpoint,
float measurement,
float dt)
192 if (!p || dt <= 0.0f)
194 return pid_step_(p, setpoint, measurement, dt, 1.0f / dt);
202static inline float pid_update_fixed(Pid *p,
float setpoint,
float measurement)
204 if (!p || p->dt <= 0.0f)
206 return pid_step_(p, setpoint, measurement, p->dt, p->inv_dt);
212void pid_update_n(Pid *p,
const float *setpoint,
const float *measurement,
float dt,
float *out, uint8_t n);
217size_t pid_log_header(uint8_t *buf,
size_t cap,
const Pid *p,
float dt);
220size_t pid_log_record(uint8_t *buf,
size_t cap,
float setpoint,
float measurement,
float output,
bool saturated);
User-facing configuration for DeterministicESPAsyncWebServer.