#![no_std]
#[cfg(feature = "f32")]
pub type Float = f32;
#[cfg(not(feature = "f32"))]
pub type Float = f64;
pub struct So2Controller {
pub w_n: Float,
pub zeta: Float,
y: Float,
y_prev: Float,
setpoint: Float,
gain: Float,
}
impl So2Controller {
pub fn new(w_n: Float, zeta: Float, initial_value: Float, gain: Float) -> Self {
Self {
w_n,
zeta,
y: initial_value,
y_prev: initial_value,
setpoint: initial_value,
gain,
}
}
pub fn update(&mut self, input: Float, dt: Float) -> Float {
if dt <= 0.0 {
return self.y;
}
let a = self.w_n * self.w_n;
let b = 2.0 * self.zeta * self.w_n;
let dy = (self.y - self.y_prev) / dt;
let d2y = (self.gain * a * input) - (b * dy) - (a * self.y);
let next_y = self.y + (dy * dt) + (0.5 * d2y * dt * dt);
self.y_prev = self.y;
self.y = next_y;
self.y
}
pub fn set_target(&mut self, target: Float) {
self.setpoint = target;
}
pub fn reset(&mut self, value: Float) {
self.y = value;
self.y_prev = value;
}
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
#[test]
fn test_so2_stability() {
let mut so2 = So2Controller::new(20.0, 0.5, 0.0, 1.0);
let dt = 0.005;
let mut current_y = 0.0;
for _ in 0..200 {
current_y = so2.update(10.0, dt);
}
assert!((current_y - 10.0).abs() < 0.5);
}
#[test]
fn test_zero_dt_integrity() {
let mut so2 = So2Controller::new(10.0, 1.0, 5.0, 1.0);
let output = so2.update(10.0, 0.0);
assert_eq!(output, 5.0);
}
}