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 | /// @file AntexReader.hpp | ||
10 | /// @brief ANTEX file reader | ||
11 | /// @author T. Topp (topp@ins.uni-stuttgart.de) | ||
12 | /// @date 2024-05-19 | ||
13 | |||
14 | #pragma once | ||
15 | |||
16 | #include <algorithm> | ||
17 | #include <cstddef> | ||
18 | #include <filesystem> | ||
19 | #include <fstream> | ||
20 | #include <mutex> | ||
21 | #include <set> | ||
22 | #include <optional> | ||
23 | #include <string> | ||
24 | #include <unordered_map> | ||
25 | #include <unordered_set> | ||
26 | #include <utility> | ||
27 | #include <vector> | ||
28 | #include "Navigation/GNSS/Core/Frequency.hpp" | ||
29 | #include "Navigation/GNSS/Core/SatelliteSystem.hpp" | ||
30 | #include "Navigation/Time/InsTime.hpp" | ||
31 | #include "Navigation/Time/TimeSystem.hpp" | ||
32 | #include "Navigation/Transformations/Units.hpp" | ||
33 | #include "internal/FlowManager.hpp" | ||
34 | #include "util/Eigen.hpp" | ||
35 | #include "util/Logger.hpp" | ||
36 | #include "util/Container/Pair.hpp" | ||
37 | #include "util/StringUtil.hpp" | ||
38 | #include <Eigen/src/Core/Matrix.h> | ||
39 | #include <fmt/core.h> | ||
40 | |||
41 | namespace NAV | ||
42 | { | ||
43 | |||
44 | /// @brief ANTEX file reader | ||
45 | class AntexReader | ||
46 | { | ||
47 | public: | ||
48 | /// Antenna frequency dependant information | ||
49 | struct AntennaFreqInfo | ||
50 | { | ||
51 | /// Eccentricities of the mean antenna phase center relative to the antenna reference point (ARP). North, east and up component in [m] | ||
52 | Eigen::Vector3d phaseCenterOffsetToARP = Eigen::Vector3d::Zero(); | ||
53 | /// Phase center variation pattern independent from azimuth [mm] | ||
54 | /// - First row is zenith angle in [rad] | ||
55 | /// - Second row is the values | ||
56 | Eigen::Matrix2Xd patternAzimuthIndependent; | ||
57 | /// Phase center variation [mm] | ||
58 | /// - First row is zenith angle in [rad] | ||
59 | /// - First column is the azimuth angle in [rad] | ||
60 | Eigen::MatrixXd pattern; | ||
61 | }; | ||
62 | |||
63 | /// Antenna information | ||
64 | struct Antenna | ||
65 | { | ||
66 | /// Antenna info | ||
67 | struct AntennaInfo | ||
68 | { | ||
69 | /// @brief Constructor | ||
70 | /// @param[in] date Date of measurement | ||
71 | /// @param[in] from Valid from | ||
72 | /// @param[in] until Valid until | ||
73 | 73164 | AntennaInfo(const InsTime& date, const InsTime& from, const InsTime& until) | |
74 | 73164 | : date(date), from(from), until(until) {} | |
75 | |||
76 | InsTime date; ///< Date of measurement | ||
77 | InsTime from; ///< Valid from | ||
78 | InsTime until; ///< Valid until | ||
79 | |||
80 | double zenithStart = 0.0; ///< Zenith start of the phase center variation pattern in [rad] | ||
81 | double zenithEnd = 0.0; ///< Zenith end of the phase center variation pattern in [rad] | ||
82 | double zenithDelta = 0.0; ///< Zenith delta of the phase center variation pattern in [rad] | ||
83 | double azimuthStart = 0.0; ///< Azimuth start of the phase center variation pattern in [rad] | ||
84 | double azimuthEnd = 0.0; ///< Azimuth end of the phase center variation pattern in [rad] | ||
85 | double azimuthDelta = 0.0; ///< Azimuth delta of the phase center variation pattern in [rad] | ||
86 | |||
87 | /// Frequency dependant information | ||
88 | std::unordered_map<Frequency_, AntennaFreqInfo> freqInformation; | ||
89 | }; | ||
90 | /// Serial number | ||
91 | std::string serialNumber; | ||
92 | |||
93 | /// Antenna Information | ||
94 | std::vector<AntennaInfo> antennaInfo; | ||
95 | }; | ||
96 | |||
97 | /// @brief Get the static Instance of the reader | ||
98 | 83880 | static AntexReader& Get() | |
99 | { | ||
100 |
3/4✓ Branch 0 taken 91 times.
✓ Branch 1 taken 83789 times.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
|
83880 | static AntexReader self; |
101 | 83880 | return self; | |
102 | } | ||
103 | |||
104 | /// @brief Initialize from ANTEX file | ||
105 | 118 | void initialize() | |
106 | { | ||
107 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 91 times.
|
118 | if (!_antennas.empty()) { return; } |
108 | |||
109 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
|
182 | LOG_DEBUG("Reading ANTEX files started..."); |
110 | |||
111 |
7/14✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 91 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 91 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 91 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 91 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 91 times.
✗ Branch 20 not taken.
|
91 | auto path = flow::GetProgramRootPath() / "resources" / "gnss" / "antex"; |
112 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
|
91 | if (!std::filesystem::exists(path)) |
113 | { | ||
114 | ✗ | LOG_WARN("Not reading ANTEX files because path does not exist: {}", path); | |
115 | ✗ | return; | |
116 | } | ||
117 |
4/6✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 11 taken 455 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 455 times.
✓ Branch 15 taken 91 times.
|
546 | for (const auto& entry : std::filesystem::directory_iterator(path)) |
118 | { | ||
119 |
4/6✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 455 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 182 times.
✓ Branch 11 taken 273 times.
|
455 | if (entry.path().extension() != ".atx") { continue; } |
120 |
3/6✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 273 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 273 times.
✗ Branch 10 not taken.
|
273 | LOG_DEBUG("Reading {}...", entry.path().string()); |
121 | |||
122 |
1/2✓ Branch 2 taken 273 times.
✗ Branch 3 not taken.
|
273 | std::ifstream fs(entry.path()); |
123 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
|
273 | if (!fs.good()) |
124 | { | ||
125 | ✗ | LOG_ERROR("Could not read ANTEX file: {}", entry.path().string()); | |
126 | ✗ | return; | |
127 | } | ||
128 | |||
129 | 25234573 | auto extHeaderLabel = [](const std::string& line) { | |
130 |
1/2✓ Branch 2 taken 25234573 times.
✗ Branch 3 not taken.
|
25234573 | return str::trim_copy(std::string_view(line).substr(60, 20)); |
131 | }; | ||
132 | |||
133 | 273 | std::string line; | |
134 | 273 | size_t lineNumber = 0; | |
135 | |||
136 | 273 | bool antennaStarted = false; | |
137 | 273 | Antenna* antenna = nullptr; | |
138 | 273 | std::vector<NAV::AntexReader::Antenna::AntennaInfo>::iterator antInfo; | |
139 | 273 | std::string antennaType; | |
140 | 273 | InsTime date; | |
141 | 273 | InsTime validFrom; | |
142 | 273 | InsTime validUntil; | |
143 | 273 | Frequency_ frequency = Freq_None; | |
144 | 273 | const double azimuthStart = 0.0; | |
145 | 273 | const double azimuthEnd = deg2rad(360.0); | |
146 | 273 | double azimuthDelta = 0.0; | |
147 | 273 | double zenithStart = 0.0; | |
148 | 273 | double zenithEnd = 0.0; | |
149 | 273 | double zenithDelta = 0.0; | |
150 | #if LOG_LEVEL <= LOG_LEVEL_DATA | ||
151 | bool patternLogging = false; | ||
152 | #endif | ||
153 |
7/10✓ Branch 1 taken 25234846 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25234846 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25234573 times.
✓ Branch 7 taken 273 times.
✓ Branch 9 taken 25234573 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 25234573 times.
✓ Branch 12 taken 273 times.
|
25234846 | while (std::getline(fs, line) && !fs.eof()) |
154 | { | ||
155 | 25234573 | lineNumber++; | |
156 |
1/2✓ Branch 1 taken 25234573 times.
✗ Branch 2 not taken.
|
25234573 | auto label = extHeaderLabel(line); |
157 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 25161227 times.
|
25234573 | if (label == "START OF ANTENNA") { antennaStarted = true; } |
158 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 25087881 times.
|
25161227 | else if (label == "END OF ANTENNA") |
159 | { | ||
160 | 73346 | antennaStarted = false; | |
161 | 73346 | antenna = nullptr; | |
162 | 73346 | antInfo = {}; | |
163 | 73346 | antennaType.clear(); | |
164 | 73346 | date.reset(); | |
165 | 73346 | validFrom.reset(); | |
166 | 73346 | validUntil.reset(); | |
167 | 73346 | azimuthDelta = 0.0; | |
168 | 73346 | zenithStart = 0.0; | |
169 | 73346 | zenithEnd = 0.0; | |
170 | 73346 | zenithDelta = 0.0; | |
171 | } | ||
172 |
2/2✓ Branch 0 taken 25049661 times.
✓ Branch 1 taken 38220 times.
|
25087881 | else if (antennaStarted) |
173 | { | ||
174 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 24976315 times.
|
25049661 | if (label == "TYPE / SERIAL NO") |
175 | { | ||
176 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | antennaType = str::trim_copy(line.substr(0, 20)); |
177 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | std::string serialNumber = str::trim_copy(line.substr(20, 20)); |
178 |
4/6✓ Branch 1 taken 33124 times.
✓ Branch 2 taken 40222 times.
✓ Branch 4 taken 33124 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33124 times.
✗ Branch 8 not taken.
|
73346 | if (!serialNumber.empty()) { antennaType += ":" + serialNumber; } |
179 | |||
180 |
1/2✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
|
73346 | antenna = &_antennas[antennaType]; |
181 |
1/2✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
|
73346 | antenna->serialNumber = serialNumber; |
182 |
1/2✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
|
73346 | _antennaNames.insert(antennaType); |
183 | 73346 | } | |
184 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 24902969 times.
|
24976315 | else if (label == "METH / BY / # / DATE") |
185 | { | ||
186 | // " COD/ESA 0 29-JAN-17 METH / BY / # / DATE" | ||
187 |
1/2✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
|
73346 | auto strDate = line.substr(50, 10); |
188 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | auto day = std::stoi(strDate.substr(0, 2)); |
189 |
1/2✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
|
73346 | auto strMon = strDate.substr(3, 3); |
190 | 73346 | int mon = 0; | |
191 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34762 times.
✓ Branch 4 taken 38584 times.
|
73346 | if (strMon == "JAN") { mon = 1; } |
192 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2184 times.
✓ Branch 4 taken 71162 times.
|
73346 | if (strMon == "FEB") { mon = 2; } |
193 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5824 times.
✓ Branch 4 taken 67522 times.
|
73346 | if (strMon == "MAR") { mon = 3; } |
194 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3458 times.
✓ Branch 4 taken 69888 times.
|
73346 | if (strMon == "APR") { mon = 4; } |
195 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5005 times.
✓ Branch 4 taken 68341 times.
|
73346 | if (strMon == "MAY") { mon = 5; } |
196 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7189 times.
✓ Branch 4 taken 66157 times.
|
73346 | if (strMon == "JUN") { mon = 6; } |
197 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1729 times.
✓ Branch 4 taken 71617 times.
|
73346 | if (strMon == "JUL") { mon = 7; } |
198 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 546 times.
✓ Branch 4 taken 72800 times.
|
73346 | if (strMon == "AUG") { mon = 8; } |
199 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4732 times.
✓ Branch 4 taken 68614 times.
|
73346 | if (strMon == "SEP") { mon = 9; } |
200 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2457 times.
✓ Branch 4 taken 70889 times.
|
73346 | if (strMon == "OCT") { mon = 10; } |
201 |
3/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2457 times.
✓ Branch 4 taken 70889 times.
|
73346 | if (strMon == "NOV") { mon = 11; } |
202 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 73346 times.
|
73346 | if (strMon == "DEZ") { mon = 12; } |
203 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | auto year = 2000 + std::stoi(strDate.substr(7, 2)); |
204 |
1/2✓ Branch 2 taken 73346 times.
✗ Branch 3 not taken.
|
73346 | date = InsTime(year, mon, day, 0, 0, 0.0, GPST); |
205 | 73346 | } | |
206 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 24829623 times.
|
24902969 | else if (label == "DAZI") |
207 | { | ||
208 | // Increment of the azimuth: 2X,F6.1,52X | ||
209 | // 0 to 360 with increment 'DAZI' (in degrees). | ||
210 | // 360 degrees have to be divisible by 'DAZI'. | ||
211 | // Common value for 'DAZI': 5.0 | ||
212 | // For non-azimuth-dependent phase center | ||
213 | // variations '0.0' has to be specified. | ||
214 | // | ||
215 | // 5.0 DAZI | ||
216 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | azimuthDelta = deg2rad(std::stod(line.substr(2, 6))); |
217 | } | ||
218 |
2/2✓ Branch 2 taken 73346 times.
✓ Branch 3 taken 24756277 times.
|
24829623 | else if (label == "ZEN1 / ZEN2 / DZEN") |
219 | { | ||
220 | // Receiver antenna: 2X,3F6.1,40X | ||
221 | // Definition of the grid in zenith angle: | ||
222 | // Zenith distance 'ZEN1' to 'ZEN2' with increment 'DZEN' (in degrees). | ||
223 | // 'DZEN' has to be > 0.0. | ||
224 | // 'ZEN1' and 'ZEN2' always have to be multiples of 'DZEN'. | ||
225 | // 'ZEN2' always has to be greater than 'ZEN1'. | ||
226 | // Common value for 'DZEN': 5.0 | ||
227 | // Example: ' 0.0 90.0 5.0' | ||
228 | // | ||
229 | // 0.0 90.0 5.0 ZEN1 / ZEN2 / DZEN | ||
230 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | zenithStart = deg2rad(std::stod(line.substr(2, 6))); |
231 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | zenithEnd = deg2rad(std::stod(line.substr(8, 6))); |
232 |
2/4✓ Branch 1 taken 73346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73346 times.
✗ Branch 5 not taken.
|
73346 | zenithDelta = deg2rad(std::stod(line.substr(14, 6))); |
233 | } | ||
234 |
2/2✓ Branch 2 taken 33124 times.
✓ Branch 3 taken 24723153 times.
|
24756277 | else if (label == "VALID FROM") |
235 | { | ||
236 |
7/14✓ Branch 1 taken 33124 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33124 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33124 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 33124 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 33124 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 33124 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 33124 times.
✗ Branch 20 not taken.
|
132496 | validFrom = InsTime(std::stoi(line.substr(0, 6)), |
237 |
1/2✓ Branch 1 taken 33124 times.
✗ Branch 2 not taken.
|
66248 | std::stoi(line.substr(6, 6)), |
238 |
1/2✓ Branch 1 taken 33124 times.
✗ Branch 2 not taken.
|
66248 | std::stoi(line.substr(12, 6)), |
239 |
1/2✓ Branch 1 taken 33124 times.
✗ Branch 2 not taken.
|
66248 | std::stoi(line.substr(18, 6)), |
240 | 33124 | std::stoi(line.substr(24, 6)), | |
241 |
3/6✓ Branch 1 taken 33124 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33124 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33124 times.
✗ Branch 8 not taken.
|
66248 | std::stod(line.substr(30, 13)), |
242 | 33124 | GPST); | |
243 | } | ||
244 |
2/2✓ Branch 2 taken 18837 times.
✓ Branch 3 taken 24704316 times.
|
24723153 | else if (label == "VALID UNTIL") |
245 | { | ||
246 |
7/14✓ Branch 1 taken 18837 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18837 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18837 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 18837 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 18837 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 18837 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 18837 times.
✗ Branch 20 not taken.
|
75348 | validUntil = InsTime(std::stoi(line.substr(0, 6)), |
247 |
1/2✓ Branch 1 taken 18837 times.
✗ Branch 2 not taken.
|
37674 | std::stoi(line.substr(6, 6)), |
248 |
1/2✓ Branch 1 taken 18837 times.
✗ Branch 2 not taken.
|
37674 | std::stoi(line.substr(12, 6)), |
249 |
1/2✓ Branch 1 taken 18837 times.
✗ Branch 2 not taken.
|
37674 | std::stoi(line.substr(18, 6)), |
250 | 18837 | std::stoi(line.substr(24, 6)), | |
251 |
3/6✓ Branch 1 taken 18837 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18837 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18837 times.
✗ Branch 8 not taken.
|
37674 | std::stod(line.substr(30, 13)), |
252 | 18837 | GPST); | |
253 | } | ||
254 |
2/2✓ Branch 2 taken 402493 times.
✓ Branch 3 taken 24301823 times.
|
24704316 | else if (label == "START OF FREQUENCY") |
255 | { | ||
256 |
2/4✓ Branch 1 taken 402493 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 402493 times.
✗ Branch 5 not taken.
|
402493 | frequency = Frequency_(Frequency::fromString(line.substr(3, 3))); |
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 402493 times.
|
402493 | if (frequency == Freq_None) |
258 | { | ||
259 | ✗ | LOG_WARN(" AntexReader: Invalid frequency [{}] in line {} of file '{}'", line.substr(3, 3), lineNumber, entry.path()); | |
260 | ✗ | continue; | |
261 | } | ||
262 | |||
263 | #if LOG_LEVEL <= LOG_LEVEL_DATA | ||
264 | patternLogging = true; | ||
265 | #endif | ||
266 | |||
267 |
1/2✓ Branch 1 taken 402493 times.
✗ Branch 2 not taken.
|
402493 | antInfo = std::ranges::find_if(antenna->antennaInfo, [&](const Antenna::AntennaInfo& antInfo) { |
268 |
3/4✓ Branch 1 taken 329329 times.
✓ Branch 2 taken 34671 times.
✓ Branch 4 taken 329329 times.
✗ Branch 5 not taken.
|
364000 | return antInfo.from == validFrom && antInfo.until == validUntil; |
269 | }); | ||
270 |
2/2✓ Branch 2 taken 73164 times.
✓ Branch 3 taken 329329 times.
|
402493 | if (antInfo == antenna->antennaInfo.end()) |
271 | { | ||
272 |
1/2✓ Branch 1 taken 73164 times.
✗ Branch 2 not taken.
|
73164 | antenna->antennaInfo.emplace_back(date, validFrom, validUntil); |
273 | 73164 | antInfo = antenna->antennaInfo.end() - 1; | |
274 | } | ||
275 | |||
276 | 402493 | antInfo->zenithStart = zenithStart; | |
277 | 402493 | antInfo->zenithEnd = zenithEnd; | |
278 | 402493 | antInfo->zenithDelta = zenithDelta; | |
279 | 402493 | antInfo->azimuthStart = azimuthStart; | |
280 | 402493 | antInfo->azimuthEnd = azimuthEnd; | |
281 | 402493 | antInfo->azimuthDelta = azimuthDelta; | |
282 | |||
283 |
6/10✓ Branch 2 taken 402493 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4550 times.
✓ Branch 5 taken 397943 times.
✓ Branch 8 taken 4550 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4550 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 402493 times.
|
402493 | if (antInfo->freqInformation.contains(frequency) && antInfo->date > date) |
284 | { | ||
285 | LOG_TRACE(" Antenna '{}' [{}]{} already exists.", antennaType, Frequency(frequency), | ||
286 | !validFrom.empty() || !validUntil.empty() ? fmt::format(" (valid [{}] - [{}])", validFrom.toYMDHMS(GPST), validUntil.toYMDHMS(GPST)) : ""); | ||
287 | ✗ | frequency = Freq_None; | |
288 | } | ||
289 | } | ||
290 |
2/2✓ Branch 2 taken 402493 times.
✓ Branch 3 taken 23899330 times.
|
24301823 | else if (label == "END OF FREQUENCY") { frequency = Freq_None; } |
291 |
2/2✓ Branch 0 taken 23495472 times.
✓ Branch 1 taken 403858 times.
|
23899330 | else if (frequency != Freq_None) |
292 | { | ||
293 |
2/2✓ Branch 2 taken 402493 times.
✓ Branch 3 taken 23092979 times.
|
23495472 | if (label == "NORTH / EAST / UP") |
294 | { | ||
295 |
2/4✓ Branch 2 taken 402493 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 402493 times.
✗ Branch 7 not taken.
|
1207479 | antInfo->freqInformation[frequency].phaseCenterOffsetToARP = Eigen::Vector3d(str::stod(line.substr(0, 10), 0.0), |
296 |
1/2✓ Branch 2 taken 402493 times.
✗ Branch 3 not taken.
|
804986 | str::stod(line.substr(10, 10), 0.0), |
297 |
1/2✓ Branch 2 taken 402493 times.
✗ Branch 3 not taken.
|
804986 | str::stod(line.substr(20, 10), 0.0)) |
298 |
3/6✓ Branch 1 taken 402493 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 402493 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 402493 times.
✗ Branch 8 not taken.
|
1609972 | * 1e-3; |
299 | LOG_DATA(" Adding antenna '{}' [{}]{} phaseCenterOffsetToARP: {}", antennaType, Frequency(frequency), | ||
300 | !validFrom.empty() || !validUntil.empty() ? fmt::format(" (valid [{}] - [{}])", validFrom.toYMDHMS(GPST), validUntil.toYMDHMS(GPST)) : "", | ||
301 | antInfo->freqInformation.at(frequency).phaseCenterOffsetToARP.transpose()); | ||
302 | } | ||
303 |
4/6✓ Branch 1 taken 23092979 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23092979 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 402493 times.
✓ Branch 8 taken 22690486 times.
|
23092979 | else if (line.substr(3, 5) == "NOAZI") |
304 | { | ||
305 | // (Values of a non- | The flag 'NOAZI' denotes a non-azimuth- | 3X,A5,mF8.2 | ||
306 | // azimuth-dependent | dependent pattern that has to be | | ||
307 | // pattern) | specified in any case (also if 'DAZI' > | | ||
308 | // | 0.0). | | ||
309 | // | Phase pattern values in millimeters from | | ||
310 | // | 'ZEN1' to 'ZEN2' (with increment 'DZEN').| | ||
311 | // | All values on one line. | | ||
312 |
1/2✓ Branch 2 taken 402493 times.
✗ Branch 3 not taken.
|
402493 | Eigen::Matrix2Xd& pattern = antInfo->freqInformation.at(frequency).patternAzimuthIndependent; |
313 |
2/4✓ Branch 1 taken 402493 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 402493 times.
✗ Branch 5 not taken.
|
402493 | pattern = Eigen::Matrix2Xd::Zero(2, static_cast<int>(std::round(zenithEnd / zenithDelta)) + 1); |
314 |
2/4✓ Branch 1 taken 402493 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 402493 times.
✗ Branch 5 not taken.
|
402493 | pattern.row(0).setLinSpaced(zenithStart, zenithEnd); |
315 |
2/2✓ Branch 1 taken 7642908 times.
✓ Branch 2 taken 402493 times.
|
8045401 | for (int c = 0; c < pattern.cols(); c++) |
316 | { | ||
317 |
3/6✓ Branch 1 taken 7642908 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7642908 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7642908 times.
✗ Branch 8 not taken.
|
7642908 | pattern(1, c) = std::stod(line.substr((static_cast<size_t>(c) + 1) * 8, 8)) * 1e-3; |
318 | } | ||
319 | LOG_DATA(" Adding antenna '{}' [{}] NOAZI pattern", antennaType, Frequency(frequency)); | ||
320 | } | ||
321 |
1/2✓ Branch 0 taken 22690486 times.
✗ Branch 1 not taken.
|
22690486 | else if (azimuthDelta > 0.0) |
322 | { | ||
323 | // (Values of an | The azimuth-dependent pattern has to be | F8.1,mF8.2 | ||
324 | // azimuth-dependent | specified, if 'DAZI' > 0.0. The first | | ||
325 | // pattern) | value in each line denotes the azimuth | | ||
326 | // | angle followed by the phase pattern | | ||
327 | // | values in millimeters from 'ZEN1' to | | ||
328 | // | 'ZEN2' (with increment 'DZEN'). | | ||
329 | // | All values of one azimuth angle on one | | ||
330 | // | line. | | ||
331 |
1/2✓ Branch 2 taken 22690486 times.
✗ Branch 3 not taken.
|
22690486 | Eigen::MatrixXd& pattern = antInfo->freqInformation.at(frequency).pattern; |
332 | |||
333 |
2/2✓ Branch 1 taken 304304 times.
✓ Branch 2 taken 22386182 times.
|
22690486 | if (pattern.cols() == 0) |
334 | { | ||
335 | ✗ | pattern = Eigen::MatrixXd::Zero(static_cast<int>(std::round(azimuthEnd / azimuthDelta)) + 2, | |
336 |
2/4✓ Branch 1 taken 304304 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 304304 times.
✗ Branch 5 not taken.
|
304304 | static_cast<int>(std::round(zenithEnd / zenithDelta)) + 2); |
337 |
3/6✓ Branch 1 taken 304304 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 304304 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 304304 times.
✗ Branch 9 not taken.
|
304304 | pattern.row(0).rightCols(pattern.cols() - 1).setLinSpaced(zenithStart, zenithEnd); |
338 |
3/6✓ Branch 1 taken 304304 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 304304 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 304304 times.
✗ Branch 9 not taken.
|
304304 | pattern.col(0).bottomRows(pattern.rows() - 1).setLinSpaced(azimuthStart, azimuthEnd); |
339 | } | ||
340 |
2/4✓ Branch 1 taken 22690486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22690486 times.
✗ Branch 5 not taken.
|
22690486 | double azimuth = deg2rad(std::stod(line.substr(0, 8))); |
341 | 22690486 | int r = static_cast<int>(std::round((azimuth - azimuthStart) / azimuthDelta)) + 1; | |
342 |
2/2✓ Branch 1 taken 450699158 times.
✓ Branch 2 taken 22690486 times.
|
473389644 | for (int c = 0; c < pattern.cols() - 1; c++) |
343 | { | ||
344 |
3/6✓ Branch 1 taken 450699158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 450699158 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 450699158 times.
✗ Branch 8 not taken.
|
450699158 | pattern(r, c + 1) = std::stod(line.substr((static_cast<size_t>(c) + 1) * 8, 8)) * 1e-3; |
345 | } | ||
346 | |||
347 | #if LOG_LEVEL <= LOG_LEVEL_DATA | ||
348 | if (patternLogging) | ||
349 | { | ||
350 | LOG_DATA(" Adding antenna '{}' [{}] azimuth dependent pattern", antennaType, Frequency(frequency)); | ||
351 | patternLogging = false; | ||
352 | } | ||
353 | #endif | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | 364 | } | |
359 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
|
182 | LOG_DEBUG("Reading ANTEX file finished."); |
360 | 91 | } | |
361 | |||
362 | /// @brief Reset the temporary variables | ||
363 | 111 | void reset() | |
364 | { | ||
365 | 111 | _notFoundAnt.clear(); | |
366 | 111 | _notFoundFreq.clear(); | |
367 | 111 | } | |
368 | |||
369 | /// @brief Get the Antenna Phase Center Offset To ARP if it is found in the ANTEX file | ||
370 | /// @param[in] antennaType Antenna Type | ||
371 | /// @param[in] freq Frequency | ||
372 | /// @param[in] insTime Time | ||
373 | /// @param[in] nameId NameId of the calling node for Log output | ||
374 | /// @return Phase center offset in north, east, up components in [m] | ||
375 | 41808 | std::optional<Eigen::Vector3d> getAntennaPhaseCenterOffsetToARP(const std::string& antennaType, Frequency_ freq, const InsTime& insTime, | |
376 | [[maybe_unused]] const std::string& nameId) const | ||
377 | { | ||
378 |
3/4✓ Branch 1 taken 41808 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 41800 times.
|
41808 | if (auto antFreqInfo = getAntennaFrequencyInfo(antennaType, freq, insTime, nameId)) |
379 | { | ||
380 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | return antFreqInfo->get().phaseCenterOffsetToARP; |
381 | } | ||
382 | |||
383 | 41800 | return std::nullopt; | |
384 | } | ||
385 | |||
386 | /// @brief Gets the phase center variation for given elevation and azimuth | ||
387 | /// @param[in] antennaType Antenna Type | ||
388 | /// @param[in] freq Frequency | ||
389 | /// @param[in] insTime Time | ||
390 | /// @param[in] elevation Elevation angle in [rad] | ||
391 | /// @param[in] azimuth Azimuth in [rad] or nullopt to use the azimuth independent (NOAZI) | ||
392 | /// @param[in] nameId NameId of the calling node for Log output | ||
393 | /// @return The interpolated phase center variation in [m] | ||
394 | 41817 | std::optional<double> getAntennaPhaseCenterVariation(const std::string& antennaType, Frequency_ freq, const InsTime& insTime, | |
395 | double elevation, std::optional<double> azimuth, | ||
396 | [[maybe_unused]] const std::string& nameId) const | ||
397 | { | ||
398 | LOG_DATA("{}: getAntennaPhaseCenterVariation({}, {}, {}, {}, {})", nameId, antennaType, Frequency(freq), insTime.toYMDHMS(GPST), elevation, azimuth); | ||
399 |
1/2✓ Branch 1 taken 41817 times.
✗ Branch 2 not taken.
|
41817 | auto antInfo = getAntennaInfo(antennaType, insTime, nameId); |
400 |
2/2✓ Branch 1 taken 41798 times.
✓ Branch 2 taken 19 times.
|
41817 | if (!antInfo.has_value()) { return std::nullopt; } |
401 | |||
402 | 19 | double zenith = deg2rad(90.0) - elevation; | |
403 | |||
404 |
2/2✓ Branch 4 taken 15 times.
✓ Branch 5 taken 2 times.
|
36 | if (zenith < antInfo->get().zenithStart || zenith > antInfo->get().zenithEnd |
405 |
10/10✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 4 times.
✓ Branch 9 taken 10 times.
✓ Branch 10 taken 1 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 9 times.
✓ Branch 17 taken 6 times.
✓ Branch 18 taken 13 times.
|
36 | || (azimuth && (azimuth < antInfo->get().azimuthStart || azimuth > antInfo->get().azimuthEnd))) |
406 | { | ||
407 | LOG_DATA("{}: The zenith or azimuth provided are outside the pattern in the ANTEX file", nameId); | ||
408 | 6 | return std::nullopt; | |
409 | } | ||
410 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | auto antFreqInfo = getAntennaFrequencyInfo(antInfo->get(), antennaType, freq, nameId); |
411 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if (!antFreqInfo.has_value()) { return std::nullopt; } |
412 | |||
413 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 9 times.
|
13 | if (!azimuth.has_value()) |
414 | { | ||
415 | 4 | const Eigen::Matrix2Xd& pattern = antFreqInfo->get().patternAzimuthIndependent; | |
416 | 4 | Eigen::Index zenithLoc = -1; | |
417 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
|
4 | if (zenith == pattern(0, 0)) { zenithLoc = 1; } |
418 |
3/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
|
3 | else if (zenith == pattern(0, Eigen::last)) { zenithLoc = pattern.cols() - 1; } |
419 | else | ||
420 | { | ||
421 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
6 | zenithLoc = std::distance( |
422 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | pattern.row(0).begin(), |
423 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | std::upper_bound(pattern.row(0).begin(), |
424 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | pattern.row(0).end(), |
425 | zenith)); | ||
426 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (zenithLoc == 0) { zenithLoc++; } |
427 | } | ||
428 | 4 | Eigen::Index uLoc = zenithLoc - 1; | |
429 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | double a = pattern(0, uLoc); |
430 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | double b = pattern(0, zenithLoc); |
431 | 4 | double t = (zenith - a) / (b - a); | |
432 | |||
433 | LOG_DATA("{}: t = {:.3f} [a = {:.1f}°, z = {:.1f}°, b = {:.1f}°]", nameId, t, rad2deg(a), rad2deg(zenith), rad2deg(b)); | ||
434 | LOG_DATA("{}: zenith {:.1f}° at idx {} = {:.5f}", nameId, rad2deg(zenith), zenithLoc, std::lerp(pattern(1, uLoc), pattern(1, zenithLoc), t)); | ||
435 | |||
436 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | return std::lerp(pattern(1, uLoc), pattern(1, zenithLoc), t); |
437 | } | ||
438 | |||
439 | 9 | const Eigen::MatrixXd& pattern = antFreqInfo->get().pattern; | |
440 | 9 | Eigen::Index zenithLoc = -1; | |
441 | 9 | Eigen::Index azimuthLoc = -1; | |
442 |
3/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 7 times.
|
9 | if (zenith == pattern(0, 1)) { zenithLoc = 2; } |
443 |
3/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
|
7 | else if (zenith == pattern(0, Eigen::last)) { zenithLoc = pattern.cols() - 1; } |
444 | else | ||
445 | { | ||
446 |
4/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
|
15 | zenithLoc = std::distance( |
447 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | pattern.row(0).rightCols(pattern.cols() - 1).begin(), |
448 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | std::upper_bound(pattern.row(0).rightCols(pattern.cols() - 1).begin(), |
449 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | pattern.row(0).rightCols(pattern.cols() - 1).end(), |
450 | zenith)); | ||
451 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | if (zenithLoc != pattern.cols() - 1) { zenithLoc++; } |
452 | } | ||
453 |
3/4✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
|
9 | if (*azimuth == pattern(1, 0)) { azimuthLoc = 2; } |
454 |
3/4✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
|
6 | else if (*azimuth == pattern(Eigen::last, 0)) { azimuthLoc = pattern.rows() - 1; } |
455 | else | ||
456 | { | ||
457 |
4/8✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
12 | azimuthLoc = std::distance( |
458 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | pattern.col(0).bottomRows(pattern.rows() - 1).begin(), |
459 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | std::upper_bound(pattern.col(0).bottomRows(pattern.rows() - 1).begin(), |
460 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | pattern.col(0).bottomRows(pattern.rows() - 1).end(), |
461 | 4 | *azimuth)); | |
462 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if (azimuthLoc != pattern.rows() - 1) { azimuthLoc++; } |
463 | } | ||
464 | |||
465 | 9 | Eigen::Index uZenithLoc = zenithLoc - 1; | |
466 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | double za = pattern(0, uZenithLoc); |
467 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | double zb = pattern(0, zenithLoc); |
468 | 9 | double zt = (zenith - za) / (zb - za); | |
469 | LOG_DATA("{}: zenith: t = {:.3f} [a = {:.1f}°, {:.1f}°, b = {:.1f}°]", nameId, zt, rad2deg(za), rad2deg(zenith), rad2deg(zb)); | ||
470 | 9 | Eigen::Index uAzimuthLoc = azimuthLoc - 1; | |
471 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | double aa = pattern(uAzimuthLoc, 0); |
472 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | double ab = pattern(azimuthLoc, 0); |
473 | 9 | double at = (*azimuth - aa) / (ab - aa); | |
474 | LOG_DATA("{}: azimuth: t = {:.3f} [a = {:.1f}°, {:.1f}°, b = {:.1f}°]", nameId, at, rad2deg(aa), rad2deg(*azimuth), rad2deg(ab)); | ||
475 | |||
476 | LOG_DATA("{}: bilinearInterpolation(tx = {:.1f}, ty = {:.1f}, c00 = {:.5f}, c10 = {:.5f}, c01 = {:.5f}, c11 = {:.5f})", nameId, | ||
477 | zt, at, | ||
478 | pattern(uAzimuthLoc, uZenithLoc), pattern(azimuthLoc, uZenithLoc), | ||
479 | pattern(uAzimuthLoc, zenithLoc), pattern(azimuthLoc, zenithLoc)); | ||
480 | 9 | double v = math::bilinearInterpolation(at, zt, | |
481 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | pattern(uAzimuthLoc, uZenithLoc), pattern(azimuthLoc, uZenithLoc), |
482 |
3/6✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
|
9 | pattern(uAzimuthLoc, zenithLoc), pattern(azimuthLoc, zenithLoc)); |
483 | LOG_DATA("{}: azimuth {:.1f}°, zenith {:.1f}° at idx ({},{}) = {:.5f}", nameId, rad2deg(*azimuth), rad2deg(zenith), azimuthLoc, zenithLoc, v); | ||
484 | |||
485 | 9 | return v; | |
486 | } | ||
487 | |||
488 | /// Antennas read from the ANTEX files | ||
489 | 1 | const std::set<std::string>& antennas() const | |
490 | { | ||
491 | 1 | return _antennaNames; | |
492 | }; | ||
493 | |||
494 | private: | ||
495 | /// @brief Constructor | ||
496 | 91 | AntexReader() = default; | |
497 | |||
498 | /// Antennas read from the ANTEX files | ||
499 | std::unordered_map<std::string, Antenna> _antennas; | ||
500 | |||
501 | /// Ordered names of all antennas | ||
502 | std::set<std::string> _antennaNames; | ||
503 | |||
504 | /// List of Antennas not found to emit a warning | ||
505 | mutable std::unordered_set<std::string> _notFoundAnt; | ||
506 | |||
507 | /// List of Frequencies not found to emit a warning | ||
508 | mutable std::unordered_set<std::pair<std::string, Frequency_>> _notFoundFreq; | ||
509 | |||
510 | /// @brief Get the antenna info object | ||
511 | /// @param[in] antennaType Antenna Type | ||
512 | /// @param[in] insTime Time | ||
513 | /// @param[in] nameId NameId of the calling node for Log output | ||
514 | 83645 | std::optional<std::reference_wrapper<const Antenna::AntennaInfo>> getAntennaInfo(const std::string& antennaType, const InsTime& insTime, | |
515 | [[maybe_unused]] const std::string& nameId) const | ||
516 | { | ||
517 |
3/4✓ Branch 1 taken 83645 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 83597 times.
✓ Branch 4 taken 48 times.
|
83645 | if (!_antennas.contains(antennaType)) |
518 | { | ||
519 |
3/4✓ Branch 1 taken 83597 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 83588 times.
|
83597 | if (!_notFoundAnt.contains(antennaType)) |
520 | { | ||
521 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
|
9 | LOG_WARN("{}: Antenna type '{}' is not found in the ANTEX files.", |
522 | nameId, antennaType); | ||
523 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | _notFoundAnt.insert(antennaType); |
524 | } | ||
525 | 83597 | return std::nullopt; | |
526 | } | ||
527 | |||
528 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | const auto& antenna = _antennas.at(antennaType); |
529 | |||
530 | 48 | auto antInfo = antenna.antennaInfo.cend(); | |
531 |
2/2✓ Branch 1 taken 44 times.
✓ Branch 2 taken 4 times.
|
48 | if (antenna.antennaInfo.size() == 1) // One element only, so take it |
532 | { | ||
533 | 44 | antInfo = antenna.antennaInfo.begin(); | |
534 | } | ||
535 | else // No element is not possible, so more than one here, so search for time | ||
536 | { | ||
537 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | antInfo = std::ranges::find_if(antenna.antennaInfo, [&](const Antenna::AntennaInfo& antInfo) { |
538 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 | return (antInfo.from.empty() && antInfo.until.empty()) |
539 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
7 | || (antInfo.from.empty() && insTime <= antInfo.until) |
540 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
7 | || (antInfo.until.empty() && antInfo.from <= insTime) |
541 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 4 times.
|
14 | || (antInfo.from <= insTime && insTime <= antInfo.until); |
542 | }); | ||
543 | } | ||
544 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 47 times.
|
48 | if (antInfo == antenna.antennaInfo.end()) // None matching, so take last |
545 | { | ||
546 | 1 | antInfo = antenna.antennaInfo.cend() - 1; | |
547 | } | ||
548 | |||
549 | 48 | return *antInfo; | |
550 | } | ||
551 | |||
552 | /// @brief Get the antenna frequency info object | ||
553 | /// @param[in] antennaType Antenna Type | ||
554 | /// @param[in] freq Frequency | ||
555 | /// @param[in] insTime Time | ||
556 | /// @param[in] nameId NameId of the calling node for Log output | ||
557 | 41827 | std::optional<std::reference_wrapper<const AntennaFreqInfo>> getAntennaFrequencyInfo(const std::string& antennaType, Frequency_ freq, | |
558 | const InsTime& insTime, | ||
559 | const std::string& nameId) const | ||
560 | { | ||
561 |
3/4✓ Branch 1 taken 41827 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 41799 times.
|
41827 | if (auto antInfo = getAntennaInfo(antennaType, insTime, nameId)) |
562 | { | ||
563 |
1/2✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
28 | return getAntennaFrequencyInfo(antInfo->get(), antennaType, freq, nameId); |
564 | } | ||
565 | |||
566 | 41799 | return std::nullopt; | |
567 | } | ||
568 | |||
569 | /// @brief Get the antenna frequency info object | ||
570 | /// @param[in] antInfo Antenna Info object | ||
571 | /// @param[in] antennaType Antenna Type | ||
572 | /// @param[in] freq Frequency | ||
573 | /// @param[in] nameId NameId of the calling node for Log output | ||
574 | 41 | std::optional<std::reference_wrapper<const AntennaFreqInfo>> getAntennaFrequencyInfo(const Antenna::AntennaInfo& antInfo, | |
575 | const std::string& antennaType, Frequency_ freq, | ||
576 | [[maybe_unused]] const std::string& nameId) const | ||
577 | { | ||
578 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 1 times.
|
41 | if (antInfo.freqInformation.contains(freq)) |
579 | { | ||
580 |
1/2✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
40 | return antInfo.freqInformation.at(freq); |
581 | } | ||
582 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | if (!_notFoundFreq.contains(std::make_pair(antennaType, freq))) |
583 | { | ||
584 |
1/2✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | LOG_WARN("{}: Antenna type '{}' is does not have frequency [{}] in the ANTEX file." |
585 | " Please provide a new ANTEX file under 'resources/gnss/antex' or consider not using the frequency, as this can introduce height errors of several centimeter.", | ||
586 | nameId, antennaType, Frequency(freq)); | ||
587 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | _notFoundFreq.insert(std::make_pair(antennaType, freq)); |
588 | } | ||
589 | |||
590 | 1 | return std::nullopt; | |
591 | } | ||
592 | }; | ||
593 | |||
594 | } // namespace NAV | ||
595 |