use crate::traits::FloatScalar;
use super::biquad::Biquad;
use super::ControlError;
pub fn lead_compensator<T: FloatScalar>(
phase_lead: T,
center_freq: T,
gain: T,
sample_rate: T,
) -> Result<Biquad<T>, ControlError> {
let zero = T::zero();
let one = T::one();
let two = one + one;
let pi = T::from(core::f64::consts::PI).unwrap();
let half_pi = pi / two;
if phase_lead <= zero || phase_lead >= half_pi {
return Err(ControlError::InvalidFrequency);
}
if center_freq <= zero || !center_freq.is_finite() {
return Err(ControlError::InvalidFrequency);
}
if sample_rate <= zero || !sample_rate.is_finite() {
return Err(ControlError::InvalidFrequency);
}
let nyquist = sample_rate / two;
if center_freq >= nyquist {
return Err(ControlError::InvalidFrequency);
}
let sin_phi = phase_lead.sin();
let alpha = (one - sin_phi) / (one + sin_phi);
let omega_m = two * pi * center_freq;
let t_const = one / (omega_m * alpha.sqrt());
let z_freq = one / t_const; let p_freq = one / (alpha * t_const); let k_analog = gain / alpha;
let c = two * sample_rate;
let b0 = k_analog * (c + z_freq) / (c + p_freq);
let b1 = k_analog * (-c + z_freq) / (c + p_freq);
let a1 = (-c + p_freq) / (c + p_freq);
Ok(Biquad::new(
[b0, b1, T::zero()],
[T::one(), a1, T::zero()],
))
}
pub fn lag_compensator<T: FloatScalar>(
dc_boost: T,
corner_freq: T,
sample_rate: T,
) -> Result<Biquad<T>, ControlError> {
let zero = T::zero();
let one = T::one();
let two = one + one;
let pi = T::from(core::f64::consts::PI).unwrap();
if dc_boost <= one {
return Err(ControlError::InvalidFrequency);
}
if corner_freq <= zero || !corner_freq.is_finite() {
return Err(ControlError::InvalidFrequency);
}
if sample_rate <= zero || !sample_rate.is_finite() {
return Err(ControlError::InvalidFrequency);
}
let nyquist = sample_rate / two;
if corner_freq >= nyquist {
return Err(ControlError::InvalidFrequency);
}
let omega = two * pi * corner_freq;
let z_freq = omega; let p_freq = omega / dc_boost; let k_analog = one;
let c = two * sample_rate;
let b0 = k_analog * (c + z_freq) / (c + p_freq);
let b1 = k_analog * (-c + z_freq) / (c + p_freq);
let a1 = (-c + p_freq) / (c + p_freq);
Ok(Biquad::new(
[b0, b1, T::zero()],
[T::one(), a1, T::zero()],
))
}