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 GnssAnalyzer.hpp |
10 |
|
|
/// @brief Allows creation of GNSS measurement combinations |
11 |
|
|
/// @author T. Topp (topp@ins.uni-stuttgart.de) |
12 |
|
|
/// @date 2023-10-17 |
13 |
|
|
|
14 |
|
|
#pragma once |
15 |
|
|
|
16 |
|
|
#include <vector> |
17 |
|
|
|
18 |
|
|
#include "internal/Node/Node.hpp" |
19 |
|
|
|
20 |
|
|
#include "Navigation/GNSS/Core/SatelliteIdentifier.hpp" |
21 |
|
|
#include "Navigation/GNSS/Ambiguity/CycleSlipDetector.hpp" |
22 |
|
|
#include "Navigation/Math/Polynomial.hpp" |
23 |
|
|
|
24 |
|
|
namespace NAV |
25 |
|
|
{ |
26 |
|
|
/// @brief Allows creation of GNSS measurement combinations |
27 |
|
|
class GnssAnalyzer : public Node |
28 |
|
|
{ |
29 |
|
|
public: |
30 |
|
|
/// @brief Default constructor |
31 |
|
|
GnssAnalyzer(); |
32 |
|
|
/// @brief Destructor |
33 |
|
|
~GnssAnalyzer() override; |
34 |
|
|
/// @brief Copy constructor |
35 |
|
|
GnssAnalyzer(const GnssAnalyzer&) = delete; |
36 |
|
|
/// @brief Move constructor |
37 |
|
|
GnssAnalyzer(GnssAnalyzer&&) = delete; |
38 |
|
|
/// @brief Copy assignment operator |
39 |
|
|
GnssAnalyzer& operator=(const GnssAnalyzer&) = delete; |
40 |
|
|
/// @brief Move assignment operator |
41 |
|
|
GnssAnalyzer& operator=(GnssAnalyzer&&) = delete; |
42 |
|
|
|
43 |
|
|
/// @brief String representation of the Class Type |
44 |
|
|
[[nodiscard]] static std::string typeStatic(); |
45 |
|
|
|
46 |
|
|
/// @brief String representation of the Class Type |
47 |
|
|
[[nodiscard]] std::string type() const override; |
48 |
|
|
|
49 |
|
|
/// @brief String representation of the Class Category |
50 |
|
|
[[nodiscard]] static std::string category(); |
51 |
|
|
|
52 |
|
|
/// @brief ImGui config window which is shown on double click |
53 |
|
|
/// @attention Don't forget to set _hasConfig to true in the constructor of the node |
54 |
|
|
void guiConfig() override; |
55 |
|
|
|
56 |
|
|
/// @brief Saves the node into a json object |
57 |
|
|
[[nodiscard]] json save() const override; |
58 |
|
|
|
59 |
|
|
/// @brief Restores the node from a json object |
60 |
|
|
/// @param[in] j Json object with the node state |
61 |
|
|
void restore(const json& j) override; |
62 |
|
|
|
63 |
|
|
private: |
64 |
|
|
constexpr static size_t INPUT_PORT_INDEX_GNSS_OBS = 0; ///< @brief Flow (GnssObs) |
65 |
|
|
constexpr static size_t OUTPUT_PORT_INDEX_GNSS_COMBINATION = 0; ///< @brief Flow (GnssCombination) |
66 |
|
|
|
67 |
|
|
/// Combination of GNSS measurements |
68 |
|
|
struct Combination |
69 |
|
|
{ |
70 |
|
|
/// Possible units to calculate the combination in |
71 |
|
|
enum class Unit : uint8_t |
72 |
|
|
{ |
73 |
|
|
Meters, ///< Meters |
74 |
|
|
Cycles, ///< Cycles |
75 |
|
|
}; |
76 |
|
|
|
77 |
|
|
/// Unit to calculate the combination in |
78 |
|
|
Unit unit = Unit::Meters; |
79 |
|
|
|
80 |
|
|
/// Term of a combination equation |
81 |
|
|
struct Term |
82 |
|
|
{ |
83 |
|
|
/// @brief Observation types |
84 |
|
|
enum class ObservationType : uint8_t |
85 |
|
|
{ |
86 |
|
|
Pseudorange, ///< Pseudorange |
87 |
|
|
Carrier, ///< Carrier-Phase |
88 |
|
|
}; |
89 |
|
|
|
90 |
|
|
int sign = +1; ///< +1 or -1 |
91 |
|
|
SatSigId satSigId = { Code::G1C, 1 }; ///< SignalId and satellite number |
92 |
|
|
int8_t freqNum = -128; ///< Frequency number. Only used for GLONASS G1 and G2 // TODO: Set this somewhere |
93 |
|
|
ObservationType obsType = ObservationType::Carrier; ///< Observation Type |
94 |
|
|
bool receivedDuringRun = false; ///< Flag weather the signal was received |
95 |
|
|
}; |
96 |
|
|
std::vector<Term> terms{ Term() }; ///< List of terms making up the combination |
97 |
|
|
|
98 |
|
|
/// Cycle-slip detector |
99 |
|
|
PolynomialCycleSlipDetector<std::string> polynomialCycleSlipDetector{ /* windowSize = */ 4, /* polyDegree = */ 2 }; |
100 |
|
|
/// Threshold to categorize a measurement as cycle slip [% of smallest wavelength] |
101 |
|
|
double polynomialCycleSlipDetectorThresholdPercentage = 0.5; |
102 |
|
|
/// Whether to output the prediction even when the window size is not reached |
103 |
|
|
bool polynomialCycleSlipDetectorOutputWhenWindowSizeNotReached = false; |
104 |
|
|
/// Whether the polynomials should be outputted |
105 |
|
|
bool polynomialCycleSlipDetectorOutputPolynomials = false; |
106 |
|
|
/// Polynomial collection |
107 |
|
|
std::vector<std::pair<InsTime, Polynomial<double>>> polynomials; |
108 |
|
|
|
109 |
|
|
/// @brief Get a string description of the combination |
110 |
|
✗ |
[[nodiscard]] std::string description() const |
111 |
|
|
{ |
112 |
|
✗ |
std::string desc; |
113 |
|
✗ |
for (const auto& term : terms) |
114 |
|
|
{ |
115 |
|
✗ |
if (!desc.empty()) { desc += " "; } |
116 |
|
✗ |
desc += term.sign == 1 ? "+" : "-"; |
117 |
|
✗ |
desc += " "; |
118 |
|
✗ |
switch (term.obsType) |
119 |
|
|
{ |
120 |
|
✗ |
case Term::ObservationType::Pseudorange: |
121 |
|
✗ |
desc += unit == Unit::Cycles ? "P" : "p"; |
122 |
|
✗ |
break; |
123 |
|
✗ |
case Term::ObservationType::Carrier: |
124 |
|
✗ |
desc += unit == Unit::Cycles ? "Φ" : "φ"; |
125 |
|
✗ |
break; |
126 |
|
|
} |
127 |
|
✗ |
desc += fmt::format("({})", term.satSigId); |
128 |
|
|
} |
129 |
|
✗ |
if (unit == Unit::Cycles) { desc += " [cycles]"; } |
130 |
|
✗ |
else { desc += " [m]"; } |
131 |
|
|
|
132 |
|
✗ |
return desc; |
133 |
|
✗ |
} |
134 |
|
|
|
135 |
|
|
/// @brief Calculates the combined frequency of all terms |
136 |
|
✗ |
[[nodiscard]] double calcCombinationFrequency() const |
137 |
|
|
{ |
138 |
|
✗ |
double combinedFreq = 0.0; |
139 |
|
✗ |
for (const auto& term : terms) |
140 |
|
|
{ |
141 |
|
✗ |
double freq = term.satSigId.freq().getFrequency(term.freqNum); |
142 |
|
✗ |
combinedFreq += static_cast<double>(term.sign) * freq; |
143 |
|
|
} |
144 |
|
✗ |
return combinedFreq == 0 ? terms.front().satSigId.freq().getFrequency(terms.front().freqNum) : combinedFreq; |
145 |
|
|
} |
146 |
|
|
}; |
147 |
|
|
|
148 |
|
|
/// Combinations to calculate |
149 |
|
|
std::vector<Combination> _combinations{ Combination() }; |
150 |
|
|
|
151 |
|
|
/// @brief Initialize the node |
152 |
|
|
bool initialize() override; |
153 |
|
|
|
154 |
|
|
/// @brief Deinitialize the node |
155 |
|
|
void deinitialize() override; |
156 |
|
|
|
157 |
|
|
/// @brief Receive Gnss observation |
158 |
|
|
/// @param[in] queue Queue with all the received data messages |
159 |
|
|
/// @param[in] pinIdx Index of the pin the data is received on |
160 |
|
|
void receiveGnssObs(InputPin::NodeDataQueue& queue, size_t pinIdx); |
161 |
|
|
|
162 |
|
|
/// @brief Write info to a json object |
163 |
|
|
/// @param[out] j Json output |
164 |
|
|
/// @param[in] data Object to read info from |
165 |
|
|
friend void to_json(json& j, const Combination& data); |
166 |
|
|
/// @brief Read info from a json object |
167 |
|
|
/// @param[in] j Json variable to read info from |
168 |
|
|
/// @param[out] data Output object |
169 |
|
|
friend void from_json(const json& j, Combination& data); |
170 |
|
|
/// @brief Write info to a json object |
171 |
|
|
/// @param[out] j Json output |
172 |
|
|
/// @param[in] data Object to read info from |
173 |
|
|
friend void to_json(json& j, const Combination::Term& data); |
174 |
|
|
/// @brief Read info from a json object |
175 |
|
|
/// @param[in] j Json variable to read info from |
176 |
|
|
/// @param[out] data Output object |
177 |
|
|
friend void from_json(const json& j, Combination::Term& data); |
178 |
|
|
}; |
179 |
|
|
|
180 |
|
|
} // namespace NAV |
181 |
|
|
|