use num_traits::float::FloatCore;
pub struct PID<T> {
pub setpoint: T,
error: T,
integral: T,
derivative: T,
measurement: T,
p: T,
i: T,
d: T,
t: T,
imin: T,
imax: T,
omin: T,
omax: T,
}
impl<T: FloatCore> PID<T> {
pub fn new(kp: T, ki: T, kd: T, tau: T, sampling_time: T, setpoint: T) -> Self {
let two = T::from(2.0_f32).expect("Unable to cast from 2.0");
let half = T::from(0.5_f32).expect("Unable to cast from 0.5");
Self {
setpoint,
error: T::zero(),
integral: T::zero(),
derivative: T::zero(),
measurement: T::zero(),
p: kp,
i: half * ki * sampling_time,
d: -two * kd,
t: (two * tau - sampling_time) / (two * tau + sampling_time),
imin: T::neg_infinity(),
imax: T::infinity(),
omin: T::neg_infinity(),
omax: T::infinity(),
}
}
pub fn bound_integral(&mut self, min: T, max: T) -> &mut Self {
assert!(min <= max);
self.imin = min;
self.imax = max;
self
}
pub fn bound_output(&mut self, min: T, max: T) -> &mut Self {
assert!(min <= max);
self.omin = min;
self.omax = max;
self
}
pub fn step(&mut self, measurement: T) -> T {
let error = self.setpoint - measurement;
let proportional = self.p * error;
let integral = self.i * (error + self.error) + self.integral;
self.integral = num_traits::clamp(integral, self.imin, self.imax);
self.derivative = self.d * (measurement - self.measurement) + self.t * self.derivative;
let output = proportional + self.integral + self.derivative;
num_traits::clamp(output, self.omin, self.omax)
}
}