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 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 | |||
19 | #include "Navigation/Constants.hpp" | ||
20 | #include "Navigation/GNSS/Core/Frequency.hpp" | ||
21 | #include "Navigation/GNSS/Positioning/Observation.hpp" | ||
22 | #include "Navigation/GNSS/Positioning/SPP/Keys.hpp" | ||
23 | #include "Navigation/Transformations/CoordinateFrames.hpp" | ||
24 | #include "util/Logger.hpp" | ||
25 | #include <fmt/format.h> | ||
26 | |||
27 | #include "internal/gui/widgets/EnumCombo.hpp" | ||
28 | #include "internal/gui/widgets/HelpMarker.hpp" | ||
29 | |||
30 | #include "Navigation/Atmosphere/Ionosphere/IonosphericCorrections.hpp" | ||
31 | #include "Navigation/Math/KeyedLeastSquares.hpp" | ||
32 | |||
33 | #include "util/Container/STL.hpp" | ||
34 | |||
35 | namespace NAV | ||
36 | { | ||
37 | namespace SPP | ||
38 | { | ||
39 | |||
40 | ✗ | bool 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 | |||
55 | ✗ | if (_estimatorType == EstimatorType::KalmanFilter) | |
56 | { | ||
57 | ✗ | changed |= _kalmanFilter.ShowGuiWidgets(id, _obsFilter.isObsTypeUsed(GnssObs::Doppler), | |
58 | ✗ | _obsFilter.getSystemFilter().toVector().size() != 1, | |
59 | ✗ | _estimateInterFreqBiases && canEstimateInterFrequencyBias(), itemWidth, unitWidth); | |
60 | } | ||
61 | |||
62 | ✗ | return changed; | |
63 | } | ||
64 | |||
65 | 21 | void Algorithm::reset() | |
66 | { | ||
67 |
3/6✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
|
21 | _receiver = Receiver(Rover, _obsFilter.getSystemFilter().toVector()); |
68 | 21 | _obsFilter.reset(); | |
69 |
3/6✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
|
21 | _kalmanFilter.reset(_obsFilter.getSystemFilter().toVector()); |
70 | 21 | _lastUpdate.reset(); | |
71 | 21 | } | |
72 | |||
73 | 343 | std::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 | 343 | _receiver.gnssObs = gnssObs; | |
78 | |||
79 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 343 times.
|
343 | 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 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | auto ionosphericCorrections = std::make_shared<const IonosphericCorrections>(gnssNavInfos); |
88 | |||
89 |
3/4✓ Branch 1 taken 7 times.
✓ Branch 2 taken 336 times.
✓ Branch 5 taken 336 times.
✗ Branch 6 not taken.
|
343 | double dt = _lastUpdate.empty() ? 0.0 : static_cast<double>((_receiver.gnssObs->insTime - _lastUpdate).count()); |
90 | LOG_DATA("{}: dt = {}s", nameId, dt); | ||
91 | 343 | _lastUpdate = _receiver.gnssObs->insTime; | |
92 | |||
93 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | auto sppSol = std::make_shared<SppSolution>(); |
94 | 343 | sppSol->insTime = _receiver.gnssObs->insTime; | |
95 | |||
96 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 343 times.
|
343 | if (_estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized()) |
97 | { | ||
98 | ✗ | _kalmanFilter.predict(dt, _receiver.lla_posMarker, nameId); | |
99 | ✗ | assignKalmanFilterResult(_kalmanFilter.getState(), _kalmanFilter.getErrorCovarianceMatrix(), nameId); | |
100 | } | ||
101 | |||
102 | 343 | constexpr size_t N_ITER_MAX_LSQ = 10; | |
103 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
343 | size_t nIter = _estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized() ? 1 : N_ITER_MAX_LSQ; |
104 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | Eigen::Vector3d e_oldPos = _receiver.e_posMarker; |
105 | 343 | bool accuracyAchieved = false; | |
106 | |||
107 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | KeyedMatrixXd<Meas::MeasKeyTypes, States::StateKeyType> H; |
108 | |||
109 |
1/2✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
|
737 | 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 |
2/2✓ Branch 5 taken 737 times.
✓ Branch 6 taken 737 times.
|
1474 | 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 |
2/2✓ Branch 5 taken 854 times.
✓ Branch 6 taken 737 times.
|
1591 | 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 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | auto posNorm = e_oldPos.norm(); |
129 |
3/4✓ Branch 0 taken 694 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 694 times.
|
737 | 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 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | Observations observations; |
132 | 737 | _obsFilter.selectObservationsForCalculation(Rover, | |
133 | 737 | _receiver.e_posMarker, | |
134 | 737 | _receiver.lla_posMarker, | |
135 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | _receiver.gnssObs, |
136 | gnssNavInfos, | ||
137 | observations, | ||
138 | nullptr, | ||
139 | nameId, | ||
140 | ignoreElevationMask); | ||
141 | |||
142 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 737 times.
|
737 | 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 | 737 | size_t nParams = SPP::States::POS_STATE_COUNT + observations.systems.size() - 1; | |
150 | |||
151 | 737 | sppSol->nSatellites = observations.satellites.size(); | |
152 | 737 | sppSol->nMeasPsr = observations.nObservables[GnssObs::Pseudorange]; | |
153 | 737 | 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 |
2/2✓ Branch 4 taken 737 times.
✓ Branch 5 taken 737 times.
|
1474 | for (const auto& satSys : observations.systems) |
159 | { | ||
160 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | [[maybe_unused]] auto satCount = std::ranges::count_if(observations.satellites, [&](const SatId& satId) { |
161 | 6515 | return satId.satSys == satSys; | |
162 | }); | ||
163 | |||
164 | LOG_DATA("{}: nSat {:5} = {}", nameId, satSys, satCount); | ||
165 | } | ||
166 | |||
167 | 737 | if (size_t nPsrMeas = observations.nObservablesUniqueSatellite[GnssObs::Pseudorange]; | |
168 |
3/8✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 737 times.
|
737 | (_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 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | updateInterFrequencyBiases(observations, nameId); |
176 | |||
177 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | _obsEstimator.calcObservationEstimates(observations, _receiver, ionosphericCorrections, nameId, ObservationEstimator::NoDifference); |
178 | |||
179 |
1/2✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
|
737 | auto stateKeys = determineStateKeys(observations.systems, observations.nObservables[GnssObs::Doppler], nameId); |
180 |
1/2✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
|
737 | auto measKeys = determineMeasKeys(observations, sppSol->nMeasPsr, sppSol->nMeasDopp, nameId); |
181 | |||
182 | 737 | sppSol->nParam = stateKeys.size(); | |
183 | |||
184 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | H = calcMatrixH(stateKeys, measKeys, observations, nameId); |
185 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | auto R = calcMatrixR(measKeys, observations, nameId); |
186 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | auto dz = calcMeasInnovation(measKeys, observations, nameId); |
187 | |||
188 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 737 times.
|
737 | if (_estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized()) |
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 | |||
210 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
|
737 | if (_estimatorType != EstimatorType::KalmanFilter || !_kalmanFilter.isInitialized()) |
211 | { | ||
212 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | KeyedLeastSquaresResult<double, States::StateKeyType> lsq; |
213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
|
737 | if (_estimatorType == EstimatorType::LeastSquares) |
214 | { | ||
215 | ✗ | lsq = solveLinearLeastSquaresUncertainties(H, dz); | |
216 | } | ||
217 | else /* if (_estimatorType == EstimatorType::WeightedLeastSquares) */ | ||
218 | { | ||
219 |
5/10✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 737 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 737 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 737 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 737 times.
✗ Branch 19 not taken.
|
737 | 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); | ||
221 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | lsq = solveWeightedLinearLeastSquaresUncertainties(H, W, dz); |
222 | 737 | } | |
223 | LOG_DATA("{}: LSQ sol (dx) =\n{}", nameId, lsq.solution.transposed()); | ||
224 | LOG_DATA("{}: LSQ var =\n{}", nameId, lsq.variance.transposed()); | ||
225 | |||
226 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | assignLeastSquaresResult(lsq.solution, lsq.variance, e_oldPos, |
227 | 737 | nParams, observations.nObservablesUniqueSatellite[GnssObs::Doppler], dt, nameId); | |
228 | |||
229 |
1/2✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
|
737 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
|
737 | if (iteration == nIter - 1) { return nullptr; } |
233 |
3/4✓ Branch 0 taken 394 times.
✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 394 times.
|
737 | if (accuracyAchieved || iteration == nIter - 1) |
234 | { | ||
235 | ✗ | if (_estimatorType == EstimatorType::KalmanFilter && !_kalmanFilter.isInitialized() | |
236 | ✗ | && sppSol->nMeasPsr > nParams // Variance can only be calculated if more measurements than parameters | |
237 |
2/10✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 343 times.
|
343 | && (!_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 |
2/4✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 343 times.
✗ Branch 5 not taken.
|
343 | if (lsq.variance.hasRows(VelKey)) |
265 | { | ||
266 |
2/4✓ Branch 4 taken 343 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 343 times.
✗ Branch 8 not taken.
|
343 | 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 |
1/2✓ Branch 3 taken 343 times.
✗ Branch 4 not taken.
|
343 | sppSol->satData.reserve(observations.satellites.size()); |
274 |
2/2✓ Branch 7 taken 11657 times.
✓ Branch 8 taken 343 times.
|
12000 | for (const auto& [satSigId, signalObs] : observations.signals) |
275 | { | ||
276 |
1/2✓ Branch 2 taken 11657 times.
✗ Branch 3 not taken.
|
11657 | if (std::ranges::find_if(sppSol->satData, |
277 |
1/2✓ Branch 1 taken 54706 times.
✗ Branch 2 not taken.
|
54706 | [&satSigId = satSigId](const auto& satIdData) { return satIdData.first == satSigId.toSatId(); }) |
278 |
2/2✓ Branch 3 taken 3041 times.
✓ Branch 4 taken 8616 times.
|
23314 | == sppSol->satData.end()) |
279 | { | ||
280 |
1/2✓ Branch 2 taken 3041 times.
✗ Branch 3 not taken.
|
6082 | sppSol->satData.emplace_back(satSigId.toSatId(), |
281 |
2/4✓ Branch 1 taken 3041 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3041 times.
✗ Branch 6 not taken.
|
3041 | SppSolution::SatData{ .satElevation = signalObs.recvObs.at(Rover)->satElevation(_receiver.e_posMarker, _receiver.lla_posMarker), |
282 |
3/6✓ Branch 1 taken 3041 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3041 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 3041 times.
✗ Branch 9 not taken.
|
6082 | .satAzimuth = signalObs.recvObs.at(Rover)->satAzimuth(_receiver.e_posMarker, _receiver.lla_posMarker) }); |
283 | } | ||
284 | } | ||
285 | |||
286 |
1/2✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
|
343 | sppSol->_e_sppCovarianceMatrix = lsq.variance; |
287 | |||
288 | 343 | break; | |
289 | } | ||
290 | 737 | } | |
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 | 2109 | } | |
324 | // use H matrix to calculate DOPs | ||
325 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | computeDOPs(sppSol, H, nameId); |
326 | |||
327 |
1/2✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
|
343 | sppSol->recvClk = _receiver.recvClk; |
328 |
1/2✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
|
343 | 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 |
2/2✓ Branch 2 taken 343 times.
✓ Branch 3 taken 343 times.
|
686 | 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 |
2/2✓ Branch 2 taken 343 times.
✓ Branch 3 taken 343 times.
|
686 | 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 |
2/2✓ Branch 6 taken 392 times.
✓ Branch 7 taken 343 times.
|
735 | 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 | 343 | return sppSol; | |
376 | 343 | } | |
377 | |||
378 | 2948 | bool Algorithm::canCalculateVelocity(size_t nDoppMeas) const | |
379 | { | ||
380 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 2948 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2948 times.
|
2948 | if (_estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized()) { return true; } |
381 | |||
382 |
2/4✓ Branch 1 taken 2948 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2948 times.
✗ Branch 4 not taken.
|
2948 | return _obsFilter.isObsTypeUsed(GnssObs::Doppler) && nDoppMeas >= 4; |
383 | } | ||
384 | |||
385 | ✗ | bool Algorithm::canEstimateInterFrequencyBias() const | |
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 | |||
396 | 737 | void Algorithm::updateInterFrequencyBiases(const Observations& observations, [[maybe_unused]] const std::string& nameId) | |
397 | { | ||
398 |
1/2✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
|
737 | if (_estimateInterFreqBiases) |
399 | { | ||
400 | 737 | std::set<Frequency> observedFrequencies; | |
401 | 737 | Frequency allObservedFrequencies; | |
402 |
2/2✓ Branch 4 taken 25404 times.
✓ Branch 5 taken 737 times.
|
26141 | for (const auto& obs : observations.signals) |
403 | { | ||
404 |
2/4✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25404 times.
✗ Branch 5 not taken.
|
25404 | observedFrequencies.insert(obs.first.freq()); |
405 |
1/2✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
|
25404 | allObservedFrequencies |= obs.first.freq(); |
406 | } | ||
407 | LOG_DATA("{}: Observed frequencies {}", nameId, fmt::join(observedFrequencies, ", ")); | ||
408 | |||
409 |
2/2✓ Branch 5 taken 1599 times.
✓ Branch 6 taken 737 times.
|
2336 | for (const auto& freq : observedFrequencies) |
410 | { | ||
411 |
8/10✓ Branch 1 taken 1599 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 862 times.
✓ Branch 4 taken 737 times.
✓ Branch 6 taken 862 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 854 times.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 1591 times.
|
1599 | if (!freq.isFirstFrequency(allObservedFrequencies) && !_receiver.interFrequencyBias.contains(freq)) |
412 | { | ||
413 | LOG_TRACE("{}: Estimating Inter-Frequency bias for {}", nameId, freq); | ||
414 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | _receiver.interFrequencyBias.emplace(freq, UncertainValue<double>{}); |
415 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | _kalmanFilter.addInterFrequencyBias(freq); |
416 | } | ||
417 | } | ||
418 | 737 | } | |
419 | 737 | } | |
420 | |||
421 | 737 | std::vector<States::StateKeyType> Algorithm::determineStateKeys(const std::set<SatelliteSystem>& usedSatSystems, size_t nDoppMeas, | |
422 | [[maybe_unused]] const std::string& nameId) const | ||
423 | { | ||
424 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 737 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 737 times.
|
737 | if (_estimatorType == EstimatorType::KalmanFilter && _kalmanFilter.isInitialized()) |
425 | { | ||
426 | LOG_DATA("{}: stateKeys = [{}]", nameId, joinToString(_kalmanFilter.getStateKeys())); | ||
427 | ✗ | return _kalmanFilter.getStateKeys(); | |
428 | } | ||
429 | |||
430 | 737 | std::vector<States::StateKeyType> stateKeys; | |
431 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
1474 | stateKeys.reserve(PosKey.size()); |
432 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 737 times.
✗ Branch 5 not taken.
|
737 | std::ranges::copy(PosKey, std::back_inserter(stateKeys)); |
433 | 737 | stateKeys.reserve(stateKeys.size() + 1 | |
434 | 737 | + canCalculateVelocity(nDoppMeas) * (VelKey.size() + 1) | |
435 |
3/6✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 737 times.
✗ Branch 9 not taken.
|
1474 | + usedSatSystems.size() * (1 + canCalculateVelocity(nDoppMeas))); |
436 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
|
737 | if (canCalculateVelocity(nDoppMeas)) |
437 | { | ||
438 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 737 times.
✗ Branch 5 not taken.
|
737 | std::ranges::copy(VelKey, std::back_inserter(stateKeys)); |
439 | } | ||
440 | |||
441 |
2/2✓ Branch 5 taken 737 times.
✓ Branch 6 taken 737 times.
|
1474 | for (const auto& satSys : usedSatSystems) |
442 | { | ||
443 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | stateKeys.emplace_back(Keys::RecvClkBias{ satSys }); |
444 |
3/6✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
|
737 | if (canCalculateVelocity(nDoppMeas)) { stateKeys.emplace_back(Keys::RecvClkDrift{ satSys }); } |
445 | } | ||
446 |
2/2✓ Branch 4 taken 862 times.
✓ Branch 5 taken 737 times.
|
1599 | for (const auto& freq : _receiver.interFrequencyBias) |
447 | { | ||
448 |
1/2✓ Branch 1 taken 862 times.
✗ Branch 2 not taken.
|
862 | stateKeys.emplace_back(Keys::InterFreqBias{ freq.first }); |
449 | } | ||
450 | |||
451 | LOG_DATA("{}: stateKeys = [{}]", nameId, joinToString(stateKeys)); | ||
452 | 737 | return stateKeys; | |
453 | 737 | } | |
454 | |||
455 | 737 | std::vector<Meas::MeasKeyTypes> Algorithm::determineMeasKeys(const Observations& observations, size_t nPsrMeas, size_t nDoppMeas, [[maybe_unused]] const std::string& nameId) const | |
456 | { | ||
457 | 737 | std::vector<Meas::MeasKeyTypes> measKeys; | |
458 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | measKeys.reserve(nPsrMeas + nDoppMeas); |
459 | |||
460 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
|
737 | if (_obsFilter.isObsTypeUsed(GnssObs::Pseudorange)) |
461 | { | ||
462 |
2/2✓ Branch 5 taken 25404 times.
✓ Branch 6 taken 737 times.
|
26141 | for (const auto& signalObs : observations.signals) |
463 | { | ||
464 |
3/6✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 25404 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 25404 times.
✗ Branch 8 not taken.
|
25404 | if (signalObs.second.recvObs.at(Rover)->obs.contains(GnssObs::Pseudorange)) |
465 | { | ||
466 |
1/2✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
|
25404 | measKeys.emplace_back(Meas::Psr{ signalObs.first }); |
467 | } | ||
468 | } | ||
469 | } | ||
470 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
|
737 | if (_obsFilter.isObsTypeUsed(GnssObs::Doppler)) |
471 | { | ||
472 |
2/2✓ Branch 5 taken 25404 times.
✓ Branch 6 taken 737 times.
|
26141 | for (const auto& signalObs : observations.signals) |
473 | { | ||
474 |
4/6✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 25404 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 24528 times.
✓ Branch 8 taken 876 times.
|
25404 | if (signalObs.second.recvObs.at(Rover)->obs.contains(GnssObs::Doppler)) |
475 | { | ||
476 |
1/2✓ Branch 1 taken 24528 times.
✗ Branch 2 not taken.
|
24528 | measKeys.emplace_back(Meas::Doppler{ signalObs.first }); |
477 | } | ||
478 | } | ||
479 | } | ||
480 | |||
481 | LOG_DATA("{}: measKeys = [{}]", nameId, joinToString(measKeys)); | ||
482 | 737 | return measKeys; | |
483 | ✗ | } | |
484 | |||
485 | 737 | KeyedMatrixXd<Meas::MeasKeyTypes, States::StateKeyType> Algorithm::calcMatrixH(const std::vector<States::StateKeyType>& stateKeys, | |
486 | const std::vector<Meas::MeasKeyTypes>& measKeys, | ||
487 | const Observations& observations, | ||
488 | const std::string& nameId) const | ||
489 | { | ||
490 |
1/2✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
|
737 | KeyedMatrixXd<Meas::MeasKeyTypes, States::StateKeyType> H(Eigen::MatrixXd::Zero(static_cast<int>(measKeys.size()), |
491 | 737 | static_cast<int>(stateKeys.size())), | |
492 |
1/2✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
|
1474 | measKeys, stateKeys); |
493 | |||
494 |
2/2✓ Branch 7 taken 25404 times.
✓ Branch 8 taken 737 times.
|
26141 | for (const auto& [satSigId, signalObs] : observations.signals) |
495 | { | ||
496 |
1/2✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
|
25404 | auto satId = satSigId.toSatId(); |
497 | |||
498 |
1/2✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
|
25404 | const auto& roverObs = signalObs.recvObs.at(Rover); |
499 |
2/2✓ Branch 8 taken 49932 times.
✓ Branch 9 taken 25404 times.
|
75336 | for (const auto& [obsType, obsData] : roverObs->obs) |
500 | { | ||
501 |
2/4✓ Branch 0 taken 25404 times.
✓ Branch 1 taken 24528 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
49932 | switch (obsType) |
502 | { | ||
503 | 25404 | case GnssObs::Pseudorange: | |
504 |
5/10✓ Branch 2 taken 25404 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25404 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 25404 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 25404 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 25404 times.
✗ Branch 17 not taken.
|
25404 | H.block<3>(Meas::Psr{ satSigId }, PosKey) = -roverObs->e_pLOS(_receiver.e_posMarker).transpose(); |
505 |
1/2✓ Branch 3 taken 25404 times.
✗ Branch 4 not taken.
|
25404 | H(Meas::Psr{ satSigId }, Keys::RecvClkBias{ satId.satSys }) = 1; |
506 |
4/6✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25404 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11391 times.
✓ Branch 7 taken 14013 times.
|
25404 | if (_receiver.interFrequencyBias.contains(satSigId.freq())) |
507 | { | ||
508 |
2/4✓ Branch 1 taken 11391 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 11391 times.
✗ Branch 7 not taken.
|
11391 | H(Meas::Psr{ satSigId }, Keys::InterFreqBias{ satSigId.freq() }) = 1; |
509 | } | ||
510 | 25404 | break; | |
511 | 24528 | case GnssObs::Doppler: | |
512 |
5/10✓ Branch 2 taken 24528 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24528 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 24528 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 24528 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 24528 times.
✗ Branch 17 not taken.
|
24528 | H.block<3>(Meas::Doppler{ satSigId }, PosKey) = -roverObs->e_vLOS(_receiver.e_posMarker, _receiver.e_vel).transpose(); |
513 |
5/10✓ Branch 2 taken 24528 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24528 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 24528 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 24528 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 24528 times.
✗ Branch 17 not taken.
|
24528 | H.block<3>(Meas::Doppler{ satSigId }, VelKey) = -roverObs->e_pLOS(_receiver.e_posMarker).transpose(); |
514 |
1/2✓ Branch 3 taken 24528 times.
✗ Branch 4 not taken.
|
24528 | H(Meas::Doppler{ satSigId }, Keys::RecvClkDrift{ satId.satSys }) = 1; |
515 | 24528 | break; | |
516 | ✗ | case GnssObs::Carrier: | |
517 | case GnssObs::ObservationType_COUNT: | ||
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 | 737 | return H; | |
527 | ✗ | } | |
528 | |||
529 | 737 | KeyedMatrixXd<Meas::MeasKeyTypes, Meas::MeasKeyTypes> Algorithm::calcMatrixR(const std::vector<Meas::MeasKeyTypes>& measKeys, | |
530 | const Observations& observations, | ||
531 | const std::string& nameId) | ||
532 | { | ||
533 |
1/2✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
|
737 | KeyedMatrixXd<Meas::MeasKeyTypes, Meas::MeasKeyTypes> R(Eigen::MatrixXd::Zero(static_cast<int>(measKeys.size()), |
534 | 737 | static_cast<int>(measKeys.size())), | |
535 |
1/2✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
|
1474 | measKeys); |
536 | |||
537 |
2/2✓ Branch 7 taken 25404 times.
✓ Branch 8 taken 737 times.
|
26141 | for (const auto& [satSigId, signalObs] : observations.signals) |
538 | { | ||
539 |
3/4✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 11 taken 49932 times.
✓ Branch 12 taken 25404 times.
|
75336 | for (const auto& [obsType, obsData] : signalObs.recvObs.at(Rover)->obs) |
540 | { | ||
541 |
2/4✓ Branch 0 taken 25404 times.
✓ Branch 1 taken 24528 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
49932 | switch (obsType) |
542 | { | ||
543 | 25404 | case GnssObs::Pseudorange: | |
544 |
1/2✓ Branch 3 taken 25404 times.
✗ Branch 4 not taken.
|
25404 | R(Meas::Psr{ satSigId }, Meas::Psr{ satSigId }) = obsData.measVar; |
545 | 25404 | break; | |
546 | 24528 | case GnssObs::Doppler: | |
547 |
1/2✓ Branch 3 taken 24528 times.
✗ Branch 4 not taken.
|
24528 | R(Meas::Doppler{ satSigId }, Meas::Doppler{ satSigId }) = obsData.measVar; |
548 | 24528 | break; | |
549 | ✗ | case GnssObs::Carrier: | |
550 | case GnssObs::ObservationType_COUNT: | ||
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 | 737 | return R; | |
560 | ✗ | } | |
561 | |||
562 | 737 | KeyedVectorXd<Meas::MeasKeyTypes> Algorithm::calcMeasInnovation(const std::vector<Meas::MeasKeyTypes>& measKeys, | |
563 | const Observations& observations, | ||
564 | const std::string& nameId) | ||
565 | { | ||
566 |
2/4✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
|
737 | KeyedVectorXd<Meas::MeasKeyTypes> dz(Eigen::VectorXd::Zero(static_cast<int>(measKeys.size())), measKeys); |
567 | |||
568 |
2/2✓ Branch 7 taken 25404 times.
✓ Branch 8 taken 737 times.
|
26141 | for (const auto& [satSigId, signalObs] : observations.signals) |
569 | { | ||
570 |
3/4✓ Branch 1 taken 25404 times.
✗ Branch 2 not taken.
✓ Branch 11 taken 49932 times.
✓ Branch 12 taken 25404 times.
|
75336 | for (const auto& [obsType, obsData] : signalObs.recvObs.at(Rover)->obs) |
571 | { | ||
572 |
2/4✓ Branch 0 taken 25404 times.
✓ Branch 1 taken 24528 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
49932 | switch (obsType) |
573 | { | ||
574 | 25404 | case GnssObs::Pseudorange: | |
575 |
1/2✓ Branch 2 taken 25404 times.
✗ Branch 3 not taken.
|
25404 | dz(Meas::Psr{ satSigId }) = obsData.measurement - obsData.estimate; |
576 | 25404 | break; | |
577 | 24528 | case GnssObs::Doppler: | |
578 |
1/2✓ Branch 2 taken 24528 times.
✗ Branch 3 not taken.
|
24528 | dz(Meas::Doppler{ satSigId }) = obsData.measurement - obsData.estimate; |
579 | 24528 | break; | |
580 | ✗ | case GnssObs::Carrier: | |
581 | case GnssObs::ObservationType_COUNT: | ||
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 | 737 | return dz; | |
591 | ✗ | } | |
592 | |||
593 | 737 | void Algorithm::assignLeastSquaresResult(const KeyedVectorXd<States::StateKeyType>& state, | |
594 | const KeyedMatrixXd<States::StateKeyType, States::StateKeyType>& variance, | ||
595 | const Eigen::Vector3d& e_oldPos, | ||
596 | size_t nParams, size_t nUniqueDopplerMeas, double dt, | ||
597 | [[maybe_unused]] const std::string& nameId) | ||
598 | { | ||
599 |
2/4✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
|
737 | _receiver.e_posMarker += state.segment<3>(PosKey); |
600 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | _receiver.lla_posMarker = trafo::ecef2lla_WGS84(_receiver.e_posMarker); |
601 |
2/2✓ Branch 6 taken 6758 times.
✓ Branch 7 taken 737 times.
|
7495 | for (const auto& s : state.rowKeys()) |
602 | { | ||
603 |
2/2✓ Branch 1 taken 737 times.
✓ Branch 2 taken 6021 times.
|
6758 | if (const auto* bias = std::get_if<Keys::RecvClkBias>(&s)) |
604 | { | ||
605 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 737 times.
✗ Branch 5 not taken.
|
737 | size_t idx = _receiver.recvClk.getIdx(bias->satSys).value(); |
606 |
2/4✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
|
737 | _receiver.recvClk.bias.at(idx) += state(*bias) / InsConst::C; |
607 |
2/4✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 737 times.
|
737 | 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 |
2/4✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
|
737 | _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 |
2/2✓ Branch 1 taken 862 times.
✓ Branch 2 taken 5159 times.
|
6021 | else if (const auto* bias = std::get_if<Keys::InterFreqBias>(&s)) |
619 | { | ||
620 |
1/2✓ Branch 1 taken 862 times.
✗ Branch 2 not taken.
|
862 | auto& freqDiff = _receiver.interFrequencyBias.at(bias->freq); |
621 |
1/2✓ Branch 2 taken 862 times.
✗ Branch 3 not taken.
|
862 | freqDiff.value += state(*bias) / InsConst::C; |
622 |
2/4✓ Branch 3 taken 862 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 862 times.
|
862 | 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 |
1/2✓ Branch 3 taken 862 times.
✗ Branch 4 not taken.
|
862 | 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 |
1/2✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
|
737 | if (nUniqueDopplerMeas >= nParams) |
636 | { | ||
637 |
2/4✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
|
737 | _receiver.e_vel += state.segment<3>(VelKey); |
638 |
2/2✓ Branch 6 taken 6758 times.
✓ Branch 7 taken 737 times.
|
7495 | for (const auto& s : state.rowKeys()) |
639 | { | ||
640 |
2/2✓ Branch 1 taken 737 times.
✓ Branch 2 taken 6021 times.
|
6758 | if (const auto* drift = std::get_if<Keys::RecvClkDrift>(&s)) |
641 | { | ||
642 |
2/4✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 737 times.
✗ Branch 5 not taken.
|
737 | size_t idx = _receiver.recvClk.getIdx(drift->satSys).value(); |
643 |
2/4✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 737 times.
✗ Branch 6 not taken.
|
737 | _receiver.recvClk.drift.at(idx) += state(*drift) / InsConst::C; |
644 |
2/4✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 737 times.
|
737 | 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 |
2/4✓ Branch 3 taken 737 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
|
737 | _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 |
2/2✓ Branch 5 taken 737 times.
✓ Branch 6 taken 737 times.
|
1474 | 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 |
2/2✓ Branch 5 taken 862 times.
✓ Branch 6 taken 737 times.
|
1599 | 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 | 737 | } | |
694 | |||
695 | ✗ | void Algorithm::assignKalmanFilterResult(const KeyedVectorXd<States::StateKeyType>& state, | |
696 | const KeyedMatrixXd<States::StateKeyType, States::StateKeyType>& variance, | ||
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 | |||
769 | 343 | void Algorithm::computeDOPs(const std::shared_ptr<SppSolution>& sppSol, | |
770 | const KeyedMatrixXd<Meas::MeasKeyTypes, States::StateKeyType>& H, | ||
771 | [[maybe_unused]] const std::string& nameId) | ||
772 | { | ||
773 |
3/6✓ Branch 5 taken 343 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 343 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 343 times.
✗ Branch 12 not taken.
|
343 | KeyedMatrixXd<States::StateKeyType, States::StateKeyType> N(H(all, all).transpose() * H(all, all), H.colKeys()); |
774 |
1/2✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
|
343 | Eigen::FullPivLU<Eigen::MatrixXd> lu_decomp(N(all, all)); |
775 |
2/4✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 343 times.
✗ Branch 5 not taken.
|
343 | if (lu_decomp.rank() == H.cols()) |
776 | { | ||
777 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | auto Q = N.inverse(); |
778 |
2/4✓ Branch 3 taken 343 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 343 times.
✗ Branch 7 not taken.
|
343 | Eigen::Matrix3d Qpp = Q(PosKey, PosKey); |
779 |
4/8✓ Branch 2 taken 343 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 343 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 343 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 343 times.
✗ Branch 13 not taken.
|
343 | Eigen::Matrix3d Qlocal = sppSol->n_Quat_e() * Qpp * sppSol->e_Quat_n(); |
780 |
2/4✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 343 times.
✗ Branch 5 not taken.
|
343 | sppSol->HDOP = std::sqrt(Qlocal(0, 0) + Qlocal(1, 1)); |
781 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | sppSol->VDOP = std::sqrt(Qlocal(2, 2)); |
782 |
1/2✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
|
343 | sppSol->PDOP = std::sqrt(Qpp.trace()); |
783 | 343 | } | |
784 | |||
785 | LOG_DATA("{}: HDOP = {}", nameId, sppSol->HDOP); | ||
786 | LOG_DATA("{}: VDOP = {}", nameId, sppSol->VDOP); | ||
787 | LOG_DATA("{}: PDOP = {}", nameId, sppSol->PDOP); | ||
788 | 343 | } | |
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 | ||
793 | ✗ | void 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 | ||
806 | 7 | void from_json(const json& j, Algorithm& obj) | |
807 | { | ||
808 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (j.contains("obsFilter")) { j.at("obsFilter").get_to(obj._obsFilter); } |
809 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (j.contains("obsEstimator")) { j.at("obsEstimator").get_to(obj._obsEstimator); } |
810 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (j.contains("estimatorType")) { j.at("estimatorType").get_to(obj._estimatorType); } |
811 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (j.contains("kalmanFilter")) { j.at("kalmanFilter").get_to(obj._kalmanFilter); } |
812 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (j.contains("estimateInterFrequencyBiases")) { j.at("estimateInterFrequencyBiases").get_to(obj._estimateInterFreqBiases); } |
813 | 7 | } | |
814 | |||
815 | } // namespace SPP | ||
816 | |||
817 | ✗ | const char* to_string(SPP::Algorithm::EstimatorType estimatorType) | |
818 | { | ||
819 | ✗ | switch (estimatorType) | |
820 | { | ||
821 | ✗ | case SPP::Algorithm::EstimatorType::LeastSquares: | |
822 | ✗ | return "Least Squares"; | |
823 | ✗ | case SPP::Algorithm::EstimatorType::WeightedLeastSquares: | |
824 | ✗ | return "Weighted Least Squares"; | |
825 | ✗ | case SPP::Algorithm::EstimatorType::KalmanFilter: | |
826 | ✗ | return "Kalman Filter"; | |
827 | ✗ | case SPP::Algorithm::EstimatorType::COUNT: | |
828 | ✗ | break; | |
829 | } | ||
830 | ✗ | return ""; | |
831 | } | ||
832 | |||
833 | ✗ | const char* to_string(SPP::Algorithm::ReceiverType receiver) | |
834 | { | ||
835 | ✗ | switch (receiver) | |
836 | { | ||
837 | ✗ | case SPP::Algorithm::ReceiverType::Rover: | |
838 | ✗ | return "Rover"; | |
839 | ✗ | case SPP::Algorithm::ReceiverType::ReceiverType_COUNT: | |
840 | ✗ | break; | |
841 | } | ||
842 | ✗ | return ""; | |
843 | } | ||
844 | |||
845 | } // namespace NAV | ||
846 | |||
847 | ✗ | std::ostream& operator<<(std::ostream& os, const NAV::SPP::Algorithm::EstimatorType& obj) | |
848 | { | ||
849 | ✗ | return os << fmt::format("{}", obj); | |
850 | } | ||
851 | |||
852 | ✗ | std::ostream& operator<<(std::ostream& os, const NAV::SPP::Algorithm::ReceiverType& obj) | |
853 | { | ||
854 | ✗ | return os << fmt::format("{}", obj); | |
855 | } | ||
856 |