| 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 | 74772 | AntennaInfo(const InsTime& date, const InsTime& from, const InsTime& until) | |
| 74 | 74772 | : 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 | 70094 | static AntexReader& Get() | |
| 99 | { | ||
| 100 |
3/4✓ Branch 0 taken 93 times.
✓ Branch 1 taken 70001 times.
✓ Branch 3 taken 93 times.
✗ Branch 4 not taken.
|
70094 | static AntexReader self; |
| 101 | 70094 | return self; | |
| 102 | } | ||
| 103 | |||
| 104 | /// @brief Initialize from ANTEX file | ||
| 105 | 120 | void initialize() | |
| 106 | { | ||
| 107 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 93 times.
|
120 | if (!_antennas.empty()) { return; } |
| 108 | |||
| 109 |
2/4✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 93 times.
✗ Branch 6 not taken.
|
93 | LOG_DEBUG("Reading ANTEX files started..."); |
| 110 | |||
| 111 |
7/14✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 93 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 93 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 93 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 93 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 93 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 93 times.
✗ Branch 20 not taken.
|
93 | auto path = flow::GetProgramRootPath() / "resources" / "gnss" / "antex"; |
| 112 |
2/4✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 93 times.
|
93 | 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 93 times.
✗ Branch 2 not taken.
✓ Branch 11 taken 465 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 465 times.
✓ Branch 15 taken 93 times.
|
558 | for (const auto& entry : std::filesystem::directory_iterator(path)) |
| 118 | { | ||
| 119 |
4/6✓ Branch 1 taken 465 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 465 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 186 times.
✓ Branch 11 taken 279 times.
|
465 | if (entry.path().extension() != ".atx") { continue; } |
| 120 |
3/6✓ Branch 1 taken 279 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 279 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 279 times.
✗ Branch 10 not taken.
|
279 | LOG_DEBUG("Reading {}...", entry.path().string()); |
| 121 | |||
| 122 |
1/2✓ Branch 2 taken 279 times.
✗ Branch 3 not taken.
|
279 | std::ifstream fs(entry.path()); |
| 123 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 279 times.
|
279 | if (!fs.good()) |
| 124 | { | ||
| 125 | ✗ | LOG_ERROR("Could not read ANTEX file: {}", entry.path().string()); | |
| 126 | ✗ | return; | |
| 127 | } | ||
| 128 | |||
| 129 | 25789179 | auto extHeaderLabel = [](const std::string& line) { | |
| 130 |
1/2✓ Branch 2 taken 25789179 times.
✗ Branch 3 not taken.
|
25789179 | return str::trim_copy(std::string_view(line).substr(60, 20)); |
| 131 | }; | ||
| 132 | |||
| 133 | 279 | std::string line; | |
| 134 | 279 | size_t lineNumber = 0; | |
| 135 | |||
| 136 | 279 | bool antennaStarted = false; | |
| 137 | 279 | Antenna* antenna = nullptr; | |
| 138 | 279 | std::vector<NAV::AntexReader::Antenna::AntennaInfo>::iterator antInfo; | |
| 139 | 279 | std::string antennaType; | |
| 140 | 279 | InsTime date; | |
| 141 | 279 | InsTime validFrom; | |
| 142 | 279 | InsTime validUntil; | |
| 143 | 279 | Frequency_ frequency = Freq_None; | |
| 144 | 279 | const double azimuthStart = 0.0; | |
| 145 | 279 | const double azimuthEnd = deg2rad(360.0); | |
| 146 | 279 | double azimuthDelta = 0.0; | |
| 147 | 279 | double zenithStart = 0.0; | |
| 148 | 279 | double zenithEnd = 0.0; | |
| 149 | 279 | double zenithDelta = 0.0; | |
| 150 | #if LOG_LEVEL <= LOG_LEVEL_DATA | ||
| 151 | bool patternLogging = false; | ||
| 152 | #endif | ||
| 153 |
7/10✓ Branch 1 taken 25789458 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25789458 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25789179 times.
✓ Branch 7 taken 279 times.
✓ Branch 9 taken 25789179 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 25789179 times.
✓ Branch 12 taken 279 times.
|
25789458 | while (std::getline(fs, line) && !fs.eof()) |
| 154 | { | ||
| 155 | 25789179 | lineNumber++; | |
| 156 |
1/2✓ Branch 1 taken 25789179 times.
✗ Branch 2 not taken.
|
25789179 | auto label = extHeaderLabel(line); |
| 157 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25714221 times.
|
25789179 | if (label == "START OF ANTENNA") { antennaStarted = true; } |
| 158 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25639263 times.
|
25714221 | else if (label == "END OF ANTENNA") |
| 159 | { | ||
| 160 | 74958 | antennaStarted = false; | |
| 161 | 74958 | antenna = nullptr; | |
| 162 | 74958 | antInfo = {}; | |
| 163 | 74958 | antennaType.clear(); | |
| 164 | 74958 | date.reset(); | |
| 165 | 74958 | validFrom.reset(); | |
| 166 | 74958 | validUntil.reset(); | |
| 167 | 74958 | azimuthDelta = 0.0; | |
| 168 | 74958 | zenithStart = 0.0; | |
| 169 | 74958 | zenithEnd = 0.0; | |
| 170 | 74958 | zenithDelta = 0.0; | |
| 171 | } | ||
| 172 |
2/2✓ Branch 0 taken 25600203 times.
✓ Branch 1 taken 39060 times.
|
25639263 | else if (antennaStarted) |
| 173 | { | ||
| 174 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25525245 times.
|
25600203 | if (label == "TYPE / SERIAL NO") |
| 175 | { | ||
| 176 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | antennaType = str::trim_copy(line.substr(0, 20)); |
| 177 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | std::string serialNumber = str::trim_copy(line.substr(20, 20)); |
| 178 |
4/6✓ Branch 1 taken 33852 times.
✓ Branch 2 taken 41106 times.
✓ Branch 4 taken 33852 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33852 times.
✗ Branch 8 not taken.
|
74958 | if (!serialNumber.empty()) { antennaType += ":" + serialNumber; } |
| 179 | |||
| 180 |
1/2✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
|
74958 | antenna = &_antennas[antennaType]; |
| 181 |
1/2✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
|
74958 | antenna->serialNumber = serialNumber; |
| 182 |
1/2✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
|
74958 | _antennaNames.insert(antennaType); |
| 183 | 74958 | } | |
| 184 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25450287 times.
|
25525245 | else if (label == "METH / BY / # / DATE") |
| 185 | { | ||
| 186 | // " COD/ESA 0 29-JAN-17 METH / BY / # / DATE" | ||
| 187 |
1/2✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
|
74958 | auto strDate = line.substr(50, 10); |
| 188 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | auto day = std::stoi(strDate.substr(0, 2)); |
| 189 |
1/2✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
|
74958 | auto strMon = strDate.substr(3, 3); |
| 190 | 74958 | int mon = 0; | |
| 191 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35526 times.
✓ Branch 4 taken 39432 times.
|
74958 | if (strMon == "JAN") { mon = 1; } |
| 192 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2232 times.
✓ Branch 4 taken 72726 times.
|
74958 | if (strMon == "FEB") { mon = 2; } |
| 193 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5952 times.
✓ Branch 4 taken 69006 times.
|
74958 | if (strMon == "MAR") { mon = 3; } |
| 194 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3534 times.
✓ Branch 4 taken 71424 times.
|
74958 | if (strMon == "APR") { mon = 4; } |
| 195 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5115 times.
✓ Branch 4 taken 69843 times.
|
74958 | if (strMon == "MAY") { mon = 5; } |
| 196 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7347 times.
✓ Branch 4 taken 67611 times.
|
74958 | if (strMon == "JUN") { mon = 6; } |
| 197 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1767 times.
✓ Branch 4 taken 73191 times.
|
74958 | if (strMon == "JUL") { mon = 7; } |
| 198 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 558 times.
✓ Branch 4 taken 74400 times.
|
74958 | if (strMon == "AUG") { mon = 8; } |
| 199 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4836 times.
✓ Branch 4 taken 70122 times.
|
74958 | if (strMon == "SEP") { mon = 9; } |
| 200 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2511 times.
✓ Branch 4 taken 72447 times.
|
74958 | if (strMon == "OCT") { mon = 10; } |
| 201 |
3/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2511 times.
✓ Branch 4 taken 72447 times.
|
74958 | if (strMon == "NOV") { mon = 11; } |
| 202 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 74958 times.
|
74958 | if (strMon == "DEZ") { mon = 12; } |
| 203 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | auto year = 2000 + std::stoi(strDate.substr(7, 2)); |
| 204 |
1/2✓ Branch 2 taken 74958 times.
✗ Branch 3 not taken.
|
74958 | date = InsTime(year, mon, day, 0, 0, 0.0, GPST); |
| 205 | 74958 | } | |
| 206 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25375329 times.
|
25450287 | 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 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | azimuthDelta = deg2rad(std::stod(line.substr(2, 6))); |
| 217 | } | ||
| 218 |
2/2✓ Branch 2 taken 74958 times.
✓ Branch 3 taken 25300371 times.
|
25375329 | 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 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | zenithStart = deg2rad(std::stod(line.substr(2, 6))); |
| 231 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | zenithEnd = deg2rad(std::stod(line.substr(8, 6))); |
| 232 |
2/4✓ Branch 1 taken 74958 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74958 times.
✗ Branch 5 not taken.
|
74958 | zenithDelta = deg2rad(std::stod(line.substr(14, 6))); |
| 233 | } | ||
| 234 |
2/2✓ Branch 2 taken 33852 times.
✓ Branch 3 taken 25266519 times.
|
25300371 | else if (label == "VALID FROM") |
| 235 | { | ||
| 236 |
7/14✓ Branch 1 taken 33852 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33852 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33852 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 33852 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 33852 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 33852 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 33852 times.
✗ Branch 20 not taken.
|
135408 | validFrom = InsTime(std::stoi(line.substr(0, 6)), |
| 237 |
1/2✓ Branch 1 taken 33852 times.
✗ Branch 2 not taken.
|
67704 | std::stoi(line.substr(6, 6)), |
| 238 |
1/2✓ Branch 1 taken 33852 times.
✗ Branch 2 not taken.
|
67704 | std::stoi(line.substr(12, 6)), |
| 239 |
1/2✓ Branch 1 taken 33852 times.
✗ Branch 2 not taken.
|
67704 | std::stoi(line.substr(18, 6)), |
| 240 | 33852 | std::stoi(line.substr(24, 6)), | |
| 241 |
3/6✓ Branch 1 taken 33852 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33852 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33852 times.
✗ Branch 8 not taken.
|
67704 | std::stod(line.substr(30, 13)), |
| 242 | 33852 | GPST); | |
| 243 | } | ||
| 244 |
2/2✓ Branch 2 taken 19251 times.
✓ Branch 3 taken 25247268 times.
|
25266519 | else if (label == "VALID UNTIL") |
| 245 | { | ||
| 246 |
7/14✓ Branch 1 taken 19251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19251 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 19251 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 19251 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 19251 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 19251 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 19251 times.
✗ Branch 20 not taken.
|
77004 | validUntil = InsTime(std::stoi(line.substr(0, 6)), |
| 247 |
1/2✓ Branch 1 taken 19251 times.
✗ Branch 2 not taken.
|
38502 | std::stoi(line.substr(6, 6)), |
| 248 |
1/2✓ Branch 1 taken 19251 times.
✗ Branch 2 not taken.
|
38502 | std::stoi(line.substr(12, 6)), |
| 249 |
1/2✓ Branch 1 taken 19251 times.
✗ Branch 2 not taken.
|
38502 | std::stoi(line.substr(18, 6)), |
| 250 | 19251 | std::stoi(line.substr(24, 6)), | |
| 251 |
3/6✓ Branch 1 taken 19251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19251 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 19251 times.
✗ Branch 8 not taken.
|
38502 | std::stod(line.substr(30, 13)), |
| 252 | 19251 | GPST); | |
| 253 | } | ||
| 254 |
2/2✓ Branch 2 taken 411339 times.
✓ Branch 3 taken 24835929 times.
|
25247268 | else if (label == "START OF FREQUENCY") |
| 255 | { | ||
| 256 |
2/4✓ Branch 1 taken 411339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411339 times.
✗ Branch 5 not taken.
|
411339 | frequency = Frequency_(Frequency::fromString(line.substr(3, 3))); |
| 257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 411339 times.
|
411339 | 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 411339 times.
✗ Branch 2 not taken.
|
411339 | antInfo = std::ranges::find_if(antenna->antennaInfo, [&](const Antenna::AntennaInfo& antInfo) { |
| 268 |
3/4✓ Branch 1 taken 336567 times.
✓ Branch 2 taken 35433 times.
✓ Branch 4 taken 336567 times.
✗ Branch 5 not taken.
|
372000 | return antInfo.from == validFrom && antInfo.until == validUntil; |
| 269 | }); | ||
| 270 |
2/2✓ Branch 2 taken 74772 times.
✓ Branch 3 taken 336567 times.
|
411339 | if (antInfo == antenna->antennaInfo.end()) |
| 271 | { | ||
| 272 |
1/2✓ Branch 1 taken 74772 times.
✗ Branch 2 not taken.
|
74772 | antenna->antennaInfo.emplace_back(date, validFrom, validUntil); |
| 273 | 74772 | antInfo = antenna->antennaInfo.end() - 1; | |
| 274 | } | ||
| 275 | |||
| 276 | 411339 | antInfo->zenithStart = zenithStart; | |
| 277 | 411339 | antInfo->zenithEnd = zenithEnd; | |
| 278 | 411339 | antInfo->zenithDelta = zenithDelta; | |
| 279 | 411339 | antInfo->azimuthStart = azimuthStart; | |
| 280 | 411339 | antInfo->azimuthEnd = azimuthEnd; | |
| 281 | 411339 | antInfo->azimuthDelta = azimuthDelta; | |
| 282 | |||
| 283 |
6/10✓ Branch 2 taken 411339 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4650 times.
✓ Branch 5 taken 406689 times.
✓ Branch 8 taken 4650 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4650 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 411339 times.
|
411339 | 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 411339 times.
✓ Branch 3 taken 24424590 times.
|
24835929 | else if (label == "END OF FREQUENCY") { frequency = Freq_None; } |
| 291 |
2/2✓ Branch 0 taken 24011856 times.
✓ Branch 1 taken 412734 times.
|
24424590 | else if (frequency != Freq_None) |
| 292 | { | ||
| 293 |
2/2✓ Branch 2 taken 411339 times.
✓ Branch 3 taken 23600517 times.
|
24011856 | if (label == "NORTH / EAST / UP") |
| 294 | { | ||
| 295 |
2/4✓ Branch 2 taken 411339 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 411339 times.
✗ Branch 7 not taken.
|
1234017 | antInfo->freqInformation[frequency].phaseCenterOffsetToARP = Eigen::Vector3d(str::stod(line.substr(0, 10), 0.0), |
| 296 |
1/2✓ Branch 2 taken 411339 times.
✗ Branch 3 not taken.
|
822678 | str::stod(line.substr(10, 10), 0.0), |
| 297 |
1/2✓ Branch 2 taken 411339 times.
✗ Branch 3 not taken.
|
822678 | str::stod(line.substr(20, 10), 0.0)) |
| 298 |
3/6✓ Branch 1 taken 411339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411339 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 411339 times.
✗ Branch 8 not taken.
|
1645356 | * 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 23600517 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23600517 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 411339 times.
✓ Branch 8 taken 23189178 times.
|
23600517 | 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 411339 times.
✗ Branch 3 not taken.
|
411339 | Eigen::Matrix2Xd& pattern = antInfo->freqInformation.at(frequency).patternAzimuthIndependent; |
| 313 |
2/4✓ Branch 1 taken 411339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411339 times.
✗ Branch 5 not taken.
|
411339 | pattern = Eigen::Matrix2Xd::Zero(2, static_cast<int>(std::round(zenithEnd / zenithDelta)) + 1); |
| 314 |
2/4✓ Branch 1 taken 411339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411339 times.
✗ Branch 5 not taken.
|
411339 | pattern.row(0).setLinSpaced(zenithStart, zenithEnd); |
| 315 |
2/2✓ Branch 1 taken 7810884 times.
✓ Branch 2 taken 411339 times.
|
8222223 | for (int c = 0; c < pattern.cols(); c++) |
| 316 | { | ||
| 317 |
3/6✓ Branch 1 taken 7810884 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7810884 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7810884 times.
✗ Branch 8 not taken.
|
7810884 | 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 23189178 times.
✗ Branch 1 not taken.
|
23189178 | 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 23189178 times.
✗ Branch 3 not taken.
|
23189178 | Eigen::MatrixXd& pattern = antInfo->freqInformation.at(frequency).pattern; |
| 332 | |||
| 333 |
2/2✓ Branch 1 taken 310992 times.
✓ Branch 2 taken 22878186 times.
|
23189178 | if (pattern.cols() == 0) |
| 334 | { | ||
| 335 | ✗ | pattern = Eigen::MatrixXd::Zero(static_cast<int>(std::round(azimuthEnd / azimuthDelta)) + 2, | |
| 336 |
2/4✓ Branch 1 taken 310992 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 310992 times.
✗ Branch 5 not taken.
|
310992 | static_cast<int>(std::round(zenithEnd / zenithDelta)) + 2); |
| 337 |
3/6✓ Branch 1 taken 310992 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 310992 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 310992 times.
✗ Branch 9 not taken.
|
310992 | pattern.row(0).rightCols(pattern.cols() - 1).setLinSpaced(zenithStart, zenithEnd); |
| 338 |
3/6✓ Branch 1 taken 310992 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 310992 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 310992 times.
✗ Branch 9 not taken.
|
310992 | pattern.col(0).bottomRows(pattern.rows() - 1).setLinSpaced(azimuthStart, azimuthEnd); |
| 339 | } | ||
| 340 |
2/4✓ Branch 1 taken 23189178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23189178 times.
✗ Branch 5 not taken.
|
23189178 | double azimuth = deg2rad(std::stod(line.substr(0, 8))); |
| 341 | 23189178 | int r = static_cast<int>(std::round((azimuth - azimuthStart) / azimuthDelta)) + 1; | |
| 342 |
2/2✓ Branch 1 taken 460604634 times.
✓ Branch 2 taken 23189178 times.
|
483793812 | for (int c = 0; c < pattern.cols() - 1; c++) |
| 343 | { | ||
| 344 |
3/6✓ Branch 1 taken 460604634 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 460604634 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 460604634 times.
✗ Branch 8 not taken.
|
460604634 | 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 | 372 | } | |
| 359 |
2/4✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 93 times.
✗ Branch 6 not taken.
|
93 | LOG_DEBUG("Reading ANTEX file finished."); |
| 360 | 93 | } | |
| 361 | |||
| 362 | /// @brief Reset the temporary variables | ||
| 363 | 113 | void reset() | |
| 364 | { | ||
| 365 | 113 | _notFoundAnt.clear(); | |
| 366 | 113 | _notFoundFreq.clear(); | |
| 367 | 113 | } | |
| 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 | 34913 | 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 34913 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 34905 times.
|
34913 | 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 | 34905 | 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 | template<typename T> | ||
| 395 | 34922 | std::optional<T> getAntennaPhaseCenterVariation(const std::string& antennaType, Frequency_ freq, const InsTime& insTime, | |
| 396 | const T& elevation, std::optional<double> azimuth, | ||
| 397 | [[maybe_unused]] const std::string& nameId) const | ||
| 398 | { | ||
| 399 |
1/2✓ Branch 1 taken 34922 times.
✗ Branch 2 not taken.
|
34922 | auto antInfo = getAntennaInfo(antennaType, insTime, nameId); |
| 400 |
2/2✓ Branch 1 taken 34903 times.
✓ Branch 2 taken 19 times.
|
34922 | if (!antInfo.has_value()) { return std::nullopt; } |
| 401 | |||
| 402 | 19 | auto 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 | auto t = (zenith - a) / (b - a); | |
| 432 | |||
| 433 |
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); |
| 434 | } | ||
| 435 | |||
| 436 | 9 | const Eigen::MatrixXd& pattern = antFreqInfo->get().pattern; | |
| 437 | 9 | Eigen::Index zenithLoc = -1; | |
| 438 | 9 | Eigen::Index azimuthLoc = -1; | |
| 439 |
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; } |
| 440 |
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; } |
| 441 | else | ||
| 442 | { | ||
| 443 |
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( |
| 444 |
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(), |
| 445 |
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(), |
| 446 |
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(), |
| 447 | zenith)); | ||
| 448 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | if (zenithLoc != pattern.cols() - 1) { zenithLoc++; } |
| 449 | } | ||
| 450 |
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; } |
| 451 |
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; } |
| 452 | else | ||
| 453 | { | ||
| 454 |
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( |
| 455 |
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(), |
| 456 |
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(), |
| 457 |
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(), |
| 458 | 4 | *azimuth)); | |
| 459 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if (azimuthLoc != pattern.rows() - 1) { azimuthLoc++; } |
| 460 | } | ||
| 461 | |||
| 462 | 9 | Eigen::Index uZenithLoc = zenithLoc - 1; | |
| 463 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | auto za = pattern(0, uZenithLoc); |
| 464 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | auto zb = pattern(0, zenithLoc); |
| 465 | 9 | auto zt = (zenith - za) / (zb - za); | |
| 466 | |||
| 467 | 9 | Eigen::Index uAzimuthLoc = azimuthLoc - 1; | |
| 468 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | auto aa = pattern(uAzimuthLoc, 0); |
| 469 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | auto ab = pattern(azimuthLoc, 0); |
| 470 | 9 | auto at = (*azimuth - aa) / (ab - aa); | |
| 471 | |||
| 472 | 18 | auto v = math::bilinearInterpolation(at, zt, | |
| 473 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | pattern(uAzimuthLoc, uZenithLoc), pattern(azimuthLoc, uZenithLoc), |
| 474 |
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)); |
| 475 | |||
| 476 | 9 | return v; | |
| 477 | } | ||
| 478 | |||
| 479 | /// Antennas read from the ANTEX files | ||
| 480 | 1 | const std::set<std::string>& antennas() const | |
| 481 | { | ||
| 482 | 1 | return _antennaNames; | |
| 483 | }; | ||
| 484 | |||
| 485 | private: | ||
| 486 | /// @brief Constructor | ||
| 487 | 93 | AntexReader() = default; | |
| 488 | |||
| 489 | /// Antennas read from the ANTEX files | ||
| 490 | std::unordered_map<std::string, Antenna> _antennas; | ||
| 491 | |||
| 492 | /// Ordered names of all antennas | ||
| 493 | std::set<std::string> _antennaNames; | ||
| 494 | |||
| 495 | /// List of Antennas not found to emit a warning | ||
| 496 | mutable std::unordered_set<std::string> _notFoundAnt; | ||
| 497 | |||
| 498 | /// List of Frequencies not found to emit a warning | ||
| 499 | mutable std::unordered_set<std::pair<std::string, Frequency_>> _notFoundFreq; | ||
| 500 | |||
| 501 | /// @brief Get the antenna info object | ||
| 502 | /// @param[in] antennaType Antenna Type | ||
| 503 | /// @param[in] insTime Time | ||
| 504 | /// @param[in] nameId NameId of the calling node for Log output | ||
| 505 | 69855 | std::optional<std::reference_wrapper<const Antenna::AntennaInfo>> getAntennaInfo(const std::string& antennaType, const InsTime& insTime, | |
| 506 | [[maybe_unused]] const std::string& nameId) const | ||
| 507 | { | ||
| 508 |
3/4✓ Branch 1 taken 69855 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69807 times.
✓ Branch 4 taken 48 times.
|
69855 | if (!_antennas.contains(antennaType)) |
| 509 | { | ||
| 510 |
3/4✓ Branch 1 taken 69807 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 69799 times.
|
69807 | if (!_notFoundAnt.contains(antennaType)) |
| 511 | { | ||
| 512 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
|
8 | LOG_WARN("{}: Antenna type '{}' is not found in the ANTEX files.", |
| 513 | nameId, antennaType); | ||
| 514 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | _notFoundAnt.insert(antennaType); |
| 515 | } | ||
| 516 | 69807 | return std::nullopt; | |
| 517 | } | ||
| 518 | |||
| 519 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | const auto& antenna = _antennas.at(antennaType); |
| 520 | |||
| 521 | 48 | auto antInfo = antenna.antennaInfo.cend(); | |
| 522 |
2/2✓ Branch 1 taken 44 times.
✓ Branch 2 taken 4 times.
|
48 | if (antenna.antennaInfo.size() == 1) // One element only, so take it |
| 523 | { | ||
| 524 | 44 | antInfo = antenna.antennaInfo.begin(); | |
| 525 | } | ||
| 526 | else // No element is not possible, so more than one here, so search for time | ||
| 527 | { | ||
| 528 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | antInfo = std::ranges::find_if(antenna.antennaInfo, [&](const Antenna::AntennaInfo& antInfo) { |
| 529 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 | return (antInfo.from.empty() && antInfo.until.empty()) |
| 530 |
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) |
| 531 |
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) |
| 532 |
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); |
| 533 | }); | ||
| 534 | } | ||
| 535 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 47 times.
|
48 | if (antInfo == antenna.antennaInfo.end()) // None matching, so take last |
| 536 | { | ||
| 537 | 1 | antInfo = antenna.antennaInfo.cend() - 1; | |
| 538 | } | ||
| 539 | |||
| 540 | 48 | return *antInfo; | |
| 541 | } | ||
| 542 | |||
| 543 | /// @brief Get the antenna frequency info object | ||
| 544 | /// @param[in] antennaType Antenna Type | ||
| 545 | /// @param[in] freq Frequency | ||
| 546 | /// @param[in] insTime Time | ||
| 547 | /// @param[in] nameId NameId of the calling node for Log output | ||
| 548 | 34932 | std::optional<std::reference_wrapper<const AntennaFreqInfo>> getAntennaFrequencyInfo(const std::string& antennaType, Frequency_ freq, | |
| 549 | const InsTime& insTime, | ||
| 550 | const std::string& nameId) const | ||
| 551 | { | ||
| 552 |
3/4✓ Branch 1 taken 34932 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 34904 times.
|
34932 | if (auto antInfo = getAntennaInfo(antennaType, insTime, nameId)) |
| 553 | { | ||
| 554 |
1/2✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
28 | return getAntennaFrequencyInfo(antInfo->get(), antennaType, freq, nameId); |
| 555 | } | ||
| 556 | |||
| 557 | 34904 | return std::nullopt; | |
| 558 | } | ||
| 559 | |||
| 560 | /// @brief Get the antenna frequency info object | ||
| 561 | /// @param[in] antInfo Antenna Info object | ||
| 562 | /// @param[in] antennaType Antenna Type | ||
| 563 | /// @param[in] freq Frequency | ||
| 564 | /// @param[in] nameId NameId of the calling node for Log output | ||
| 565 | 41 | std::optional<std::reference_wrapper<const AntennaFreqInfo>> getAntennaFrequencyInfo(const Antenna::AntennaInfo& antInfo, | |
| 566 | const std::string& antennaType, Frequency_ freq, | ||
| 567 | [[maybe_unused]] const std::string& nameId) const | ||
| 568 | { | ||
| 569 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 1 times.
|
41 | if (antInfo.freqInformation.contains(freq)) |
| 570 | { | ||
| 571 |
1/2✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
40 | return antInfo.freqInformation.at(freq); |
| 572 | } | ||
| 573 |
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))) |
| 574 | { | ||
| 575 |
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." |
| 576 | " 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.", | ||
| 577 | nameId, antennaType, Frequency(freq)); | ||
| 578 |
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)); |
| 579 | } | ||
| 580 | |||
| 581 | 1 | return std::nullopt; | |
| 582 | } | ||
| 583 | }; | ||
| 584 | |||
| 585 | } // namespace NAV | ||
| 586 |