1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//! Ionospheric delay models.
//!
//! This module exposes the single-frequency ionospheric group-delay models used
//! to correct GNSS pseudoranges. The GPS broadcast Klobuchar model and the IONEX
//! vertical-TEC grid path are both reached through the same [`ionosphere_delay`]
//! entry, and the IONEX grid parser is exposed directly as [`Ionex`].
//!
//! All delays returned are group delays and are positive: they increase the
//! measured pseudorange (the carrier-phase advance is the negation of this
//! value). The ionosphere is dispersive, so a delay reported on a carrier other
//! than the model's native L1 is the L1 delay scaled by `(f_l1 / f)^2`.
use PI;
use ;
use crateWgs84Geodetic;
pub use Ionex;
pub use klobuchar_l1_components;
use F_L1;
/// Broadcast Klobuchar alpha/beta coefficients.
///
/// `alpha` are the four coefficients of the cosine-amplitude polynomial (in
/// seconds and seconds-per-semicircle powers); `beta` are the four coefficients
/// of the period polynomial (in seconds and seconds-per-semicircle powers).
/// These are the eight values transmitted in the GPS navigation message.
/// Selects which ionospheric model produces the delay.
/// Single-frequency ionospheric group delay (code, positive meters).
///
/// Dispatches on `model`. `frequency_hz` is the carrier on which the delay is
/// reported; the model is dispersive, so the delay scales as `1 / f^2`. The
/// returned value is positive meters that increase the pseudorange.
/// GPS broadcast Klobuchar ionospheric group delay (positive meters).
///
/// Lower-level entry the Klobuchar arm of [`ionosphere_delay`] calls; exposed so
/// the broadcast model can be used directly. The receiver geodetic
/// latitude/longitude and the satellite azimuth/elevation are converted from
/// radians to the model's published degree boundary, and the GPS second-of-day
/// is taken from `epoch`. The model evaluates the L1 group delay; the result is
/// then scaled to `frequency_hz` by the dispersive `(f_l1 / f)^2` factor.
///
/// Note on bit-exactness: this wrapper converts both angle (radians -> degrees)
/// and time (`epoch` -> GPS second-of-day) at its boundary; both are
/// representation-bound, so the wrapper is NOT bit-exact to a golden expressed
/// in the kernel's native units (degrees and an exact second-of-day) — the
/// difference is at the nanometre level. The 0-ULP parity contract is on the
/// model kernel in those native units; this convenience entry agrees with it to
/// within that conversion bound.
/// GPS broadcast Klobuchar group delay in the model's native input units
/// (positive meters).
///
/// Latitude/longitude and azimuth/elevation are in **degrees** (the model's
/// published boundary) and `t_gps_s` is the GPS **second-of-day** in
/// `[0, 86400)`. This is the bit-exact (0-ULP) entry: it feeds the model kernel
/// directly with no angle or time conversion, so a caller holding native inputs
/// (for example the Elixir wrapper, which already has degrees and an integer
/// time of day) gets exactly the reference result. The L1 delay is scaled to
/// `frequency_hz` by the dispersive `(f_l1 / f)^2` factor.
/// IONEX vertical-TEC-grid slant ionospheric group delay (positive meters).
///
/// Maps the parsed [`Ionex`] vertical-TEC grid to the line of sight in the
/// single-layer-model convention: a single-layer pierce point at the product's
/// shell height, an explicit four-term bilinear VTEC per map, a linear-in-time
/// blend between the two maps bracketing `epoch_j2000_s` (holding the endpoint
/// map outside coverage), the `1/sqrt(1 - s^2)` obliquity factor, and the
/// dispersive `40.3e16 / f^2` frequency scaling.
///
/// The receiver geodetic latitude/longitude come from `receiver` (height is
/// unused: the pierce point rides on the IONEX shell, not the antenna height).
/// The epoch is taken as integer J2000 seconds so it lands exactly on the
/// product's own epoch axis, with no float-rounded time entering the temporal
/// bracket. `frequency_hz` is the carrier on which the delay is reported. The
/// returned value is positive meters that increase the pseudorange.
/// GPS second-of-day in `[0, 86400)` carried by an instant.
///
/// The Klobuchar diurnal term needs the local-solar-time argument, built from
/// the GPS second-of-day. A Julian date's civil day begins at noon, so the
/// midnight day fraction is `(jd + 0.5)` modulo one.
///
/// Precision: for a split-Julian-date instant the second-of-day is
/// `day_fraction * 86400`, and `day_fraction` is itself a rounded binary
/// fraction of a day, so this recovers the second-of-day only to within the
/// float granularity of a day fraction (a few microseconds) — a
/// sub-nanometre-to-nanometre perturbation in the delay. The bit-exact (0-ULP)
/// contract is on the model kernel evaluated at an exact second-of-day, not on
/// this convenience conversion. An integer-nanosecond instant is exact (it
/// reduces by the seconds-per-day modulus).