0.3.0
Loading...
Searching...
No Matches
Algorithm.cpp
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 Algorithm.cpp
10/// @brief Single Point Positioning Algorithm
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2023-12-20
13
14#include "Algorithm.hpp"
15#include <algorithm>
16#include <spdlog/common.h>
17#include <spdlog/spdlog.h>
18
24#include "util/Logger.hpp"
25#include <fmt/format.h>
26
29
32
34
35namespace NAV
36{
37namespace SPP
38{
39
40bool Algorithm::ShowGuiWidgets(const char* id, float itemWidth, float unitWidth)
41{
42 bool changed = false;
43
44 changed |= _obsFilter.ShowGuiWidgets<ReceiverType>(id, itemWidth);
45
46 ImGui::SetNextItemWidth(itemWidth);
47 changed |= gui::widgets::EnumCombo(fmt::format("Estimation algorithm##{}", id).c_str(), _estimatorType);
48
49 if (!canEstimateInterFrequencyBias()) { ImGui::BeginDisabled(); }
50 changed |= ImGui::Checkbox(fmt::format("Estimate inter-frequency biases##{}", id).c_str(), &_estimateInterFreqBiases);
51 if (!canEstimateInterFrequencyBias()) { ImGui::EndDisabled(); }
52
53 changed |= _obsEstimator.ShowGuiWidgets<ReceiverType>(id, itemWidth);
54
56 {
57 changed |= _kalmanFilter.ShowGuiWidgets(id, _obsFilter.isObsTypeUsed(GnssObs::Doppler),
58 _obsFilter.getSystemFilter().toVector().size() != 1,
60 }
61
62 return changed;
63}
64
66{
67 _receiver = Receiver(Rover, _obsFilter.getSystemFilter().toVector());
68 _obsFilter.reset();
69 _kalmanFilter.reset(_obsFilter.getSystemFilter().toVector());
70 _lastUpdate.reset();
71}
72
73std::shared_ptr<SppSolution> Algorithm::calcSppSolution(const std::shared_ptr<const GnssObs>& gnssObs,
74 const std::vector<const GnssNavInfo*>& gnssNavInfos,
75 const std::string& nameId)
76{
77 _receiver.gnssObs = gnssObs;
78
79 if (gnssNavInfos.empty())
80 {
81 LOG_ERROR("{}: [{}] SPP cannot calculate position because no navigation data provided.", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
82 return nullptr;
83 }
84 LOG_DATA("{}: [{}] Calculating SPP", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
85
86 // Collection of all connected Ionospheric Corrections
87 auto ionosphericCorrections = std::make_shared<const IonosphericCorrections>(gnssNavInfos);
88
89 double dt = _lastUpdate.empty() ? 0.0 : static_cast<double>((_receiver.gnssObs->insTime - _lastUpdate).count());
90 LOG_DATA("{}: dt = {}s", nameId, dt);
91 _lastUpdate = _receiver.gnssObs->insTime;
92
93 auto sppSol = std::make_shared<SppSolution>();
94 sppSol->insTime = _receiver.gnssObs->insTime;
95
97 {
98 _kalmanFilter.predict(dt, _receiver.lla_posMarker, nameId);
99 assignKalmanFilterResult(_kalmanFilter.getState(), _kalmanFilter.getErrorCovarianceMatrix(), nameId);
100 }
101
102 constexpr size_t N_ITER_MAX_LSQ = 10;
103 size_t nIter = _estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized() ? 1 : N_ITER_MAX_LSQ;
104 Eigen::Vector3d e_oldPos = _receiver.e_posMarker;
105 bool accuracyAchieved = false;
106
108
109 for (size_t iteration = 0; iteration < nIter; iteration++)
110 {
111 LOG_DATA("{}: [{}] iteration {}/{}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), iteration + 1, nIter);
112 LOG_DATA("{}: [{}] e_pos = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_posMarker.transpose());
113 LOG_DATA("{}: [{}] e_vel = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_vel.transpose());
114 LOG_DATA("{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
115 rad2deg(_receiver.lla_posMarker.x()), rad2deg(_receiver.lla_posMarker.y()), _receiver.lla_posMarker.z());
116 for ([[maybe_unused]] const auto& satSys : _receiver.recvClk.satelliteSystems)
117 {
118 LOG_DATA("{}: [{}] {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), satSys);
119 LOG_DATA("{}: [{}] clkBias = {} [s] (StdDev = {})", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.biasFor(satSys), *_receiver.recvClk.biasStdDevFor(satSys));
120 LOG_DATA("{}: [{}] clkDrift = {} [s/s] (StdDev = {})", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.driftFor(satSys), *_receiver.recvClk.driftStdDevFor(satSys));
121 }
122 for ([[maybe_unused]] const auto& freq : _receiver.interFrequencyBias)
123 {
124 LOG_DATA("{}: [{}] IFBBias [{:3}] = {} [s] (StdDev = {})", nameId,
125 _receiver.gnssObs->insTime.toYMDHMS(GPST), freq.first, freq.second.value, freq.second.stdDev);
126 }
127
128 auto posNorm = e_oldPos.norm();
129 bool ignoreElevationMask = posNorm < 0.5 * InsConst::WGS84::a || posNorm > 1.5 * InsConst::WGS84::a;
130 LOG_DATA("{}: [{}] ignoreElevationMask = {} (posNorm = {} [m])", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), ignoreElevationMask, posNorm);
131 Observations observations;
132 _obsFilter.selectObservationsForCalculation(Rover,
133 _receiver.e_posMarker,
134 _receiver.lla_posMarker,
135 _receiver.gnssObs,
136 gnssNavInfos,
137 observations,
138 nullptr,
139 nameId,
140 ignoreElevationMask);
141
142 if (observations.signals.empty())
143 {
144 LOG_TRACE("{}: [{}] SPP cannot calculate position because no valid observations. Try changing filter settings or reposition your antenna.",
145 nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
146 return nullptr;
147 }
148
149 size_t nParams = SPP::States::POS_STATE_COUNT + observations.systems.size() - 1;
150
151 sppSol->nSatellites = observations.satellites.size();
152 sppSol->nMeasPsr = observations.nObservables[GnssObs::Pseudorange];
153 sppSol->nMeasDopp = observations.nObservables[GnssObs::Doppler];
154 LOG_DATA("{}: nParams = {}", nameId, nParams);
155 LOG_DATA("{}: nSatellites = {}", nameId, sppSol->nSatellites);
156 LOG_DATA("{}: nMeasPsr = {}", nameId, sppSol->nMeasPsr);
157 LOG_DATA("{}: nMeasDopp = {}", nameId, sppSol->nMeasDopp);
158 for (const auto& satSys : observations.systems)
159 {
160 [[maybe_unused]] auto satCount = std::ranges::count_if(observations.satellites, [&](const SatId& satId) {
161 return satId.satSys == satSys;
162 });
163
164 LOG_DATA("{}: nSat {:5} = {}", nameId, satSys, satCount);
165 }
166
167 if (size_t nPsrMeas = observations.nObservablesUniqueSatellite[GnssObs::Pseudorange];
168 (_estimatorType != EstimatorType::KalmanFilter || !_kalmanFilter.isInitialized()) && nPsrMeas <= nParams)
169 {
170 LOG_TRACE("{}: [{}] SPP cannot calculate position because only {} satellites with pseudorange observations ({} needed). Try changing filter settings or reposition your antenna.",
171 nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), nPsrMeas, nParams + 1);
172 return nullptr;
173 }
174
175 updateInterFrequencyBiases(observations, nameId);
176
177 _obsEstimator.calcObservationEstimates(observations, _receiver, ionosphericCorrections, nameId, ObservationEstimator::NoDifference);
178
179 auto stateKeys = determineStateKeys(observations.systems, observations.nObservables[GnssObs::Doppler], nameId);
180 auto measKeys = determineMeasKeys(observations, sppSol->nMeasPsr, sppSol->nMeasDopp, nameId);
181
182 sppSol->nParam = stateKeys.size();
183
184 H = calcMatrixH(stateKeys, measKeys, observations, nameId);
185 auto R = calcMatrixR(measKeys, observations, nameId);
186 auto dz = calcMeasInnovation(measKeys, observations, nameId);
187
189 {
190 std::string highInnovation;
191 size_t highInnovationCounter = 0;
192 for (const auto& key : dz.rowKeys())
193 {
194 if (double val = dz(key); std::abs(val) > 1000)
195 {
196 highInnovation += fmt::format("{}[{} {:.0f}], ", highInnovationCounter++ % 3 == 0 ? "\n" : "", key, val);
197 }
198 }
199 if (highInnovationCounter != 0)
200 {
201 std::string msg = fmt::format("Potential clock jump detected. Adjusting KF clock error covariance.\n"
202 "Too large innovations: {}",
203 highInnovation.substr(0, highInnovation.length() - 2));
204 LOG_WARN("{}: [{}] {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), msg);
205 _kalmanFilter.setClockBiasErrorCovariance(1e1);
206 sppSol->addEvent(msg);
207 }
208 }
209
211 {
214 {
216 }
217 else /* if (_estimatorType == EstimatorType::WeightedLeastSquares) */
218 {
219 auto W = KeyedMatrixXd<Meas::MeasKeyTypes, Meas::MeasKeyTypes>(Eigen::MatrixXd(R(all, all).diagonal().cwiseInverse().asDiagonal()), R.colKeys(), R.rowKeys());
220 LOG_DATA("{}: W =\n{}", nameId, W);
222 }
223 LOG_DATA("{}: LSQ sol (dx) =\n{}", nameId, lsq.solution.transposed());
224 LOG_DATA("{}: LSQ var =\n{}", nameId, lsq.variance.transposed());
225
226 assignLeastSquaresResult(lsq.solution, lsq.variance, e_oldPos,
227 nParams, observations.nObservablesUniqueSatellite[GnssObs::Doppler], dt, nameId);
228
229 accuracyAchieved = lsq.solution(all).norm() < 1e-4;
230 if (accuracyAchieved) { LOG_DATA("{}: [{}] Accuracy achieved on iteration {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), iteration + 1); }
231 else { LOG_DATA("{}: [{}] Bad accuracy on iteration {}: {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), iteration + 1, lsq.solution(all).norm()); }
232 if (iteration == nIter - 1) { return nullptr; }
233 if (accuracyAchieved || iteration == nIter - 1)
234 {
236 && sppSol->nMeasPsr > nParams // Variance can only be calculated if more measurements than parameters
237 && (!_obsFilter.isObsTypeUsed(GnssObs::Doppler) || sppSol->nMeasDopp > nParams))
238 {
239 LOG_TRACE("{}: [{}] Initializing KF with LSQ solution", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
240 KeyedVectorXd<States::StateKeyType> x(Eigen::VectorXd::Zero(lsq.solution.rows()), lsq.solution.rowKeys());
241 x.segment<3>(PosKey) = _receiver.e_posMarker;
242 if (x.hasAnyRows(VelKey)) { x.segment<3>(VelKey) = _receiver.e_vel; }
243 for (size_t i = 0; i < _receiver.recvClk.satelliteSystems.size(); i++)
244 {
245 auto satSys = _receiver.recvClk.satelliteSystems.at(i);
246 x(Keys::RecvClkBias{ satSys }) = _receiver.recvClk.bias.at(i) * InsConst::C;
247 if (x.hasRow(Keys::RecvClkDrift{ satSys }))
248 {
249 x(Keys::RecvClkDrift{ satSys }) = _receiver.recvClk.drift.at(i) * InsConst::C;
250 }
251 }
252 for (const auto& state : x.rowKeys())
253 {
254 if (const auto* bias = std::get_if<Keys::InterFreqBias>(&state))
255 {
256 x(*bias) = _receiver.interFrequencyBias.at(bias->freq).value * InsConst::C;
257 }
258 }
259
260 _kalmanFilter.initialize(x, lsq.variance);
261 LOG_DATA("{}: x =\n{}", nameId, _kalmanFilter.getState().transposed());
262 LOG_DATA("{}: P =\n{}", nameId, _kalmanFilter.getErrorCovarianceMatrix());
263 }
264 if (lsq.variance.hasRows(VelKey))
265 {
266 sppSol->setPosVelAndCov_e(_receiver.e_posMarker, _receiver.e_vel, lsq.variance(PosVelKey, PosVelKey));
267 }
268 else
269 {
270 sppSol->setPositionAndCov_e(_receiver.e_posMarker, lsq.variance.block<3>(PosKey, PosKey));
271 }
272
273 sppSol->satData.reserve(observations.satellites.size());
274 for (const auto& [satSigId, signalObs] : observations.signals)
275 {
276 if (std::ranges::find_if(sppSol->satData,
277 [&satSigId = satSigId](const auto& satIdData) { return satIdData.first == satSigId.toSatId(); })
278 == sppSol->satData.end())
279 {
280 sppSol->satData.emplace_back(satSigId.toSatId(),
281 SppSolution::SatData{ .satElevation = signalObs.recvObs.at(Rover)->satElevation(_receiver.e_posMarker, _receiver.lla_posMarker),
282 .satAzimuth = signalObs.recvObs.at(Rover)->satAzimuth(_receiver.e_posMarker, _receiver.lla_posMarker) });
283 }
284 }
285
286 sppSol->_e_sppCovarianceMatrix = lsq.variance;
287
288 break;
289 }
290 }
291 else // if (_estimatorType == EstimatorType::KalmanFilter)
292 {
293 _kalmanFilter.update(measKeys, H, R, dz, nameId);
294
295 if (double posDiff = (_kalmanFilter.getState()(PosKey) - _receiver.e_posMarker).norm();
296 posDiff > 100)
297 {
298 std::string msg = fmt::format("Potential clock jump detected. Reinitializing KF with WLSQ.\nPosition difference to previous epoch {:.1f}m", posDiff);
299 LOG_WARN("{}: [{}] {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), msg);
300 sppSol->addEvent(msg);
301 // _kalmanFilter.deinitialize();
302 // nIter = N_ITER_MAX_LSQ + 1;
303 // continue;
304 }
305
306 assignKalmanFilterResult(_kalmanFilter.getState(), _kalmanFilter.getErrorCovarianceMatrix(), nameId);
307 sppSol->setPosVelAndCov_e(_receiver.e_posMarker, _receiver.e_vel, _kalmanFilter.getErrorCovarianceMatrix()(PosVelKey, PosVelKey));
308
309 sppSol->satData.reserve(observations.satellites.size());
310 for (const auto& [satSigId, signalObs] : observations.signals)
311 {
312 if (std::ranges::find_if(sppSol->satData,
313 [&satSigId = satSigId](const auto& satIdData) { return satIdData.first == satSigId.toSatId(); })
314 == sppSol->satData.end())
315 {
316 sppSol->satData.emplace_back(satSigId.toSatId(),
317 SppSolution::SatData{ .satElevation = signalObs.recvObs.at(Rover)->satElevation(_receiver.e_posMarker, _receiver.lla_posMarker),
318 .satAzimuth = signalObs.recvObs.at(Rover)->satAzimuth(_receiver.e_posMarker, _receiver.lla_posMarker) });
319 }
320 }
321 sppSol->_e_sppCovarianceMatrix = _kalmanFilter.getErrorCovarianceMatrix();
322 }
323 }
324 // use H matrix to calculate DOPs
325 computeDOPs(sppSol, H, nameId);
326
327 sppSol->recvClk = _receiver.recvClk;
328 sppSol->interFrequencyBias = _receiver.interFrequencyBias;
329
330#if LOG_LEVEL <= LOG_LEVEL_DATA
331 if (sppSol->e_position() != _receiver.e_posMarker)
332 {
333 LOG_DATA("{}: [{}] Receiver: e_pos = {:.6f}m, {:.6f}m, {:.6f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
334 _receiver.e_posMarker(0), _receiver.e_posMarker(1), _receiver.e_posMarker(2));
335 LOG_DATA("{}: [{}] Receiver: lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
336 rad2deg(_receiver.lla_posMarker.x()), rad2deg(_receiver.lla_posMarker.y()), _receiver.lla_posMarker.z());
337 }
338 if (sppSol->e_velocity() != _receiver.e_vel)
339 {
340 LOG_DATA("{}: [{}] Receiver: e_vel = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_vel.transpose());
341 }
342 for (const auto& satSys : _receiver.recvClk.satelliteSystems)
343 {
344 if (*sppSol->recvClk.biasFor(satSys) != *_receiver.recvClk.biasFor(satSys))
345 {
346 LOG_DATA("{}: [{}] Receiver: clkBias = {} s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.biasFor(satSys));
347 }
348 if (*sppSol->recvClk.driftFor(satSys) != *_receiver.recvClk.driftFor(satSys))
349 {
350 LOG_DATA("{}: [{}] Receiver: clkDrift = {} s/s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.driftFor(satSys));
351 }
352 }
353#endif
354
355 LOG_DATA("{}: [{}] Solution: e_pos = {:.6f}m, {:.6f}m, {:.6f}m", nameId, sppSol->insTime.toYMDHMS(GPST),
356 sppSol->e_position()(0), sppSol->e_position()(1), sppSol->e_position()(2));
357 LOG_DATA("{}: [{}] Solution: lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId, sppSol->insTime.toYMDHMS(GPST),
358 rad2deg(sppSol->latitude()), rad2deg(sppSol->longitude()), sppSol->altitude());
359 LOG_DATA("{}: [{}] Solution: e_vel = {}", nameId, sppSol->insTime.toYMDHMS(GPST), sppSol->e_velocity().transpose());
360 for (size_t i = 0; i < sppSol->recvClk.satelliteSystems.size(); i++) // NOLINT
361 {
362 LOG_DATA("{}: [{}] Solution: clkBias [{:5}] = {} s", nameId, sppSol->insTime.toYMDHMS(GPST),
363 sppSol->recvClk.satelliteSystems.at(i), sppSol->recvClk.bias.at(i));
364 }
365 for (size_t i = 0; i < sppSol->recvClk.satelliteSystems.size(); i++) // NOLINT
366 {
367 LOG_DATA("{}: [{}] Solution: clkDrift [{:5}] = {} s/s", nameId, sppSol->insTime.toYMDHMS(GPST),
368 sppSol->recvClk.satelliteSystems.at(i), sppSol->recvClk.drift.at(i));
369 }
370 for ([[maybe_unused]] const auto& freq : sppSol->interFrequencyBias)
371 {
372 LOG_DATA("{}: [{}] Solution: IFBBias [{:5}] = {} s", nameId, sppSol->insTime.toYMDHMS(GPST), freq.first, freq.second.value);
373 }
374
375 return sppSol;
376}
377
378bool Algorithm::canCalculateVelocity(size_t nDoppMeas) const
379{
380 if (_estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized()) { return true; }
381
382 return _obsFilter.isObsTypeUsed(GnssObs::Doppler) && nDoppMeas >= 4;
383}
384
386{
387 for (const auto& satSys : SatelliteSystem::GetAll())
388 {
389 auto filter = Frequency(_obsFilter.getFrequencyFilter() & satSys);
390 if (filter.count() > 1) { return true; }
391 }
392
393 return false;
394}
395
396void Algorithm::updateInterFrequencyBiases(const Observations& observations, [[maybe_unused]] const std::string& nameId)
397{
399 {
400 std::set<Frequency> observedFrequencies;
401 Frequency allObservedFrequencies;
402 for (const auto& obs : observations.signals)
403 {
404 observedFrequencies.insert(obs.first.freq());
405 allObservedFrequencies |= obs.first.freq();
406 }
407 LOG_DATA("{}: Observed frequencies {}", nameId, fmt::join(observedFrequencies, ", "));
408
409 for (const auto& freq : observedFrequencies)
410 {
411 if (!freq.isFirstFrequency(allObservedFrequencies) && !_receiver.interFrequencyBias.contains(freq))
412 {
413 LOG_TRACE("{}: Estimating Inter-Frequency bias for {}", nameId, freq);
414 _receiver.interFrequencyBias.emplace(freq, UncertainValue<double>{});
415 _kalmanFilter.addInterFrequencyBias(freq);
416 }
417 }
418 }
419}
420
421std::vector<States::StateKeyType> Algorithm::determineStateKeys(const std::set<SatelliteSystem>& usedSatSystems, size_t nDoppMeas,
422 [[maybe_unused]] const std::string& nameId) const
423{
425 {
426 LOG_DATA("{}: stateKeys = [{}]", nameId, joinToString(_kalmanFilter.getStateKeys()));
427 return _kalmanFilter.getStateKeys();
428 }
429
430 std::vector<States::StateKeyType> stateKeys;
431 stateKeys.reserve(PosKey.size());
432 std::ranges::copy(PosKey, std::back_inserter(stateKeys));
433 stateKeys.reserve(stateKeys.size() + 1
434 + canCalculateVelocity(nDoppMeas) * (VelKey.size() + 1)
435 + usedSatSystems.size() * (1 + canCalculateVelocity(nDoppMeas)));
436 if (canCalculateVelocity(nDoppMeas))
437 {
438 std::ranges::copy(VelKey, std::back_inserter(stateKeys));
439 }
440
441 for (const auto& satSys : usedSatSystems)
442 {
443 stateKeys.emplace_back(Keys::RecvClkBias{ satSys });
444 if (canCalculateVelocity(nDoppMeas)) { stateKeys.emplace_back(Keys::RecvClkDrift{ satSys }); }
445 }
446 for (const auto& freq : _receiver.interFrequencyBias)
447 {
448 stateKeys.emplace_back(Keys::InterFreqBias{ freq.first });
449 }
450
451 LOG_DATA("{}: stateKeys = [{}]", nameId, joinToString(stateKeys));
452 return stateKeys;
453}
454
455std::vector<Meas::MeasKeyTypes> Algorithm::determineMeasKeys(const Observations& observations, size_t nPsrMeas, size_t nDoppMeas, [[maybe_unused]] const std::string& nameId) const
456{
457 std::vector<Meas::MeasKeyTypes> measKeys;
458 measKeys.reserve(nPsrMeas + nDoppMeas);
459
460 if (_obsFilter.isObsTypeUsed(GnssObs::Pseudorange))
461 {
462 for (const auto& signalObs : observations.signals)
463 {
464 if (signalObs.second.recvObs.at(Rover)->obs.contains(GnssObs::Pseudorange))
465 {
466 measKeys.emplace_back(Meas::Psr{ signalObs.first });
467 }
468 }
469 }
470 if (_obsFilter.isObsTypeUsed(GnssObs::Doppler))
471 {
472 for (const auto& signalObs : observations.signals)
473 {
474 if (signalObs.second.recvObs.at(Rover)->obs.contains(GnssObs::Doppler))
475 {
476 measKeys.emplace_back(Meas::Doppler{ signalObs.first });
477 }
478 }
479 }
480
481 LOG_DATA("{}: measKeys = [{}]", nameId, joinToString(measKeys));
482 return measKeys;
483}
484
486 const std::vector<Meas::MeasKeyTypes>& measKeys,
487 const Observations& observations,
488 const std::string& nameId) const
489{
490 KeyedMatrixXd<Meas::MeasKeyTypes, States::StateKeyType> H(Eigen::MatrixXd::Zero(static_cast<int>(measKeys.size()),
491 static_cast<int>(stateKeys.size())),
492 measKeys, stateKeys);
493
494 for (const auto& [satSigId, signalObs] : observations.signals)
495 {
496 auto satId = satSigId.toSatId();
497
498 const auto& roverObs = signalObs.recvObs.at(Rover);
499 for (const auto& [obsType, obsData] : roverObs->obs)
500 {
501 switch (obsType)
502 {
504 H.block<3>(Meas::Psr{ satSigId }, PosKey) = -roverObs->e_pLOS(_receiver.e_posMarker).transpose();
505 H(Meas::Psr{ satSigId }, Keys::RecvClkBias{ satId.satSys }) = 1;
506 if (_receiver.interFrequencyBias.contains(satSigId.freq()))
507 {
508 H(Meas::Psr{ satSigId }, Keys::InterFreqBias{ satSigId.freq() }) = 1;
509 }
510 break;
511 case GnssObs::Doppler:
512 H.block<3>(Meas::Doppler{ satSigId }, PosKey) = -roverObs->e_vLOS(_receiver.e_posMarker, _receiver.e_vel).transpose();
513 H.block<3>(Meas::Doppler{ satSigId }, VelKey) = -roverObs->e_pLOS(_receiver.e_posMarker).transpose();
514 H(Meas::Doppler{ satSigId }, Keys::RecvClkDrift{ satId.satSys }) = 1;
515 break;
516 case GnssObs::Carrier:
518 LOG_CRITICAL("{}: [{}] is not supported by the SPP algorithm as observation type.", nameId, obsType);
519 break;
520 }
521 }
522 }
523
524 LOG_DATA("{}: H =\n{}", nameId, H);
525
526 return H;
527}
528
530 const Observations& observations,
531 const std::string& nameId)
532{
533 KeyedMatrixXd<Meas::MeasKeyTypes, Meas::MeasKeyTypes> R(Eigen::MatrixXd::Zero(static_cast<int>(measKeys.size()),
534 static_cast<int>(measKeys.size())),
535 measKeys);
536
537 for (const auto& [satSigId, signalObs] : observations.signals)
538 {
539 for (const auto& [obsType, obsData] : signalObs.recvObs.at(Rover)->obs)
540 {
541 switch (obsType)
542 {
544 R(Meas::Psr{ satSigId }, Meas::Psr{ satSigId }) = obsData.measVar;
545 break;
546 case GnssObs::Doppler:
547 R(Meas::Doppler{ satSigId }, Meas::Doppler{ satSigId }) = obsData.measVar;
548 break;
549 case GnssObs::Carrier:
551 LOG_CRITICAL("{}: These observation types are not supported by the SPP algorithm", nameId);
552 break;
553 }
554 }
555 }
556
557 LOG_DATA("{}: R =\n{}", nameId, R);
558
559 return R;
560}
561
562KeyedVectorXd<Meas::MeasKeyTypes> Algorithm::calcMeasInnovation(const std::vector<Meas::MeasKeyTypes>& measKeys,
563 const Observations& observations,
564 const std::string& nameId)
565{
566 KeyedVectorXd<Meas::MeasKeyTypes> dz(Eigen::VectorXd::Zero(static_cast<int>(measKeys.size())), measKeys);
567
568 for (const auto& [satSigId, signalObs] : observations.signals)
569 {
570 for (const auto& [obsType, obsData] : signalObs.recvObs.at(Rover)->obs)
571 {
572 switch (obsType)
573 {
575 dz(Meas::Psr{ satSigId }) = obsData.measurement - obsData.estimate;
576 break;
577 case GnssObs::Doppler:
578 dz(Meas::Doppler{ satSigId }) = obsData.measurement - obsData.estimate;
579 break;
580 case GnssObs::Carrier:
582 LOG_CRITICAL("{}: These observation types are not supported by the SPP algorithm", nameId);
583 break;
584 }
585 }
586 }
587
588 LOG_DATA("{}: dz =\n{}", nameId, dz);
589
590 return dz;
591}
592
595 const Eigen::Vector3d& e_oldPos,
596 size_t nParams, size_t nUniqueDopplerMeas, double dt,
597 [[maybe_unused]] const std::string& nameId)
598{
599 _receiver.e_posMarker += state.segment<3>(PosKey);
600 _receiver.lla_posMarker = trafo::ecef2lla_WGS84(_receiver.e_posMarker);
601 for (const auto& s : state.rowKeys())
602 {
603 if (const auto* bias = std::get_if<Keys::RecvClkBias>(&s))
604 {
605 size_t idx = _receiver.recvClk.getIdx(bias->satSys).value();
606 _receiver.recvClk.bias.at(idx) += state(*bias) / InsConst::C;
607 if (variance(*bias, *bias) < 0)
608 {
609 _receiver.recvClk.biasStdDev.at(idx) = 1000 / InsConst::C;
610 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m]", nameId, *bias, _receiver.recvClk.biasStdDev.at(idx) * InsConst::C);
611 }
612 else
613 {
614 _receiver.recvClk.biasStdDev.at(idx) = std::sqrt(variance(*bias, *bias)) / InsConst::C;
615 }
616 LOG_DATA("{}: Setting Clk Bias [{}] = {} [s] (StdDev = {})", nameId, bias->satSys, _receiver.recvClk.bias.at(idx), _receiver.recvClk.biasStdDev.at(idx));
617 }
618 else if (const auto* bias = std::get_if<Keys::InterFreqBias>(&s))
619 {
620 auto& freqDiff = _receiver.interFrequencyBias.at(bias->freq);
621 freqDiff.value += state(*bias) / InsConst::C;
622 if (variance(*bias, *bias) < 0)
623 {
624 freqDiff.stdDev = 1000 / InsConst::C;
625 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m]", nameId, *bias, freqDiff.stdDev * InsConst::C);
626 }
627 else
628 {
629 freqDiff.stdDev = std::sqrt(variance(*bias, *bias)) / InsConst::C;
630 }
631 LOG_DATA("{}: Setting IFB Bias [{}] = {} [s] (StdDev = {})", nameId, bias->freq, freqDiff.value, freqDiff.stdDev);
632 }
633 }
634
635 if (nUniqueDopplerMeas >= nParams)
636 {
637 _receiver.e_vel += state.segment<3>(VelKey);
638 for (const auto& s : state.rowKeys())
639 {
640 if (const auto* drift = std::get_if<Keys::RecvClkDrift>(&s))
641 {
642 size_t idx = _receiver.recvClk.getIdx(drift->satSys).value();
643 _receiver.recvClk.drift.at(idx) += state(*drift) / InsConst::C;
644 if (variance(*drift, *drift) < 0)
645 {
646 _receiver.recvClk.driftStdDev.at(idx) = 1000 / InsConst::C;
647 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *drift, _receiver.recvClk.driftStdDev.at(idx) * InsConst::C);
648 }
649 else
650 {
651 _receiver.recvClk.driftStdDev.at(idx) = std::sqrt(variance(*drift, *drift)) / InsConst::C;
652 }
653 LOG_DATA("{}: Setting Clk Drift [{}] = {} [s/s] (StdDev = {})", nameId, drift->satSys,
654 _receiver.recvClk.drift.at(idx), _receiver.recvClk.driftStdDev.at(idx));
655 }
656 }
657 }
658 else
659 {
660 if (dt > 1e-6 && !e_oldPos.isZero())
661 {
662 if (_obsFilter.isObsTypeUsed(GnssObs::Doppler))
663 {
664 LOG_TRACE("{}: [{}] SPP has only {} satellites with doppler observations ({} needed). Calculating velocity as position difference.",
665 nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), nUniqueDopplerMeas, nParams);
666 }
667 LOG_DATA("{}: [{}] e_oldPos = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), e_oldPos.transpose());
668 LOG_DATA("{}: [{}] e_newPos = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_posMarker.transpose());
669 LOG_DATA("{}: [{}] dt = {}s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), dt);
670 _receiver.e_vel = (_receiver.e_posMarker - e_oldPos) / dt;
671 LOG_DATA("{}: [{}] e_vel = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_vel.transpose());
672 }
673 }
674
675 LOG_DATA("{}: [{}] Assigning solution to _receiver", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
676 LOG_DATA("{}: [{}] e_pos = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_posMarker.transpose());
677 LOG_DATA("{}: [{}] e_vel = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_vel.transpose());
678 LOG_DATA("{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
679 rad2deg(_receiver.lla_posMarker.x()), rad2deg(_receiver.lla_posMarker.y()), _receiver.lla_posMarker.z());
680 for ([[maybe_unused]] const auto& satSys : _receiver.recvClk.satelliteSystems)
681 {
682 LOG_DATA("{}: [{}] clkBias = {} [s] (StdDev = {})", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
683 *_receiver.recvClk.biasFor(satSys), *_receiver.recvClk.biasStdDevFor(satSys));
684 LOG_DATA("{}: [{}] clkDrift = {} [s/s] (StdDev = {})", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
685 *_receiver.recvClk.driftFor(satSys), *_receiver.recvClk.driftStdDevFor(satSys));
686 }
687
688 for ([[maybe_unused]] const auto& freq : _receiver.interFrequencyBias)
689 {
690 LOG_DATA("{}: [{}] IFBBias [{:3}] = {} [s] (StdDev = {})", nameId,
691 _receiver.gnssObs->insTime.toYMDHMS(GPST), freq.first, freq.second.value, freq.second.stdDev);
692 }
693}
694
697 [[maybe_unused]] const std::string& nameId)
698{
699 _receiver.e_posMarker = state(PosKey);
700 _receiver.lla_posMarker = trafo::ecef2lla_WGS84(_receiver.e_posMarker);
701 _receiver.e_vel = state(VelKey);
702 for (const auto& s : state.rowKeys())
703 {
704 if (const auto* bias = std::get_if<Keys::RecvClkBias>(&s))
705 {
706 size_t idx = _receiver.recvClk.getIdx(bias->satSys).value();
707 _receiver.recvClk.bias.at(idx) = state(*bias) / InsConst::C;
708 if (variance(*bias, *bias) < 0)
709 {
710 _receiver.recvClk.biasStdDev.at(idx) = 1000 / InsConst::C;
711 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m]", nameId, *bias, _receiver.recvClk.biasStdDev.at(idx) * InsConst::C);
712 }
713 else
714 {
715 _receiver.recvClk.biasStdDev.at(idx) = std::sqrt(variance(*bias, *bias)) / InsConst::C;
716 }
717 LOG_DATA("{}: Setting Clock Bias [{}] = {}", nameId, bias->satSys, _receiver.recvClk.bias.at(idx));
718 }
719 else if (const auto* drift = std::get_if<Keys::RecvClkDrift>(&s))
720 {
721 size_t idx = _receiver.recvClk.getIdx(drift->satSys).value();
722 _receiver.recvClk.drift.at(idx) = state(*drift) / InsConst::C;
723 if (variance(*drift, *drift) < 0)
724 {
725 _receiver.recvClk.driftStdDev.at(idx) = 1000 / InsConst::C;
726 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *drift, _receiver.recvClk.driftStdDev.at(idx) * InsConst::C);
727 }
728 else
729 {
730 _receiver.recvClk.driftStdDev.at(idx) = std::sqrt(variance(*drift, *drift)) / InsConst::C;
731 }
732 LOG_DATA("{}: Setting Clock Drift [{}] = {}", nameId, drift->satSys, _receiver.recvClk.drift.at(idx));
733 }
734 else if (const auto* bias = std::get_if<Keys::InterFreqBias>(&s))
735 {
736 auto& freqDiff = _receiver.interFrequencyBias.at(bias->freq);
737 freqDiff.value = state(*bias) / InsConst::C;
738 if (variance(*bias, *bias) < 0)
739 {
740 freqDiff.stdDev = 1000 / InsConst::C;
741 LOG_WARN("{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *bias, freqDiff.stdDev * InsConst::C);
742 }
743 else
744 {
745 freqDiff.stdDev = std::sqrt(variance(*bias, *bias)) / InsConst::C;
746 }
747 LOG_DATA("{}: Setting Inter-Freq Bias [{}] = {}", nameId, bias->freq, freqDiff.value);
748 }
749 }
750
751 LOG_DATA("{}: [{}] Assigning solution to _receiver", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST));
752 LOG_DATA("{}: [{}] e_pos = {:.6f}m, {:.6f}m, {:.6f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
753 _receiver.e_posMarker(0), _receiver.e_posMarker(1), _receiver.e_posMarker(2));
754 LOG_DATA("{}: [{}] e_vel = {}", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), _receiver.e_vel.transpose());
755 LOG_DATA("{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST),
756 rad2deg(_receiver.lla_posMarker.x()), rad2deg(_receiver.lla_posMarker.y()), _receiver.lla_posMarker.z());
757 for ([[maybe_unused]] const auto& satSys : _receiver.recvClk.satelliteSystems)
758 {
759 LOG_DATA("{}: [{}] clkBias = {} s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.biasFor(satSys));
760 LOG_DATA("{}: [{}] clkDrift = {} s/s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), *_receiver.recvClk.driftFor(satSys));
761 }
762
763 for ([[maybe_unused]] const auto& freq : _receiver.interFrequencyBias)
764 {
765 LOG_DATA("{}: [{}] IFBBias [{:3}] = {} s", nameId, _receiver.gnssObs->insTime.toYMDHMS(GPST), freq.first, freq.second.value);
766 }
767}
768
769void Algorithm::computeDOPs(const std::shared_ptr<SppSolution>& sppSol,
771 [[maybe_unused]] const std::string& nameId)
772{
774 Eigen::FullPivLU<Eigen::MatrixXd> lu_decomp(N(all, all));
775 if (lu_decomp.rank() == H.cols())
776 {
777 auto Q = N.inverse();
778 Eigen::Matrix3d Qpp = Q(PosKey, PosKey);
779 Eigen::Matrix3d Qlocal = sppSol->n_Quat_e() * Qpp * sppSol->e_Quat_n();
780 sppSol->HDOP = std::sqrt(Qlocal(0, 0) + Qlocal(1, 1));
781 sppSol->VDOP = std::sqrt(Qlocal(2, 2));
782 sppSol->PDOP = std::sqrt(Qpp.trace());
783 }
784
785 LOG_DATA("{}: HDOP = {}", nameId, sppSol->HDOP);
786 LOG_DATA("{}: VDOP = {}", nameId, sppSol->VDOP);
787 LOG_DATA("{}: PDOP = {}", nameId, sppSol->PDOP);
788}
789
790/// @brief Converts the provided object into json
791/// @param[out] j Json object which gets filled with the info
792/// @param[in] obj Object to convert into json
793void to_json(json& j, const Algorithm& obj)
794{
795 j = json{
796 { "obsFilter", obj._obsFilter },
797 { "obsEstimator", obj._obsEstimator },
798 { "estimatorType", obj._estimatorType },
799 { "kalmanFilter", obj._kalmanFilter },
800 { "estimateInterFrequencyBiases", obj._estimateInterFreqBiases },
801 };
802}
803/// @brief Converts the provided json object into a node object
804/// @param[in] j Json object with the needed values
805/// @param[out] obj Object to fill from the json
806void from_json(const json& j, Algorithm& obj)
807{
808 if (j.contains("obsFilter")) { j.at("obsFilter").get_to(obj._obsFilter); }
809 if (j.contains("obsEstimator")) { j.at("obsEstimator").get_to(obj._obsEstimator); }
810 if (j.contains("estimatorType")) { j.at("estimatorType").get_to(obj._estimatorType); }
811 if (j.contains("kalmanFilter")) { j.at("kalmanFilter").get_to(obj._kalmanFilter); }
812 if (j.contains("estimateInterFrequencyBiases")) { j.at("estimateInterFrequencyBiases").get_to(obj._estimateInterFreqBiases); }
813}
814
815} // namespace SPP
816
817const char* to_string(SPP::Algorithm::EstimatorType estimatorType)
818{
819 switch (estimatorType)
820 {
822 return "Least Squares";
824 return "Weighted Least Squares";
826 return "Kalman Filter";
828 break;
829 }
830 return "";
831}
832
834{
835 switch (receiver)
836 {
838 return "Rover";
840 break;
841 }
842 return "";
843}
844
845} // namespace NAV
846
847std::ostream& operator<<(std::ostream& os, const NAV::SPP::Algorithm::EstimatorType& obj)
848{
849 return os << fmt::format("{}", obj);
850}
851
852std::ostream& operator<<(std::ostream& os, const NAV::SPP::Algorithm::ReceiverType& obj)
853{
854 return os << fmt::format("{}", obj);
855}
std::ostream & operator<<(std::ostream &os, const NAV::SPP::Algorithm::EstimatorType &obj)
Stream insertion operator overload.
Single Point Positioning Algorithm.
Holds all Constants.
Transformation collection.
Combo representing an enumeration.
nlohmann::json json
json namespace
Frequency definition for different satellite systems.
Keys for the SPP algorithm for use inside the KeyedMatrices.
Text Help Marker (?) with Tooltip.
Ionospheric Correction data.
Least squares with keyed states.
Utility class for logging to console and file.
#define LOG_CRITICAL(...)
Critical Event, which causes the program to work entirely and throws an exception.
Definition Logger.hpp:75
#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
Observation data used for calculations.
Algorithms concerning the STL containers.
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
@ 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 a
Semi-major axis = equatorial radius.
Definition Constants.hpp:50
static constexpr double C
Speed of light [m/s].
Definition Constants.hpp:34
@ NoDifference
Estimation is not differenced.
Single Point Positioning Algorithm.
Definition Algorithm.hpp:38
KeyedMatrixXd< Meas::MeasKeyTypes, States::StateKeyType > calcMatrixH(const std::vector< States::StateKeyType > &stateKeys, const std::vector< Meas::MeasKeyTypes > &measKeys, const Observations &observations, const std::string &nameId) const
Calculates the measurement sensitivity matrix 𝐇
std::vector< States::StateKeyType > determineStateKeys(const std::set< SatelliteSystem > &usedSatSystems, size_t nDoppMeas, const std::string &nameId) const
Returns a list of state keys.
Receiver _receiver
Receiver.
bool canEstimateInterFrequencyBias() const
Checks if the SPP algorithm can estimate inter-frequency biases.
void reset()
Reset the algorithm.
Definition Algorithm.cpp:65
NAV::Receiver< ReceiverType > Receiver
Receiver.
Definition Algorithm.hpp:92
void computeDOPs(const std::shared_ptr< SppSolution > &sppSol, const KeyedMatrixXd< Meas::MeasKeyTypes, States::StateKeyType > &H, const std::string &nameId)
Computes all DOP values (by reference)
void updateInterFrequencyBiases(const Observations &observations, const std::string &nameId)
Updates the inter frequency biases.
std::vector< Meas::MeasKeyTypes > determineMeasKeys(const Observations &observations, size_t nPsrMeas, size_t nDoppMeas, const std::string &nameId) const
Returns a list of measurement keys.
void assignKalmanFilterResult(const KeyedVectorXd< States::StateKeyType > &state, const KeyedMatrixXd< States::StateKeyType, States::StateKeyType > &variance, const std::string &nameId)
Assigns the result to the receiver variable.
ObservationFilter _obsFilter
Observation Filter.
Definition Algorithm.hpp:81
InsTime _lastUpdate
Time of last update.
bool _estimateInterFreqBiases
Estimate Inter-frequency biases.
Definition Algorithm.hpp:89
static KeyedVectorXd< Meas::MeasKeyTypes > calcMeasInnovation(const std::vector< Meas::MeasKeyTypes > &measKeys, const Observations &observations, const std::string &nameId)
Calculates the measurement innovation vector 𝜹𝐳
std::shared_ptr< SppSolution > calcSppSolution(const std::shared_ptr< const GnssObs > &gnssObs, const std::vector< const GnssNavInfo * > &gnssNavInfos, const std::string &nameId)
Calculate the SPP solution.
Definition Algorithm.cpp:73
const std::array< SPP::States::StateKeyType, 3 > & PosKey
All position keys.
Definition Algorithm.hpp:95
bool canCalculateVelocity(size_t nDoppMeas) const
Checks if the SPP algorithm can calculate the position (always true for Kalman filter)
const std::array< SPP::States::StateKeyType, 6 > & PosVelKey
All position and velocity keys.
Definition Algorithm.hpp:99
static KeyedMatrixXd< Meas::MeasKeyTypes, Meas::MeasKeyTypes > calcMatrixR(const std::vector< Meas::MeasKeyTypes > &measKeys, const Observations &observations, const std::string &nameId)
Calculates the measurement noise covariance matrix 𝐑
SPP::KalmanFilter _kalmanFilter
SPP specific Kalman filter.
void assignLeastSquaresResult(const KeyedVectorXd< States::StateKeyType > &state, const KeyedMatrixXd< States::StateKeyType, States::StateKeyType > &variance, const Eigen::Vector3d &e_oldPos, size_t nParams, size_t nUniqueDopplerMeas, double dt, const std::string &nameId)
Assigns the result to the receiver variable.
ObservationEstimator _obsEstimator
Observation Estimator.
Definition Algorithm.hpp:86
EstimatorType
Possible SPP estimation algorithms.
Definition Algorithm.hpp:42
@ WeightedLeastSquares
Weighted Linear Least Squares.
Definition Algorithm.hpp:44
@ COUNT
Amount of items in the enum.
Definition Algorithm.hpp:46
@ LeastSquares
Linear Least Squares.
Definition Algorithm.hpp:43
const std::array< SPP::States::StateKeyType, 3 > & VelKey
All velocity keys.
Definition Algorithm.hpp:97
ReceiverType
Receiver Types.
Definition Algorithm.hpp:51
@ ReceiverType_COUNT
Amount of receiver types.
Definition Algorithm.hpp:53
EstimatorType _estimatorType
Estimator type used for the calculations.
bool ShowGuiWidgets(const char *id, float itemWidth, float unitWidth)
Shows the GUI input to select the options.
Definition Algorithm.cpp:40
decltype(auto) block(std::span< const RowKeyType > rowKeys, std::span< const ColKeyType > colKeys) const
Gets the values for the row and col keys.
const std::vector< ColKeyType > & colKeys() const
Returns the col keys.
decltype(auto) cols() const
Return the cols of the underlying Eigen matrix.
bool hasRow(const RowKeyType &key) const
Checks if the matrix has the key.
const std::vector< RowKeyType > & rowKeys() const
Returns the row keys.
bool hasAnyRows(std::span< const RowKeyType > keys) const
Checks if the matrix has any key.
decltype(auto) segment(std::span< const RowKeyType > rowKeys) const
Gets the values for the row keys.
constexpr size_t POS_STATE_COUNT
Amount of states to estimate for the position.
Definition Keys.hpp:31
void to_json(json &j, const Algorithm &obj)
Converts the provided object into json.
void from_json(const json &j, Algorithm &obj)
Converts the provided json object into a node object.
bool EnumCombo(const char *label, T &enumeration, size_t startIdx=0)
Combo representing an enumeration.
Definition EnumCombo.hpp:30
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.
std::string joinToString(const T &container, const char *delimiter=", ", const std::string &elementFormat="")
Joins the container to a string.
Definition STL.hpp:30
@ GPST
GPS Time.
KeyedLeastSquaresResult< Scalar, StateKeyType > solveLinearLeastSquaresUncertainties(const KeyedMatrixX< Scalar, MeasKeyType, StateKeyType > &H, const KeyedVectorX< Scalar, MeasKeyType > &dz)
Finds the "least squares" solution for the equation .
const char * to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
Converts the enum to a string.
KeyedVectorX< double, RowKeyType > KeyedVectorXd
Dynamic size KeyedVector with double types.
KeyedLeastSquaresResult< Scalar, StateKeyType > solveWeightedLinearLeastSquaresUncertainties(const KeyedMatrixX< Scalar, MeasKeyType, StateKeyType > &H, const KeyedMatrixX< Scalar, MeasKeyType, MeasKeyType > &W, const KeyedVectorX< Scalar, MeasKeyType > &dz)
Finds the "weighted least squares" solution.
static const internal::all_t all
Used to request all rows or columns in KeyedMatrices.
KeyedMatrixX< double, RowKeyType, ColKeyType > KeyedMatrixXd
Dynamic size KeyedMatrix with double types.
constexpr auto rad2deg(const T &rad)
Convert Radians to Degree.
Definition Units.hpp:39
Least Squares Uncertainties return value.
KeyedMatrixX< Scalar, StateKeyType, StateKeyType > variance
Least squares variance.
KeyedVectorX< Scalar, StateKeyType > solution
Least squares solution.
Receiver clock error [m].
Receiver clock drift [m/s].
Observation storage type.
std::set< SatelliteSystem > systems
Satellite systems used.
std::array< size_t, GnssObs::ObservationType_COUNT > nObservables
Number of observables.
std::unordered_set< SatId > satellites
Satellites used.
std::array< size_t, GnssObs::ObservationType_COUNT > nObservablesUniqueSatellite
Number of observables (counted once for each satellite)
unordered_map< SatSigId, SignalObservation > signals
Observations and calculated data for each signal.
Range-rate (doppler) measurement [m/s].
Definition Keys.hpp:55
Pseudorange measurement [m].
Definition Keys.hpp:46
Identifies a satellite (satellite system and number)
static std::vector< SatelliteSystem > GetAll()
Returns a list with all possible satellite systems.
Satellite specific data.
Value with standard deviation.