0.4.1
Loading...
Searching...
No Matches
GnssObs.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 GnssObs.hpp
10/// @brief GNSS Observation messages
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2022-04-26
13
14#pragma once
15
16#include <cstdint>
17#include <limits>
18#include <optional>
19#include <vector>
20#include <algorithm>
21#include <Eigen/Core>
22
23#include "NodeData/NodeData.hpp"
24
27#include "util/Assert.h"
28
29namespace NAV
30{
31/// GNSS Observation message information
32class GnssObs : public NodeData
33{
34 public:
35 /// @brief Observation types
36 enum ObservationType : uint8_t
37 {
38 Pseudorange, ///< Pseudorange
39 Carrier, ///< Carrier-Phase
40 Doppler, ///< Doppler (Pseudorange rate)
42 };
43
44 /// @brief Stores the satellites observations
46 {
47 /// Pseudorange
49 {
50 /// Pseudorange measurement [m]
51 double value = 0.0;
52
53 /// @brief Signal Strength Indicator (SSI) projected into interval 1-9
54 ///
55 /// Carrier to Noise ratio(dbHz) | Carrier to Noise ratio(RINEX)
56 /// :-: | ---
57 /// - | 0 or blank: not known, don't care
58 /// < 12 | 1 (minimum possible signal strength)
59 /// 12-17 | 2
60 /// 18-23 | 3
61 /// 24-29 | 4
62 /// 30-35 | 5 (threshold for good tracking)
63 /// 36-41 | 6
64 /// 42-47 | 7
65 /// 48-53 | 8
66 /// ≥ 54 | 9 (maximum possible signal strength)
67 uint8_t SSI = 0;
68 };
69
70 /// Carrier phase
72 {
73 /// Carrier phase measurement [cycles]
74 double value = 0.0;
75
76 /// @brief Signal Strength Indicator (SSI) projected into interval 1-9
77 ///
78 /// Carrier to Noise ratio(dbHz) | Carrier to Noise ratio(RINEX)
79 /// :-: | ---
80 /// - | 0 or blank: not known, don't care
81 /// < 12 | 1 (minimum possible signal strength)
82 /// 12-17 | 2
83 /// 18-23 | 3
84 /// 24-29 | 4
85 /// 30-35 | 5 (threshold for good tracking)
86 /// 36-41 | 6
87 /// 42-47 | 7
88 /// 48-53 | 8
89 /// ≥ 54 | 9 (maximum possible signal strength)
90 uint8_t SSI = 0;
91
92 /// Loss of Lock Indicator [0...6] (only associated with the phase observation)
93 uint8_t LLI = 0;
94 };
95
96 /// @brief Constructor
97 /// @param[in] satSigId Satellite signal identifier (frequency and satellite number)
99
100#ifdef TESTING
101 /// @brief Constructor
102 /// @param[in] satSigId Satellite signal identifier (frequency and satellite number)
103 /// @param[in] pseudorange Pseudorange measurement [m] and Signal Strength Indicator (SSI)
104 /// @param[in] carrierPhase Carrier phase measurement [cycles], Signal Strength Indicator (SSI) and Loss of Lock Indicator (LLI)
105 /// @param[in] doppler Doppler measurement [Hz]
106 /// @param[in] CN0 Carrier-to-Noise density [dBHz]
108 std::optional<Pseudorange> pseudorange,
109 std::optional<CarrierPhase> carrierPhase,
110 std::optional<double> doppler,
111 std::optional<double> CN0)
116 CN0(CN0)
117 {}
118#endif
119
120 SatSigId satSigId = { Code::None, 0 }; ///< SignalId and satellite number
121 std::optional<Pseudorange> pseudorange; ///< Pseudorange measurement [m]
122 std::optional<CarrierPhase> carrierPhase; ///< Carrier phase measurement [cycles]
123 std::optional<double> doppler; ///< Doppler measurement [Hz]
124 std::optional<double> CN0; ///< Carrier-to-Noise density [dBHz]
125 };
126
127 /// @brief Useful information of the satellites
129 {
130 SatId satId; ///< Satellite identifier
131 Frequency frequencies = Freq_None; ///< Frequencies transmitted by this satellite
132 };
133
134#ifdef TESTING
135 /// Default constructor
136 GnssObs() = default;
137
138 /// @brief Constructor
139 /// @param[in] insTime Epoch time
140 /// @param[in] data Observation data
141 /// @param[in] satData Satellite data
142 GnssObs(const InsTime& insTime, std::vector<ObservationData> data, std::vector<SatelliteData> satData)
144 {
145 this->insTime = insTime;
146 }
147#endif
148 /// @brief Returns the type of the data class
149 /// @return The data type
150 [[nodiscard]] static std::string type()
151 {
152 return "GnssObs";
153 }
154
155 /// @brief Returns the type of the data class
156 /// @return The data type
157 [[nodiscard]] std::string getType() const override { return type(); }
158
159 /// @brief Returns the parent types of the data class
160 /// @return The parent data types
161 [[nodiscard]] static std::vector<std::string> parentTypes()
162 {
163 return { NodeData::type() };
164 }
165
166 /// @brief Satellite observations
167 std::vector<ObservationData> data;
168
169 /// @brief Access or insert the satellite data
170 /// @param satId Satellite identifier
171 /// @return The satellite data
173 {
174 auto iter = std::ranges::find_if(_satData, [&satId](const SatelliteData& sat) {
175 return sat.satId == satId;
176 });
177 if (iter != _satData.end())
178 {
179 return *iter;
180 }
181
182 _satData.emplace_back();
183 _satData.back().satId = satId;
184 return _satData.back();
185 }
186
187 /// @brief Access the satellite data
188 /// @param satId Satellite identifier
189 /// @return The satellite data if in the list
190 [[nodiscard]] std::optional<std::reference_wrapper<const SatelliteData>> satData(const SatId& satId) const
191 {
192 auto iter = std::ranges::find_if(_satData, [&satId](const SatelliteData& sat) {
193 return sat.satId == satId;
194 });
195 if (iter != _satData.end())
196 {
197 return *iter;
198 }
199 return std::nullopt;
200 }
201
202 /// @brief Checks if an element with the identifier exists
203 /// @param[in] satSigId Signal id
204 /// @return True if the element exists
205 [[nodiscard]] bool contains(const SatSigId& satSigId) const
206 {
207 auto iter = std::ranges::find_if(data, [&satSigId](const ObservationData& idData) {
208 return idData.satSigId == satSigId;
209 });
210 return iter != data.end();
211 }
212
213 /// @brief Return the element with the identifier or a newly constructed one if it did not exist
214 /// @param[in] satSigId Signal id
215 /// @return The element found in the observations or a newly constructed one
217 {
218 auto iter = std::ranges::find_if(data, [&satSigId](const ObservationData& idData) {
219 return idData.satSigId == satSigId;
220 });
221 if (iter != data.end())
222 {
223 return *iter;
224 }
225
226 data.emplace_back(satSigId);
227 return data.back();
228 }
229
230 /// @brief Return the element with the identifier
231 /// @param[in] satSigId Signal id
232 /// @return The element found in the observations
233 [[nodiscard]] std::optional<std::reference_wrapper<const ObservationData>> operator()(const SatSigId& satSigId) const
234 {
235 auto iter = std::ranges::find_if(data, [&satSigId](const ObservationData& idData) {
236 return idData.satSigId == satSigId;
237 });
238
239 if (iter != data.end())
240 {
241 return *iter;
242 }
243 return std::nullopt;
244 }
245
246 /// @brief Useful information of the satellites
247 [[nodiscard]] const std::vector<SatelliteData>& getSatData() const { return _satData; }
248
249 /// @brief Returns a vector of data descriptors for the dynamic data
250 [[nodiscard]] std::vector<std::string> dynamicDataDescriptors() const override
251 {
252 std::vector<std::string> descriptors;
253 descriptors.reserve(data.size() * 7);
254
255 for (const auto& obsData : data)
256 {
257 descriptors.push_back(fmt::format("{} Pseudorange [m]", obsData.satSigId));
258 descriptors.push_back(fmt::format("{} Pseudorange SSI", obsData.satSigId));
259
260 descriptors.push_back(fmt::format("{} Carrier-phase [cycles]", obsData.satSigId));
261 descriptors.push_back(fmt::format("{} Carrier-phase SSI", obsData.satSigId));
262 descriptors.push_back(fmt::format("{} Carrier-phase LLI", obsData.satSigId));
263
264 descriptors.push_back(fmt::format("{} Doppler [Hz]", obsData.satSigId));
265 descriptors.push_back(fmt::format("{} Carrier-to-Noise density [dBHz]", obsData.satSigId));
266 }
267
268 return descriptors;
269 }
270
271 /// @brief Get the value for the descriptor
272 /// @return Value if in the observation
273 [[nodiscard]] std::optional<double> getDynamicDataAt(const std::string& descriptor) const override
274 {
275 for (const auto& obsData : data)
276 {
277 if (descriptor == fmt::format("{} Pseudorange [m]", obsData.satSigId) && obsData.pseudorange)
278 {
279 return obsData.pseudorange->value;
280 }
281 if (descriptor == fmt::format("{} Pseudorange SSI", obsData.satSigId) && obsData.pseudorange)
282 {
283 return obsData.pseudorange->SSI;
284 }
285 if (descriptor == fmt::format("{} Carrier-phase [cycles]", obsData.satSigId) && obsData.carrierPhase)
286 {
287 return obsData.carrierPhase->value;
288 }
289 if (descriptor == fmt::format("{} Carrier-phase SSI", obsData.satSigId) && obsData.carrierPhase)
290 {
291 return obsData.carrierPhase->SSI;
292 }
293 if (descriptor == fmt::format("{} Carrier-phase LLI", obsData.satSigId) && obsData.carrierPhase)
294 {
295 return obsData.carrierPhase->LLI;
296 }
297 if (descriptor == fmt::format("{} Doppler [Hz]", obsData.satSigId))
298 {
299 return obsData.doppler;
300 }
301 if (descriptor == fmt::format("{} Carrier-to-Noise density [dBHz]", obsData.satSigId))
302 {
303 return obsData.CN0;
304 }
305 }
306 return std::nullopt;
307 }
308
309 /// @brief Returns a vector of data descriptors and values for the dynamic data
310 [[nodiscard]] std::vector<std::pair<std::string, double>> getDynamicData() const override
311 {
312 std::vector<std::pair<std::string, double>> dynData;
313 dynData.reserve(data.size() * 7);
314 for (const auto& obsData : data)
315 {
316 if (obsData.pseudorange) { dynData.emplace_back(fmt::format("{} Pseudorange [m]", obsData.satSigId), obsData.pseudorange->value); }
317 if (obsData.pseudorange) { dynData.emplace_back(fmt::format("{} Pseudorange SSI", obsData.satSigId), obsData.pseudorange->SSI); }
318
319 if (obsData.carrierPhase) { dynData.emplace_back(fmt::format("{} Carrier-phase [cycles]", obsData.satSigId), obsData.carrierPhase->value); }
320 if (obsData.carrierPhase) { dynData.emplace_back(fmt::format("{} Carrier-phase SSI", obsData.satSigId), obsData.carrierPhase->SSI); }
321 if (obsData.carrierPhase) { dynData.emplace_back(fmt::format("{} Carrier-phase LLI", obsData.satSigId), obsData.carrierPhase->LLI); }
322
323 if (obsData.doppler) { dynData.emplace_back(fmt::format("{} Doppler [Hz]", obsData.satSigId), obsData.doppler.value()); }
324
325 if (obsData.CN0) { dynData.emplace_back(fmt::format("{} Carrier-to-Noise density [dBHz]", obsData.satSigId), obsData.CN0.value()); }
326 }
327 return dynData;
328 }
329
330 /// Receiver Information, e.g. from RINEX header
332 {
333 ///< Approximate receiver position in [m], e.g. from RINEX header
334 std::optional<Eigen::Vector3d> e_approxPos;
335
336 /// Antenna Type. Empty if unknown
337 std::string antennaType;
338
339 /// @brief Antenna Delta (North, East, Up) in [m]
340 ///
341 /// - Horizontal eccentricity of ARP relative to the marker (north/east)
342 /// - Height of the antenna reference point (ARP) above the marker
343 Eigen::Vector3d antennaDeltaNEU = Eigen::Vector3d::Zero();
344 };
345
346 /// Optional Receiver Information, e.g. from RINEX header
347 std::optional<std::reference_wrapper<ReceiverInfo>> receiverInfo;
348
349 private:
350 /// @brief Useful information of the satellites
351 std::vector<SatelliteData> _satData;
352};
353
354/// @brief Converts the enum to a string
355/// @param[in] obsType Enum value to convert into text
356/// @return String representation of the enum
357constexpr const char* to_string(GnssObs::ObservationType obsType)
358{
359 switch (obsType)
360 {
362 return "Pseudorange";
363 case GnssObs::Carrier:
364 return "Carrier";
365 case GnssObs::Doppler:
366 return "Doppler";
368 return "COUNT";
369 }
370 return "";
371}
372
373} // namespace NAV
374
375#ifndef DOXYGEN_IGNORE
376
377template<>
378struct fmt::formatter<NAV::GnssObs::ObservationType> : fmt::formatter<const char*>
379{
380 /// @brief Defines how to format Frequency structs
381 /// @param[in] obsType Struct to format
382 /// @param[in, out] ctx Format context
383 /// @return Output iterator
384 template<typename FormatContext>
385 auto format(const NAV::GnssObs::ObservationType& obsType, FormatContext& ctx) const
386 {
387 return fmt::formatter<const char*>::format(to_string(obsType), ctx);
388 }
389};
390
391#endif
392
393/// @brief Stream insertion operator overload
394/// @param[in, out] os Output stream object to stream the time into
395/// @param[in] obj Object to print
396/// @return Returns the output stream object in order to chain stream insertions
397std::ostream& operator<<(std::ostream& os, const NAV::GnssObs::ObservationType& obj);
Assertion helpers.
Code definitions.
std::ostream & operator<<(std::ostream &os, const NAV::GnssObs::ObservationType &obj)
Stream insertion operator overload.
Definition GnssObs.cpp:16
Abstract NodeData Class.
Structs identifying a unique satellite.
@ None
None.
Definition Code.hpp:94
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
GNSS Observation message information.
Definition GnssObs.hpp:33
ObservationType
Observation types.
Definition GnssObs.hpp:37
@ Doppler
Doppler (Pseudorange rate)
Definition GnssObs.hpp:40
@ ObservationType_COUNT
Count.
Definition GnssObs.hpp:41
@ Carrier
Carrier-Phase.
Definition GnssObs.hpp:39
@ Pseudorange
Pseudorange.
Definition GnssObs.hpp:38
std::vector< std::string > dynamicDataDescriptors() const override
Returns a vector of data descriptors for the dynamic data.
Definition GnssObs.hpp:250
std::string getType() const override
Returns the type of the data class.
Definition GnssObs.hpp:157
std::vector< std::pair< std::string, double > > getDynamicData() const override
Returns a vector of data descriptors and values for the dynamic data.
Definition GnssObs.hpp:310
std::optional< double > getDynamicDataAt(const std::string &descriptor) const override
Get the value for the descriptor.
Definition GnssObs.hpp:273
static std::string type()
Returns the type of the data class.
Definition GnssObs.hpp:150
static std::vector< std::string > parentTypes()
Returns the parent types of the data class.
Definition GnssObs.hpp:161
std::optional< std::reference_wrapper< const SatelliteData > > satData(const SatId &satId) const
Access the satellite data.
Definition GnssObs.hpp:190
bool contains(const SatSigId &satSigId) const
Checks if an element with the identifier exists.
Definition GnssObs.hpp:205
std::optional< std::reference_wrapper< ReceiverInfo > > receiverInfo
Optional Receiver Information, e.g. from RINEX header.
Definition GnssObs.hpp:347
SatelliteData & satData(const SatId &satId)
Access or insert the satellite data.
Definition GnssObs.hpp:172
ObservationData & operator()(const SatSigId &satSigId)
Return the element with the identifier or a newly constructed one if it did not exist.
Definition GnssObs.hpp:216
std::vector< SatelliteData > _satData
Useful information of the satellites.
Definition GnssObs.hpp:351
const std::vector< SatelliteData > & getSatData() const
Useful information of the satellites.
Definition GnssObs.hpp:247
std::vector< ObservationData > data
Satellite observations.
Definition GnssObs.hpp:167
std::optional< std::reference_wrapper< const ObservationData > > operator()(const SatSigId &satSigId) const
Return the element with the identifier.
Definition GnssObs.hpp:233
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
NodeData()=default
Default constructor.
static std::string type()
Returns the type of the data class.
Definition NodeData.hpp:45
InsTime insTime
Time at which the message was received.
Definition NodeData.hpp:123
@ Freq_None
None.
Definition Frequency.hpp:27
const char * to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
Converts the enum to a string.
void move(std::vector< T > &v, size_t sourceIdx, size_t targetIdx)
Moves an element within a vector to a new position.
Definition Vector.hpp:27
uint8_t LLI
Loss of Lock Indicator [0...6] (only associated with the phase observation)
Definition GnssObs.hpp:93
double value
Carrier phase measurement [cycles].
Definition GnssObs.hpp:74
uint8_t SSI
Signal Strength Indicator (SSI) projected into interval 1-9.
Definition GnssObs.hpp:90
uint8_t SSI
Signal Strength Indicator (SSI) projected into interval 1-9.
Definition GnssObs.hpp:67
double value
Pseudorange measurement [m].
Definition GnssObs.hpp:51
Stores the satellites observations.
Definition GnssObs.hpp:46
std::optional< Pseudorange > pseudorange
Pseudorange measurement [m].
Definition GnssObs.hpp:121
std::optional< CarrierPhase > carrierPhase
Carrier phase measurement [cycles].
Definition GnssObs.hpp:122
ObservationData(const SatSigId &satSigId)
Constructor.
Definition GnssObs.hpp:98
std::optional< double > CN0
Carrier-to-Noise density [dBHz].
Definition GnssObs.hpp:124
SatSigId satSigId
SignalId and satellite number.
Definition GnssObs.hpp:120
std::optional< double > doppler
Doppler measurement [Hz].
Definition GnssObs.hpp:123
Receiver Information, e.g. from RINEX header.
Definition GnssObs.hpp:332
Eigen::Vector3d antennaDeltaNEU
Antenna Delta (North, East, Up) in [m].
Definition GnssObs.hpp:343
std::optional< Eigen::Vector3d > e_approxPos
< Approximate receiver position in [m], e.g. from RINEX header
Definition GnssObs.hpp:334
std::string antennaType
Antenna Type. Empty if unknown.
Definition GnssObs.hpp:337
Useful information of the satellites.
Definition GnssObs.hpp:129
Frequency frequencies
Frequencies transmitted by this satellite.
Definition GnssObs.hpp:131
SatId satId
Satellite identifier.
Definition GnssObs.hpp:130
Identifies a satellite (satellite system and number)
Identifies a satellite signal (satellite frequency and number)