14#include <imgui_internal.h>
65 std::mt19937_64 gen(
static_cast<uint64_t
>(std::chrono::system_clock::now().time_since_epoch().count()));
66 std::uniform_int_distribution<uint64_t> dist(0, std::numeric_limits<uint64_t>::max() / 2);
104 return "Data Processor";
109 if (
outputPins.front().dataIdentifier.size() != 1
112 ImGui::TextUnformatted(
"Please connect the input pin to show the options");
119 auto inputDoubleWithUnit = [&](
const char* title,
double& data,
auto& unit,
const char* combo_items_separated_by_zeros,
const char* format) {
121 &data, unit, combo_items_separated_by_zeros, 0.0, 0.0,
122 format, ImGuiInputTextFlags_CharsScientific))
130 auto inputVector3WithUnit = [&](
const char* title, Eigen::Vector3d& data,
auto& unit,
const char* combo_items_separated_by_zeros,
const char* format) {
132 data.data(), unit, combo_items_separated_by_zeros,
133 format, ImGuiInputTextFlags_CharsScientific))
142 float currentCursorX = ImGui::GetCursorPosX();
143 if (ImGui::Checkbox(fmt::format(
"##rng.useSeed {} {}", title,
size_t(
id)).c_str(), &rng.useSeed))
145 LOG_DEBUG(
"{}: {} rng.useSeed changed to {}",
nameId(), title, rng.useSeed);
148 if (ImGui::IsItemHovered()) { ImGui::SetTooltip(
"Use seed?"); }
152 ImGui::BeginDisabled();
154 ImGui::SetNextItemWidth(itemWidth - (ImGui::GetCursorPosX() - currentCursorX));
155 if (
ImGui::SliderULong(fmt::format(
"{} Seed##{}", title,
size_t(
id)).c_str(), &rng.seed, 0, std::numeric_limits<uint64_t>::max() / 2,
"%lu"))
162 ImGui::EndDisabled();
166 auto noiseGuiInput = [&]<
typename T>(
const char* title, T& data,
auto& unit,
const char* combo_items_separated_by_zeros,
const char* format,
RandomNumberGenerator& rng) {
167 if constexpr (std::is_same_v<T, double>) { inputDoubleWithUnit(title, data, unit, combo_items_separated_by_zeros, format); }
168 else if constexpr (std::is_same_v<T, Eigen::Vector3d>) { inputVector3WithUnit(title, data, unit, combo_items_separated_by_zeros, format); }
170 rngInput(title, rng);
176 ImGui::TextUnformatted(
"Offsets:");
205 ImGui::TextUnformatted(
"Measurement noise:");
216 ?
"Standard deviation"
230 ?
"Standard deviation"
248 ImGui::TextUnformatted(
"Random walk noise:");
253 ImGui::TextUnformatted(
"Integrated Random walk noise:");
262 ImGui::TextUnformatted(
"Ambiguities:");
265 ImGui::SetNextItemWidth((itemWidth - ImGui::GetStyle().ItemInnerSpacing.x) / 2.0F);
273 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
274 ImGui::SetNextItemWidth((itemWidth - ImGui::GetStyle().ItemInnerSpacing.x) / 2.0F);
285 ImGui::TextUnformatted(
"Cycle-slip:");
301 ImGui::SetNextItemWidth(itemWidth);
302 if (ImGui::DragInt(fmt::format(
"Ambiguity Range to slip to##{}",
size_t(
id)).c_str(), &
_gui_cycleSlipRange,
303 1.0F, 1, std::numeric_limits<int>::max(),
"+/- %d"))
311 ImGui::SetNextItemWidth(itemWidth);
319 ImGui::SetNextItemWidth(itemWidth);
324 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
325 if (ImGui::TreeNode(fmt::format(
"Manual Cycle-slips Tree##{}",
size_t(
id)).c_str()))
329 ImGui::TextUnformatted(
"New:");
331 float groupWidth = 62.0F * 2 + ImGui::GetStyle().ItemSpacing.x;
332 ImGui::BeginHorizontal(fmt::format(
"Horizontal SatSigId {}",
size_t(
id)).c_str());
334 ImGui::SetNextItemWidth(62.0F);
339 ImGui::SetNextItemWidth(62.0F);
346 ImGui::EndHorizontal();
349 ImGui::SetNextItemWidth(groupWidth);
351 if (ImGui::IsItemHovered()) { ImGui::SetTooltip(
"Ambiguity value"); }
353 ImGui::BeginHorizontal(fmt::format(
"Horizontal LLI/Button {}",
size_t(
id)).c_str(), ImVec2(groupWidth, 0.0F));
357 if (ImGui::Button(fmt::format(
"Add##manual cycle-slip {}",
size_t(
id)).c_str()))
362 ImGui::EndHorizontal();
375 && ImGui::BeginTable(fmt::format(
"Manual cycle-slips Table##{}",
size_t(
id)).c_str(), 5,
376 ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY,
377 ImVec2(0.0F, std::min(25.0F +
static_cast<float>(
_manualCycleSlips.size()) * 28.0F, 300.0F)
380 ImGui::TableSetupColumn(
"Time");
381 ImGui::TableSetupColumn(
"Signal");
382 ImGui::TableSetupColumn(
"Value");
383 ImGui::TableSetupColumn(
"LLI");
384 ImGui::TableSetupColumn(
"Delete");
386 ImGui::TableSetupScrollFreeze(1, 1);
387 ImGui::TableHeadersRow();
389 std::optional<std::pair<InsTime, SatSigId>> _toRemove;
392 const auto& [insTime, satSigId] = cycleSlip.first;
393 auto& [ambValue, setLLI] = cycleSlip.second;
394 ImGui::TableNextRow();
396 ImGui::TableNextColumn();
397 ImGui::TextUnformatted(fmt::format(
"{}", insTime.toYMDHMS(
GPST)).c_str());
399 ImGui::TableNextColumn();
401 ImGui::SetNextItemWidth(62.0F);
402 auto newSatSigId = satSigId;
403 if (
ShowCodeSelector(fmt::format(
"##Manual cycle-slip code {} {} {}",
size_t(
id), insTime, satSigId).c_str(), newSatSigId.code,
Freq_All,
true))
408 ImGui::SetNextItemWidth(62.0F);
409 SatId satId = newSatSigId.toSatId();
410 if (
ShowSatelliteSelector(fmt::format(
"##Manual cycle-slip sat{} {} {}",
size_t(
id), insTime, satSigId).c_str(), satId, satId.
satSys,
true))
412 newSatSigId.satNum = satId.
satNum;
415 if (newSatSigId != satSigId)
417 _toRemove = cycleSlip.first;
422 ImGui::TableNextColumn();
423 ImGui::SetNextItemWidth(120.0F);
424 if (ImGui::InputInt(fmt::format(
"##Ambiguity value {} {} {}",
size_t(
id), insTime, satSigId).c_str(), &ambValue))
429 ImGui::TableNextColumn();
430 if (ImGui::Checkbox(fmt::format(
"##Ambiguity LLI {} {} {}",
size_t(
id), insTime, satSigId).c_str(), &setLLI))
435 ImGui::TableNextColumn();
436 if (ImGui::Button(fmt::format(
"X##Manual cycle remove {} {} {}",
size_t(
id), insTime, satSigId).c_str()))
438 _toRemove = cycleSlip.first;
454 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
455 if (ImGui::TreeNode(fmt::format(
"Simulated Ambiguities and Cycle-slips##{}",
size_t(
id)).c_str()))
460 std::set<InsTime> ambiguityTimes;
461 for (
int i = 0; i < nAmb; i++)
463 const auto& ambVec = std::next(
_ambiguities.begin(), i)->second;
464 for (
const auto& amb : ambVec)
466 ambiguityTimes.insert(amb.first);
469 if (ambiguityTimes.size() < 64 - 1)
471 ImGui::PushFont(Application::MonoFont());
473 if (ImGui::BeginTable(fmt::format(
"Ambiguities##{}",
size_t(
id)).c_str(),
static_cast<int>(ambiguityTimes.size() + 1),
474 ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY,
477 ImGui::TableSetupColumn(
"");
478 for (
const auto& time : ambiguityTimes)
480 auto t = time.toYMDHMS(
GPST);
481 t.sec = std::round(t.sec * 1e2) / 1e2;
484 ImGui::TableSetupScrollFreeze(1, 1);
485 ImGui::TableHeadersRow();
487 for (
int i = 0; i < nAmb; i++)
489 ImGui::TableNextRow();
490 ImGui::TableNextColumn();
491 const auto& ambiguities = std::next(
_ambiguities.begin(), i);
493 ImGui::TextUnformatted(fmt::format(
"{}", ambiguities->first).c_str());
494 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGui::GetStyle().Colors[ImGuiCol_TableHeaderBg]));
496 for (
const auto& time : ambiguityTimes)
498 ImGui::TableNextColumn();
499 auto iter = std::ranges::find_if(ambiguities->second, [&time](
const auto& timeAndAmb) {
500 return timeAndAmb.first == time;
502 if (iter != ambiguities->second.end())
506 return cycleSlip.
time == time && cycleSlip.
satSigId == ambiguities->first;
508 if (cycleIter !=
_cycleSlips.end()) { color = ImColor(240, 128, 128); }
509 else if (ambiguities->second.back().first == time) { color = ImGui::GetStyle().Colors[ImGuiCol_Text]; }
510 else { color = ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]; }
511 ImGui::TextColored(color,
"%s%s",
512 fmt::format(
"{}", iter->second).c_str(),
513 cycleIter !=
_cycleSlips.end() && cycleIter->LLI ?
" (LLI)" :
"");
514 if (ImGui::IsItemHovered() && cycleIter !=
_cycleSlips.end()) { ImGui::SetTooltip(
"Cycle-slip"); }
516 else if (time < ambiguities->second.front().first)
518 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImColor(70, 70, 70));
529 ImGui::TextColored(ImColor(255, 0, 0),
"More than 64 timestamps for ambiguities, which cannot be displayed in a table");
621 if (j.contains(
"imuGyroscopeBiasUnit")) { j.at(
"imuGyroscopeBiasUnit").get_to(
_imuGyroscopeBiasUnit); }
622 if (j.contains(
"imuGyroscopeBias_p")) { j.at(
"imuGyroscopeBias_p").get_to(
_imuGyroscopeBias_p); }
624 if (j.contains(
"imuAccelerometerNoise")) { j.at(
"imuAccelerometerNoise").get_to(
_imuAccelerometerNoise); }
625 if (j.contains(
"imuAccelerometerRng")) { j.at(
"imuAccelerometerRng").get_to(
_imuAccelerometerRng); }
626 if (j.contains(
"imuGyroscopeNoiseUnit")) { j.at(
"imuGyroscopeNoiseUnit").get_to(
_imuGyroscopeNoiseUnit); }
627 if (j.contains(
"imuGyroscopeNoise")) { j.at(
"imuGyroscopeNoise").get_to(
_imuGyroscopeNoise); }
628 if (j.contains(
"imuGyroscopeRng")) { j.at(
"imuGyroscopeRng").get_to(
_imuGyroscopeRng); }
631 if (j.contains(
"imuAccelerometerRW")) { j.at(
"imuAccelerometerRW").get_to(
_imuAccelerometerRW); }
632 if (j.contains(
"imuAccelerometerRWRng")) { j.at(
"imuAccelerometerRWRng").get_to(
_imuAccelerometerRWRng); }
633 if (j.contains(
"imuGyroscopeRWUnit")) { j.at(
"imuGyroscopeRWUnit").get_to(
_imuGyroscopeRWUnit); }
634 if (j.contains(
"imuGyroscopeRW")) { j.at(
"imuGyroscopeRW").get_to(
_imuGyroscopeRW); }
635 if (j.contains(
"imuGyroscopeRWRng")) { j.at(
"imuGyroscopeRWRng").get_to(
_imuGyroscopeRWRng); }
637 if (j.contains(
"imuAccelerometerIRW")) { j.at(
"imuAccelerometerIRW").get_to(
_imuAccelerometerIRW); }
639 if (j.contains(
"imuGyroscopeIRWUnit")) { j.at(
"imuGyroscopeIRWUnit").get_to(
_imuGyroscopeIRWUnit); }
640 if (j.contains(
"imuGyroscopeIRW")) { j.at(
"imuGyroscopeIRW").get_to(
_imuGyroscopeIRW); }
641 if (j.contains(
"imuGyroscopeIRWRng")) { j.at(
"imuGyroscopeIRWRng").get_to(
_imuGyroscopeIRWRng); }
643 if (j.contains(
"positionBiasUnit")) { j.at(
"positionBiasUnit").get_to(
_positionBiasUnit); }
644 if (j.contains(
"positionBias")) { j.at(
"positionBias").get_to(
_positionBias); }
645 if (j.contains(
"velocityBiasUnit")) { j.at(
"velocityBiasUnit").get_to(
_velocityBiasUnit); }
646 if (j.contains(
"velocityBias")) { j.at(
"velocityBias").get_to(
_velocityBias); }
647 if (j.contains(
"attitudeBiasUnit")) { j.at(
"attitudeBiasUnit").get_to(
_attitudeBiasUnit); }
648 if (j.contains(
"attitudeBias")) { j.at(
"attitudeBias").get_to(
_attitudeBias); }
649 if (j.contains(
"positionNoiseUnit")) { j.at(
"positionNoiseUnit").get_to(
_positionNoiseUnit); }
650 if (j.contains(
"positionNoise")) { j.at(
"positionNoise").get_to(
_positionNoise); }
651 if (j.contains(
"positionRng")) { j.at(
"positionRng").get_to(
_positionRng); }
652 if (j.contains(
"velocityNoiseUnit")) { j.at(
"velocityNoiseUnit").get_to(
_velocityNoiseUnit); }
653 if (j.contains(
"velocityNoise")) { j.at(
"velocityNoise").get_to(
_velocityNoise); }
654 if (j.contains(
"velocityRng")) { j.at(
"velocityRng").get_to(
_velocityRng); }
655 if (j.contains(
"attitudeNoiseUnit")) { j.at(
"attitudeNoiseUnit").get_to(
_attitudeNoiseUnit); }
656 if (j.contains(
"attitudeNoise")) { j.at(
"attitudeNoise").get_to(
_attitudeNoise); }
657 if (j.contains(
"attitudeRng")) { j.at(
"attitudeRng").get_to(
_attitudeRng); }
661 if (j.contains(
"pseudorangeRng")) { j.at(
"pseudorangeRng").get_to(
_pseudorangeRng); }
664 if (j.contains(
"carrierPhaseRng")) { j.at(
"carrierPhaseRng").get_to(
_carrierPhaseRng); }
666 if (j.contains(
"dopplerNoise")) { j.at(
"dopplerNoise").get_to(
_gui_dopplerNoise); }
667 if (j.contains(
"dopplerRng")) { j.at(
"dopplerRng").get_to(
_dopplerRng); }
669 if (j.contains(
"ambiguityRng")) { j.at(
"ambiguityRng").get_to(
_ambiguityRng); }
670 if (j.contains(
"manualAmbiguities")) { j.at(
"manualAmbiguities").get_to(
_manualCycleSlips); }
671 if (j.contains(
"manualCycleSlipTime")) { j.at(
"manualCycleSlipTime").get_to(
_manualCycleSlipTime); }
673 if (j.contains(
"manualCycleSlipSignal")) { j.at(
"manualCycleSlipSignal").get_to(
_manualCycleSlipSignal); }
675 if (j.contains(
"manualCycleSlipSetLLI")) { j.at(
"manualCycleSlipSetLLI").get_to(
_manualCycleSlipSetLLI); }
681 if (j.contains(
"cycleSlipRng")) { j.at(
"cycleSlipRng").get_to(
_cycleSlipRng); }
682 if (j.contains(
"filterFreq"))
685 j.at(
"filterFreq").get_to(value);
688 if (j.contains(
"filterCode")) { j.at(
"filterCode").get_to(
_filterCode); }
740 auto previousOutputPinDataIdentifier =
outputPins.front().dataIdentifier;
744 if (previousOutputPinDataIdentifier !=
outputPins.front().dataIdentifier)
749 if (
auto* endPin = link.getConnectedPin())
751 if (!
outputPins.front().canCreateLink(*endPin))
760 if (
outputPins.front().dataIdentifier != previousOutputPinDataIdentifier)
764 if (
auto* connectedPin = link.getConnectedPin())
766 outputPins.front().recreateLink(*connectedPin);
793 LOG_DATA(
"{}: accelerometerBias_p = {} [m/s^2]",
nameId(), accelerometerBias_p.transpose());
797 LOG_DATA(
"{}: gyroscopeBias_p = {} [rad/s]",
nameId(), gyroscopeBias_p.transpose());
803 LOG_DATA(
"{}: accelerometerNoiseStd = {} [m/s^2/sqrt(s)]",
nameId(), accelerometerNoiseStd.transpose());
807 LOG_DATA(
"{}: gyroscopeNoiseStd = {} [rad/s/sqrt(s)]",
nameId(), gyroscopeNoiseStd.transpose());
813 receiveImuObsWDelta(std::make_shared<ImuObsSimulated>(*std::static_pointer_cast<const ImuObsSimulated>(obs)),
816 accelerometerNoiseStd,
822 receiveImuObsWDelta(std::make_shared<ImuObsWDelta>(*std::static_pointer_cast<const ImuObsWDelta>(obs)),
825 accelerometerNoiseStd,
831 receiveImuObs(std::make_shared<ImuObs>(*std::static_pointer_cast<const ImuObs>(obs)),
834 accelerometerNoiseStd,
858 const Eigen::Vector3d& accelerometerBias_p,
859 const Eigen::Vector3d& gyroscopeBias_p,
860 const Eigen::Vector3d& accelerometerNoiseStd,
861 const Eigen::Vector3d& gyroscopeNoiseStd)
868 LOG_DATA(
"{}: accelerometerRWStd = {} [m/s^2/sqrt(s)]",
nameId(), accelerometerRWStd.transpose());
879 LOG_DATA(
"{}: accelerometerIRWStd = {} [m/s^3/sqrt(s)]",
nameId(), accelerometerIRWStd.transpose());
894 LOG_DATA(
"{}: gyroscopeRWStd = {} [rad/s/sqrt(s)]",
nameId(), gyroscopeRWStd.transpose());
905 LOG_DATA(
"{}: gyroscopeIRWStd = {} [rad/s^2/sqrt(s)]",
nameId(), gyroscopeIRWStd.transpose());
921 imuObs->p_acceleration += accelerometerBias_p
925 imuObs->p_angularRate += gyroscopeBias_p
930 imuObs->p_acceleration += Eigen::Vector3d{
_imuAccelerometerRng.getRand_normalDist(0.0, accelerometerNoiseStd(0)),
934 imuObs->p_angularRate += Eigen::Vector3d{
_imuGyroscopeRng.getRand_normalDist(0.0, gyroscopeNoiseStd(0)),
944 const Eigen::Vector3d& accelerometerBias_p,
945 const Eigen::Vector3d& gyroscopeBias_p,
946 const Eigen::Vector3d& accelerometerNoiseStd,
947 const Eigen::Vector3d& gyroscopeNoiseStd)
949 receiveImuObs(imuObsWDelta, accelerometerBias_p, gyroscopeBias_p, accelerometerNoiseStd, gyroscopeNoiseStd);
951 double imuObsWDeltaAverageWindow =
_dt != 0.0 ?
_dt / imuObsWDelta->dtime : 1.0;
957 imuObsWDelta->dvel += Eigen::Vector3d{
_imuAccelerometerRng.getRand_normalDist(0.0, accelerometerNoiseStd(0) / std::sqrt(imuObsWDeltaAverageWindow)),
958 _imuAccelerometerRng.getRand_normalDist(0.0, accelerometerNoiseStd(1) / std::sqrt(imuObsWDeltaAverageWindow)),
959 _imuAccelerometerRng.getRand_normalDist(0.0, accelerometerNoiseStd(2) / std::sqrt(imuObsWDeltaAverageWindow)) }
960 * imuObsWDelta->dtime / std::sqrt(
_dt);
961 imuObsWDelta->dtheta += Eigen::Vector3d{
_imuGyroscopeRng.getRand_normalDist(0.0, gyroscopeNoiseStd(0) / std::sqrt(imuObsWDeltaAverageWindow)),
962 _imuGyroscopeRng.getRand_normalDist(0.0, gyroscopeNoiseStd(1) / std::sqrt(imuObsWDeltaAverageWindow)),
963 _imuGyroscopeRng.getRand_normalDist(0.0, gyroscopeNoiseStd(2) / std::sqrt(imuObsWDeltaAverageWindow)) }
964 * imuObsWDelta->dtime / std::sqrt(
_dt);
973 Eigen::Vector3d lla_positionBias = Eigen::Vector3d::Zero();
979 if (!e_positionBias.isZero())
986 LOG_DATA(
"{}: lla_positionBias = {} [rad, rad, m]",
nameId(), lla_positionBias.transpose());
989 Eigen::Vector3d n_velocityBias = Eigen::Vector3d::Zero();
996 LOG_DATA(
"{}: n_velocityBias = {} [m/s]",
nameId(), n_velocityBias.transpose());
999 Eigen::Vector3d attitudeBias = Eigen::Vector3d::Zero();
1009 LOG_DATA(
"{}: attitudeBias = {} [rad]",
nameId(), attitudeBias.transpose());
1014 Eigen::Vector3d lla_positionNoiseStd = Eigen::Vector3d::Zero();
1015 Eigen::Vector3d NED_pos_variance = Eigen::Vector3d::Zero();
1021 if (!e_positionNoiseStd.isZero())
1023 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(pos->e_position() + e_positionNoiseStd) - pos->lla_position();
1031 if (!e_positionNoiseStd.isZero())
1033 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(pos->e_position() + e_positionNoiseStd) - pos->lla_position();
1039 LOG_DATA(
"{}: lla_positionNoiseStd = {} [rad, rad, m]",
nameId(), lla_positionNoiseStd.transpose());
1043 pos->setPositionAndCov_n(pos->lla_position()
1045 + Eigen::Vector3d{ _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(0)),
1046 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(1)),
1047 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(2)) },
1048 NED_pos_variance.asDiagonal().toDenseMatrix());
1056 Eigen::Vector3d lla_positionBias = Eigen::Vector3d::Zero();
1062 if (!e_positionBias.isZero())
1064 lla_positionBias =
trafo::ecef2lla_WGS84(posVel->e_position() + e_positionBias) - posVel->lla_position();
1069 LOG_DATA(
"{}: lla_positionBias = {} [rad, rad, m]",
nameId(), lla_positionBias.transpose());
1072 Eigen::Vector3d n_velocityBias = Eigen::Vector3d::Zero();
1079 LOG_DATA(
"{}: n_velocityBias = {} [m/s]",
nameId(), n_velocityBias.transpose());
1084 Eigen::Vector3d lla_positionNoiseStd = Eigen::Vector3d::Zero();
1085 Eigen::Vector3d NED_pos_variance = Eigen::Vector3d::Zero();
1086 Eigen::Vector3d NED_velocity_variance = Eigen::Vector3d::Zero();
1092 if (!e_positionNoiseStd.isZero())
1094 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(posVel->e_position() + e_positionNoiseStd) - posVel->lla_position();
1102 if (!e_positionNoiseStd.isZero())
1104 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(posVel->e_position() + e_positionNoiseStd) - posVel->lla_position();
1110 LOG_DATA(
"{}: lla_positionNoiseStd = {} [rad, rad, m]",
nameId(), lla_positionNoiseStd.transpose());
1113 Eigen::Vector3d n_velocityNoiseStd = Eigen::Vector3d::Zero();
1125 LOG_DATA(
"{}: n_velocityNoiseStd = {} [m/s]",
nameId(), n_velocityNoiseStd.transpose());
1129 Eigen::Matrix<double, 6, 6> cov_n = Eigen::Matrix<double, 6, 6>::Zero();
1130 cov_n.block<3, 3>(0, 0).diagonal() = NED_pos_variance;
1131 cov_n.block<3, 3>(3, 3).diagonal() = NED_velocity_variance;
1133 posVel->setPosVelAndCov_n(posVel->lla_position()
1135 + Eigen::Vector3d{ _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(0)),
1136 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(1)),
1137 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(2)) },
1138 posVel->n_velocity()
1140 + Eigen::Vector3d{ _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(0)),
1141 _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(1)),
1142 _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(2)) },
1151 Eigen::Vector3d lla_positionBias = Eigen::Vector3d::Zero();
1157 if (!e_positionBias.isZero())
1159 lla_positionBias =
trafo::ecef2lla_WGS84(posVelAtt->e_position() + e_positionBias) - posVelAtt->lla_position();
1164 LOG_DATA(
"{}: lla_positionBias = {} [rad, rad, m]",
nameId(), lla_positionBias.transpose());
1167 Eigen::Vector3d n_velocityBias = Eigen::Vector3d::Zero();
1174 LOG_DATA(
"{}: n_velocityBias = {} [m/s]",
nameId(), n_velocityBias.transpose());
1177 Eigen::Vector3d attitudeBias = Eigen::Vector3d::Zero();
1187 LOG_DATA(
"{}: attitudeBias = {} [rad]",
nameId(), attitudeBias.transpose());
1192 Eigen::Vector3d lla_positionNoiseStd = Eigen::Vector3d::Zero();
1193 Eigen::Vector3d NED_pos_variance = Eigen::Vector3d::Zero();
1194 Eigen::Vector3d NED_velocity_variance = Eigen::Vector3d::Zero();
1195 Eigen::Vector3d RPY_attitude_variance = Eigen::Vector3d::Zero();
1201 if (!e_positionNoiseStd.isZero())
1203 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(posVelAtt->e_position() + e_positionNoiseStd) - posVelAtt->lla_position();
1211 if (!e_positionNoiseStd.isZero())
1213 lla_positionNoiseStd =
trafo::ecef2lla_WGS84(posVelAtt->e_position() + e_positionNoiseStd) - posVelAtt->lla_position();
1219 LOG_DATA(
"{}: lla_positionNoiseStd = {} [rad, rad, m]",
nameId(), lla_positionNoiseStd.transpose());
1222 Eigen::Vector3d n_velocityNoiseStd = Eigen::Vector3d::Zero();
1234 LOG_DATA(
"{}: n_velocityNoiseStd = {} [m/s]",
nameId(), n_velocityNoiseStd.transpose());
1237 Eigen::Vector3d attitudeNoiseStd = Eigen::Vector3d::Zero();
1257 LOG_DATA(
"{}: attitudeNoiseStd = {} [rad]",
nameId(), attitudeNoiseStd.transpose());
1261 Eigen::Matrix<double, 9, 9> cov_n = Eigen::Matrix<double, 9, 9>::Zero();
1262 cov_n.block<3, 3>(0, 0).diagonal() = NED_pos_variance;
1263 cov_n.block<3, 3>(3, 3).diagonal() = NED_velocity_variance;
1264 cov_n.block<3, 3>(6, 6).diagonal() = RPY_attitude_variance;
1266 Eigen::Matrix<double, 10, 9> J = Eigen::Matrix<double, 10, 9>::Zero();
1267 J.topLeftCorner<6, 6>().setIdentity();
1270 posVelAtt->setPosVelAttAndCov_n(posVelAtt->lla_position()
1272 + Eigen::Vector3d{ _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(0)),
1273 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(1)),
1274 _positionRng.getRand_normalDist(0.0, lla_positionNoiseStd(2)) },
1275 posVelAtt->n_velocity()
1277 + Eigen::Vector3d{ _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(0)),
1278 _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(1)),
1279 _velocityRng.getRand_normalDist(0.0, n_velocityNoiseStd(2)) },
1282 + Eigen::Vector3d{ _attitudeRng.getRand_normalDist(0.0, attitudeNoiseStd(0)),
1283 _attitudeRng.getRand_normalDist(0.0, attitudeNoiseStd(1)),
1284 _attitudeRng.getRand_normalDist(0.0, attitudeNoiseStd(2)) }),
1285 J * cov_n * J.transpose());
1292 LOG_DATA(
"{}: [{}] Simulating error on GnssObs",
nameId(), gnssObs->insTime.toYMDHMS(
GPST));
1293 double pseudorangeNoise{};
1300 double carrierPhaseNoise{};
1307 double dopplerNoise{};
1315 double dtCycleSlipSeconds{};
1328 auto dtCycleSlip = std::chrono::nanoseconds(
static_cast<int64_t
>(dtCycleSlipSeconds * 1e9));
1330 double cycleSlipDetectionProbability{};
1346 for (
auto& obs : gnssObs->data)
1355 for (
auto& obs : gnssObs->data)
1357 if (obs.pseudorange) { obs.pseudorange.value().value +=
_pseudorangeRng.getRand_normalDist(0.0, pseudorangeNoise); }
1358 if (obs.doppler) { obs.doppler.value() +=
rangeRate2doppler(
_dopplerRng.getRand_normalDist(0.0, dopplerNoise), obs.satSigId.freq(), 0); }
1360 if (obs.carrierPhase)
1363 auto lambda =
InsConst::C / obs.satSigId.freq().getFrequency(0);
1364 obs.carrierPhase.value().value +=
_carrierPhaseRng.getRand_normalDist(0.0, carrierPhaseNoise) / lambda;
1368 bool manualCycleSlip =
false;
1371 const auto& [insTime, satSigId] = cycleSlip.first;
1372 if (std::abs((insTime - gnssObs->insTime).count()) < 1e-4 && obs.satSigId == satSigId)
1374 manualCycleSlip =
true;
1376 const auto& [ambValue, setLLI] = cycleSlip.second;
1377 _ambiguities[obs.satSigId].emplace_back(gnssObs->insTime, ambValue);
1378 obs.carrierPhase.value().LLI =
static_cast<uint8_t
>(setLLI);
1379 _cycleSlips.push_back(
CycleSlipInfo{ .time = gnssObs->insTime, .satSigId = obs.satSigId, .LLI = obs.carrierPhase.value().LLI != 0 });
1381 LOG_DEBUG(
"{}: [{}] Applied manual cycle-slip for satellite [{}] with LLI {}",
nameId(), gnssObs->insTime.toYMDHMS(
GPST),
1382 obs.satSigId, obs.carrierPhase.value().LLI);
1386 if (!manualCycleSlip
1393 double probabilityCycleSlip =
_dt / (dtCycleSlipSeconds *
static_cast<double>(nObs)) * 2.0;
1394 if (
_cycleSlipRng.getRand_uniformRealDist(0.0, 1.0) <= probabilityCycleSlip
1395 || (gnssObs->insTime >=
_cycleSlipWindowStartTime + dtCycleSlip - std::chrono::nanoseconds(
static_cast<int64_t
>((
_dt + 0.001) * 1e9))))
1397 int newAmbiguity = 0;
1402 auto signAmbiguity =
_cycleSlipRng.getRand_uniformIntDist(0, 1) == 0.0 ? 1 : -1;
1406 newAmbiguity = oldAmbiguity + signAmbiguity * deltaAmbiguity;
1421 _ambiguities[obs.satSigId].emplace_back(gnssObs->insTime, newAmbiguity);
1423 if (
_cycleSlipRng.getRand_uniformRealDist(0.0, 1.0) <= cycleSlipDetectionProbability)
1425 obs.carrierPhase.value().LLI = 1;
1427 _cycleSlips.push_back(
CycleSlipInfo{ .time = gnssObs->insTime, .satSigId = obs.satSigId, .LLI = obs.carrierPhase.value().LLI != 0 });
1428 LOG_DEBUG(
"{}: [{}] Simulating cycle-slip for satellite [{}] with LLI {}",
nameId(), gnssObs->insTime.toYMDHMS(
GPST),
1429 obs.satSigId, obs.carrierPhase.value().LLI);
1440 obs.carrierPhase.value().value +=
_ambiguities.at(obs.satSigId).back().second;
Transformation collection.
Adds errors (biases and noise) to measurements.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
Data storage class for simulated IMU observations.
Data storage class for one VectorNavImu observation.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Utility class which specifies available nodes.
Structs identifying a unique satellite.
Utility functions for working with std::strings.
Frequency _filterFreq
Frequencies used for calculation (GUI filter)
std::shared_ptr< PosVel > receivePosVel(const std::shared_ptr< PosVel > &posVel)
Callback when receiving an PosVelObs.
RandomNumberGenerator _imuAccelerometerRng
Random number generator for the accelerometer noise.
SatSigId _manualCycleSlipSignal
GUI input for new manual cycle-slips.
int _gui_cycleSlipRange
Ambiguity limits cycle-slip.
RandomNumberGenerator _carrierPhaseRng
Random number generator for the carrier-phase noise.
Units::ImuAccelerometerUnits _imuAccelerometerBiasUnit
Selected unit for the accelerometer bias in the GUI.
std::shared_ptr< ImuObs > receiveImuObs(const std::shared_ptr< ImuObs > &imuObs, const Eigen::Vector3d &accelerometerBias_p, const Eigen::Vector3d &gyroscopeBias_p, const Eigen::Vector3d &accelerometerNoiseStd, const Eigen::Vector3d &gyroscopeNoiseStd)
Callback when receiving an ImuObs.
VelocityBiasUnits _velocityBiasUnit
Selected unit for the velocity bias in the GUI.
bool _manualCycleSlipSetLLI
GUI input for new manual cycle-slips.
std::array< int, 2 > _gui_ambiguityLimits
Ambiguity limits.
CarrierPhaseNoiseUnits _gui_carrierPhaseNoiseUnit
Selected unit for the carrier-phase noise in the GUI.
RandomNumberGenerator _imuGyroscopeRng
Random number generator for the gyroscope noise.
RandomNumberGenerator _imuAccelerometerIRWRng
Random number generator for the accelerometer IRW noise.
Units::ImuGyroscopeIRWUnits _imuGyroscopeIRWUnit
Selected unit for the accelerometer IRW noise in the GUI.
RandomNumberGenerator _imuGyroscopeRWRng
Random number generator for the accelerometer RW noise.
RandomNumberGenerator _imuAccelerometerRWRng
Random number generator for the accelerometer RW noise.
~ErrorModel() override
Destructor.
PositionNoiseUnits _positionNoiseUnit
Selected unit for the position noise in the GUI.
Eigen::Vector3d _positionNoise
Noise of the position (Unit as selected)
Units::ImuGyroscopeUnits _imuGyroscopeBiasUnit
Selected unit for the gyroscope bias in the GUI.
static std::string typeStatic()
String representation of the Class Type.
Eigen::Vector3d _imuAccelerometerNoise
Noise of the accelerometer (Unit as selected)
static constexpr size_t OUTPUT_PORT_INDEX_FLOW
Flow.
VelocityNoiseUnits _velocityNoiseUnit
Selected unit for the velocity noise in the GUI.
void restore(const json &j) override
Restores the node from a json object.
void afterDeleteLink(OutputPin &startPin, InputPin &endPin) override
Called when a link was deleted.
Eigen::Vector3d _integratedRandomWalkGyroscope
3D array which allow to accumulate IRW for gyro
Units::ImuAccelerometerNoiseUnits _imuAccelerometerNoiseUnit
Selected unit for the accelerometer noise in the GUI.
std::shared_ptr< GnssObs > receiveGnssObs(const std::shared_ptr< GnssObs > &gnssObs)
Callback when receiving an GnssObs.
RandomNumberGenerator _attitudeRng
Random number generator for the attitude noise.
AttitudeBiasUnits _attitudeBiasUnit
Selected unit for the attitude bias in the GUI.
@ rad
[rad] (Standard deviation)
@ deg
[deg] (Standard deviation)
json save() const override
Saves the node into a json object.
std::string type() const override
String representation of the Class Type.
RandomNumberGenerator _imuGyroscopeIRWRng
Random number generator for the accelerometer RW noise.
Eigen::Vector3d _velocityBias
Bias of the velocity (Unit as selected)
InsTime _lastObservationTime
Last observation time.
RandomNumberGenerator _cycleSlipRng
Random number generator for the cycle-slip.
double _gui_cycleSlipDetectionProbability
The chance to detect a cycle slip and set the Loss-of-Lock indicator.
Eigen::Vector3d _integratedRandomWalkGyroscope_velocity
3D array which allow to accumulate IRW veloctiy noise for gyro
CycleSlipDetectionProbabilityUnits _gui_cycleSlipDetectionProbabilityUnit
Selected unit for the cycle-slip detection probability in the GUI.
Eigen::Vector3d _velocityNoise
Noise of the velocity (Unit as selected)
InsTime _manualCycleSlipTime
GUI input for new manual cycle-slips.
std::shared_ptr< Pos > receivePos(const std::shared_ptr< Pos > &pos)
Callback when receiving an PosObs.
CycleSlipFrequencyUnits _gui_cycleSlipFrequencyUnit
Selected unit for the cycle-slip frequency in the GUI.
Eigen::Vector3d _imuAccelerometerRW
RW noise of the accelerometer (Unit as selected)
double _gui_pseudorangeNoise
Noise of the pseudorange (Unit as selected)
double _gui_carrierPhaseNoise
Noise of the carrier-phase (Unit as selected)
double _dt
Time interval of the messages [s].
RandomNumberGenerator _pseudorangeRng
Random number generator for the pseudorange noise.
Eigen::Vector3d _integratedRandomWalkAccelerometer
3D array which allow to accumulate IRW for accelerometer
std::shared_ptr< PosVelAtt > receivePosVelAtt(const std::shared_ptr< PosVelAtt > &posVelAtt)
Callback when receiving an PosVelAttObs.
Units::ImuGyroscopeNoiseUnits _imuGyroscopeRWUnit
Selected unit for the accelerometer RW noise in the GUI.
@ meter2
NED [m^2 m^2 m^2] (Variance)
@ meter
NED [m m m] (Standard deviation)
DopplerNoiseUnits _gui_dopplerNoiseUnit
Selected unit for the range-rate noise in the GUI.
RandomNumberGenerator _ambiguityRng
Random number generator for the ambiguity.
@ m_s
[m/s] (Standard deviation)
Eigen::Vector3d _imuAccelerometerBias_p
Bias of the accelerometer in platform coordinates (Unit as selected)
std::map< std::pair< InsTime, SatSigId >, std::pair< int, bool > > _manualCycleSlips
Cycle-slips set by the user.
RandomNumberGenerator _positionRng
Random number generator for the position noise.
Eigen::Vector3d _imuGyroscopeBias_p
Bias of the gyroscope in platform coordinates (Unit as selected)
Code _filterCode
Codes used for calculation (GUI filter)
double _gui_dopplerNoise
Noise of the range-rate (Unit as selected)
void receiveObs(InputPin::NodeDataQueue &queue, size_t pinIdx)
Callback when receiving data on a port.
Units::ImuAccelerometerNoiseUnits _imuAccelerometerRWUnit
Selected unit for the accelerometer RW noise in the GUI.
Eigen::Vector3d _imuGyroscopeNoise
Noise of the gyroscope (Unit as selected)
static std::string category()
String representation of the Class Category.
Eigen::Vector3d _positionBias
Bias of the position (Unit as selected)
void afterCreateLink(OutputPin &startPin, InputPin &endPin) override
Called when a new link was established.
gui::widgets::TimeEditFormat _manualCycleSlipTimeEditFormat
GUI input for new manual cycle-slips.
@ meter
[m] (Standard deviation)
Eigen::Vector3d _imuGyroscopeIRW
RW noise of the accelerometer (Unit as selected)
@ meter
[m] (Standard deviation)
Units::ImuAccelerometerIRWUnits _imuAccelerometerIRWUnit
Selected unit for the accelerometer IRW noise in the GUI.
Eigen::Vector3d _randomWalkGyroscope
3D array which allow to accumulate RW noise for gyro
Eigen::Vector3d _attitudeBias
Bias of the attitude (Unit as selected)
void guiConfig() override
ImGui config window which is shown on double click.
Eigen::Vector3d _imuAccelerometerIRW
IRW noise of the accelerometer (Unit as selected)
PositionBiasUnits _positionBiasUnit
Selected unit for the position bias in the GUI.
Eigen::Vector3d _imuGyroscopeRW
RW noise of the accelerometer (Unit as selected)
AttitudeNoiseUnits _attitudeNoiseUnit
Selected unit for the attitude noise in the GUI.
ErrorModel()
Default constructor.
Eigen::Vector3d _randomWalkAccelerometer
3D array which allow to accumulate RW noise for accelerometer
@ m_s
[m/s] (Standard deviation)
@ m2_s2
[m^2/s^2] (Variance)
Eigen::Vector3d _integratedRandomWalkAccelerometer_velocity
3D array which allow to accumulate IRW veloctiy noise for accelerometer
InsTime _cycleSlipWindowStartTime
The time frame which is considered for a cycle slip.
double _gui_cycleSlipFrequency
The cycle-slip frequency (Unit as selected)
std::shared_ptr< ImuObsWDelta > receiveImuObsWDelta(const std::shared_ptr< ImuObsWDelta > &imuObs, const Eigen::Vector3d &accelerometerBias_p, const Eigen::Vector3d &gyroscopeBias_p, const Eigen::Vector3d &accelerometerNoiseStd, const Eigen::Vector3d &gyroscopeNoiseStd)
Callback when receiving an ImuObsWDelta.
RandomNumberGenerator _velocityRng
Random number generator for the velocity noise.
std::vector< CycleSlipInfo > _cycleSlips
List of produced cycle-slips.
RandomNumberGenerator _dopplerRng
Random number generator for the range-rate noise.
Units::ImuGyroscopeNoiseUnits _imuGyroscopeNoiseUnit
Selected unit for the gyroscope noise in the GUI.
Eigen::Vector3d _attitudeNoise
Noise of the attitude (Unit as selected)
std::map< SatSigId, std::vector< std::pair< InsTime, int > > > _ambiguities
Ambiguity map.
int _manualCycleSlipAmbiguity
GUI input for new manual cycle-slips.
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
PseudorangeNoiseUnits _gui_pseudorangeNoiseUnit
Selected unit for the pseudorange noise in the GUI.
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
static constexpr double C
Speed of light [m/s].
ImVec2 _guiConfigDefaultWindowSize
std::vector< OutputPin > outputPins
List of output pins.
Node(std::string name)
Constructor.
std::vector< InputPin > inputPins
List of input pins.
OutputPin * CreateOutputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
std::string nameId() const
Node name and id.
std::string name
Name of the Node.
InputPin * CreateInputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier={}, InputPin::Callback callback=static_cast< InputPin::FlowFirableCallbackFunc >(nullptr), InputPin::FlowFirableCheckFunc firable=nullptr, int priority=0, int idx=-1)
Create an Input Pin object.
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
ax::NodeEditor::NodeId id
Unique Id of the Node.
bool _hasConfig
Flag if the config window should be shown.
Node * parentNode
Reference to the parent node.
ax::NodeEditor::PinId id
Unique Id of the Pin.
std::vector< std::string > dataIdentifier
One or multiple Data Identifiers (Unique name which is used for data flows)
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
Manages a thread which calls a specified function at a specified interval.
auto extract_front()
Returns a copy of the first element in the container and removes it from the container.
static float windowFontRatio()
Ratio to multiply for GUI window elements.
static float monoFontRatio()
Ratio to multiply for log output GUI elements.
bool InputIntL(const char *label, int *v, int v_min, int v_max, int step, int step_fast, ImGuiInputTextFlags flags)
Shows a value limited InputText GUI element for 'int'.
bool SliderULong(const char *label, uint64_t *v, uint64_t v_min, uint64_t v_max, const char *format, ImGuiSliderFlags flags)
Shows a Slider GUI element for 'uint64'.
constexpr int32_t SECONDS_PER_DAY
Seconds / Day.
constexpr int32_t SECONDS_PER_HOUR
Seconds / Hour.
constexpr int32_t SECONDS_PER_MINUTE
Seconds / Minute.
bool NodeDataTypeAnyIsChildOf(const std::vector< std::string > &childTypes, const std::vector< std::string > &parentTypes)
Checks if any of the provided child types is a child of any of the provided parent types.
void ApplyChanges()
Signals that there have been changes to the flow.
static std::string replaceAll_copy(std::string str, const std::string &from, const std::string &to, CaseSensitivity cs)
Replaces all occurrence of a search pattern with another sequence.
Eigen::Vector3< typename Derived::Scalar > ecef2lla_WGS84(const Eigen::MatrixBase< Derived > &e_position)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude using WGS84.
Eigen::Quaternion< Scalar > e_Quat_n(const Scalar &latitude, const Scalar &longitude)
Quaternion for rotations from navigation to Earth-fixed frame.
Eigen::Matrix< typename Derived::Scalar, 4, 3 > covRPY2quatJacobian(const Eigen::QuaternionBase< Derived > &n_quat_b)
Calculates the Jacobian to convert an attitude represented in Euler angels (roll, pitch,...
Eigen::Quaternion< Scalar > n_Quat_b(Scalar roll, Scalar pitch, Scalar yaw)
Quaternion for rotations from body to navigation frame.
constexpr Frequency_ Freq_All
All Frequencies.
Frequency_
Enumerate for GNSS frequencies.
bool ShowFrequencySelector(const char *label, Frequency &frequency, bool singleSelect)
Shows a ComboBox to select GNSS frequencies.
bool ShowCodeSelector(const char *label, Code &code, const Frequency &filterFreq, bool singleSelect)
Shows a ComboBox to select signal codes.
double convertUnit(const double &value, Units::PositionUncertaintyUnits unit)
Converts the value depending on the unit provided.
constexpr auto deg2rad(const T °)
Convert Degree to Radians.
std::string MakeComboItems()
Units separated by '\0' and terminated by double '\0'.
const std::vector< std::string > supportedDataIdentifier
List of supported data identifiers.
bool ShowSatelliteSelector(const char *label, std::vector< SatId > &satellites, SatelliteSystem filterSys, bool displayOnlyNumber)
Shows a ComboBox to select satellites.
double rangeRate2doppler(double rangeRate, Frequency freq, int8_t num)
Transforms a range-rate into a doppler-shift.
InsTime time
Time of the cycle-slip.
SatSigId satSigId
Satellite Signal identifier.
Identifies a satellite (satellite system and number)
SatelliteSystem satSys
Satellite system (GPS, GLONASS, GALILEO, QZSS, BDS, IRNSS, SBAS)
uint16_t satNum
Number of the satellite.