0.4.1
Loading...
Searching...
No Matches
GPSEphemeris.cpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#include "GPSEphemeris.hpp"
10
13
14#include "util/Logger.hpp"
15
16namespace NAV
17{
18
21
23 const size_t& IODE, const size_t& IODC,
24 const std::array<double, 3>& a,
25 const double& sqrt_A, const double& e, const double& i_0, const double& Omega_0, const double& omega, const double& M_0,
26 const double& delta_n, const double& Omega_dot, const double& i_dot, const double& Cus, const double& Cuc,
27 const double& Cis, const double& Cic, const double& Crs, const double& Crc,
28 const double& svAccuracy, uint8_t svHealth,
29 uint8_t L2ChannelCodes, bool L2DataFlagPCode,
30 const double& T_GD,
31 const double& fitInterval)
33 toc(toc),
34 toe(toe),
35 IODE(IODE),
36 IODC(IODC),
37 a(a),
39 e(e),
40 i_0(i_0),
42 omega(omega),
43 M_0(M_0),
46 i_dot(i_dot),
47 Cus(Cus),
48 Cuc(Cuc),
49 Cis(Cis),
50 Cic(Cic),
51 Crs(Crs),
52 Crc(Crc),
57 T_GD(T_GD),
59
60#ifdef TESTING
61
62GPSEphemeris::GPSEphemeris(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, double second, double svClockBias, double svClockDrift, double svClockDriftRate,
63 double IODE, double Crs, double delta_n, double M_0,
64 double Cuc, double e, double Cus, double sqrt_A,
65 double Toe, double Cic, double Omega_0, double Cis,
66 double i_0, double Crc, double omega, double Omega_dot,
67 double i_dot, double L2ChannelCodes, double GPSWeek, double L2DataFlagPCode,
68 double svAccuracy, double svHealth, double T_GD, double IODC,
69 double /* TransmissionTimeOfMessage */, double fitInterval, double /* spare1 */, double /* spare2 */)
70 : SatNavData(SatNavData::GPSEphemeris, InsTime(year, month, day, hour, minute, second, SatelliteSystem(GPS).getTimeSystem())),
71 toc(refTime),
72 toe(InsTime(0, static_cast<int32_t>(GPSWeek), Toe, SatelliteSystem(GPS).getTimeSystem())),
73 IODE(static_cast<size_t>(IODE)),
74 IODC(static_cast<size_t>(IODC)),
75 a({ svClockBias, svClockDrift, svClockDriftRate }),
76 sqrt_A(sqrt_A),
77 e(e),
78 i_0(i_0),
79 Omega_0(Omega_0),
80 omega(omega),
81 M_0(M_0),
82 delta_n(delta_n),
83 Omega_dot(Omega_dot),
84 i_dot(i_dot),
85 Cus(Cus),
86 Cuc(Cuc),
87 Cis(Cis),
88 Cic(Cic),
89 Crs(Crs),
90 Crc(Crc),
91 svAccuracy(svAccuracy),
92 svHealth(static_cast<uint8_t>(svHealth)),
93 L2ChannelCodes(static_cast<uint8_t>(L2ChannelCodes)),
94 L2DataFlagPCode(static_cast<bool>(L2DataFlagPCode)),
95 T_GD(T_GD),
96 fitInterval(fitInterval)
97{}
98
99#endif
100
101Clock::Corrections GPSEphemeris::calcClockCorrections(const InsTime& recvTime, double dist, const Frequency& freq) const
102{
103 LOG_DATA("Calc Sat Clock corrections at receiver time {}", recvTime.toGPSweekTow());
104 // Earth gravitational constant [m³/s²] (WGS 84 value of the earth's gravitational constant for GPS user)
105 const auto mu = InsConst::GPS::MU;
106 // Relativistic constant F for clock corrections [s/√m] (-2*√µ/c²)
107 const auto F = InsConst::GPS::F;
108
109 LOG_DATA(" toe {} [{}] (Time of ephemeris)", toe.toGPSweekTow(), toe.toYMDHMS(GPST));
110
111 const auto A = sqrt_A * sqrt_A; // Semi-major axis [m]
112 LOG_DATA(" A {} [m] (Semi-major axis)", A);
113 auto n_0 = std::sqrt(mu / std::pow(A, 3)); // Computed mean motion [rad/s]
114 LOG_DATA(" n_0 {} [rad/s] (Computed mean motion)", n_0);
115 auto n = n_0 + delta_n; // Corrected mean motion [rad/s]
116 LOG_DATA(" n {} [rad/s] (Corrected mean motion)", n);
117
118 // Time at transmission
119 InsTime transTime0 = recvTime - std::chrono::duration<double>(dist / InsConst::C);
120
121 InsTime transTime = transTime0;
122 LOG_DATA(" Iterating Time at transmission");
123 double dt_sv = 0.0;
124 double clkDrift = 0.0;
125
126 for (size_t i = 0; i < 2; i++)
127 {
128 LOG_DATA(" [{}]", i);
129 LOG_DATA(" transTime {} [{}] (Time at transmission)", transTime.toGPSweekTow(), transTime.toYMDHMS(GPST));
130
131 // [s]
132 auto t_minus_toc = static_cast<double>((transTime - toc).count());
133 LOG_DATA(" transTime - toc {} [s]", t_minus_toc);
134
135 // Time difference from ephemeris reference epoch [s]
136 double t_k = static_cast<double>((transTime - toe).count());
137 LOG_DATA(" transTime - toe {} [s] (t_k = Time difference from ephemeris reference epoch)", t_k);
138
139 // Mean anomaly [rad]
140 auto M_k = M_0 + n * t_k;
141 LOG_DATA(" M_k {} [s] (Mean anomaly)", M_k);
142
143 // Eccentric anomaly [rad]
144 double E_k = M_k;
145 double E_k_old = 0.0;
146
147 for (size_t i = 0; std::abs(E_k - E_k_old) > 1e-13 && i < 10; i++)
148 {
149 E_k_old = E_k; // Kepler’s equation ( Mk = E_k − e sin E_k ) may be solved for Eccentric anomaly (E_k) by iteration:
150 E_k = M_k + e * sin(E_k);
151 }
152
153 // Relativistic correction term [s]
154 double dt_r = F * e * sqrt_A * std::sin(E_k);
155 LOG_DATA(" dt_r {} [s] (Relativistic correction term)", dt_r);
156
157 // SV PRN code phase time offset [s]
158 dt_sv = a[0] + a[1] * t_minus_toc + a[2] * std::pow(t_minus_toc, 2) + dt_r;
159
160 // See IS-GPS-200M GPS ICD L1/L2, ch. 20.3.3.3.3.2, p.99
161 // See IS-GPS-705J GPS ICD L5, ch. 20.3.3.3.2.1, p.78
162 dt_sv -= freq & (G01 | G05) ? T_GD : ratioFreqSquared(G01, freq, -128, -128) * T_GD;
163
164 LOG_DATA(" dt_sv {} [s] (SV PRN code phase time offset)", dt_sv);
165
166 // Groves ch. 9.3.1, eq. 9.78, p. 391
167 clkDrift = a[1] + a[2] / 2.0 * t_minus_toc;
168
169 // Correct transmit time for the satellite clock bias
170 transTime = transTime0 - std::chrono::duration<double>(dt_sv);
171 }
172 LOG_DATA(" transTime {} [{}] (Time at transmission)", transTime.toGPSweekTow(), transTime.toYMDHMS(GPST));
173
174 return { .transmitTime = transTime, .bias = dt_sv, .drift = clkDrift };
175}
176
178{
179 Eigen::Vector3d e_pos = Eigen::Vector3d::Zero();
180 Eigen::Vector3d e_vel = Eigen::Vector3d::Zero();
181 Eigen::Vector3d e_accel = Eigen::Vector3d::Zero();
182
183 LOG_DATA("Calc Sat Position at transmit time {}", transTime.toGPSweekTow());
184 // Earth gravitational constant [m³/s²] (WGS 84 value of the earth's gravitational constant for GPS user)
185 const auto mu = InsConst::GPS::MU;
186 // Earth angular velocity [rad/s] (WGS 84 value of the earth's rotation rate)
187 const auto Omega_e_dot = InsConst::GPS::omega_ie;
188
189 LOG_DATA(" toe {} (Time of ephemeris)", toe.toGPSweekTow());
190
191 const auto A = sqrt_A * sqrt_A; // Semi-major axis [m]
192 LOG_DATA(" A {} [m] (Semi-major axis)", A);
193 auto n_0 = std::sqrt(mu / std::pow(A, 3)); // Computed mean motion [rad/s]
194 LOG_DATA(" n_0 {} [rad/s] (Computed mean motion)", n_0);
195 auto n = n_0 + delta_n; // Corrected mean motion [rad/s]
196 LOG_DATA(" n {} [rad/s] (Corrected mean motion)", n);
197
198 // Eccentric anomaly [rad]
199 double E_k = 0.0;
200
201 // Time difference from ephemeris reference epoch [s]
202 double t_k = static_cast<double>((transTime - toe).count());
203 LOG_DATA(" t_k {} [s] (Time difference from ephemeris reference epoch)", t_k);
204
205 // Mean anomaly [rad]
206 auto M_k = M_0 + n * t_k;
207 LOG_DATA(" M_k {} [s] (Mean anomaly)", M_k);
208
209 E_k = M_k; // Initial Value [rad]
210 double E_k_old = 0.0;
211 LOG_DATA(" Iterating E_k");
212 LOG_DATA(" E_k {} [rad] (Eccentric anomaly)", E_k);
213 for (size_t i = 0; std::abs(E_k - E_k_old) > 1e-13 && i < 10; i++)
214 {
215 E_k_old = E_k; // Kepler’s equation ( Mk = E_k − e sin E_k ) may be solved for Eccentric anomaly (E_k) by iteration:
216 E_k = E_k + (M_k - E_k + e * std::sin(E_k)) / (1 - e * std::cos(E_k)); // - Refined Value, minimum of three iterations, (j=1,2,3)
217 LOG_DATA(" E_k {} [rad] (Eccentric anomaly)", E_k); // - Final Value (radians)
218 }
219
220 // auto v_k = 2.0 * std::atan(std::sqrt((1.0 + e) / (1.0 - e)) * std::tan(E_k / 2.0)); // True Anomaly (unambiguous quadrant) [rad] (GPS ICD algorithm)
221 // auto v_k = std::atan2(std::sqrt(1 - e * e) * std::sin(E_k) / (1 - e * std::cos(E_k)), (std::cos(E_k) - e) / (1 - e * std::cos(E_k))); // True Anomaly [rad] (GALILEO ICD algorithm)
222 auto v_k = std::atan2(std::sqrt(1 - e * e) * std::sin(E_k), (std::cos(E_k) - e)); // True Anomaly [rad] // simplified, since the denominators cancel out
223 LOG_DATA(" v_k {} [rad] (True Anomaly (unambiguous quadrant))", v_k);
224 auto Phi_k = v_k + omega; // Argument of Latitude [rad]
225 LOG_DATA(" Phi_k {} [rad] (Argument of Latitude)", Phi_k);
226
227 // Second Harmonic Perturbations
228 auto delta_u_k = Cus * std::sin(2 * Phi_k) + Cuc * std::cos(2 * Phi_k); // Argument of Latitude Correction [rad]
229 LOG_DATA(" delta_u_k {} [rad] (Argument of Latitude Correction)", delta_u_k);
230 auto delta_r_k = Crs * std::sin(2 * Phi_k) + Crc * std::cos(2 * Phi_k); // Radius Correction [m]
231 LOG_DATA(" delta_r_k {} [m] (Radius Correction)", delta_r_k);
232 auto delta_i_k = Cis * std::sin(2 * Phi_k) + Cic * std::cos(2 * Phi_k); // Inclination Correction [rad]
233 LOG_DATA(" delta_i_k {} [rad] (Inclination Correction)", delta_i_k);
234
235 auto u_k = Phi_k + delta_u_k; // Corrected Argument of Latitude [rad]
236 LOG_DATA(" u_k {} [rad] (Corrected Argument of Latitude)", u_k);
237 auto r_k = A * (1 - e * std::cos(E_k)) + delta_r_k; // Corrected Radius [m]
238 LOG_DATA(" r_k {} [m] (Corrected Radius)", r_k);
239 auto i_k = i_0 + delta_i_k + i_dot * t_k; // Corrected Inclination [rad]
240 LOG_DATA(" i_k {} [rad] (Corrected Inclination)", i_k);
241
242 auto x_k_op = r_k * std::cos(u_k); // Position in orbital plane [m]
243 LOG_DATA(" x_k_op {} [m] (Position in orbital plane)", x_k_op);
244 auto y_k_op = r_k * std::sin(u_k); // Position in orbital plane [m]
245 LOG_DATA(" y_k_op {} [m] (Position in orbital plane)", y_k_op);
246
247 // Corrected longitude of ascending node [rad]
248 auto Omega_k = Omega_0 + (Omega_dot - Omega_e_dot) * t_k - Omega_e_dot * static_cast<double>(toe.toGPSweekTow().tow);
249 LOG_DATA(" Omega_k {} [rad] (Corrected longitude of ascending node)", Omega_k);
250
251 // Earth-fixed x coordinates [m]
252 auto x_k = x_k_op * std::cos(Omega_k) - y_k_op * std::cos(i_k) * std::sin(Omega_k);
253 LOG_DATA(" x_k {} [m] (Earth-fixed x coordinates)", x_k);
254 // Earth-fixed y coordinates [m]
255 auto y_k = x_k_op * std::sin(Omega_k) + y_k_op * std::cos(i_k) * std::cos(Omega_k);
256 LOG_DATA(" y_k {} [m] (Earth-fixed y coordinates)", y_k);
257 // Earth-fixed z coordinates [m]
258 auto z_k = y_k_op * std::sin(i_k);
259 LOG_DATA(" z_k {} [m] (Earth-fixed z coordinates)", z_k);
260
261 e_pos = Eigen::Vector3d{ x_k, y_k, z_k };
262
263 if (calc & Calc_Velocity || calc & Calc_Acceleration)
264 {
265 // Eccentric Anomaly Rate [rad/s]
266 auto E_k_dot = n / (1 - e * std::cos(E_k));
267 // True Anomaly Rate [rad/s]
268 auto v_k_dot = E_k_dot * std::sqrt(1 - e * e) / (1 - e * std::cos(E_k));
269 // Corrected Inclination Angle Rate [rad/s]
270 auto i_k_dot = i_dot + 2 * v_k_dot * (Cis * std::cos(2 * Phi_k) - Cic * std::sin(2 * Phi_k));
271 // Corrected Argument of Latitude Rate [rad/s]
272 auto u_k_dot = v_k_dot + 2 * v_k_dot * (Cus * std::cos(2 * Phi_k) - Cuc * std::sin(2 * Phi_k));
273 // Corrected Radius Rate [m/s]
274 auto r_k_dot = e * A * E_k_dot * std::sin(E_k) + 2 * v_k_dot * (Crs * std::cos(2 * Phi_k) - Crc * std::sin(2 * Phi_k));
275 // Longitude of Ascending Node Rate [rad/s]
276 auto Omega_k_dot = Omega_dot - Omega_e_dot;
277 // In-plane x velocity [m/s]
278 auto vx_k_op = r_k_dot * std::cos(u_k) - r_k * u_k_dot * std::sin(u_k);
279 // In-plane y velocity [m/s]
280 auto vy_k_op = r_k_dot * std::sin(u_k) + r_k * u_k_dot * std::cos(u_k);
281 // Earth-Fixed x velocity [m/s]
282 auto vx_k = -x_k_op * Omega_k_dot * std::sin(Omega_k) + vx_k_op * std::cos(Omega_k) - vy_k_op * std::sin(Omega_k) * std::cos(i_k)
283 - y_k_op * (Omega_k_dot * std::cos(Omega_k) * std::cos(i_k) - i_k_dot * std::sin(Omega_k) * std::sin(i_k));
284 // Earth-Fixed y velocity [m/s]
285 auto vy_k = x_k_op * Omega_k_dot * std::cos(Omega_k) + vx_k_op * std::sin(Omega_k) + vy_k_op * std::cos(Omega_k) * std::cos(i_k)
286 - y_k_op * (Omega_k_dot * std::sin(Omega_k) * std::cos(i_k) + i_k_dot * std::cos(Omega_k) * std::sin(i_k));
287 // Earth-Fixed z velocity [m/s]
288 auto vz_k = vy_k_op * std::sin(i_k) + y_k_op * i_k_dot * std::cos(i_k);
289
290 if (calc & Calc_Velocity)
291 {
292 e_vel = Eigen::Vector3d{ vx_k, vy_k, vz_k };
293 }
294
295 if (calc & Calc_Acceleration)
296 {
297 // Oblate Earth acceleration Factor [m/s^2]
298 auto F = -(3.0 / 2.0) * InsConst::GPS::J2 * (mu / std::pow(r_k, 2)) * std::pow(InsConst::GPS::R_E / r_k, 2);
299 // Earth-Fixed x acceleration [m/s^2]
300 auto ax_k = -mu * (x_k / std::pow(r_k, 3)) + F * ((1.0 - 5.0 * std::pow(z_k / r_k, 2)) * (x_k / r_k))
301 + 2 * vy_k * Omega_e_dot + x_k * std::pow(Omega_e_dot, 2);
302 // Earth-Fixed y acceleration [m/s^2]
303 auto ay_k = -mu * (y_k / std::pow(r_k, 3)) + F * ((1.0 - 5.0 * std::pow(z_k / r_k, 2)) * (y_k / r_k))
304 + 2 * vx_k * Omega_e_dot + y_k * std::pow(Omega_e_dot, 2);
305 // Earth-Fixed z acceleration [m/s^2]
306 auto az_k = -mu * (z_k / std::pow(r_k, 3)) + F * ((3.0 - 5.0 * std::pow(z_k / r_k, 2)) * (z_k / r_k));
307
308 e_accel = Eigen::Vector3d{ ax_k, ay_k, az_k };
309 }
310 }
311
312 return { .e_pos = e_pos,
313 .e_vel = e_vel,
314 .e_accel = e_accel };
315}
316
318{
319 return svHealth == 0;
320}
321
323{
324 return std::pow(svAccuracy, 2);
325}
326
327} // namespace NAV
Holds all Constants.
GNSS helper functions.
GPS Ephemeris information.
Utility class for logging to console and file.
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
Broadcasted ephemeris message data.
double Crc
Amplitude of the cosine harmonic correction term to the orbit radius [m].
double Cuc
Amplitude of the cosine harmonic correction term to the argument of latitude [rad].
bool isHealthy() const final
Checks whether the signal is healthy.
double i_dot
Rate of change of inclination [rad/s].
double svAccuracy
SV accuracy [m].
size_t IODC
Issue of Data, Clock.
double Cic
Amplitude of the cosine harmonic correction term to the angle of inclination [rad].
double T_GD
Estimated Group Delay Differential. L1 and L2 correction term [s].
double Cus
Amplitude of the sine harmonic correction term to the argument of latitude [rad].
double i_0
Inclination angle at reference time [rad].
Corrections calcClockCorrections(const InsTime &recvTime, double dist, const Frequency &freq) const final
Calculates clock bias and drift of the satellite.
double delta_n
Mean motion difference from computed value [rad/s].
bool L2DataFlagPCode
Data Flag for L2 P-Code.
std::array< double, 3 > a
uint8_t L2ChannelCodes
Indicate which code(s) is (are) commanded ON for the in-phase component of the L2 channel.
double sqrt_A
Square root of the semi-major axis [m^1/2].
double omega
Argument of perigee [rad].
GPSEphemeris(const InsTime &toc)
Default Constructor.
double calcSatellitePositionVariance() const final
Calculates the Variance of the satellite position in [m^2].
uint8_t svHealth
SV health.
double M_0
Mean anomaly at reference time [rad].
double Omega_dot
Rate of change of right ascension [rad/s].
size_t IODE
Issue of Data, Ephemeris.
PosVelAccel calcSatelliteData(const InsTime &transTime, Orbit::Calc calc) const final
Calculates position, velocity and acceleration of the satellite at transmission time.
double fitInterval
Fit Interval of ephemerides [h].
InsTime toc
Time of Clock.
double Cis
Amplitude of the sine harmonic correction term to the angle of inclination [rad].
double Crs
Amplitude of the sine harmonic correction term to the orbit radius [m].
double e
Eccentricity [-].
double Omega_0
Longitude of the ascending node at reference time [rad].
InsTime toe
Time of Ephemeris.
static constexpr double R_E
Earth Equatorial Radius [m].
static constexpr double J2
Oblate Earth Gravity Coefficient [-].
static constexpr double F
Relativistic constant F for GPS clock corrections [s/√m] (-2*√µ/c²)
static constexpr double MU
Gravitational constant GPS [m³/s²]. See is-gps-200m IS-GPS-200M p. 106.
static constexpr double omega_ie
Earth angular velocity GPS [rad/s]. See is-gps-200m IS-GPS-200M p. 106.
static constexpr double C
Speed of light [m/s].
Definition Constants.hpp:34
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
constexpr InsTime_GPSweekTow toGPSweekTow(TimeSystem timesys=GPST) const
Converts this time object into a different format.
Definition InsTime.hpp:854
constexpr InsTime_YMDHMS toYMDHMS(TimeSystem timesys=UTC, int digits=-1) const
Converts this time object into a different format.
Definition InsTime.hpp:871
Calc
Calculation flags.
Definition Orbit.hpp:75
@ Calc_Velocity
Velocity calculation flag.
Definition Orbit.hpp:78
@ Calc_Acceleration
Acceleration calculation flag.
Definition Orbit.hpp:79
Satellite Navigation data (to calculate SatNavData and clock)
SatNavData(Type type, const InsTime &refTime)
Constructor.
@ GPSEphemeris
GPS Broadcast Ephemeris.
@ GPST
GPS Time.
double ratioFreqSquared(Frequency f1, Frequency f2, int8_t num1, int8_t num2)
Calculates the ration of the frequencies squared γ
Definition Functions.cpp:24
@ G01
GPS L1 (1575.42 MHz).
Definition Frequency.hpp:28
@ G05
GPS L5 (1176.45 MHz).
Definition Frequency.hpp:30
@ GPS
Global Positioning System.
Satellite clock corrections.
Definition Clock.hpp:28
Satellite Position, Velocity and Acceleration.
Definition Orbit.hpp:40
Satellite System type.