0.4.1
Loading...
Searching...
No Matches
ObservationEstimator.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 ObservationEstimator.hpp
10/// @brief Calculates Observation estimates
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2023-12-21
13
14#pragma once
15
16#include <algorithm>
17#include <cmath>
18#include <cstddef>
19#include <cstdint>
20#include <memory>
21#include <unordered_map>
22#include <utility>
23#include <vector>
24
25#include <imgui.h>
26#include <application.h>
27#include <imgui_stdlib.h>
36
43
45#include "util/Json.hpp"
46#include <Eigen/src/Core/MatrixBase.h>
47#include <fmt/core.h>
48#include <fmt/format.h>
49#include <fmt/ranges.h>
50
51namespace NAV
52{
53
54/// @brief Calculates Observation estimates
56{
57 public:
58 /// @brief Constructor
59 /// @param[in] receiverCount Number of receivers
60 explicit ObservationEstimator(size_t receiverCount)
61 : _receiverCount(receiverCount)
62 {
63 for (size_t i = 0; i < receiverCount; i++)
64 {
65 _antenna.emplace(i, Antenna{});
66 }
67 }
68
69 /// @brief How the observation gets used. Influenced the measurement variance
70 enum ObservationDifference : uint8_t
71 {
72 NoDifference, ///< Estimation is not differenced
73 SingleDifference, ///< Single Difference
74 DoubleDifference, ///< Double Difference
75 };
76
77 /// @brief Calculates the observation estimates
78 /// @param[in, out] observations List of GNSS observation data used for the calculation of this epoch
79 /// @param[in] ionosphericCorrections Ionospheric correction parameters collected from the Nav data
80 /// @param[in] receiver Receiver
81 /// @param[in] nameId Name and Id of the node used for log messages only
82 /// @param[in] obsDiff Observation Difference type to estimate
83 template<typename ReceiverType>
85 const Receiver<ReceiverType>& receiver,
86 const std::shared_ptr<const IonosphericCorrections>& ionosphericCorrections,
87 [[maybe_unused]] const std::string& nameId,
88 ObservationDifference obsDiff) const
89 {
90 LOG_DATA("{}: Calculating all observation estimates:", nameId);
91 for (auto& [satSigId, observation] : observations.signals)
92 {
93 calcObservationEstimate(satSigId, observation, receiver, ionosphericCorrections, nameId, obsDiff);
94 }
95 }
96
97 /// @brief Calculates the observation estimate for the given signal
98 /// @param[in] satSigId Satellite signal identifier
99 /// @param[in, out] observation GNSS observation data used for the calculation of this epoch
100 /// @param[in] ionosphericCorrections Ionospheric correction parameters collected from the Nav data
101 /// @param[in] receiver Receiver
102 /// @param[in] nameId Name and Id of the node used for log messages only
103 /// @param[in] obsDiff Observation Difference type to estimate
104 template<typename ReceiverType>
105 void calcObservationEstimate(const SatSigId& satSigId,
107 const Receiver<ReceiverType>& receiver,
108 const std::shared_ptr<const IonosphericCorrections>& ionosphericCorrections,
109 [[maybe_unused]] const std::string& nameId,
110 ObservationDifference obsDiff) const
111 {
112 LOG_DATA("{}: Calculating observation estimates for [{}]", nameId, satSigId);
113 const Frequency freq = satSigId.freq();
114 const SatelliteSystem satSys = freq.getSatSys();
115
116 auto& recvObs = observation.recvObs.at(receiver.type);
117
118 Eigen::Vector3d e_recvPosAPC = e_calcRecvPosAPC(freq,
119 receiver.type,
120 receiver.e_posMarker,
121 receiver.gnssObs, nameId);
122 Eigen::Vector3d lla_recvPosAPC = trafo::ecef2lla_WGS84(e_recvPosAPC);
123
124 double elevation = recvObs->satElevation(e_recvPosAPC, lla_recvPosAPC);
125 double azimuth = recvObs->satAzimuth(e_recvPosAPC, lla_recvPosAPC);
126 Eigen::Vector3d e_pLOS = recvObs->e_pLOS(e_recvPosAPC);
127
128 // Receiver-Satellite Range [m]
129 double rho_r_s = (recvObs->e_satPos() - e_recvPosAPC).norm();
130 recvObs->terms.rho_r_s = rho_r_s;
131 // Troposphere
132 auto tropo_r_s = calcTroposphericDelayAndMapping(receiver.gnssObs->insTime, lla_recvPosAPC,
133 elevation, azimuth, _troposphereModels, nameId);
134 recvObs->terms.tropoZenithDelay = tropo_r_s;
135 // Estimated troposphere propagation error [m]
136 double dpsr_T_r_s = tropo_r_s.ZHD * tropo_r_s.zhdMappingFactor + tropo_r_s.ZWD * tropo_r_s.zwdMappingFactor;
137 recvObs->terms.dpsr_T_r_s = dpsr_T_r_s;
138 // Estimated ionosphere propagation error [m]
139 double dpsr_I_r_s = calcIonosphericDelay(static_cast<double>(receiver.gnssObs->insTime.toGPSweekTow().tow),
140 freq, observation.freqNum(), lla_recvPosAPC, elevation, azimuth,
141 _ionosphereModel, ionosphericCorrections.get());
142 recvObs->terms.dpsr_I_r_s = dpsr_I_r_s;
143 // Sagnac correction [m]
144 double dpsr_ie_r_s = calcSagnacCorrection(e_recvPosAPC, recvObs->e_satPos());
145 recvObs->terms.dpsr_ie_r_s = dpsr_ie_r_s;
146
147 // Earth's gravitational field causes relativistic signal delay due to space-time curvature (Shapiro effect) [s]
148 // double posNorm = recvObs->e_satPos().norm() + e_recvPosAPC.norm();
149 // double dt_rel_stc = e_recvPosAPC.norm() > InsConst::WGS84::a / 2.0 ? 2.0 * InsConst::WGS84::MU / std::pow(InsConst::C, 3) * std::log((posNorm + rho_r_s) / (posNorm - rho_r_s))
150 // : 0.0;
151
152 double cn0 = recvObs->gnssObsData().CN0.value_or(1.0);
153
154 double pcv = calcPCV(freq, receiver.gnssObs->insTime, elevation, std::nullopt, receiver.type, receiver.gnssObs, nameId); // TODO: use 'azimuth', but need antenna azimuth
155
156 for (auto& [obsType, obsData] : recvObs->obs)
157 {
158 LOG_DATA("{}: [{}][{:11}][{:5}] Observation estimate", nameId, satSigId, obsType, receiver.type);
159 switch (obsType)
160 {
162 obsData.estimate = rho_r_s
163 + dpsr_ie_r_s
164 + dpsr_T_r_s
165 + dpsr_I_r_s
167 * (*receiver.recvClk.biasFor(satSys) - recvObs->satClock().bias
168 // + dt_rel_stc
169 + (receiver.interFrequencyBias.contains(freq) ? receiver.interFrequencyBias.at(freq).value : 0.0))
170 + pcv;
171 obsData.measVar = _gnssMeasurementErrorModel.psrMeasErrorVar(satSys, elevation, cn0);
172 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m] Geometrical range", nameId, satSigId, obsType, receiver.type, rho_r_s);
173 LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Sagnac correction", nameId, satSigId, obsType, receiver.type, dpsr_ie_r_s);
174 if (dpsr_T_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Tropospheric delay", nameId, satSigId, obsType, receiver.type, dpsr_T_r_s); }
175 if (dpsr_I_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Ionospheric delay", nameId, satSigId, obsType, receiver.type, dpsr_I_r_s); }
176 if (*receiver.recvClk.biasFor(satSys) != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Receiver clock bias", nameId, satSigId, obsType, receiver.type, InsConst::C * *receiver.recvClk.biasFor(satSys)); }
177 LOG_DATA("{}: [{}][{:11}][{:5}] - {:.4f} [m] Satellite clock bias", nameId, satSigId, obsType, receiver.type, InsConst::C * recvObs->satClock().bias);
178 // LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Shapiro effect", nameId, satSigId, obsType, receiver.type, InsConst::C * dt_rel_stc);
179 if (receiver.interFrequencyBias.contains(freq)) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Inter-frequency bias", nameId, satSigId, obsType, receiver.type, InsConst::C * receiver.interFrequencyBias.at(freq).value); }
180 LOG_DATA("{}: [{}][{:11}][{:5}] = {:.4f} [m] Pseudorange estimate", nameId, satSigId, obsType, receiver.type, obsData.estimate);
181 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m] Pseudorange measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement);
182 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4e} [m] Difference to measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement - obsData.estimate);
183 break;
184 case GnssObs::Carrier:
185 obsData.estimate = rho_r_s
186 + dpsr_ie_r_s
187 + dpsr_T_r_s
188 - dpsr_I_r_s
190 * (*receiver.recvClk.biasFor(satSys) - recvObs->satClock().bias
191 // + dt_rel_stc
192 )
193 + pcv;
194 obsData.measVar = _gnssMeasurementErrorModel.carrierMeasErrorVar(satSys, elevation, cn0);
195 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m] Geometrical range", nameId, satSigId, obsType, receiver.type, rho_r_s);
196 LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Sagnac correction", nameId, satSigId, obsType, receiver.type, dpsr_ie_r_s);
197 if (dpsr_T_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Tropospheric delay", nameId, satSigId, obsType, receiver.type, dpsr_T_r_s); }
198 if (dpsr_I_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] - {:.4f} [m] Ionospheric delay", nameId, satSigId, obsType, receiver.type, dpsr_I_r_s); }
199 if (*receiver.recvClk.biasFor(satSys) != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Receiver clock bias", nameId, satSigId, obsType, receiver.type, InsConst::C * *receiver.recvClk.biasFor(satSys)); }
200 LOG_DATA("{}: [{}][{:11}][{:5}] - {:.4f} [m] Satellite clock bias", nameId, satSigId, obsType, receiver.type, InsConst::C * recvObs->satClock().bias);
201 // LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m] Shapiro effect", nameId, satSigId, obsType, receiver.type, InsConst::C * dt_rel_stc);
202 LOG_DATA("{}: [{}][{:11}][{:5}] = {:.4f} [m] Carrier-phase estimate", nameId, satSigId, obsType, receiver.type, obsData.estimate);
203 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m] Carrier-phase measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement);
204 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4e} [m] Difference to measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement - obsData.estimate);
205 break;
206 case GnssObs::Doppler:
207 obsData.estimate = e_pLOS.dot(recvObs->e_satVel() - receiver.e_vel)
208 - calcSagnacRateCorrection(e_recvPosAPC, recvObs->e_satPos(), receiver.e_vel, recvObs->e_satVel())
210 * (*receiver.recvClk.driftFor(satSys)
211 - recvObs->satClock().drift);
212 obsData.measVar = _gnssMeasurementErrorModel.psrRateMeasErrorVar(freq, observation.freqNum(), elevation, cn0);
213 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m/s] ", nameId, satSigId, obsType, receiver.type, e_pLOS.dot(recvObs->e_satVel() - receiver.e_vel));
214 LOG_DATA("{}: [{}][{:11}][{:5}] - {:.4f} [m/s] Sagnac rate correction", nameId, satSigId, obsType, receiver.type, calcSagnacRateCorrection(e_recvPosAPC, recvObs->e_satPos(), receiver.e_vel, recvObs->e_satVel()));
215 if (*receiver.recvClk.driftFor(satSys) != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m/s] Receiver clock drift", nameId, satSigId, obsType, receiver.type, InsConst::C * *receiver.recvClk.driftFor(satSys)); }
216 LOG_DATA("{}: [{}][{:11}][{:5}] - {:.4f} [m/s] Satellite clock drift", nameId, satSigId, obsType, receiver.type, InsConst::C * recvObs->satClock().drift);
217 LOG_DATA("{}: [{}][{:11}][{:5}] = {:.4f} [m/s] Doppler estimate", nameId, satSigId, obsType, receiver.type, obsData.estimate);
218 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4f} [m/s] Doppler measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement);
219 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4e} [m/s] Difference to measurement", nameId, satSigId, obsType, receiver.type, obsData.measurement - obsData.estimate);
220 break;
222 break;
223 }
224 LOG_DATA("{}: [{}][{:11}][{:5}] Observation error variance", nameId, satSigId, obsType, receiver.type);
225 LOG_DATA("{}: [{}][{:11}][{:5}] {:.4g} [{}] Measurement error variance", nameId, satSigId, obsType, receiver.type, obsData.measVar,
226 obsType == GnssObs::Doppler ? "m^2/s^2" : "m^2");
227
228 if (obsDiff == NoDifference)
229 {
230 if (obsType == GnssObs::Pseudorange || obsType == GnssObs::Carrier)
231 {
232 obsData.measVar += observation.navData()->calcSatellitePositionVariance()
233 + ionoErrorVar(dpsr_I_r_s, freq, observation.freqNum())
234 + tropoErrorVar(dpsr_T_r_s, elevation);
235 LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m^2] Satellite position variance", nameId, satSigId, obsType, receiver.type, observation.navData()->calcSatellitePositionVariance());
236 if (dpsr_I_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m^2] Ionosphere variance", nameId, satSigId, obsType, receiver.type, ionoErrorVar(dpsr_I_r_s, freq, observation.freqNum())); }
237 if (dpsr_T_r_s != 0.0) { LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m^2] Troposphere variance", nameId, satSigId, obsType, receiver.type, tropoErrorVar(dpsr_T_r_s, elevation)); }
238 }
239 if (obsType == GnssObs::Pseudorange)
240 {
241 obsData.measVar += _gnssMeasurementErrorModel.codeBiasErrorVar();
242 LOG_DATA("{}: [{}][{:11}][{:5}] + {:.4f} [m^2] Code bias variance", nameId, satSigId, obsType, receiver.type, _gnssMeasurementErrorModel.codeBiasErrorVar());
243 }
244 }
245 LOG_DATA("{}: [{}][{:11}][{:5}] = {:.4g} [{}] Observation error variance", nameId, satSigId, obsType, receiver.type, obsData.measVar,
246 obsType == GnssObs::Doppler ? "m^2/s^2" : "m^2");
247 }
248 }
249
250 /// Satellite Info used for estimate calculation
252 {
253 /// @brief Constructor
254 /// @param[in] e_satPos Satellite position in ECEF coordinates [m]
255 /// @param[in] e_satVel Satellite velocity in ECEF frame [m/s]
256 /// @param[in] satClockBias Satellite clock bias [s]
257 /// @param[in] satClockDrift Satellite clock drift [s/s]
260
261 Eigen::Vector3d e_satPos; ///< Satellite position in ECEF coordinates [m]
262 Eigen::Vector3d e_satVel; ///< Satellite velocity in ECEF frame [m/s]
263 double satClockBias{}; ///< Satellite clock bias [s]
264 double satClockDrift{}; ///< Satellite clock drift [s/s]
265 };
266
267 /// @brief Calculates the pseudorange estimate
268 /// @param[in] freq Signal frequency
269 /// @param[in] receiverType Receiver type to select the correct antenna
270 /// @param[in] e_recvPosAPC Receiver antenna phase center position in ECEF coordinates [m]
271 /// @param[in] recvClockBias Receiver clock bias [s]
272 /// @param[in] interFreqBias Receiver inter-frequency bias [s]
273 /// @param[in] dpsr_T_r_s Estimated troposphere propagation error [m]
274 /// @param[in] dpsr_I_r_s Estimated ionosphere propagation error [m]
275 /// @param[in] satInfo Satellite Information (pos, vel, clock)
276 /// @param[in] elevation Elevation of the satellite [rad]
277 /// @param[in] gnssObs GNSS observation
278 /// @param[in] nameId Name and Id of the node used for log messages only
279 /// @return The estimate [m] and the position line-of-sight unit vector (used for the Jacobian)
280 template<typename Derived>
282 size_t receiverType,
283 const Eigen::MatrixBase<Derived>& e_recvPosAPC,
284 const auto& recvClockBias,
285 const auto& interFreqBias,
286 const auto& dpsr_T_r_s,
287 const auto& dpsr_I_r_s,
288 const std::shared_ptr<const SatelliteInfo>& satInfo,
289 const auto& elevation,
290 const std::shared_ptr<const GnssObs>& gnssObs,
291 [[maybe_unused]] const std::string& nameId) const
292 {
293 // Receiver-Satellite Range [m]
294 auto rho_r_s = (satInfo->e_satPos - e_recvPosAPC).norm();
295
296 // Sagnac correction [m]
297 auto dpsr_ie_r_s = calcSagnacCorrection(e_recvPosAPC, satInfo->e_satPos);
298
299 // Earth's gravitational field causes relativistic signal delay due to space-time curvature (Shapiro effect) [s]
300 // double posNorm = e_satPos.norm() + e_recvPosAPC.norm();
301 // double dt_rel_stc = e_recvPosAPC.norm() > InsConst::WGS84::a / 2.0 ? 2.0 * InsConst::WGS84::MU / std::pow(InsConst::C, 3) * std::log((posNorm + rho_r_s) / (posNorm - rho_r_s))
302 // : 0.0;
303
304 auto pcv = calcPCV(freq, gnssObs->insTime, elevation, std::nullopt, receiverType, gnssObs, nameId); // TODO: use 'azimuth', but need antenna azimuth
305
306 return rho_r_s
307 + dpsr_ie_r_s
308 + dpsr_T_r_s
309 + dpsr_I_r_s
310 + InsConst::C * (recvClockBias - satInfo->satClockBias /* + dt_rel_stc */ + interFreqBias)
311 + pcv;
312 }
313
314 /// @brief Calculates the carrier-phase estimate
315 /// @param[in] freq Signal frequency
316 /// @param[in] freqNum Frequency number. Only used for GLONASS G1 and G2
317 /// @param[in] receiverType Receiver type to select the correct antenna
318 /// @param[in] e_recvPosMarker Receiver marker position in ECEF coordinates [m]
319 /// @param[in] recvClockBias Receiver clock bias [s]
320 /// @param[in] satInfo Satellite Information (pos, vel, clock)
321 /// @param[in] gnssObs GNSS observation
322 /// @param[in] ionosphericCorrections Ionospheric correction parameters collected from the Nav data
323 /// @param[in] nameId Name and Id of the node used for log messages only
324 /// @return The estimate [m] and the position line-of-sight unit vector (used for the Jacobian)
325 template<typename Derived>
326 std::pair<double, Eigen::Vector3d>
328 int8_t freqNum,
329 size_t receiverType,
330 const Eigen::MatrixBase<Derived>& e_recvPosMarker,
331 double recvClockBias,
332 const std::shared_ptr<const SatelliteInfo>& satInfo,
333 const std::shared_ptr<const GnssObs>& gnssObs,
334 const std::shared_ptr<const IonosphericCorrections>& ionosphericCorrections,
335 [[maybe_unused]] const std::string& nameId) const
336 {
337 Eigen::Vector3d e_recvPosAPC = e_calcRecvPosAPC(freq, receiverType, e_recvPosMarker, gnssObs, nameId);
338 Eigen::Vector3d lla_recvPosAPC = trafo::ecef2lla_WGS84(e_recvPosAPC);
339
340 Eigen::Vector3d e_pLOS = e_calcLineOfSightUnitVector(e_recvPosAPC, satInfo->e_satPos);
341 Eigen::Vector3d n_lineOfSightUnitVector = trafo::n_Quat_e(lla_recvPosAPC(0), lla_recvPosAPC(1)) * e_pLOS;
342 double elevation = calcSatElevation(n_lineOfSightUnitVector);
343 double azimuth = calcSatAzimuth(n_lineOfSightUnitVector);
344
345 // Receiver-Satellite Range [m]
346 double rho_r_s = (satInfo->e_satPos - e_recvPosAPC).norm();
347 // Estimated troposphere propagation error [m]
348 double dpsr_T_r_s = calculateTroposphericDelay(lla_recvPosAPC, gnssObs, elevation, azimuth, nameId);
349 // Estimated ionosphere propagation error [m]
350 double dpsr_I_r_s = calculateIonosphericDelay(freq, freqNum, lla_recvPosAPC, gnssObs, ionosphericCorrections, elevation, azimuth);
351 // Sagnac correction [m]
352 double dpsr_ie_r_s = calcSagnacCorrection(e_recvPosAPC, satInfo->e_satPos);
353
354 // Earth's gravitational field causes relativistic signal delay due to space-time curvature (Shapiro effect) [s]
355 // double posNorm = e_satPos.norm() + e_recvPosAPC.norm();
356 // double dt_rel_stc = e_recvPosAPC.norm() > InsConst::WGS84::a / 2.0 ? 2.0 * InsConst::WGS84::MU / std::pow(InsConst::C, 3) * std::log((posNorm + rho_r_s) / (posNorm - rho_r_s))
357 // : 0.0;
358
359 auto pcv = calcPCV(freq, gnssObs->insTime, elevation, std::nullopt, receiverType, gnssObs, nameId); // TODO: use 'azimuth', but need antenna azimuth
360
361 double estimate = rho_r_s
362 + dpsr_ie_r_s
363 + dpsr_T_r_s
364 - dpsr_I_r_s
365 + InsConst::C * (recvClockBias - satInfo->satClockBias /* + dt_rel_stc */)
366 + pcv;
367
368 return { estimate, e_pLOS };
369 }
370
371 /// @brief Calculates the doppler estimate
372 /// @param[in] freq Signal frequency
373 /// @param[in] receiverType Receiver type to select the correct antenna
374 /// @param[in] e_recvPosMarker Receiver marker position in ECEF coordinates [m]
375 /// @param[in] e_recvVel Receiver velocity in ECEF frame [m/s]
376 /// @param[in] recvClockDrift Receiver clock drift [s/s]
377 /// @param[in] satInfo Satellite Information (pos, vel, clock)
378 /// @param[in] gnssObs GNSS observation
379 /// @param[in] nameId Name and Id of the node used for log messages only
380 /// @return The estimate [m/s] and the position line-of-sight unit vector (used for the Jacobian)
381 template<typename DerivedPos, typename DerivedVel>
383 size_t receiverType,
384 const Eigen::MatrixBase<DerivedPos>& e_recvPosMarker,
385 const Eigen::MatrixBase<DerivedVel>& e_recvVel,
386 const auto& recvClockDrift,
387 const std::shared_ptr<const SatelliteInfo>& satInfo,
388 const std::shared_ptr<const GnssObs>& gnssObs,
389 [[maybe_unused]] const std::string& nameId) const
390 {
391 auto e_recvPosAPC = e_calcRecvPosAPC(freq, receiverType, e_recvPosMarker, gnssObs, nameId);
392
393 auto e_pLOS = e_calcLineOfSightUnitVector(e_recvPosAPC, satInfo->e_satPos);
394
395 return e_pLOS.dot(satInfo->e_satVel - e_recvVel)
396 - calcSagnacRateCorrection(e_recvPosAPC, satInfo->e_satPos, e_recvVel, satInfo->e_satVel)
397 + InsConst::C * (recvClockDrift - satInfo->satClockDrift);
398 }
399
400 /// @brief Calculates the observation variance
401 /// @param[in] freq Signal Frequency
402 /// @param[in] freqNum Frequency number. Only used for GLONASS G1 and G2
403 /// @param[in] receiverType Receiver type to select the correct antenna
404 /// @param[in] obsType Observation type to calculate the variance for
405 /// @param[in] e_recvPosMarker Receiver marker position in ECEF coordinates [m]
406 /// @param[in] e_satPos Satellite position in ECEF coordinates [m]
407 /// @param[in] cn0 Carrier-to-Noise density [dBHz]
408 /// @param[in] gnssObs GNSS observation
409 /// @param[in] navData Navigation data including this satellite
410 /// @param[in] ionosphericCorrections Ionospheric correction parameters collected from the Nav data
411 /// @param[in] nameId Name and Id of the node used for log messages only
412 /// @param[in] obsDiff Observation Difference type to estimate
413 /// @return Observation variance in [m] (pseudorange, carrier) or [m/s] (doppler)
415 int8_t freqNum,
416 size_t receiverType,
418 const Eigen::Vector3d& e_recvPosMarker,
419 const Eigen::Vector3d& e_satPos,
420 double cn0,
421 const std::shared_ptr<const GnssObs>& gnssObs,
422 const std::shared_ptr<const SatNavData>& navData,
423 const std::shared_ptr<const IonosphericCorrections>& ionosphericCorrections,
424 [[maybe_unused]] const std::string& nameId,
425 ObservationDifference obsDiff) const
426 {
427 const SatelliteSystem satSys = freq.getSatSys();
428
429 Eigen::Vector3d e_recvPosAPC = e_calcRecvPosAPC(freq, receiverType, e_recvPosMarker, gnssObs, nameId);
430 Eigen::Vector3d lla_recvPosAPC = trafo::ecef2lla_WGS84(e_recvPosAPC);
431
432 Eigen::Vector3d e_pLOS = e_calcLineOfSightUnitVector(e_recvPosAPC, e_satPos);
433 Eigen::Vector3d n_lineOfSightUnitVector = trafo::n_Quat_e(lla_recvPosAPC(0), lla_recvPosAPC(1)) * e_pLOS;
434 double elevation = calcSatElevation(n_lineOfSightUnitVector);
435 double azimuth = calcSatAzimuth(n_lineOfSightUnitVector);
436
437 // Estimated troposphere propagation error [m]
438 double dpsr_T_r_s = calculateTroposphericDelay(lla_recvPosAPC, gnssObs, elevation, azimuth, nameId);
439 // Estimated ionosphere propagation error [m]
440 double dpsr_I_r_s = calculateIonosphericDelay(freq, freqNum, lla_recvPosAPC, gnssObs, ionosphericCorrections, elevation, azimuth);
441
442 double variance = 0.0;
443
444 switch (obsType)
445 {
447 variance = _gnssMeasurementErrorModel.psrMeasErrorVar(satSys, elevation, cn0);
448 break;
449 case GnssObs::Carrier:
450 variance = _gnssMeasurementErrorModel.carrierMeasErrorVar(satSys, elevation, cn0);
451 break;
452 case GnssObs::Doppler:
453 variance = _gnssMeasurementErrorModel.psrRateMeasErrorVar(freq, freqNum, elevation, cn0);
454 break;
456 break;
457 }
458
459 if (obsDiff == NoDifference)
460 {
461 if (obsType == GnssObs::Pseudorange || obsType == GnssObs::Carrier)
462 {
463 variance += navData->calcSatellitePositionVariance()
464 + ionoErrorVar(dpsr_I_r_s, freq, freqNum)
465 + tropoErrorVar(dpsr_T_r_s, elevation);
466 }
467 if (obsType == GnssObs::Pseudorange)
468 {
469 variance += _gnssMeasurementErrorModel.codeBiasErrorVar();
470 }
471 }
472
473 return variance;
474 }
475
476 /// @brief Calculates the antenna phase center position for the marker
477 /// @param[in] freq Signal frequency
478 /// @param[in] receiverType Receiver type to select the correct antenna
479 /// @param[in] e_recvPosMarker Receiver marker position in ECEF coordinates [m]
480 /// @param[in] gnssObs GNSS observation
481 /// @param[in] nameId Name and Id of the node used for log messages only
482 template<typename Derived>
483 [[nodiscard]] Eigen::Vector3<typename Derived::Scalar> e_calcRecvPosAPC(const Frequency& freq,
484 size_t receiverType,
485 const Eigen::MatrixBase<Derived>& e_recvPosMarker,
486 const std::shared_ptr<const GnssObs>& gnssObs,
487 [[maybe_unused]] const std::string& nameId) const
488 {
489 const Antenna& antenna = _antenna.at(receiverType);
490
491 auto e_recvPosAPC = trafo::e_posMarker2ARP(e_recvPosMarker,
492 gnssObs,
493 antenna.hen_delta);
494 if (antenna.correctPCO)
495 {
496 std::string antennaType;
497 if (antenna.autoDetermine && gnssObs->receiverInfo)
498 {
499 antennaType = gnssObs->receiverInfo->get().antennaType;
500 }
501 else if (!antenna.autoDetermine)
502 {
503 antennaType = antenna.name;
504 }
505 e_recvPosAPC = trafo::e_posARP2APC(e_recvPosAPC, gnssObs, freq, antennaType, nameId);
506 }
507
508 return e_recvPosAPC;
509 }
510
511 /// @brief Calculates the phase center variation
512 /// @param[in] freq Signal frequency
513 /// @param[in] insTime Time to lookup the PCV pattern
514 /// @param[in] elevation Elevation angle in [rad]
515 /// @param[in] azimuth Azimuth in [rad] or nullopt to use the azimuth independent (NOAZI)
516 /// @param[in] receiverType Receiver type to select the correct antenna
517 /// @param[in] gnssObs GNSS observation
518 /// @param[in] nameId Name and Id of the node used for log messages only
519 /// @return The PCV value in [m]
520 template<typename T>
521 [[nodiscard]] T calcPCV(const Frequency& freq,
522 const InsTime& insTime,
523 const T& elevation,
524 std::optional<double> azimuth,
525 size_t receiverType,
526 const std::shared_ptr<const GnssObs>& gnssObs,
527 [[maybe_unused]] const std::string& nameId) const
528 {
529 if (std::isnan(elevation)
530 || (azimuth.has_value() && std::isnan(*azimuth))) { return T(0.0); }
531 const Antenna& antenna = _antenna.at(receiverType);
532 if (antenna.correctPCV)
533 {
534 std::string antennaType;
535 if (antenna.autoDetermine && gnssObs->receiverInfo)
536 {
537 antennaType = gnssObs->receiverInfo->get().antennaType;
538 }
539 else if (!antenna.autoDetermine)
540 {
541 antennaType = antenna.name;
542 }
544 Frequency_(freq),
545 insTime,
546 elevation,
547 azimuth,
548 nameId)
549 .value_or(T(0.0));
550 }
551
552 return T(0.0);
553 }
554
555 /// @brief Calculate the ionospheric delay with the model selected in the GUI
556 /// @param[in] freq Frequency of the signal
557 /// @param[in] freqNum Frequency number. Only used for GLONASS G1 and G2
558 /// @param[in] lla_recvPosAPC Receiver antenna phase center position in LLA coordinates [rad, rad, m]
559 /// @param[in] gnssObs GNSS observation
560 /// @param[in] ionosphericCorrections Ionospheric correction parameters collected from the Nav data
561 /// @param[in] elevation Satellite elevation [rad]
562 /// @param[in] azimuth Satellite azimuth [rad]
563 /// @return Estimated ionosphere propagation error [m]
565 int8_t freqNum,
566 const Eigen::Vector3d& lla_recvPosAPC,
567 const std::shared_ptr<const GnssObs>& gnssObs,
568 const std::shared_ptr<const IonosphericCorrections>& ionosphericCorrections,
569 double elevation,
570 double azimuth) const
571 {
572 return calcIonosphericDelay(static_cast<double>(gnssObs->insTime.toGPSweekTow().tow),
573 freq, freqNum, lla_recvPosAPC,
574 elevation, azimuth,
575 _ionosphereModel, ionosphericCorrections.get());
576 }
577
578 /// @brief Calculate the tropospheric delay with the model selected in the GUI
579 /// @param[in] lla_recvPosAPC Receiver antenna phase center position in LLA coordinates [rad, rad, m]
580 /// @param[in] gnssObs GNSS observation
581 /// @param[in] elevation Satellite elevation [rad]
582 /// @param[in] azimuth Satellite azimuth [rad]
583 /// @param[in] nameId Name and Id of the node used for log messages only
584 /// @return Estimated troposphere propagation error [m]
585 double calculateTroposphericDelay(const Eigen::Vector3d& lla_recvPosAPC,
586 const std::shared_ptr<const GnssObs>& gnssObs,
587 double elevation,
588 double azimuth,
589 [[maybe_unused]] const std::string& nameId) const
590 {
591 auto tropo_r_s = calcTroposphericDelayAndMapping(gnssObs->insTime, lla_recvPosAPC,
592 elevation, azimuth, _troposphereModels, nameId);
593
594 return tropo_r_s.ZHD * tropo_r_s.zhdMappingFactor + tropo_r_s.ZWD * tropo_r_s.zwdMappingFactor;
595 }
596
597 /// @brief Shows the GUI input to select the options
598 /// @param[in] id Unique id for ImGui.
599 /// @param[in] itemWidth Width of the widgets
600 template<typename ReceiverType>
601 bool ShowGuiWidgets(const char* id, float itemWidth)
602 {
603 bool changed = false;
604
605 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
606 if (ImGui::TreeNode(fmt::format("Compensation models##{}", id).c_str()))
607 {
608 ImGui::SetNextItemWidth(itemWidth - ImGui::GetStyle().IndentSpacing);
609 if (ComboIonosphereModel(fmt::format("Ionosphere Model##{}", id).c_str(), _ionosphereModel))
610 {
611 LOG_DEBUG("{}: Ionosphere Model changed to {}", id, NAV::to_string(_ionosphereModel));
612 changed = true;
613 }
614 if (ComboTroposphereModel(fmt::format("Troposphere Model##{}", id).c_str(), _troposphereModels, itemWidth - ImGui::GetStyle().IndentSpacing))
615 {
616 changed = true;
617 }
618 ImGui::TreePop();
619 }
620
621 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
622 if (ImGui::TreeNode(fmt::format("GNSS Measurement Error##{}", id).c_str()))
623 {
624 if (_gnssMeasurementErrorModel.ShowGuiWidgets(id, itemWidth - ImGui::GetStyle().IndentSpacing))
625 {
626 LOG_DEBUG("{}: GNSS Measurement Error Model changed.", id);
627 changed = true;
628 }
629 ImGui::TreePop();
630 }
631
632 if (ImGui::TreeNode(fmt::format("Antenna settings##{}", id).c_str()))
633 {
634 for (size_t i = 0; i < _receiverCount; ++i)
635 {
636 if (_receiverCount > 1)
637 {
638 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
639 if (!ImGui::TreeNode(fmt::format("{}", static_cast<ReceiverType>(i)).c_str())) { continue; }
640 }
641
642 if (ImGui::Checkbox(fmt::format("Correct Phase-center offset##antenna {} {}", id, i).c_str(), &_antenna.at(i).correctPCO))
643 {
644 LOG_DEBUG("{}: Antenna {} correctPCO: {}", id, i, _antenna.at(i).correctPCO);
645 changed = true;
646 }
647 ImGui::SameLine();
648 if (ImGui::Checkbox(fmt::format("Correct Phase-center variation##antenna {} {}", id, i).c_str(), &_antenna.at(i).correctPCV))
649 {
650 LOG_DEBUG("{}: Antenna {} correctPCV: {}", id, i, _antenna.at(i).correctPCV);
651 changed = true;
652 }
653
654 if (!_antenna.at(i).correctPCO && !_antenna.at(i).correctPCV) { ImGui::BeginDisabled(); }
655 if (ImGui::Checkbox(fmt::format("Auto determine##antenna {} {}", id, i).c_str(), &_antenna.at(i).autoDetermine))
656 {
657 LOG_DEBUG("{}: Antenna {} auto: {}", id, i, _antenna.at(i).autoDetermine);
658 changed = true;
659 }
660 ImGui::SameLine();
661 if (_antenna.at(i).autoDetermine) { ImGui::BeginDisabled(); }
662 ImGui::SetNextItemWidth(itemWidth - (1.0F + static_cast<float>(_receiverCount > 1)) * ImGui::GetStyle().IndentSpacing);
663
664 if (ImGui::BeginCombo(fmt::format("Type##Combo {} {}", id, i).c_str(), _antenna.at(i).name.c_str()))
665 {
666 ImGui::PushFont(Application::MonoFont());
667 if (ImGui::Selectable(fmt::format("##Selectable {} {}", id, i).c_str(), _antenna.at(i).name.empty()))
668 {
669 _antenna.at(i).name = "";
670 }
671
672 for (const auto& iter : AntexReader::Get().antennas())
673 {
674 const bool is_selected = (_antenna.at(i).name == iter);
675 if (ImGui::Selectable(iter.c_str(), is_selected))
676 {
677 _antenna.at(i).name = iter;
678 }
679 if (is_selected) { ImGui::SetItemDefaultFocus(); }
680 }
681 ImGui::PopFont();
682 ImGui::EndCombo();
683 }
684 if (_antenna.at(i).autoDetermine) { ImGui::EndDisabled(); }
685 if (!_antenna.at(i).correctPCO && !_antenna.at(i).correctPCV) { ImGui::EndDisabled(); }
686 ImGui::SameLine();
687 gui::widgets::HelpMarker("Used for lookup in ANTEX file.");
688
689 ImGui::SetNextItemWidth(itemWidth - (1.0F + static_cast<float>(_receiverCount > 1)) * ImGui::GetStyle().IndentSpacing);
690 if (ImGui::InputDouble3(fmt::format("Delta H/E/N [m]##{} {}", id, i).c_str(), _antenna.at(i).hen_delta.data(), "%.3f"))
691 {
692 LOG_DEBUG("{}: Antenna {} delta: {}", id, i, _antenna.at(i).hen_delta.transpose());
693 changed = true;
694 }
695 ImGui::SameLine();
696 gui::widgets::HelpMarker("- Antenna height: Height of the antenna reference point (ARP) above the marker\n"
697 "- Horizontal eccentricity of ARP relative to the marker (east/north)");
698
699 if (_receiverCount > 1) { ImGui::TreePop(); }
700 }
701 ImGui::TreePop();
702 }
703
704 return changed;
705 }
706
707 /// @brief Get the Ionosphere Model selected
708 [[nodiscard]] const IonosphereModel& getIonosphereModel() const { return _ionosphereModel; }
709 /// @brief Get the Troposphere Model selection
711 /// @brief Get the GNSS measurement error model
713
714 private:
715 IonosphereModel _ionosphereModel = IonosphereModel::Klobuchar; ///< Ionosphere Model used for the calculation
716 TroposphereModelSelection _troposphereModels; ///< Troposphere Models used for the calculation
717 GnssMeasurementErrorModel _gnssMeasurementErrorModel; ///< GNSS measurement error model to use
718
719 size_t _receiverCount; ///< Number of receivers (used for GUI)
720
721 /// Antenna information
722 struct Antenna
723 {
724 bool correctPCO = true; ///< Correct phase center offset
725 bool correctPCV = true; ///< Correct phase center variation
726 bool autoDetermine = true; ///< Try determine antenna type from e.g. RINEX file
727 std::string name; ///< Type of the antenna for the Antex lookup
728 Eigen::Vector3d hen_delta = Eigen::Vector3d::Zero(); ///< Delta values of marker to antenna base
729 };
730
731 std::unordered_map<size_t, Antenna> _antenna; ///< User antenna selection. Key is receiver type
732
733 /// @brief Converts the provided object into json
734 /// @param[out] j Json object which gets filled with the info
735 /// @param[in] obj Object to convert into json
736 friend void to_json(json& j, const ObservationEstimator::Antenna& obj)
737 {
738 j = json{
739 { "correctPCO", obj.correctPCO },
740 { "correctPCV", obj.correctPCV },
741 { "autoDetermine", obj.autoDetermine },
742 { "name", obj.name },
743 { "hen_delta", obj.hen_delta },
744 };
745 }
746 /// @brief Converts the provided json object into a node object
747 /// @param[in] j Json object with the needed values
748 /// @param[out] obj Object to fill from the json
749 friend void from_json(const json& j, ObservationEstimator::Antenna& obj)
750 {
751 if (j.contains("correctPCO")) { j.at("correctPCO").get_to(obj.correctPCO); }
752 if (j.contains("correctPCV")) { j.at("correctPCV").get_to(obj.correctPCV); }
753 if (j.contains("autoDetermine")) { j.at("autoDetermine").get_to(obj.autoDetermine); }
754 if (j.contains("name")) { j.at("name").get_to(obj.name); }
755 if (j.contains("hen_delta")) { j.at("hen_delta").get_to(obj.hen_delta); }
756 }
757
758 /// @brief Converts the provided object into json
759 /// @param[out] j Json object which gets filled with the info
760 /// @param[in] obj Object to convert into json
761 friend void to_json(json& j, const ObservationEstimator& obj)
762 {
763 j = json{
764 { "ionosphereModel", obj._ionosphereModel },
765 { "troposphereModels", obj._troposphereModels },
766 { "gnssMeasurementError", obj._gnssMeasurementErrorModel },
767 { "antenna", obj._antenna },
768 };
769 }
770 /// @brief Converts the provided json object into a node object
771 /// @param[in] j Json object with the needed values
772 /// @param[out] obj Object to fill from the json
773 friend void from_json(const json& j, ObservationEstimator& obj)
774 {
775 if (j.contains("ionosphereModel")) { j.at("ionosphereModel").get_to(obj._ionosphereModel); }
776 if (j.contains("troposphereModels")) { j.at("troposphereModels").get_to(obj._troposphereModels); }
777 if (j.contains("gnssMeasurementError")) { j.at("gnssMeasurementError").get_to(obj._gnssMeasurementErrorModel); }
778 if (j.contains("antenna")) { j.at("antenna").get_to(obj._antenna); }
779 }
780};
781
782} // namespace NAV
GNSS Antenna related transformations.
ANTEX file reader.
Transformation collection.
nlohmann::json json
json namespace
Frequency definition for different satellite systems.
Galileo Ephemeris information.
GNSS Observation messages.
Text Help Marker (?) with Tooltip.
Ionosphere Models.
Defines how to save certain datatypes to json.
#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
Errors concerning GNSS observations.
Observation data used for calculations.
Receiver information.
Structs identifying a unique satellite.
Troposphere Models.
Values with an uncertainty (Standard Deviation)
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.
static AntexReader & Get()
Get the static Instance of the reader.
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
SatelliteSystem getSatSys() const
Get the satellite system for which this frequency is defined.
Errors concerning GNSS observations.
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
static constexpr double C
Speed of light [m/s].
Definition Constants.hpp:34
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
friend void to_json(json &j, const ObservationEstimator::Antenna &obj)
Converts the provided object into json.
const IonosphereModel & getIonosphereModel() const
Get the Ionosphere Model selected.
TroposphereModelSelection _troposphereModels
Troposphere Models used for the calculation.
friend void from_json(const json &j, ObservationEstimator &obj)
Converts the provided json object into a node object.
ObservationDifference
How the observation gets used. Influenced the measurement variance.
@ NoDifference
Estimation is not differenced.
@ DoubleDifference
Double Difference.
@ SingleDifference
Single Difference.
ObservationEstimator(size_t receiverCount)
Constructor.
GnssMeasurementErrorModel _gnssMeasurementErrorModel
GNSS measurement error model to use.
Eigen::Vector3< typename Derived::Scalar > e_calcRecvPosAPC(const Frequency &freq, size_t receiverType, const Eigen::MatrixBase< Derived > &e_recvPosMarker, const std::shared_ptr< const GnssObs > &gnssObs, const std::string &nameId) const
Calculates the antenna phase center position for the marker.
double calculateIonosphericDelay(const Frequency &freq, int8_t freqNum, const Eigen::Vector3d &lla_recvPosAPC, const std::shared_ptr< const GnssObs > &gnssObs, const std::shared_ptr< const IonosphericCorrections > &ionosphericCorrections, double elevation, double azimuth) const
Calculate the ionospheric delay with the model selected in the GUI.
const GnssMeasurementErrorModel & getGnssMeasurementErrorModel() const
Get the GNSS measurement error model.
size_t _receiverCount
Number of receivers (used for GUI)
IonosphereModel _ionosphereModel
Ionosphere Model used for the calculation.
double calcObservationVariance(Frequency freq, int8_t freqNum, size_t receiverType, GnssObs::ObservationType obsType, const Eigen::Vector3d &e_recvPosMarker, const Eigen::Vector3d &e_satPos, double cn0, const std::shared_ptr< const GnssObs > &gnssObs, const std::shared_ptr< const SatNavData > &navData, const std::shared_ptr< const IonosphericCorrections > &ionosphericCorrections, const std::string &nameId, ObservationDifference obsDiff) const
Calculates the observation variance.
void calcObservationEstimate(const SatSigId &satSigId, Observations::SignalObservation &observation, const Receiver< ReceiverType > &receiver, const std::shared_ptr< const IonosphericCorrections > &ionosphericCorrections, const std::string &nameId, ObservationDifference obsDiff) const
Calculates the observation estimate for the given signal.
double calculateTroposphericDelay(const Eigen::Vector3d &lla_recvPosAPC, const std::shared_ptr< const GnssObs > &gnssObs, double elevation, double azimuth, const std::string &nameId) const
Calculate the tropospheric delay with the model selected in the GUI.
std::pair< double, Eigen::Vector3d > calcCarrierEstimate(Frequency freq, int8_t freqNum, size_t receiverType, const Eigen::MatrixBase< Derived > &e_recvPosMarker, double recvClockBias, const std::shared_ptr< const SatelliteInfo > &satInfo, const std::shared_ptr< const GnssObs > &gnssObs, const std::shared_ptr< const IonosphericCorrections > &ionosphericCorrections, const std::string &nameId) const
Calculates the carrier-phase estimate.
bool ShowGuiWidgets(const char *id, float itemWidth)
Shows the GUI input to select the options.
const TroposphereModelSelection & getTroposphereModels() const
Get the Troposphere Model selection.
auto calcPseudorangeEstimate(Frequency freq, size_t receiverType, const Eigen::MatrixBase< Derived > &e_recvPosAPC, const auto &recvClockBias, const auto &interFreqBias, const auto &dpsr_T_r_s, const auto &dpsr_I_r_s, const std::shared_ptr< const SatelliteInfo > &satInfo, const auto &elevation, const std::shared_ptr< const GnssObs > &gnssObs, const std::string &nameId) const
Calculates the pseudorange estimate.
T calcPCV(const Frequency &freq, const InsTime &insTime, const T &elevation, std::optional< double > azimuth, size_t receiverType, const std::shared_ptr< const GnssObs > &gnssObs, const std::string &nameId) const
Calculates the phase center variation.
auto calcDopplerEstimate(Frequency freq, size_t receiverType, const Eigen::MatrixBase< DerivedPos > &e_recvPosMarker, const Eigen::MatrixBase< DerivedVel > &e_recvVel, const auto &recvClockDrift, const std::shared_ptr< const SatelliteInfo > &satInfo, const std::shared_ptr< const GnssObs > &gnssObs, const std::string &nameId) const
Calculates the doppler estimate.
friend void from_json(const json &j, ObservationEstimator::Antenna &obj)
Converts the provided json object into a node object.
std::unordered_map< size_t, Antenna > _antenna
User antenna selection. Key is receiver type.
friend void to_json(json &j, const ObservationEstimator &obj)
Converts the provided object into json.
void calcObservationEstimates(Observations &observations, const Receiver< ReceiverType > &receiver, const std::shared_ptr< const IonosphericCorrections > &ionosphericCorrections, const std::string &nameId, ObservationDifference obsDiff) const
Calculates the observation estimates.
ImGui extensions.
bool InputDouble3(const char *label, double v[3], const char *format, ImGuiInputTextFlags flags)
Shows an InputText GUI element for an array of 'double[3]'.
Definition imgui_ex.cpp:178
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
Eigen::Vector3< typename Derived::Scalar > e_posMarker2ARP(const Eigen::MatrixBase< Derived > &e_posMarker, const std::shared_ptr< const GnssObs > &gnssObs, const Eigen::Vector3d &hen_delta=Eigen::Vector3d::Zero())
Converts a marker position to the antenna reference point position.
Definition Antenna.hpp:33
Eigen::Vector3< typename Derived::Scalar > ecef2lla_WGS84(const Eigen::MatrixBase< Derived > &e_position)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude using WGS84.
Eigen::Quaternion< Scalar > n_Quat_e(const Scalar &latitude, const Scalar &longitude)
Quaternion for rotations from Earth-fixed to navigation frame.
Eigen::Vector3< typename Derived::Scalar > e_posARP2APC(const Eigen::MatrixBase< Derived > &e_posARP, const std::shared_ptr< const GnssObs > &gnssObs, Frequency freq, const std::string &antennaType, const std::string &nameId)
Converts a antenna reference point position position to the antenna phase center position.
Definition Antenna.hpp:89
Frequency_
Enumerate for GNSS frequencies.
Definition Frequency.hpp:26
bool ComboTroposphereModel(const char *label, TroposphereModelSelection &troposphereModelSelection, float width)
Shows a ComboBox and button for advanced configuration to select the troposphere models.
Derived::Scalar calcSatElevation(const Eigen::MatrixBase< Derived > &n_lineOfSightUnitVector)
Calculates the elevation of the satellite from the antenna.
Definition Functions.hpp:43
IonosphereModel
Available Ionosphere Models.
@ Klobuchar
Klobuchar model (GPS), also called Broadcast sometimes.
const char * to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
Converts the enum to a string.
DerivedA::Scalar calcSagnacCorrection(const Eigen::MatrixBase< DerivedA > &e_posAnt, const Eigen::MatrixBase< DerivedB > &e_satPos)
Calculates the Earth rotation/Sagnac correction.
Definition Functions.hpp:66
double ionoErrorVar(double dpsr_I, Frequency freq, int8_t num)
Calculates the ionospheric error variance.
double tropoErrorVar(double dpsr_T, double elevation)
Calculates the tropospheric error variance.
bool ComboIonosphereModel(const char *label, IonosphereModel &ionosphereModel)
Shows a ComboBox to select the ionosphere model.
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
DerivedA::Scalar calcSagnacRateCorrection(const Eigen::MatrixBase< DerivedA > &e_recvPos, const Eigen::MatrixBase< DerivedB > &e_satPos, const Eigen::MatrixBase< DerivedC > &e_recvVel, const Eigen::MatrixBase< DerivedD > &e_satVel)
Calculates the Range-rate Earth rotation/Sagnac correction.
Definition Functions.hpp:81
ZenithDelay calcTroposphericDelayAndMapping(const InsTime &insTime, const Eigen::Vector3d &lla_pos, double elevation, double, const TroposphereModelSelection &troposphereModels, const std::string &nameId)
Calculates the tropospheric zenith hydrostatic and wet delays and corresponding mapping factors.
Derived::Scalar calcSatAzimuth(const Eigen::MatrixBase< Derived > &n_lineOfSightUnitVector)
Calculates the azimuth of the satellite from the antenna.
Definition Functions.hpp:54
double calcIonosphericDelay(double tow, Frequency freq, int8_t freqNum, const Eigen::Vector3d &lla_pos, double elevation, double azimuth, IonosphereModel ionosphereModel, const IonosphericCorrections *corrections)
Calculates the ionospheric delay.
Eigen::Vector3< typename DerivedA::Scalar > e_calcLineOfSightUnitVector(const Eigen::MatrixBase< DerivedA > &e_posAnt, const Eigen::MatrixBase< DerivedB > &e_posSat)
Calculates the line-of-sight unit vector from the user antenna to the satellite.
Definition Functions.hpp:31
bool autoDetermine
Try determine antenna type from e.g. RINEX file.
Eigen::Vector3d hen_delta
Delta values of marker to antenna base.
bool correctPCV
Correct phase center variation.
std::string name
Type of the antenna for the Antex lookup.
bool correctPCO
Correct phase center offset.
Eigen::Vector3d e_satVel
Satellite velocity in ECEF frame [m/s].
SatelliteInfo(Eigen::Vector3d e_satPos, Eigen::Vector3d e_satVel, double satClockBias, double satClockDrift)
Constructor.
Eigen::Vector3d e_satPos
Satellite position in ECEF coordinates [m].
double satClockBias
Satellite clock bias [s].
double satClockDrift
Satellite clock drift [s/s].
Receiver specific observation of the signal.
int8_t freqNum() const
Frequency number. Only used for GLONASS G1 and G2.
std::unordered_map< size_t, std::shared_ptr< ReceiverSpecificData > > recvObs
Receiver specific data.
const std::shared_ptr< const SatNavData > & navData() const
Satellite Navigation data.
Observation storage type.
unordered_map< SatSigId, SignalObservation > signals
Observations and calculated data for each signal.
const double * biasFor(SatelliteSystem satSys) const
Get the bias for the given satellite system.
const double * driftFor(SatelliteSystem satSys) const
Get the drift for the given satellite system.
Receiver information.
Definition Receiver.hpp:34
std::shared_ptr< const GnssObs > gnssObs
Latest GNSS observation.
Definition Receiver.hpp:54
std::unordered_map< Frequency, UncertainValue< double > > interFrequencyBias
Inter frequency biases [s].
Definition Receiver.hpp:52
ReceiverType type
Receiver Type.
Definition Receiver.hpp:42
Eigen::Vector3d e_posMarker
Marker Position in ECEF frame [m].
Definition Receiver.hpp:44
Eigen::Vector3d e_vel
Velocity in ECEF frame [m/s].
Definition Receiver.hpp:48
ReceiverClock recvClk
Estimated receiver clock parameters.
Definition Receiver.hpp:50
Identifies a satellite signal (satellite frequency and number)
Frequency freq() const
Returns the frequency of the satellite signal.
Satellite System type.
Collection of troposphere model selections.