Packages/MoonriseKit/Sources/SkyEngine/DeltaT.swift
40 lines · 2041 bytes
3 symbols in this file
1import CAstronomy
2import Foundation
3
4/// ΔT = TT − UT1, seconds. Measured and predicted IERS values from 2020, with the difference from
5/// Astronomy Engine's Espenak–Meeus polynomial fading to zero by 2010 and by 2050, so other eras are unchanged.
6enum DeltaT {
7 /// Decimal year and 32.184 s + (TAI − UTC = 37 s) − (UT1 − UTC), from IERS finals2000A as of
8 /// Bulletin A of 15 October 2026. Later entries are its predictions.
9 static let table: [(year: Double, seconds: Double)] = [
10 (2020.0, 69.361), (2021.0, 69.359), (2022.0, 69.295), (2023.0, 69.204), (2024.0, 69.175), (2025.0, 69.138),
11 (2026.0, 69.110), (2026.789, 69.221), (2027.0, 69.308), (2027.584, 69.382), (2027.748, 69.371),
12 ]
13 static let fadeFrom = 2010.0, fadeTo = 2050.0
14
15 /// `ut`: days since J2000, as Astronomy Engine passes it.
16 static func seconds(ut: Double) -> Double {
17 let model = Astronomy_DeltaT_EspenakMeeus(ut)
18 // The polynomial's own year scale.
19 let year = 2000 + (ut - 14) / 365.24217
20 guard year > fadeFrom, year < fadeTo else { return model }
21 let first = table[0], last = table[table.count - 1]
22 if year < first.year {
23 return model + (first.seconds - polynomial(first.year)) * (year - fadeFrom) / (first.year - fadeFrom)
24 }
25 if year > last.year {
26 return model + (last.seconds - polynomial(last.year)) * (fadeTo - year) / (fadeTo - last.year)
27 }
28 let i = table.firstIndex { $0.year >= year }!
29 guard i > 0 else { return first.seconds }
30 let a = table[i - 1], b = table[i]
31 return a.seconds + (b.seconds - a.seconds) * (year - a.year) / (b.year - a.year)
32 }
33
34 static func polynomial(_ year: Double) -> Double {
35 Astronomy_DeltaT_EspenakMeeus((year - 2000) * 365.24217 + 14)
36 }
37
38 /// Astronomy Engine reads ΔT through a global function pointer; `SkyEngine.time` touches this first.
39 static let installed: Void = Astronomy_SetDeltaTFunction { DeltaT.seconds(ut: $0) }
40}