INSTINCT Code Coverage Report


Directory: src/
File: Navigation/Atmosphere/Ionosphere/Models/Klobuchar.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 24 25 96.0%
Functions: 1 1 100.0%
Branches: 11 16 68.8%

Line Branch Exec Source
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 "Klobuchar.hpp"
10
11 #include <algorithm>
12 #include "Navigation/GNSS/Functions.hpp"
13 #include "Navigation/Time/InsTime.hpp"
14 #include "Navigation/Transformations/Units.hpp"
15 #include "util/Assert.h"
16 #include "util/Logger.hpp"
17
18 namespace NAV
19 {
20
21 22237 double calcIonosphericTimeDelay_Klobuchar(double tow, Frequency freq, int8_t freqNum,
22 double latitude, double longitude,
23 double elevation, double azimuth,
24 const std::array<double, 4>& alpha, const std::array<double, 4>& beta)
25 {
26 22237 double phi_u = rad2semicircles(latitude); // User geodetic latitude [semi-circles] WGS 84
27 22237 double lambda_u = rad2semicircles(longitude); // User geodetic longitude [semi-circles] WGS 84
28 22237 double E = rad2semicircles(elevation); // Angle between the user and satellite [semi-circles]
29
30 // Earth's central angle between the user position and the earth projection of ionospheric intersection point [semi-circles]
31 22237 double psi = 0.0137 / (E + 0.11) - 0.022;
32 LOG_DATA("psi {} [semi-circles] (Earth's central angle between the user position and the earth projection of ionospheric intersection point)", psi);
33
34 // Sub-ionospheric latitude (geodetic latitude of the earth projection of the ionospheric intersection point) [semi-circles]
35 // Also known as Ionospheric Pierce Point IPP
36
1/2
✓ Branch 1 taken 22237 times.
✗ Branch 2 not taken.
22237 double phi_I = std::clamp(phi_u + psi * std::cos(azimuth), -0.416, 0.416);
37 LOG_DATA("phi_I {} [semi-circles] (Sub-ionospheric latitude)", phi_I);
38
39 // Sub-ionospheric longitude (geodetic longitude of the earth projection of the ionospheric intersection point) [semi-circles]
40 // Also known as Ionospheric Pierce Point IPP
41 22237 double lambda_I = lambda_u + (psi * std::sin(azimuth)) / std::cos(semicircles2rad(phi_I));
42 LOG_DATA("lambda_I {} [semi-circles] (Sub-ionospheric longitude)", lambda_I);
43
44 // Geomagnetic latitude of the earth projection of the ionospheric intersection point (mean ionospheric height assumed 350 km) [semi-circles]
45 22237 double phi_m = phi_I + 0.064 * std::cos(semicircles2rad(lambda_I - 1.617));
46 LOG_DATA("phi_m {} [semi-circles] (Geomagnetic latitude)", phi_m);
47
48 // Local time [s]
49 22237 double t = std::fmod(4.32e4 * lambda_I + tow, InsTimeUtil::SECONDS_PER_DAY);
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22237 times.
22237 if (t < 0)
51 {
52 t += InsTimeUtil::SECONDS_PER_DAY;
53 }
54 LOG_DATA("t {} [s] (Local time)", t);
55
56 // Slant factor / obliquity factor [-]
57 22237 double F = 1.0 + 16.0 * std::pow(0.53 - E, 3);
58 LOG_DATA("F {} [-] (Slant factor / obliquity factor)", F);
59
60 // Period of the model in [s]
61 22237 double PER = 0.0;
62
2/2
✓ Branch 0 taken 88948 times.
✓ Branch 1 taken 22237 times.
133422 for (size_t n = 0; n < beta.size(); ++n)
63 {
64
1/2
✓ Branch 1 taken 88948 times.
✗ Branch 2 not taken.
88948 PER += beta.at(n) * std::pow(phi_m, n);
65 }
66 22237 PER = std::max(PER, 72000.0);
67 LOG_DATA("PER {} [s] (Period of the model)", PER);
68
69 // Amplitude of the vertical delay in [s]
70 22237 double AMP = 0.0;
71
2/2
✓ Branch 0 taken 88948 times.
✓ Branch 1 taken 22237 times.
133422 for (size_t n = 0; n < beta.size(); ++n)
72 {
73
1/2
✓ Branch 1 taken 88948 times.
✗ Branch 2 not taken.
88948 AMP += alpha.at(n) * std::pow(phi_m, n);
74 }
75 22237 AMP = std::max(AMP, 0.0);
76 LOG_DATA("AMP {} [s] (Amplitude of the vertical delay)", AMP);
77
78 // Phase [rad]
79 22237 double x = (2 * M_PI * (t - 50400.0)) / PER;
80 LOG_DATA("x {} [rad] (Phase)", x);
81
82 // Ionospheric delay [s]
83
2/2
✓ Branch 1 taken 21781 times.
✓ Branch 2 taken 456 times.
22237 double T_iono = std::abs(x) < 1.57 ? F * (5e-9 + AMP * (1.0 - std::pow(x, 2) / 2.0 + std::pow(x, 4) / 24.0))
84 22237 : F * 5e-9;
85 LOG_DATA("T_iono_L1 {} [s] (Ionospheric delay)", T_iono);
86
87 // T_iono is referred to the L1 frequency; if the user is operating on the L2 frequency, the correction term must be multiplied by γ
88
1/2
✓ Branch 2 taken 22237 times.
✗ Branch 3 not taken.
22237 T_iono *= ratioFreqSquared(G01, freq, 0, freqNum);
89 LOG_DATA("T_iono {} [s] (Ionospheric delay for requested frequency)", T_iono);
90
91 22237 return T_iono;
92 }
93
94 } // namespace NAV
95