/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hifitime-4.3.0/src/timescale/tcl.rs
Line | Count | Source |
1 | | /* |
2 | | * Hifitime |
3 | | * Copyright (C) 2017-onward Christopher Rabotin <christopher.rabotin@gmail.com> et al. (cf. https://github.com/nyx-space/hifitime/graphs/contributors) |
4 | | * This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at https://mozilla.org/MPL/2.0/. |
7 | | * |
8 | | * Documentation: https://nyxspace.com/ |
9 | | */ |
10 | | |
11 | | use crate::{Duration, TimeUnits}; |
12 | | |
13 | | /// Mean fractional rate of TCL relative to TT. |
14 | | /// |
15 | | /// Paper option iii removes this secular TCL-TT drift when defining TL. |
16 | | /// The paper gives approximately 6.8e-10, i.e. about 58.7 us/day. |
17 | | pub(crate) const TCL_MINUS_TT_MEAN_RATE: f64 = 6.8e-10; |
18 | | |
19 | | /// TL option iii: |
20 | | /// |
21 | | /// ```text |
22 | | /// TL = TCL + Δf * (TCL - TCL0) + const0 |
23 | | /// ``` |
24 | | /// If: |
25 | | /// ```text |
26 | | /// dTCL / dTT = 1 + k |
27 | | /// ``` |
28 | | /// then choosing: |
29 | | /// ```text |
30 | | /// 1 + Δf = 1 / (1 + k) |
31 | | /// |
32 | | /// gives: |
33 | | /// ```text |
34 | | /// dTL / dTT = 1 |
35 | | /// ``` |
36 | | /// so TL has no secular drift relative to TT. |
37 | | pub(crate) const TL_DELTA_F: f64 = -TCL_MINUS_TT_MEAN_RATE / (1.0 + TCL_MINUS_TT_MEAN_RATE); |
38 | | |
39 | | /// Recommended experimental convention: |
40 | | /// ```text |
41 | | /// TL = TCL = TT at T0 |
42 | | /// ``` |
43 | | /// with: |
44 | | /// ```text |
45 | | /// T0 = 1977-01-01T00:00:00 TAI |
46 | | /// = 1977-01-01T00:00:32.184 TT |
47 | | /// ``` |
48 | | pub(crate) const TL_CONST0_S: f64 = 0.0; |
49 | | |
50 | | #[inline] |
51 | 0 | pub fn tt_since_t77_to_tcl_since_t77(tt_since_t77: Duration) -> Duration { |
52 | | // Mean TCL model: |
53 | | // |
54 | | // TCL - TCL0 = (TT - TT0) * (1 + k) |
55 | | // |
56 | | // Do not factor this into tt_since_t77 * (1.0 + k), matching the |
57 | | // style used for TCG/TCB to reduce avoidable rounding noise. |
58 | 0 | tt_since_t77 + tt_since_t77 * TCL_MINUS_TT_MEAN_RATE |
59 | 0 | } |
60 | | |
61 | | #[inline] |
62 | 0 | pub fn tcl_since_t77_to_tt_since_t77(tcl_since_t77: Duration) -> Duration { |
63 | | // Inverse of: |
64 | | // |
65 | | // TCL = TT * (1 + k) |
66 | | // |
67 | | // so: |
68 | | // |
69 | | // TT = TCL / (1 + k) |
70 | | // = TCL * (1 - k / (1 + k)) |
71 | 0 | tcl_since_t77 - tcl_since_t77 * (TCL_MINUS_TT_MEAN_RATE / (1.0 + TCL_MINUS_TT_MEAN_RATE)) |
72 | 0 | } |
73 | | |
74 | | #[inline] |
75 | 0 | pub fn tcl_since_t77_to_tl_since_t77(tcl_since_t77: Duration) -> Duration { |
76 | | // Option iii: |
77 | | // |
78 | | // TL = TCL + Δf * (TCL - TCL0) + const0 |
79 | | // |
80 | | // with const0 = 0 and TCL0 = T0. |
81 | 0 | tcl_since_t77 + tcl_since_t77 * TL_DELTA_F + TL_CONST0_S.seconds() |
82 | 0 | } |
83 | | |
84 | | #[inline] |
85 | 0 | pub fn tl_since_t77_to_tcl_since_t77(tl_since_t77: Duration) -> Duration { |
86 | | // Since TL = TCL / (1 + k), the inverse is: |
87 | | // |
88 | | // TCL = TL * (1 + k) |
89 | | // |
90 | | // const0 is zero in this convention. |
91 | 0 | let tl_minus_const0 = tl_since_t77 - TL_CONST0_S.seconds(); |
92 | 0 | tl_minus_const0 + tl_minus_const0 * TCL_MINUS_TT_MEAN_RATE |
93 | 0 | } |
94 | | |
95 | | #[cfg(test)] |
96 | | mod ut_tcl { |
97 | | use super::*; |
98 | | use crate::{Epoch, TimeScale, TimeUnits}; |
99 | | |
100 | | /// This test uses the private prime_epoch_offset, hence its definition here. |
101 | | #[test] |
102 | | fn tcl_accumulates_mean_drift_from_tt() { |
103 | | let tt = Epoch::from_gregorian_at_midnight(2024, 2, 29, TimeScale::TT); |
104 | | let tcl = tt.to_time_scale(TimeScale::TCL); |
105 | | |
106 | | let tt_since_t77 = tt.duration - TimeScale::TCL.prime_epoch_offset(); |
107 | | let expected = tt_since_t77 * TCL_MINUS_TT_MEAN_RATE; |
108 | | |
109 | | let actual = tcl.duration - tt_since_t77; |
110 | | |
111 | | assert!( |
112 | | (actual - expected).abs() <= 1.nanoseconds(), |
113 | | "actual={actual}, expected={expected}" |
114 | | ); |
115 | | } |
116 | | } |