use crate::math::{SVector6, oe_to_radians, wrap_to_2pi};
use crate::{AngleFormat, DEG2RAD, RAD2DEG};
pub fn state_oe_to_roe(
oe_chief: SVector6,
oe_deputy: SVector6,
angle_format: AngleFormat,
) -> SVector6 {
let oec = oe_to_radians(oe_chief, angle_format);
let oed = oe_to_radians(oe_deputy, angle_format);
let ac = oec[0];
let ad = oed[0];
let ec = oec[1];
let ed = oed[1];
let ic = oec[2];
let id = oed[2];
let raan_c = oec[3];
let raan_d = oed[3];
let ωc = oec[4];
let ωd = oed[4];
let m_c = oec[5];
let m_d = oed[5];
let uc = m_c + ωc;
let ud = m_d + ωd;
let da = (ad - ac) / ac;
let d_lambda = (ud - uc) + (raan_d - raan_c) * ic.cos();
let dex = ed * ωd.cos() - ec * ωc.cos();
let dey = ed * ωd.sin() - ec * ωc.sin();
let dix = id - ic;
let diy = (raan_d - raan_c) * ic.sin();
let d_lambda = wrap_to_2pi(d_lambda);
let diy = wrap_to_2pi(diy);
let dix = wrap_to_2pi(dix);
match angle_format {
AngleFormat::Degrees => SVector6::new(
da,
d_lambda * RAD2DEG,
dex,
dey,
dix * RAD2DEG,
diy * RAD2DEG,
),
AngleFormat::Radians => SVector6::new(da, d_lambda, dex, dey, dix, diy),
}
}
pub fn state_roe_to_oe(oe_chief: SVector6, roe: SVector6, angle_format: AngleFormat) -> SVector6 {
let oec = oe_to_radians(oe_chief, angle_format);
let ac = oec[0];
let ec = oec[1];
let ic = oec[2];
let raan_c = oec[3];
let ωc = oec[4];
let m_c = oec[5];
let da = roe[0];
let d_lambda = match angle_format {
AngleFormat::Degrees => roe[1] * DEG2RAD,
AngleFormat::Radians => roe[1],
};
let dix = match angle_format {
AngleFormat::Degrees => roe[4] * DEG2RAD,
AngleFormat::Radians => roe[4],
};
let diy = match angle_format {
AngleFormat::Degrees => roe[5] * DEG2RAD,
AngleFormat::Radians => roe[5],
};
let dex = roe[2];
let dey = roe[3];
let ad = ac * (1.0 + da);
let ed = ((dex + ec * ωc.cos()).powi(2) + (dey + ec * ωc.sin()).powi(2)).sqrt();
let idep = dix + ic;
let raan_d = raan_c + (diy / ic.sin());
let ωd = (dey + ec * ωc.sin()).atan2(dex + ec * ωc.cos());
let m_d = d_lambda - ωd + m_c + ωc - (raan_d - raan_c) * ic.cos();
let raan_d = wrap_to_2pi(raan_d);
let ωd = wrap_to_2pi(ωd);
let idep = wrap_to_2pi(idep);
let m_d = wrap_to_2pi(m_d);
match angle_format {
AngleFormat::Degrees => SVector6::new(
ad,
ed,
idep * RAD2DEG,
raan_d * RAD2DEG,
ωd * RAD2DEG,
m_d * RAD2DEG,
),
AngleFormat::Radians => SVector6::new(ad, ed, idep, raan_d, ωd, m_d),
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
use crate::constants::R_EARTH;
use approx::assert_abs_diff_eq;
#[test]
fn test_state_oe_to_roe() {
let oe_chief = SVector6::new(R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0);
let oe_deputy = SVector6::new(R_EARTH + 701e3, 0.0015, 97.85, 15.05, 30.05, 45.05);
let roe = state_oe_to_roe(oe_chief, oe_deputy, AngleFormat::Degrees);
assert_abs_diff_eq!(roe[0], 1.412_801_276_516_814e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[1], 9.321_422_137_829_084e-2, epsilon = 1e-12);
assert_abs_diff_eq!(roe[2], 4.323_577_088_687_794e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[3], 2.511_333_388_799_496e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[4], 5.0e-2, epsilon = 1e-12);
assert_abs_diff_eq!(roe[5], 4.953_739_202_357_54e-2, epsilon = 1e-12);
}
#[test]
fn test_state_roe_to_oe() {
let oe_chief = SVector6::new(R_EARTH + 700e3, 0.001, 97.8, 15.0, 30.0, 45.0);
let oe_deputy_orig = SVector6::new(R_EARTH + 701e3, 0.0015, 97.85, 15.05, 30.05, 45.05);
let roe = state_oe_to_roe(oe_chief, oe_deputy_orig, AngleFormat::Degrees);
let oe_deputy = state_roe_to_oe(oe_chief, roe, AngleFormat::Degrees);
assert_abs_diff_eq!(oe_deputy[0], R_EARTH + 701e3, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[1], 0.0015, epsilon = 1e-9);
assert_abs_diff_eq!(oe_deputy[2], 97.85, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[3], 15.05, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[4], 30.05, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[5], 45.05, epsilon = 1e-6);
}
#[test]
fn test_state_oe_to_roe_radians() {
use crate::constants::DEG2RAD;
let oe_chief = SVector6::new(
R_EARTH + 700e3,
0.001,
97.8 * DEG2RAD,
15.0 * DEG2RAD,
30.0 * DEG2RAD,
45.0 * DEG2RAD,
);
let oe_deputy = SVector6::new(
R_EARTH + 701e3,
0.0015,
97.85 * DEG2RAD,
15.05 * DEG2RAD,
30.05 * DEG2RAD,
45.05 * DEG2RAD,
);
let roe = state_oe_to_roe(oe_chief, oe_deputy, AngleFormat::Radians);
assert_abs_diff_eq!(roe[0], 1.412_801_276_516_814e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[1], 9.321_422_137_829_084e-2 * DEG2RAD, epsilon = 1e-12);
assert_abs_diff_eq!(roe[2], 4.323_577_088_687_794e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[3], 2.511_333_388_799_496e-4, epsilon = 1e-12);
assert_abs_diff_eq!(roe[4], 5.0e-2 * DEG2RAD, epsilon = 1e-12);
assert_abs_diff_eq!(roe[5], 4.953_739_202_357_54e-2 * DEG2RAD, epsilon = 1e-12);
}
#[test]
fn test_state_roe_to_oe_radians() {
use crate::constants::DEG2RAD;
let oe_chief = SVector6::new(
R_EARTH + 700e3,
0.001,
97.8 * DEG2RAD,
15.0 * DEG2RAD,
30.0 * DEG2RAD,
45.0 * DEG2RAD,
);
let oe_deputy_orig = SVector6::new(
R_EARTH + 701e3,
0.0015,
97.85 * DEG2RAD,
15.05 * DEG2RAD,
30.05 * DEG2RAD,
45.05 * DEG2RAD,
);
let roe = state_oe_to_roe(oe_chief, oe_deputy_orig, AngleFormat::Radians);
let oe_deputy = state_roe_to_oe(oe_chief, roe, AngleFormat::Radians);
assert_abs_diff_eq!(oe_deputy[0], R_EARTH + 701e3, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[1], 0.0015, epsilon = 1e-9);
assert_abs_diff_eq!(oe_deputy[2], 97.85 * DEG2RAD, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[3], 15.05 * DEG2RAD, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[4], 30.05 * DEG2RAD, epsilon = 1e-6);
assert_abs_diff_eq!(oe_deputy[5], 45.05 * DEG2RAD, epsilon = 1e-6);
}
}