use fixed::types::I16F16;
use crate::park_clarke::TwoPhaseReferenceFrame;
pub trait Modulation {
fn modulate(value: TwoPhaseReferenceFrame) -> [I16F16; 3];
fn as_compare_value<const MAX: u16>(value: TwoPhaseReferenceFrame) -> [u16; 3] {
Self::modulate(value).map(|val| {
(((val + I16F16::from_num(1)) * (MAX as i32 + 1)) / 2)
.round()
.saturating_to_num::<u16>()
.clamp(0, MAX)
})
}
}
pub struct SpaceVector;
impl Modulation for SpaceVector {
fn modulate(value: TwoPhaseReferenceFrame) -> [I16F16; 3] {
let sqrt_3_alpha = I16F16::SQRT_3 * value.alpha;
let beta = value.beta;
let x = beta;
let y = (beta + sqrt_3_alpha) / 2;
let z = (beta - sqrt_3_alpha) / 2;
let sector: u8 = match (x.is_positive(), y.is_positive(), z.is_positive()) {
(true, true, false) => 1,
(_, true, true) => 2,
(true, false, true) => 3,
(false, false, true) => 4,
(_, false, false) => 5,
(false, true, false) => 6,
};
let (ta, tb, tc);
match sector {
1 | 4 => {
ta = x - z;
tb = x + z;
tc = -x + z;
}
2 | 5 => {
ta = y - z;
tb = y + z;
tc = -y - z;
}
3 | 6 => {
ta = y - x;
tb = -y + x;
tc = -y - x;
}
_ => unreachable!("invalid sector"),
}
[ta, tb, tc]
}
}
pub struct Sinusoidal;
impl Modulation for Sinusoidal {
fn modulate(value: TwoPhaseReferenceFrame) -> [I16F16; 3] {
let voltages = crate::park_clarke::inverse_clarke(value);
[voltages.a, voltages.b, voltages.c]
}
}
pub struct Trapezoidal;
impl Modulation for Trapezoidal {
fn modulate(value: TwoPhaseReferenceFrame) -> [I16F16; 3] {
let voltages = crate::park_clarke::inverse_clarke(value);
[
(voltages.a * 2).round_to_zero().signum(),
(voltages.b * 2).round_to_zero().signum(),
(voltages.c * 2).round_to_zero().signum(),
]
}
}
pub struct Square;
impl Modulation for Square {
fn modulate(value: TwoPhaseReferenceFrame) -> [I16F16; 3] {
let voltages = crate::park_clarke::inverse_clarke(value);
[
voltages.a.signum(),
voltages.b.signum(),
voltages.c.signum(),
]
}
}