use crate::error::PlantError;
use crate::linear_algebra::Vector;
use crate::scalar::Numeric;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RotorLag<const ROTOR_COUNT: usize, T: Numeric = f64> {
time_constant: T,
timestep: T,
carried_over: T,
caught_up: T,
thrusts: Vector<ROTOR_COUNT, T>,
}
impl<const ROTOR_COUNT: usize, T: Numeric> RotorLag<ROTOR_COUNT, T> {
pub fn new(time_constant: T, timestep: T) -> Result<Self, PlantError> {
if !time_constant.is_finite() || !timestep.is_finite() {
return Err(PlantError::NonFinite);
}
if time_constant <= T::ZERO {
return Err(PlantError::NonPositiveTimeConstant);
}
if timestep <= T::ZERO {
return Err(PlantError::NonPositiveTimestep);
}
let ticks_of_lag = -timestep / time_constant;
Ok(RotorLag {
time_constant,
timestep,
carried_over: ticks_of_lag.exp(),
caught_up: -ticks_of_lag.expm1(),
thrusts: Vector::zeros(),
})
}
#[inline]
#[must_use]
pub fn with_thrusts(mut self, thrusts: Vector<ROTOR_COUNT, T>) -> Self {
self.thrusts = thrusts;
self
}
pub fn stepped(&mut self, commanded: Vector<ROTOR_COUNT, T>) -> Vector<ROTOR_COUNT, T> {
let before = self.thrusts;
self.thrusts = Vector::from_fn(|rotor| {
self.carried_over * before[rotor] + self.caught_up * commanded[rotor]
});
self.thrusts
}
pub fn stepped_over(
&mut self,
commanded: Vector<ROTOR_COUNT, T>,
timestep: T,
) -> Vector<ROTOR_COUNT, T> {
let ticks_of_lag = -timestep / self.time_constant;
let carried_over = ticks_of_lag.exp();
let caught_up = -ticks_of_lag.expm1();
let before = self.thrusts;
self.thrusts =
Vector::from_fn(|rotor| carried_over * before[rotor] + caught_up * commanded[rotor]);
self.thrusts
}
pub fn rate(&self, commanded: Vector<ROTOR_COUNT, T>) -> Vector<ROTOR_COUNT, T> {
Vector::from_fn(|rotor| (commanded[rotor] - self.thrusts[rotor]) / self.time_constant)
}
#[inline]
pub fn thrusts(&self) -> Vector<ROTOR_COUNT, T> {
self.thrusts
}
#[inline]
#[must_use]
pub fn time_constant(&self) -> T {
self.time_constant
}
#[inline]
#[must_use]
pub fn timestep(&self) -> T {
self.timestep
}
#[inline]
pub fn reset(&mut self) {
self.thrusts = Vector::zeros();
}
}