#![no_std]
#![deny(nonstandard_style, future_incompatible, rust_2018_idioms)]
use core::ops::*;
pub struct PID<F, const W: usize> {
pub kp: F,
pub ki: F,
pub kd: F,
pub kf: F,
pub kv: F,
last_sp: F,
last_error_idx: usize,
errors: [F; W],
err_history: F,
}
impl<F, const W: usize> PID<F, W>
where
F: Default + Add<Output = F> + Sub<Output = F> + Mul<Output = F> + PartialOrd + Copy,
{
pub fn new(
kp: impl Into<F>,
ki: impl Into<F>,
kd: impl Into<F>,
kf: impl Into<F>,
kv: impl Into<F>,
) -> Self {
assert!(W > 0);
Self {
kp: kp.into(),
ki: ki.into(),
kd: kd.into(),
kf: kf.into(),
kv: kv.into(),
last_sp: F::default(),
errors: [F::default(); W],
last_error_idx: usize::default(),
err_history: F::default(),
}
}
pub fn reset(&mut self) {
self.last_sp = F::default();
self.err_history = F::default();
self.errors = [F::default(); W];
self.last_error_idx = usize::default();
}
pub fn next(&mut self, sp: impl Into<F>, fb: impl Into<F>) -> F {
let sp = sp.into();
let fb = fb.into();
let error = sp - fb;
let error_delta = error - self.errors[self.last_error_idx];
self.push_error(error);
let sp_delta = sp - self.last_sp;
self.last_sp = sp;
let p = self.kp * error;
let i = self.ki * self.err_history;
let d = self.kd * error_delta;
let f = self.kf * sp_delta;
let v = self.kv * fb;
p + i + d + f + v
}
fn push_error(&mut self, error: F) {
self.last_error_idx += 1;
if self.last_error_idx >= W {
self.last_error_idx = 0;
}
self.err_history = self.err_history - self.errors[self.last_error_idx];
self.err_history = self.err_history + error;
self.errors[self.last_error_idx] = error;
}
}