Skip to main content

deep_time/dt/
et.rs

1use crate::{Dt, Real, Scale, TT_TAI_OFFSET, sin};
2
3impl Dt {
4    /// NAIF/SPICE simplified ET–TT periodic correction (only the ~1.657 ms term).
5    pub const fn et_minus_tt(seconds_since_j2000_tt: Real) -> Real {
6        const M0: Real = f!(6.239996);
7        const M1: Real = f!(1.99096871e-7);
8        const EB: Real = f!(0.01671);
9        const K: Real = f!(0.001657);
10
11        let m = M0 + M1 * seconds_since_j2000_tt;
12        let e = m + EB * sin(m);
13        K * sin(e)
14    }
15
16    /// Converts a TAI [`Dt`] to ET (NAIF/SPICE simplified model).
17    pub const fn tai_to_et(tai: Dt) -> Dt {
18        let tt = tai.add(TT_TAI_OFFSET);
19        let correction = Self::et_minus_tt(tt.to_sec_f());
20        tt.add(Dt::from_sec_f(correction, Scale::TAI))
21    }
22
23    /// Converts an ET [`Dt`] to TAI (NAIF/SPICE simplified model).
24    pub const fn et_to_tai(et: Dt) -> Dt {
25        // Initial guess: subtract the constant TT–TAI offset
26        let mut tt = et.sub(TT_TAI_OFFSET);
27
28        // Fixed-point iteration: TT_{n+1} = ET − P(TT_n)
29        let mut i = 0u8;
30        while i < 8 {
31            let p = Self::et_minus_tt(tt.to_sec_f());
32            let new_tt = et.sub(Dt::from_sec_f(p, Scale::TAI));
33
34            // Early exit when change is smaller than ~1 attosecond
35            let delta = new_tt.to_diff_raw(tt);
36            if delta.to_attos().abs() < 1 {
37                tt = new_tt;
38                break;
39            }
40
41            tt = new_tt;
42            i += 1;
43        }
44
45        tt.sub(TT_TAI_OFFSET)
46    }
47}