pounder_test/src/iir.rs

66 lines
1.6 KiB
Rust
Raw Normal View History

2019-03-28 17:02:32 +08:00
use core::f32;
2019-03-28 02:48:22 +08:00
pub type IIRState = [f32; 5];
2019-03-28 17:02:32 +08:00
#[derive(Default,Copy,Clone,Debug)]
2019-03-28 02:48:22 +08:00
pub struct IIR {
2019-03-28 17:02:32 +08:00
pub x_offset: f32,
pub y_offset: f32,
2019-03-28 02:48:22 +08:00
pub ba: IIRState,
pub scale: f32,
}
2019-03-28 23:10:04 +08:00
fn abs(x: f32) -> f32 {
if x >= 0. { x } else { -x }
}
fn copysign(x: f32, y: f32) -> f32 {
match () {
_ if (x >= 0. && y >= 0.) || (x <= 0. && y <= 0.) => y,
_ => -y
}
}
2019-03-28 02:48:22 +08:00
impl IIR {
2019-03-28 17:02:32 +08:00
pub fn pi(&mut self, kp: f32, ki: f32, g: f32) -> Result<(), &str> {
2019-03-28 23:10:04 +08:00
let ki = copysign(kp, ki);
let g = copysign(kp, g);
let (a1, b0, b1) = match () {
_ if abs(ki) < f32::EPSILON => (0., kp, 0.),
2019-03-28 17:02:32 +08:00
_ => {
2019-03-28 23:10:04 +08:00
let c = match () {
_ if abs(g) < f32::EPSILON => 1.,
_ => 1./(1. + ki/g)
2019-03-28 17:02:32 +08:00
};
2019-03-28 23:10:04 +08:00
let a1 = 2.*c - 1.;
let b0 = ki*c + kp;
let b1 = ki*c - a1*kp;
if abs(b0 + b1) < f32::EPSILON {
return Err("low integrator gain and/or gain limit")
2019-03-28 17:02:32 +08:00
}
2019-03-28 23:10:04 +08:00
(a1, b0, b1)
2019-03-28 17:02:32 +08:00
}
};
self.ba[0] = b0;
self.ba[1] = b1;
self.ba[2] = 0.;
self.ba[3] = a1;
self.ba[4] = 0.;
Ok(())
}
2019-03-28 02:48:22 +08:00
pub fn update(&self, xy: &mut IIRState, x0: f32) -> f32 {
xy.rotate_right(1);
2019-03-28 20:04:25 +08:00
xy[0] = x0 + self.x_offset;
2019-03-28 17:02:32 +08:00
let y0 = macc(self.y_offset, xy, &self.ba)
.min(self.scale).max(-self.scale);
2019-03-28 02:48:22 +08:00
xy[xy.len()/2] = y0;
y0
}
}
2019-03-28 17:02:32 +08:00
fn macc(y0: f32, x: &[f32], a: &[f32]) -> f32 {
2019-03-28 02:48:22 +08:00
y0 + x.iter().zip(a.iter())
.map(|(&i, &j)| i * j).sum::<f32>()
}