0.4.1
Loading...
Searching...
No Matches
AntexReader.hpp
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/// @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>
34#include "util/Eigen.hpp"
35#include "util/Logger.hpp"
37#include "util/StringUtil.hpp"
38#include <Eigen/src/Core/Matrix.h>
39#include <fmt/core.h>
40
41namespace NAV
42{
43
44/// @brief ANTEX file reader
46{
47 public:
48 /// Antenna frequency dependant information
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
68 {
69 /// @brief Constructor
70 /// @param[in] date Date of measurement
71 /// @param[in] from Valid from
72 /// @param[in] until Valid until
74 : 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 static AntexReader& Get()
99 {
100 static AntexReader self;
101 return self;
102 }
103
104 /// @brief Initialize from ANTEX file
106 {
107 if (!_antennas.empty()) { return; }
108
109 LOG_DEBUG("Reading ANTEX files started...");
110
111 auto path = flow::GetProgramRootPath() / "resources" / "gnss" / "antex";
112 if (!std::filesystem::exists(path))
113 {
114 LOG_WARN("Not reading ANTEX files because path does not exist: {}", path);
115 return;
116 }
117 for (const auto& entry : std::filesystem::directory_iterator(path))
118 {
119 if (entry.path().extension() != ".atx") { continue; }
120 LOG_DEBUG("Reading {}...", entry.path().string());
121
122 std::ifstream fs(entry.path());
123 if (!fs.good())
124 {
125 LOG_ERROR("Could not read ANTEX file: {}", entry.path().string());
126 return;
127 }
128
129 auto extHeaderLabel = [](const std::string& line) {
130 return str::trim_copy(std::string_view(line).substr(60, 20));
131 };
132
133 std::string line;
134 size_t lineNumber = 0;
135
136 bool antennaStarted = false;
137 Antenna* antenna = nullptr;
138 std::vector<NAV::AntexReader::Antenna::AntennaInfo>::iterator antInfo;
139 std::string antennaType;
140 InsTime date;
141 InsTime validFrom;
142 InsTime validUntil;
143 Frequency_ frequency = Freq_None;
144 const double azimuthStart = 0.0;
145 const double azimuthEnd = deg2rad(360.0);
146 double azimuthDelta = 0.0;
147 double zenithStart = 0.0;
148 double zenithEnd = 0.0;
149 double zenithDelta = 0.0;
150#if LOG_LEVEL <= LOG_LEVEL_DATA
151 bool patternLogging = false;
152#endif
153 while (std::getline(fs, line) && !fs.eof())
154 {
155 lineNumber++;
156 auto label = extHeaderLabel(line);
157 if (label == "START OF ANTENNA") { antennaStarted = true; }
158 else if (label == "END OF ANTENNA")
159 {
160 antennaStarted = false;
161 antenna = nullptr;
162 antInfo = {};
163 antennaType.clear();
164 date.reset();
165 validFrom.reset();
166 validUntil.reset();
167 azimuthDelta = 0.0;
168 zenithStart = 0.0;
169 zenithEnd = 0.0;
170 zenithDelta = 0.0;
171 }
172 else if (antennaStarted)
173 {
174 if (label == "TYPE / SERIAL NO")
175 {
176 antennaType = str::trim_copy(line.substr(0, 20));
177 std::string serialNumber = str::trim_copy(line.substr(20, 20));
178 if (!serialNumber.empty()) { antennaType += ":" + serialNumber; }
179
180 antenna = &_antennas[antennaType];
181 antenna->serialNumber = serialNumber;
182 _antennaNames.insert(antennaType);
183 }
184 else if (label == "METH / BY / # / DATE")
185 {
186 // " COD/ESA 0 29-JAN-17 METH / BY / # / DATE"
187 auto strDate = line.substr(50, 10);
188 auto day = std::stoi(strDate.substr(0, 2));
189 auto strMon = strDate.substr(3, 3);
190 int mon = 0;
191 if (strMon == "JAN") { mon = 1; }
192 if (strMon == "FEB") { mon = 2; }
193 if (strMon == "MAR") { mon = 3; }
194 if (strMon == "APR") { mon = 4; }
195 if (strMon == "MAY") { mon = 5; }
196 if (strMon == "JUN") { mon = 6; }
197 if (strMon == "JUL") { mon = 7; }
198 if (strMon == "AUG") { mon = 8; }
199 if (strMon == "SEP") { mon = 9; }
200 if (strMon == "OCT") { mon = 10; }
201 if (strMon == "NOV") { mon = 11; }
202 if (strMon == "DEZ") { mon = 12; }
203 auto year = 2000 + std::stoi(strDate.substr(7, 2));
204 date = InsTime(year, mon, day, 0, 0, 0.0, GPST);
205 }
206 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 azimuthDelta = deg2rad(std::stod(line.substr(2, 6)));
217 }
218 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 zenithStart = deg2rad(std::stod(line.substr(2, 6)));
231 zenithEnd = deg2rad(std::stod(line.substr(8, 6)));
232 zenithDelta = deg2rad(std::stod(line.substr(14, 6)));
233 }
234 else if (label == "VALID FROM")
235 {
236 validFrom = InsTime(std::stoi(line.substr(0, 6)),
237 std::stoi(line.substr(6, 6)),
238 std::stoi(line.substr(12, 6)),
239 std::stoi(line.substr(18, 6)),
240 std::stoi(line.substr(24, 6)),
241 std::stod(line.substr(30, 13)),
242 GPST);
243 }
244 else if (label == "VALID UNTIL")
245 {
246 validUntil = InsTime(std::stoi(line.substr(0, 6)),
247 std::stoi(line.substr(6, 6)),
248 std::stoi(line.substr(12, 6)),
249 std::stoi(line.substr(18, 6)),
250 std::stoi(line.substr(24, 6)),
251 std::stod(line.substr(30, 13)),
252 GPST);
253 }
254 else if (label == "START OF FREQUENCY")
255 {
256 frequency = Frequency_(Frequency::fromString(line.substr(3, 3)));
257 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 antInfo = std::ranges::find_if(antenna->antennaInfo, [&](const Antenna::AntennaInfo& antInfo) {
268 return antInfo.from == validFrom && antInfo.until == validUntil;
269 });
270 if (antInfo == antenna->antennaInfo.end())
271 {
272 antenna->antennaInfo.emplace_back(date, validFrom, validUntil);
273 antInfo = antenna->antennaInfo.end() - 1;
274 }
275
276 antInfo->zenithStart = zenithStart;
277 antInfo->zenithEnd = zenithEnd;
278 antInfo->zenithDelta = zenithDelta;
279 antInfo->azimuthStart = azimuthStart;
280 antInfo->azimuthEnd = azimuthEnd;
281 antInfo->azimuthDelta = azimuthDelta;
282
283 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 else if (label == "END OF FREQUENCY") { frequency = Freq_None; }
291 else if (frequency != Freq_None)
292 {
293 if (label == "NORTH / EAST / UP")
294 {
295 antInfo->freqInformation[frequency].phaseCenterOffsetToARP = Eigen::Vector3d(str::stod(line.substr(0, 10), 0.0),
296 str::stod(line.substr(10, 10), 0.0),
297 str::stod(line.substr(20, 10), 0.0))
298 * 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 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 Eigen::Matrix2Xd& pattern = antInfo->freqInformation.at(frequency).patternAzimuthIndependent;
313 pattern = Eigen::Matrix2Xd::Zero(2, static_cast<int>(std::round(zenithEnd / zenithDelta)) + 1);
314 pattern.row(0).setLinSpaced(zenithStart, zenithEnd);
315 for (int c = 0; c < pattern.cols(); c++)
316 {
317 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 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 Eigen::MatrixXd& pattern = antInfo->freqInformation.at(frequency).pattern;
332
333 if (pattern.cols() == 0)
334 {
335 pattern = Eigen::MatrixXd::Zero(static_cast<int>(std::round(azimuthEnd / azimuthDelta)) + 2,
336 static_cast<int>(std::round(zenithEnd / zenithDelta)) + 2);
337 pattern.row(0).rightCols(pattern.cols() - 1).setLinSpaced(zenithStart, zenithEnd);
338 pattern.col(0).bottomRows(pattern.rows() - 1).setLinSpaced(azimuthStart, azimuthEnd);
339 }
340 double azimuth = deg2rad(std::stod(line.substr(0, 8)));
341 int r = static_cast<int>(std::round((azimuth - azimuthStart) / azimuthDelta)) + 1;
342 for (int c = 0; c < pattern.cols() - 1; c++)
343 {
344 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 }
359 LOG_DEBUG("Reading ANTEX file finished.");
360 }
361
362 /// @brief Reset the temporary variables
363 void reset()
364 {
365 _notFoundAnt.clear();
366 _notFoundFreq.clear();
367 }
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 std::optional<Eigen::Vector3d> getAntennaPhaseCenterOffsetToARP(const std::string& antennaType, Frequency_ freq, const InsTime& insTime,
376 [[maybe_unused]] const std::string& nameId) const
377 {
378 if (auto antFreqInfo = getAntennaFrequencyInfo(antennaType, freq, insTime, nameId))
379 {
380 return antFreqInfo->get().phaseCenterOffsetToARP;
381 }
382
383 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 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 auto antInfo = getAntennaInfo(antennaType, insTime, nameId);
400 if (!antInfo.has_value()) { return std::nullopt; }
401
402 auto zenith = deg2rad(90.0) - elevation;
403
404 if (zenith < antInfo->get().zenithStart || zenith > antInfo->get().zenithEnd
405 || (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 return std::nullopt;
409 }
410 auto antFreqInfo = getAntennaFrequencyInfo(antInfo->get(), antennaType, freq, nameId);
411 if (!antFreqInfo.has_value()) { return std::nullopt; }
412
413 if (!azimuth.has_value())
414 {
415 const Eigen::Matrix2Xd& pattern = antFreqInfo->get().patternAzimuthIndependent;
416 Eigen::Index zenithLoc = -1;
417 if (zenith == pattern(0, 0)) { zenithLoc = 1; }
418 else if (zenith == pattern(0, Eigen::last)) { zenithLoc = pattern.cols() - 1; }
419 else
420 {
421 zenithLoc = std::distance(
422 pattern.row(0).begin(),
423 std::upper_bound(pattern.row(0).begin(),
424 pattern.row(0).end(),
425 zenith));
426 if (zenithLoc == 0) { zenithLoc++; }
427 }
428 Eigen::Index uLoc = zenithLoc - 1;
429 double a = pattern(0, uLoc);
430 double b = pattern(0, zenithLoc);
431 auto t = (zenith - a) / (b - a);
432
433 return std::lerp(pattern(1, uLoc), pattern(1, zenithLoc), t);
434 }
435
436 const Eigen::MatrixXd& pattern = antFreqInfo->get().pattern;
437 Eigen::Index zenithLoc = -1;
438 Eigen::Index azimuthLoc = -1;
439 if (zenith == pattern(0, 1)) { zenithLoc = 2; }
440 else if (zenith == pattern(0, Eigen::last)) { zenithLoc = pattern.cols() - 1; }
441 else
442 {
443 zenithLoc = std::distance(
444 pattern.row(0).rightCols(pattern.cols() - 1).begin(),
445 std::upper_bound(pattern.row(0).rightCols(pattern.cols() - 1).begin(),
446 pattern.row(0).rightCols(pattern.cols() - 1).end(),
447 zenith));
448 if (zenithLoc != pattern.cols() - 1) { zenithLoc++; }
449 }
450 if (*azimuth == pattern(1, 0)) { azimuthLoc = 2; }
451 else if (*azimuth == pattern(Eigen::last, 0)) { azimuthLoc = pattern.rows() - 1; }
452 else
453 {
454 azimuthLoc = std::distance(
455 pattern.col(0).bottomRows(pattern.rows() - 1).begin(),
456 std::upper_bound(pattern.col(0).bottomRows(pattern.rows() - 1).begin(),
457 pattern.col(0).bottomRows(pattern.rows() - 1).end(),
458 *azimuth));
459 if (azimuthLoc != pattern.rows() - 1) { azimuthLoc++; }
460 }
461
462 Eigen::Index uZenithLoc = zenithLoc - 1;
463 auto za = pattern(0, uZenithLoc);
464 auto zb = pattern(0, zenithLoc);
465 auto zt = (zenith - za) / (zb - za);
466
467 Eigen::Index uAzimuthLoc = azimuthLoc - 1;
468 auto aa = pattern(uAzimuthLoc, 0);
469 auto ab = pattern(azimuthLoc, 0);
470 auto at = (*azimuth - aa) / (ab - aa);
471
472 auto v = math::bilinearInterpolation(at, zt,
473 pattern(uAzimuthLoc, uZenithLoc), pattern(azimuthLoc, uZenithLoc),
474 pattern(uAzimuthLoc, zenithLoc), pattern(azimuthLoc, zenithLoc));
475
476 return v;
477 }
478
479 /// Antennas read from the ANTEX files
480 const std::set<std::string>& antennas() const
481 {
482 return _antennaNames;
483 };
484
485 private:
486 /// @brief Constructor
487 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 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 if (!_antennas.contains(antennaType))
509 {
510 if (!_notFoundAnt.contains(antennaType))
511 {
512 LOG_WARN("{}: Antenna type '{}' is not found in the ANTEX files.",
513 nameId, antennaType);
514 _notFoundAnt.insert(antennaType);
515 }
516 return std::nullopt;
517 }
518
519 const auto& antenna = _antennas.at(antennaType);
520
521 auto antInfo = antenna.antennaInfo.cend();
522 if (antenna.antennaInfo.size() == 1) // One element only, so take it
523 {
524 antInfo = antenna.antennaInfo.begin();
525 }
526 else // No element is not possible, so more than one here, so search for time
527 {
528 antInfo = std::ranges::find_if(antenna.antennaInfo, [&](const Antenna::AntennaInfo& antInfo) {
529 return (antInfo.from.empty() && antInfo.until.empty())
530 || (antInfo.from.empty() && insTime <= antInfo.until)
531 || (antInfo.until.empty() && antInfo.from <= insTime)
532 || (antInfo.from <= insTime && insTime <= antInfo.until);
533 });
534 }
535 if (antInfo == antenna.antennaInfo.end()) // None matching, so take last
536 {
537 antInfo = antenna.antennaInfo.cend() - 1;
538 }
539
540 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 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 if (auto antInfo = getAntennaInfo(antennaType, insTime, nameId))
553 {
554 return getAntennaFrequencyInfo(antInfo->get(), antennaType, freq, nameId);
555 }
556
557 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 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 if (antInfo.freqInformation.contains(freq))
570 {
571 return antInfo.freqInformation.at(freq);
572 }
573 if (!_notFoundFreq.contains(std::make_pair(antennaType, freq)))
574 {
575 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 _notFoundFreq.insert(std::make_pair(antennaType, freq));
579 }
580
581 return std::nullopt;
582 }
583};
584
585} // namespace NAV
Vector space operations.
Save/Load the Nodes.
Frequency definition for different satellite systems.
The class is responsible for all time-related tasks.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Utility functions for std::pair.
GNSS Satellite System.
Utility functions for working with std::strings.
Time System defintions.
std::optional< T > getAntennaPhaseCenterVariation(const std::string &antennaType, Frequency_ freq, const InsTime &insTime, const T &elevation, std::optional< double > azimuth, const std::string &nameId) const
Gets the phase center variation for given elevation and azimuth.
const std::set< std::string > & antennas() const
Antennas read from the ANTEX files.
AntexReader()=default
Constructor.
std::optional< std::reference_wrapper< const Antenna::AntennaInfo > > getAntennaInfo(const std::string &antennaType, const InsTime &insTime, const std::string &nameId) const
Get the antenna info object.
std::set< std::string > _antennaNames
Ordered names of all antennas.
std::unordered_set< std::string > _notFoundAnt
List of Antennas not found to emit a warning.
static AntexReader & Get()
Get the static Instance of the reader.
std::optional< std::reference_wrapper< const AntennaFreqInfo > > getAntennaFrequencyInfo(const std::string &antennaType, Frequency_ freq, const InsTime &insTime, const std::string &nameId) const
Get the antenna frequency info object.
std::unordered_set< std::pair< std::string, Frequency_ > > _notFoundFreq
List of Frequencies not found to emit a warning.
std::optional< std::reference_wrapper< const AntennaFreqInfo > > getAntennaFrequencyInfo(const Antenna::AntennaInfo &antInfo, const std::string &antennaType, Frequency_ freq, const std::string &nameId) const
Get the antenna frequency info object.
void initialize()
Initialize from ANTEX file.
std::unordered_map< std::string, Antenna > _antennas
Antennas read from the ANTEX files.
std::optional< Eigen::Vector3d > getAntennaPhaseCenterOffsetToARP(const std::string &antennaType, Frequency_ freq, const InsTime &insTime, const std::string &nameId) const
Get the Antenna Phase Center Offset To ARP if it is found in the ANTEX file.
void reset()
Reset the temporary variables.
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
static Frequency fromString(const std::string &typeString)
Construct new object from std::string.
Definition Frequency.cpp:22
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
constexpr InsTime_YMDHMS toYMDHMS(TimeSystem timesys=UTC, int digits=-1) const
Converts this time object into a different format.
Definition InsTime.hpp:871
constexpr bool empty() const
Checks if the Time object has a value.
Definition InsTime.hpp:1089
void reset()
Resets the InsTime object.
Definition InsTime.hpp:1095
std::filesystem::path GetProgramRootPath()
Get the program root path.
auto bilinearInterpolation(const auto &tx, const auto &ty, const auto &c00, const auto &c10, const auto &c01, const auto &c11)
Bilinear interpolation.
Definition Math.hpp:394
double stod(const String &str, double default_value, std::size_t *pos=nullptr) noexcept
Interprets a value in the string str.
static std::string trim_copy(std::string s)
Trim from both ends (copying)
@ GPST
GPS Time.
Frequency_
Enumerate for GNSS frequencies.
Definition Frequency.hpp:26
@ Freq_None
None.
Definition Frequency.hpp:27
constexpr auto deg2rad(const T &deg)
Convert Degree to Radians.
Definition Units.hpp:21
Antenna frequency dependant information.
Eigen::Vector3d phaseCenterOffsetToARP
Eccentricities of the mean antenna phase center relative to the antenna reference point (ARP)....
Eigen::Matrix2Xd patternAzimuthIndependent
double azimuthStart
Azimuth start of the phase center variation pattern in [rad].
AntennaInfo(const InsTime &date, const InsTime &from, const InsTime &until)
Constructor.
InsTime date
Date of measurement.
double zenithEnd
Zenith end of the phase center variation pattern in [rad].
double zenithDelta
Zenith delta of the phase center variation pattern in [rad].
double azimuthEnd
Azimuth end of the phase center variation pattern in [rad].
double azimuthDelta
Azimuth delta of the phase center variation pattern in [rad].
double zenithStart
Zenith start of the phase center variation pattern in [rad].
std::unordered_map< Frequency_, AntennaFreqInfo > freqInformation
Frequency dependant information.
Antenna information.
std::vector< AntennaInfo > antennaInfo
Antenna Information.
std::string serialNumber
Serial number.