74 const std::vector<const GnssNavInfo*>& gnssNavInfos,
75 const std::string& nameId)
79 if (gnssNavInfos.empty())
81 LOG_ERROR(
"{}: [{}] SPP cannot calculate position because no navigation data provided.", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST));
87 auto ionosphericCorrections = std::make_shared<const IonosphericCorrections>(gnssNavInfos);
90 LOG_DATA(
"{}: dt = {}s", nameId, dt);
93 auto sppSol = std::make_shared<SppSolution>();
94 sppSol->insTime =
_receiver.gnssObs->insTime;
102 constexpr size_t N_ITER_MAX_LSQ = 10;
104 Eigen::Vector3d e_oldPos =
_receiver.e_posMarker;
105 bool accuracyAchieved =
false;
109 for (
size_t iteration = 0; iteration < nIter; iteration++)
111 LOG_DATA(
"{}: [{}] iteration {}/{}", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST), iteration + 1, nIter);
114 LOG_DATA(
"{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
116 for ([[maybe_unused]]
const auto& satSys :
_receiver.recvClk.satelliteSystems)
122 for ([[maybe_unused]]
const auto& freq :
_receiver.interFrequencyBias)
124 LOG_DATA(
"{}: [{}] IFBBias [{:3}] = {} [s] (StdDev = {})", nameId,
125 _receiver.gnssObs->insTime.toYMDHMS(
GPST), freq.first, freq.second.value, freq.second.stdDev);
128 auto posNorm = e_oldPos.norm();
130 LOG_DATA(
"{}: [{}] ignoreElevationMask = {} (posNorm = {} [m])", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST), ignoreElevationMask, posNorm);
140 ignoreElevationMask);
142 if (observations.
signals.empty())
144 LOG_TRACE(
"{}: [{}] SPP cannot calculate position because no valid observations. Try changing filter settings or reposition your antenna.",
151 sppSol->nSatellites = observations.
satellites.size();
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)
160 [[maybe_unused]]
auto satCount = std::ranges::count_if(observations.
satellites, [&](
const SatId& satId) {
161 return satId.satSys == satSys;
164 LOG_DATA(
"{}: nSat {:5} = {}", nameId, satSys, satCount);
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);
180 auto measKeys =
determineMeasKeys(observations, sppSol->nMeasPsr, sppSol->nMeasDopp, nameId);
182 sppSol->nParam = stateKeys.size();
184 H =
calcMatrixH(stateKeys, measKeys, observations, nameId);
185 auto R =
calcMatrixR(measKeys, observations, nameId);
190 std::string highInnovation;
191 size_t highInnovationCounter = 0;
192 for (
const auto& key : dz.rowKeys())
194 if (
double val = dz(key); std::abs(val) > 1000)
196 highInnovation += fmt::format(
"{}[{} {:.0f}], ", highInnovationCounter++ % 3 == 0 ?
"\n" :
"", key, val);
199 if (highInnovationCounter != 0)
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));
206 sppSol->addEvent(msg);
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); }
232 if (iteration == nIter - 1) {
return nullptr; }
233 if (accuracyAchieved || iteration == nIter - 1)
236 && sppSol->nMeasPsr > nParams
239 LOG_TRACE(
"{}: [{}] Initializing KF with LSQ solution", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST));
243 for (
size_t i = 0; i <
_receiver.recvClk.satelliteSystems.size(); i++)
245 auto satSys =
_receiver.recvClk.satelliteSystems.at(i);
252 for (
const auto& state : x.
rowKeys())
254 if (
const auto* bias = std::get_if<Keys::InterFreqBias>(&state))
273 sppSol->satData.reserve(observations.
satellites.size());
274 for (
const auto& [satSigId, signalObs] : observations.
signals)
276 if (std::ranges::find_if(sppSol->satData,
277 [&satSigId = satSigId](
const auto& satIdData) { return satIdData.first == satSigId.toSatId(); })
278 == sppSol->satData.end())
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) });
286 sppSol->_e_sppCovarianceMatrix = lsq.
variance;
298 std::string msg = fmt::format(
"Potential clock jump detected. Reinitializing KF with WLSQ.\nPosition difference to previous epoch {:.1f}m", posDiff);
300 sppSol->addEvent(msg);
309 sppSol->satData.reserve(observations.
satellites.size());
310 for (
const auto& [satSigId, signalObs] : observations.
signals)
312 if (std::ranges::find_if(sppSol->satData,
313 [&satSigId = satSigId](
const auto& satIdData) { return satIdData.first == satSigId.toSatId(); })
314 == sppSol->satData.end())
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) });
321 sppSol->_e_sppCovarianceMatrix =
_kalmanFilter.getErrorCovarianceMatrix();
328 sppSol->interFrequencyBias =
_receiver.interFrequencyBias;
330#if LOG_LEVEL <= LOG_LEVEL_DATA
331 if (sppSol->e_position() !=
_receiver.e_posMarker)
333 LOG_DATA(
"{}: [{}] Receiver: e_pos = {:.6f}m, {:.6f}m, {:.6f}m", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
335 LOG_DATA(
"{}: [{}] Receiver: lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
338 if (sppSol->e_velocity() !=
_receiver.e_vel)
342 for (
const auto& satSys :
_receiver.recvClk.satelliteSystems)
344 if (*sppSol->recvClk.biasFor(satSys) != *
_receiver.recvClk.biasFor(satSys))
348 if (*sppSol->recvClk.driftFor(satSys) != *
_receiver.recvClk.driftFor(satSys))
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++)
362 LOG_DATA(
"{}: [{}] Solution: clkBias [{:5}] = {} s", nameId, sppSol->insTime.toYMDHMS(
GPST),
363 sppSol->recvClk.satelliteSystems.at(i), sppSol->recvClk.bias.at(i));
365 for (
size_t i = 0; i < sppSol->recvClk.satelliteSystems.size(); i++)
367 LOG_DATA(
"{}: [{}] Solution: clkDrift [{:5}] = {} s/s", nameId, sppSol->insTime.toYMDHMS(
GPST),
368 sppSol->recvClk.satelliteSystems.at(i), sppSol->recvClk.drift.at(i));
370 for ([[maybe_unused]]
const auto& freq : sppSol->interFrequencyBias)
372 LOG_DATA(
"{}: [{}] Solution: IFBBias [{:5}] = {} s", nameId, sppSol->insTime.toYMDHMS(
GPST), freq.first, freq.second.value);
595 const Eigen::Vector3d& e_oldPos,
596 size_t nParams,
size_t nUniqueDopplerMeas,
double dt,
597 [[maybe_unused]]
const std::string& nameId)
601 for (
const auto& s : state.
rowKeys())
603 if (
const auto* bias = std::get_if<Keys::RecvClkBias>(&s))
605 size_t idx =
_receiver.recvClk.getIdx(bias->satSys).value();
607 if (variance(*bias, *bias) < 0)
616 LOG_DATA(
"{}: Setting Clk Bias [{}] = {} [s] (StdDev = {})", nameId, bias->satSys,
_receiver.recvClk.bias.at(idx),
_receiver.recvClk.biasStdDev.at(idx));
618 else if (
const auto* bias = std::get_if<Keys::InterFreqBias>(&s))
620 auto& freqDiff =
_receiver.interFrequencyBias.at(bias->freq);
622 if (variance(*bias, *bias) < 0)
625 LOG_WARN(
"{}: Negative variance for {}. Defauting to {:.0f} [m]", nameId, *bias, freqDiff.stdDev *
InsConst::C);
629 freqDiff.stdDev = std::sqrt(variance(*bias, *bias)) /
InsConst::C;
631 LOG_DATA(
"{}: Setting IFB Bias [{}] = {} [s] (StdDev = {})", nameId, bias->freq, freqDiff.value, freqDiff.stdDev);
635 if (nUniqueDopplerMeas >= nParams)
638 for (
const auto& s : state.
rowKeys())
640 if (
const auto* drift = std::get_if<Keys::RecvClkDrift>(&s))
642 size_t idx =
_receiver.recvClk.getIdx(drift->satSys).value();
644 if (variance(*drift, *drift) < 0)
647 LOG_WARN(
"{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *drift,
_receiver.recvClk.driftStdDev.at(idx) *
InsConst::C);
653 LOG_DATA(
"{}: Setting Clk Drift [{}] = {} [s/s] (StdDev = {})", nameId, drift->satSys,
660 if (dt > 1e-6 && !e_oldPos.isZero())
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);
667 LOG_DATA(
"{}: [{}] e_oldPos = {}", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST), e_oldPos.transpose());
675 LOG_DATA(
"{}: [{}] Assigning solution to _receiver", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST));
678 LOG_DATA(
"{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
680 for ([[maybe_unused]]
const auto& satSys :
_receiver.recvClk.satelliteSystems)
682 LOG_DATA(
"{}: [{}] clkBias = {} [s] (StdDev = {})", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
684 LOG_DATA(
"{}: [{}] clkDrift = {} [s/s] (StdDev = {})", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
688 for ([[maybe_unused]]
const auto& freq :
_receiver.interFrequencyBias)
690 LOG_DATA(
"{}: [{}] IFBBias [{:3}] = {} [s] (StdDev = {})", nameId,
691 _receiver.gnssObs->insTime.toYMDHMS(
GPST), freq.first, freq.second.value, freq.second.stdDev);
697 [[maybe_unused]]
const std::string& nameId)
702 for (
const auto& s : state.
rowKeys())
704 if (
const auto* bias = std::get_if<Keys::RecvClkBias>(&s))
706 size_t idx =
_receiver.recvClk.getIdx(bias->satSys).value();
708 if (variance(*bias, *bias) < 0)
717 LOG_DATA(
"{}: Setting Clock Bias [{}] = {}", nameId, bias->satSys,
_receiver.recvClk.bias.at(idx));
719 else if (
const auto* drift = std::get_if<Keys::RecvClkDrift>(&s))
721 size_t idx =
_receiver.recvClk.getIdx(drift->satSys).value();
723 if (variance(*drift, *drift) < 0)
726 LOG_WARN(
"{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *drift,
_receiver.recvClk.driftStdDev.at(idx) *
InsConst::C);
732 LOG_DATA(
"{}: Setting Clock Drift [{}] = {}", nameId, drift->satSys,
_receiver.recvClk.drift.at(idx));
734 else if (
const auto* bias = std::get_if<Keys::InterFreqBias>(&s))
736 auto& freqDiff =
_receiver.interFrequencyBias.at(bias->freq);
738 if (variance(*bias, *bias) < 0)
741 LOG_WARN(
"{}: Negative variance for {}. Defauting to {:.0f} [m/s]", nameId, *bias, freqDiff.stdDev *
InsConst::C);
745 freqDiff.stdDev = std::sqrt(variance(*bias, *bias)) /
InsConst::C;
747 LOG_DATA(
"{}: Setting Inter-Freq Bias [{}] = {}", nameId, bias->freq, freqDiff.value);
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),
755 LOG_DATA(
"{}: [{}] lla_pos = {:.6f}°, {:.6f}°, {:.3f}m", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST),
757 for ([[maybe_unused]]
const auto& satSys :
_receiver.recvClk.satelliteSystems)
763 for ([[maybe_unused]]
const auto& freq :
_receiver.interFrequencyBias)
765 LOG_DATA(
"{}: [{}] IFBBias [{:3}] = {} s", nameId,
_receiver.gnssObs->insTime.toYMDHMS(
GPST), freq.first, freq.second.value);