package controllers import ( "math" "git.joco.dk/snr/fermentord/internal/metrics" ) type PIDController struct { kp float64 ki float64 kd float64 lastError float64 lastOutput float64 integration float64 lbound float64 ubound float64 } func NewPIDController(p, i, d float64) *PIDController { return &PIDController{ kp: p, // 2.0 ki: i, // 0.0001 kd: d, // 2.0 lbound: -15.0, ubound: 15.0, } } func (p *PIDController) Compute(input float64, setpoint float64) float64 { error := setpoint - input if p.lastError == 0 { p.lastError = error } pv := p.kp * error dv := -(p.kd * (error - p.lastError)) p.lastError = error if p.lastOutput > p.lbound && p.lastOutput < p.ubound { p.integration += error } iv := p.integration * p.ki p.lastOutput = math.Max(math.Min(pv+iv+dv, p.ubound), p.lbound) metrics.PID.WithLabelValues("pv", "main").Set(pv) metrics.PID.WithLabelValues("dv", "main").Set(dv) metrics.PID.WithLabelValues("iv", "main").Set(iv) metrics.PID.WithLabelValues("offset", "main").Set(p.lastOutput) metrics.PID.WithLabelValues("setpoint", "main").Set(setpoint) return p.lastOutput }