lox_frames/iers/
nutation.rs1use std::ops::Add;
10
11use glam::DMat3;
12use lox_core::units::Angle;
13use lox_test_utils::ApproxEq;
14use lox_time::{
15 Time,
16 time_scales::{Tdb, Tt},
17};
18
19use crate::iers::{Corrections, Iau2000Model, ReferenceSystem, ecliptic::MeanObliquity};
20
21mod iau1980;
22mod iau2000;
23mod iau2006;
24
25impl ReferenceSystem {
26 pub fn nutation(&self, time: Time<Tdb>) -> Nutation {
27 match self {
28 ReferenceSystem::Iers1996 => Nutation::iau1980(time),
29 ReferenceSystem::Iers2003(model) => match model {
30 Iau2000Model::A => Nutation::iau2000a(time),
31 Iau2000Model::B => Nutation::iau2000b(time),
32 },
33 ReferenceSystem::Iers2010 => Nutation::iau2006a(time),
34 }
35 }
36
37 pub fn nutation_matrix(&self, time: Time<Tdb>, corr: Corrections) -> DMat3 {
38 match self {
39 ReferenceSystem::Iers1996 => {
40 let mut nut = self.nutation(time);
41 nut += corr;
42 nut.nutation_matrix(self.mean_obliquity(time.with_scale(Tt)))
43 }
44 ReferenceSystem::Iers2003(_) | ReferenceSystem::Iers2010 => {
45 let tt = time.with_scale(Tt);
46 let epsa = self.mean_obliquity(tt);
47 let mut nut = self.nutation(time);
48 let rpb = self.bias_precession_matrix(tt);
49
50 nut += self.ecliptic_corrections(corr, nut, epsa, rpb);
51
52 nut.nutation_matrix(epsa)
53 }
54 }
55 }
56}
57
58#[derive(Debug, Default, Clone, Copy, PartialEq, ApproxEq)]
60pub struct Nutation {
61 pub dpsi: Angle,
63 pub deps: Angle,
65}
66
67impl Nutation {
68 pub fn nutation_matrix(&self, epsa: MeanObliquity) -> DMat3 {
69 let epsa = epsa.0;
70 let rot1 = epsa.rotation_x();
71 let rot2 = (-self.dpsi).rotation_z();
72 let rot3 = (-(self.deps + epsa)).rotation_x();
73 rot3 * rot2 * rot1
74 }
75}
76
77impl Add for Nutation {
78 type Output = Self;
79
80 fn add(self, rhs: Self) -> Self::Output {
81 Self {
82 dpsi: self.dpsi + rhs.dpsi,
83 deps: self.deps + rhs.deps,
84 }
85 }
86}
87
88impl Add<&Self> for Nutation {
89 type Output = Self;
90
91 fn add(self, rhs: &Self) -> Self::Output {
92 Nutation {
93 dpsi: self.dpsi + rhs.dpsi,
94 deps: self.deps + rhs.deps,
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use lox_core::units::AngleUnits;
102 use lox_test_utils::assert_approx_eq;
103
104 use super::*;
105
106 #[test]
107 fn test_nutation_matrix() {
108 let nut = Nutation {
109 dpsi: -9.630_909_107_115_582e-6.rad(),
110 deps: 4.063_239_174_001_679e-5.rad(),
111 };
112 let obl = MeanObliquity(Angle::new(0.409_078_976_335_651));
113 let exp = DMat3::from_cols_array(&[
114 0.999_999_999_953_622_8,
115 8.836_239_320_236_25e-6,
116 3.830_833_447_458_252e-6,
117 -8.836_083_657_016_69e-6,
118 0.999_999_999_135_465_4,
119 -4.063_240_865_361_857_4e-5,
120 -3.831_192_481_833_385_5e-6,
121 4.063_237_480_216_934e-5,
122 0.999_999_999_167_166_1,
123 ])
124 .transpose();
125 let act = nut.nutation_matrix(obl);
126 assert_approx_eq!(act, exp, rtol <= 1e-12);
127 }
128}