24#include <Eigen/src/Geometry/AngleAxis.h>
25#include <Eigen/src/Geometry/Quaternion.h>
53 return "ImuSimulator";
63 return "Data Simulator";
83 std::time_t t = std::time(
nullptr);
84 std::tm* now = std::localtime(&t);
86 ImGui::Text(
"%d-%02d-%02d %02d:%02d:%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
91 if (ImGui::RadioButton(fmt::format(
"Custom Time##{}",
size_t(
id)).c_str(), &startTimeSource,
static_cast<int>(
StartTimeSource::CustomTime)))
110 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
111 if (ImGui::TreeNode(
"Output data-rate"))
113 ImGui::SetNextItemWidth(columnWidth);
121 ImGui::SetNextItemWidth(columnWidth);
127 ImGui::SetNextItemWidth(columnWidth);
128 if (ImGui::InputDouble(fmt::format(
"Trajectory output rate##{}",
size_t(
id)).c_str(), &
_gnssFrequency, 0.0, 0.0,
"%.3f Hz"))
137 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
138 if (ImGui::TreeNode(
"Scenario"))
140 ImGui::SetNextItemWidth(columnWidth);
166 ImGui::SetItemDefaultFocus();
173 auto TextColoredIfExists = [
this](
int index,
const char* text,
const char*
type) {
174 ImGui::TableSetColumnIndex(index);
175 auto displayTable = [&]() {
177 csvData && std::ranges::find(csvData->v->description, text) != csvData->v->description.end())
179 ImGui::TextUnformatted(text);
180 ImGui::TableNextColumn();
181 ImGui::TextUnformatted(
type);
185 ImGui::TextDisabled(
"%s", text);
186 ImGui::TableNextColumn();
187 ImGui::TextDisabled(
"%s",
type);
193 if (ImGui::TreeNode(fmt::format(
"Format description##{}",
size_t(
id)).c_str()))
195 ImGui::TextUnformatted(
"Time information:");
198 if (ImGui::BeginTable(fmt::format(
"##Time ({})",
size_t(
id)).c_str(), 5,
199 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
201 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
202 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
203 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
204 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
205 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
206 ImGui::TableHeadersRow();
208 ImGui::TableNextRow();
209 TextColoredIfExists(0,
"GpsCycle",
"uint");
210 TextColoredIfExists(3,
"YearUTC",
"uint");
211 ImGui::TableNextRow();
212 TextColoredIfExists(0,
"GpsWeek",
"uint");
213 TextColoredIfExists(3,
"MonthUTC",
"uint");
214 ImGui::TableNextRow();
215 TextColoredIfExists(0,
"GpsToW [s]",
"uint");
216 TextColoredIfExists(3,
"DayUTC",
"uint");
217 ImGui::TableNextRow();
218 TextColoredIfExists(3,
"HourUTC",
"uint");
219 ImGui::TableNextRow();
220 TextColoredIfExists(3,
"MinUTC",
"uint");
221 ImGui::TableNextRow();
222 TextColoredIfExists(3,
"SecUTC",
"double");
227 ImGui::TextUnformatted(
"Position information:");
229 gui::widgets::HelpMarker(
"You can either provide the position in ECEF coordinates\nor in latitude, longitude and altitude.");
230 if (ImGui::BeginTable(fmt::format(
"##Position ({})",
size_t(
id)).c_str(), 5,
231 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
233 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
234 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
235 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
236 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
237 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
238 ImGui::TableHeadersRow();
240 ImGui::TableNextRow();
241 TextColoredIfExists(0,
"X-ECEF [m]",
"double");
242 TextColoredIfExists(3,
"Latitude [deg]",
"double");
243 ImGui::TableNextRow();
244 TextColoredIfExists(0,
"Y-ECEF [m]",
"double");
245 TextColoredIfExists(3,
"Longitude [deg]",
"double");
246 ImGui::TableNextRow();
247 TextColoredIfExists(0,
"Z-ECEF [m]",
"double");
248 TextColoredIfExists(3,
"Altitude [m]",
"double");
253 ImGui::TextUnformatted(
"Attitude information:");
256 if (ImGui::BeginTable(fmt::format(
"##Attitude ({})",
size_t(
id)).c_str(), 5,
257 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
259 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
260 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
261 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
262 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
263 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
264 ImGui::TableHeadersRow();
266 ImGui::TableNextRow();
267 TextColoredIfExists(0,
"Roll [deg]",
"double");
268 TextColoredIfExists(3,
"n_Quat_b w",
"double");
269 ImGui::TableNextRow();
270 TextColoredIfExists(0,
"Pitch [deg]",
"double");
271 TextColoredIfExists(3,
"n_Quat_b x",
"double");
272 ImGui::TableNextRow();
273 TextColoredIfExists(0,
"Yaw [deg]",
"double");
274 TextColoredIfExists(3,
"n_Quat_b y",
"double");
275 ImGui::TableNextRow();
276 TextColoredIfExists(3,
"n_Quat_b z",
"double");
293 ?
"Center/Tangential position"
305 ImGui::SetNextItemWidth(columnWidth);
315 ImGui::SetNextItemWidth(columnWidth);
325 ImGui::SetNextItemWidth(columnWidth);
335 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
336 ImGui::TextUnformatted(
"Orientation (Roll, Pitch, Yaw)");
340 ImGui::SetNextItemWidth(columnWidth);
348 ImGui::SetNextItemWidth(columnWidth);
356 ImGui::SetNextItemWidth(columnWidth);
364 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
365 ImGui::TextUnformatted(
"Velocity (North, East, Down)");
369 if (ImGui::BeginTable(fmt::format(
"CircularOrRoseTrajectory##{}",
size_t(
id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX))
371 ImGui::TableNextColumn();
372 ImGui::SetNextItemWidth(columnWidth);
380 ImGui::TableNextColumn();
381 ImGui::SetNextItemWidth(columnWidth);
382 if (ImGui::InputDouble(fmt::format(
"Horizontal speed##{}",
size_t(
id)).c_str(), &
_trajectoryHorizontalSpeed, 0.0, 0.0,
"%.3f m/s"))
389 ImGui::TableNextColumn();
390 ImGui::SetNextItemWidth(columnWidth);
400 ImGui::TableNextColumn();
401 ImGui::SetNextItemWidth(columnWidth);
402 if (ImGui::InputDouble(fmt::format(
"Vertical speed (Up)##{}",
size_t(
id)).c_str(), &
_trajectoryVerticalSpeed, 0.0, 0.0,
"%.3f m/s"))
409 ImGui::TableNextColumn();
410 auto tableStartX = ImGui::GetCursorPosX();
427 ImGui::SetItemDefaultFocus();
432 ImGui::SetCursorPosX(tableStartX + columnWidth * 2.0F + ImGui::GetStyle().ItemSpacing.x * 1.0F);
434 ImGui::TableNextColumn();
438 ImGui::TableNextColumn();
439 ImGui::SetNextItemWidth(columnWidth);
440 if (ImGui::DragInt(fmt::format(
"Osc Frequency##{}",
size_t(
id)).c_str(), &
_circularHarmonicFrequency, 1.0F, 0, 100,
"%d [cycles/rev]"))
448 "The frequency is in units [cycles per revolution].");
450 ImGui::TableNextColumn();
451 ImGui::SetNextItemWidth(columnWidth);
460 "This factor determines the amplitude of the oscillation\n"
461 "with respect to the radius of the circle.");
465 ImGui::TableNextColumn();
466 ImGui::SetNextItemWidth(columnWidth);
467 if (
ImGui::InputIntL(fmt::format(
"n (angular freq.)##{}",
size_t(
id)).c_str(), &
_rosePetNum, 1.0, std::numeric_limits<int>::max(), 1, 1))
474 ImGui::TableNextColumn();
475 ImGui::SetNextItemWidth(columnWidth);
485 ImGui::TextUnformatted(
"Angular frequency k=n/d, n,d = natural numbers. In case of d=1,\n"
486 "for even k number of petals is 2*k, for odd k, number of petals is k.\n"
487 "Adjusts the integration limits of the incomplete elliptical integral\n"
488 "of the second kind. If k is rational (d >1), the correct limit needs \n"
489 "to be choosen depending on the symmetry (petals) of the figure.");
490 float width = 500.0F;
492 ImGui::TextUnformatted(
"Graphic by Jason Davies, CC BY-SA 3.0,\nhttps://commons.wikimedia.org/w/index.php?curid=30515231");
504 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
510 if (ImGui::RadioButton(fmt::format(
"##simulationStopConditionDuration{}",
size_t(
id)).c_str(), &simulationStopCondition,
static_cast<int>(
StopCondition::Duration)))
520 ImGui::SetNextItemWidth(columnWidth);
529 if (ImGui::RadioButton(fmt::format(
"##simulationStopConditionDistanceOrCirclesOrRoses{}",
size_t(
id)).c_str(), &simulationStopCondition,
static_cast<int>(
StopCondition::DistanceOrCirclesOrRoses)))
541 ImGui::SetNextItemWidth(columnWidth);
551 ImGui::SetNextItemWidth(columnWidth);
561 ImGui::SetNextItemWidth(columnWidth);
572 ImGui::SetNextItemOpen(
false, ImGuiCond_FirstUseEver);
573 if (ImGui::TreeNode(
"Simulation models"))
577 ImGui::TextUnformatted(fmt::format(
"Spline (current knots {})",
_splines.x.size()).c_str());
580 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
581 if (
ImGui::InputDoubleL(fmt::format(
"Sample Interval##{}",
size_t(
id)).c_str(), &
_splines.sampleInterval, 0.0, std::numeric_limits<double>::max(), 0.0, 0.0,
"%.3e s"))
592 ImGui::TextUnformatted(fmt::format(
"Spline (current knots {})",
_splines.x.size()).c_str());
595 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
605 ImGui::TextUnformatted(
"Measured acceleration");
608 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
627 ImGui::TextUnformatted(
"Measured angular rates");
683 j[
"splineSampleInterval"] =
_splines.sampleInterval;
700 if (j.contains(
"startTimeSource"))
704 if (j.contains(
"startTimeEditFormat"))
708 if (j.contains(
"startTime"))
713 if (j.contains(
"imuInternalFrequency"))
717 if (j.contains(
"imuFrequency"))
721 if (j.contains(
"gnssFrequency"))
726 if (j.contains(
"trajectoryType"))
739 if (j.contains(
"startPosition"))
743 if (j.contains(
"fixedTrajectoryStartOrientation"))
747 if (j.contains(
"n_linearTrajectoryStartVelocity"))
751 if (j.contains(
"circularHarmonicFrequency"))
755 if (j.contains(
"circularHarmonicAmplitudeFactor"))
759 if (j.contains(
"trajectoryHorizontalSpeed"))
763 if (j.contains(
"trajectoryVerticalSpeed"))
767 if (j.contains(
"trajectoryRadius"))
771 if (j.contains(
"trajectoryRotationAngle"))
775 if (j.contains(
"trajectoryDirection"))
779 if (j.contains(
"rosePetNum"))
783 if (j.contains(
"rosePetDenom"))
788 if (j.contains(
"simulationStopCondition"))
792 if (j.contains(
"simulationDuration"))
796 if (j.contains(
"linearTrajectoryDistanceForStop"))
800 if (j.contains(
"circularTrajectoryCircleCountForStop"))
804 if (j.contains(
"roseTrajectoryCountForStop"))
809 if (j.contains(
"splineSampleInterval"))
811 j.at(
"splineSampleInterval").get_to(
_splines.sampleInterval);
813 if (j.contains(
"roseStepLengthMax"))
817 if (j.contains(
"gravitationModel"))
821 if (j.contains(
"coriolisAccelerationEnabled"))
825 if (j.contains(
"centrifgalAccelerationEnabled"))
829 if (j.contains(
"angularRateEarthRotationEnabled"))
833 if (j.contains(
"angularRateTransportRateEnabled"))
838 if (j.contains(
"Imu"))
846 auto gpsCycleIter = std::ranges::find(description,
"GpsCycle");
847 auto gpsWeekIter = std::ranges::find(description,
"GpsWeek");
848 auto gpsTowIter = std::ranges::find(description,
"GpsToW [s]");
849 if (gpsCycleIter != description.end() && gpsWeekIter != description.end() && gpsTowIter != description.end())
851 const auto* gpsCycle = std::get_if<double>(&line.at(
static_cast<size_t>(gpsCycleIter - description.begin())));
852 const auto* gpsWeek = std::get_if<double>(&line.at(
static_cast<size_t>(gpsWeekIter - description.begin())));
853 const auto* gpsTow = std::get_if<double>(&line.at(
static_cast<size_t>(gpsTowIter - description.begin())));
854 if (gpsCycle && gpsWeek && gpsTow)
856 return InsTime{
static_cast<int32_t
>(*gpsCycle),
static_cast<int32_t
>(*gpsWeek), *gpsTow };
861 auto yearUTCIter = std::ranges::find(description,
"YearUTC");
862 auto monthUTCIter = std::ranges::find(description,
"MonthUTC");
863 auto dayUTCIter = std::ranges::find(description,
"DayUTC");
864 auto hourUTCIter = std::ranges::find(description,
"HourUTC");
865 auto minUTCIter = std::ranges::find(description,
"MinUTC");
866 auto secUTCIter = std::ranges::find(description,
"SecUTC");
867 if (yearUTCIter != description.end() && monthUTCIter != description.end() && dayUTCIter != description.end()
868 && hourUTCIter != description.end() && minUTCIter != description.end() && secUTCIter != description.end())
870 const auto* yearUTC = std::get_if<double>(&line.at(
static_cast<size_t>(yearUTCIter - description.begin())));
871 const auto* monthUTC = std::get_if<double>(&line.at(
static_cast<size_t>(monthUTCIter - description.begin())));
872 const auto* dayUTC = std::get_if<double>(&line.at(
static_cast<size_t>(dayUTCIter - description.begin())));
873 const auto* hourUTC = std::get_if<double>(&line.at(
static_cast<size_t>(hourUTCIter - description.begin())));
874 const auto* minUTC = std::get_if<double>(&line.at(
static_cast<size_t>(minUTCIter - description.begin())));
875 const auto* secUTC = std::get_if<double>(&line.at(
static_cast<size_t>(secUTCIter - description.begin())));
876 if (yearUTC && monthUTC && dayUTC && hourUTC && minUTC && secUTC)
879 static_cast<uint16_t
>(*yearUTC),
static_cast<uint16_t
>(*monthUTC),
static_cast<uint16_t
>(*dayUTC),
880 static_cast<uint16_t
>(*hourUTC),
static_cast<uint16_t
>(*minUTC), *secUTC,
UTC
886 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the time.",
nameId());
892 auto posXIter = std::ranges::find(description,
"X-ECEF [m]");
893 auto posYIter = std::ranges::find(description,
"Y-ECEF [m]");
894 auto posZIter = std::ranges::find(description,
"Z-ECEF [m]");
895 if (posXIter != description.end() && posYIter != description.end() && posZIter != description.end())
897 const auto* posX = std::get_if<double>(&line.at(
static_cast<size_t>(posXIter - description.begin())));
898 const auto* posY = std::get_if<double>(&line.at(
static_cast<size_t>(posYIter - description.begin())));
899 const auto* posZ = std::get_if<double>(&line.at(
static_cast<size_t>(posZIter - description.begin())));
900 if (posX && posY && posZ && !std::isnan(*posX) && !std::isnan(*posY) && !std::isnan(*posZ))
902 return Eigen::Vector3d{ *posX, *posY, *posZ };
907 auto latIter = std::ranges::find(description,
"Latitude [deg]");
908 auto lonIter = std::ranges::find(description,
"Longitude [deg]");
909 auto altIter = std::ranges::find(description,
"Altitude [m]");
910 if (latIter != description.end() && lonIter != description.end() && altIter != description.end())
912 const auto* lat = std::get_if<double>(&line.at(
static_cast<size_t>(latIter - description.begin())));
913 const auto* lon = std::get_if<double>(&line.at(
static_cast<size_t>(lonIter - description.begin())));
914 const auto* alt = std::get_if<double>(&line.at(
static_cast<size_t>(altIter - description.begin())));
915 if (lat && lon && alt && !std::isnan(*lat) && !std::isnan(*lon) && !std::isnan(*alt))
922 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the position.",
nameId());
928 auto rollIter = std::ranges::find(description,
"Roll [deg]");
929 auto pitchIter = std::ranges::find(description,
"Pitch [deg]");
930 auto yawIter = std::ranges::find(description,
"Yaw [deg]");
931 if (rollIter != description.end() && pitchIter != description.end() && yawIter != description.end())
933 const auto*
roll = std::get_if<double>(&line.at(
static_cast<size_t>(rollIter - description.begin())));
934 const auto*
pitch = std::get_if<double>(&line.at(
static_cast<size_t>(pitchIter - description.begin())));
935 const auto*
yaw = std::get_if<double>(&line.at(
static_cast<size_t>(yawIter - description.begin())));
943 auto quatWIter = std::ranges::find(description,
"n_Quat_b w");
944 auto quatXIter = std::ranges::find(description,
"n_Quat_b x");
945 auto quatYIter = std::ranges::find(description,
"n_Quat_b y");
946 auto quatZIter = std::ranges::find(description,
"n_Quat_b z");
947 if (quatWIter != description.end() && quatXIter != description.end() && quatYIter != description.end() && quatZIter != description.end())
949 const auto* w = std::get_if<double>(&line.at(
static_cast<size_t>(quatWIter - description.begin())));
950 const auto*
x = std::get_if<double>(&line.at(
static_cast<size_t>(quatXIter - description.begin())));
951 const auto*
y = std::get_if<double>(&line.at(
static_cast<size_t>(quatYIter - description.begin())));
952 const auto*
z = std::get_if<double>(&line.at(
static_cast<size_t>(quatZIter - description.begin())));
953 if (w &&
x &&
y &&
z && !std::isnan(*w) && !std::isnan(*
x) && !std::isnan(*
y) && !std::isnan(*
z))
955 return Eigen::Quaterniond{ *w, *
x, *
y, *
z };
960 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the attitude.",
nameId());
966 std::vector<long double> splineTime;
968 auto unwrapAngle = [](
auto angle,
auto prevAngle,
auto rangeMax) {
969 auto x = angle - prevAngle;
970 x = std::fmod(
x + rangeMax, 2 * rangeMax);
977 return prevAngle +
x;
982 splineTime.push_back(-30.0);
983 splineTime.push_back(-20.0);
984 splineTime.push_back(-10.0);
985 splineTime.push_back(0.0);
991 Eigen::Vector3d e_startPosition =
_startPosition.e_position.cast<
double>();
992 std::vector<long double> X(splineTime.size(), e_startPosition[0]);
993 std::vector<long double> Y(splineTime.size(), e_startPosition[1]);
994 std::vector<long double> Z(splineTime.size(), e_startPosition[2]);
999 _splines.x.setPoints(splineTime, X);
1000 _splines.y.setPoints(splineTime, Y);
1001 _splines.z.setPoints(splineTime, Z);
1003 _splines.roll.setPoints(splineTime, Roll);
1004 _splines.pitch.setPoints(splineTime, Pitch);
1005 _splines.yaw.setPoints(splineTime, Yaw);
1014 size_t nOverhead =
static_cast<size_t>(std::round(1.0 /
_splines.sampleInterval)) + 1;
1016 splineTime = std::vector<long double>(nOverhead, 0.0);
1017 std::vector<long double> splineX(nOverhead, e_startPosition[0]);
1018 std::vector<long double> splineY(nOverhead, e_startPosition[1]);
1019 std::vector<long double> splineZ(nOverhead, e_startPosition[2]);
1020 std::vector<long double> splineRoll(nOverhead,
roll);
1021 std::vector<long double> splinePitch(nOverhead,
pitch);
1022 std::vector<long double> splineYaw(nOverhead,
yaw);
1028 auto f = [](
const Eigen::Vector<double, 6>&
y,
const Eigen::Vector3d& n_acceleration) {
1029 Eigen::Vector<double, 6> y_dot;
1041 for (
size_t i = 2; i <= nOverhead; i++)
1043 Eigen::Vector<double, 6>
y;
1044 y << lla_lastPosition,
1047 y += -
_splines.sampleInterval * f(
y, Eigen::Vector3d::Zero());
1048 lla_lastPosition =
y.head<3>();
1052 splineTime.at(nOverhead - i) = -
_splines.sampleInterval *
static_cast<double>(i - 1);
1053 splineX.at(nOverhead - i) = e_position(0);
1054 splineY.at(nOverhead - i) = e_position(1);
1055 splineZ.at(nOverhead - i) = e_position(2);
1059 for (
size_t i = 1;; i++)
1061 Eigen::Vector<double, 6>
y;
1062 y << lla_lastPosition,
1065 y +=
_splines.sampleInterval * f(
y, Eigen::Vector3d::Zero());
1066 lla_lastPosition =
y.head<3>();
1070 auto simTime =
_splines.sampleInterval *
static_cast<double>(i);
1071 splineTime.push_back(simTime);
1072 splineX.push_back(e_position(0));
1073 splineY.push_back(e_position(1));
1074 splineZ.push_back(e_position(2));
1075 splineRoll.push_back(
roll);
1076 splinePitch.push_back(
pitch);
1077 splineYaw.push_back(
yaw);
1087 lla_lastPosition(0), lla_lastPosition(1));
1088 auto distance = std::sqrt(std::pow(horizontalDistance, 2) + std::pow(
_startPosition.altitude() - lla_lastPosition(2), 2))
1097 _splines.x.setPoints(splineTime, splineX);
1098 _splines.y.setPoints(splineTime, splineY);
1099 _splines.z.setPoints(splineTime, splineZ);
1101 _splines.roll.setPoints(splineTime, splineRoll);
1102 _splines.pitch.setPoints(splineTime, splinePitch);
1103 _splines.yaw.setPoints(splineTime, splineYaw);
1107 double simDuration{};
1118 constexpr double OFFSET = 1.0;
1120 for (
size_t i = 0; i <= static_cast<size_t>(std::round((simDuration + 2.0 * OFFSET) /
_splines.sampleInterval)); i++)
1122 splineTime.push_back(
_splines.sampleInterval *
static_cast<double>(i) - OFFSET);
1124 LOG_DATA(
"{}: Sim Time [{:.3f}, {:.3f}] with dt = {:.3f} (simDuration = {:.3f})",
nameId(),
1125 static_cast<double>(splineTime.front()),
static_cast<double>(splineTime.back()),
static_cast<double>(splineTime.at(1) - splineTime.at(0)), simDuration);
1127 std::vector<long double> splineX(splineTime.size());
1128 std::vector<long double> splineY(splineTime.size());
1129 std::vector<long double> splineZ(splineTime.size());
1134 Eigen::Quaterniond e_quatCenter_n =
trafo::e_Quat_n(lla_origin(0), lla_origin(1));
1136 for (uint64_t i = 0; i < splineTime.size(); i++)
1147 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1149 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1151 splineX[i] = e_position[0];
1152 splineY[i] = e_position[1];
1153 splineZ[i] = e_position[2];
1156 _splines.x.setPoints(splineTime, splineX);
1157 _splines.y.setPoints(splineTime, splineY);
1158 _splines.z.setPoints(splineTime, splineZ);
1180 for (
int i = 2; i <= n; i++)
1182 if (n % i == 0 && d % i == 0)
1190 auto isOdd = [](
auto a) {
return static_cast<int>(a) % 2 != 0; };
1191 auto isEven = [](
auto a) {
return static_cast<int>(a) % 2 == 0; };
1193 double integrationFactor = 0.0;
1196 if (isOdd(n)) { integrationFactor =
static_cast<double>(d); }
1197 else { integrationFactor = 2.0 *
static_cast<double>(d); }
1201 if (isEven(n)) { integrationFactor =
static_cast<double>(d); }
1202 else { integrationFactor = 2.0 *
static_cast<double>(d); }
1206 splineTime.resize(nVirtPoints);
1207 std::vector<long double> splineX(splineTime.size());
1208 std::vector<long double> splineY(splineTime.size());
1209 std::vector<long double> splineZ(splineTime.size());
1216 double dPhi = 0.001;
1217 double maxPhi = std::numeric_limits<double>::infinity();
1229 for (
double phi = dPhi; phi <= maxPhi + static_cast<double>(nVirtPoints) * dPhi; phi += dPhi)
1232 double dL = length - lengthOld;
1249 splineTime.push_back(time);
1254 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1255 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1259 splineX.push_back(e_position[0]);
1260 splineY.push_back(e_position[1]);
1261 splineZ.push_back(e_position[2]);
1265 LOG_TRACE(
"{}: Rose figure simulation duration: {:8.6}s | l={:8.6}m",
nameId(), time, length);
1275 maxPhi = integrationFactor * M_PI + 1e-15;
1279 for (
size_t i = 0; i < nVirtPoints; i++)
1281 double phi = maxPhi -
static_cast<double>(i) * dPhi;
1284 splineTime[nVirtPoints - i - 1] = time;
1290 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1291 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1295 splineX[nVirtPoints - i - 1] = e_position[0];
1296 splineY[nVirtPoints - i - 1] = e_position[1];
1297 splineZ[nVirtPoints - i - 1] = e_position[2];
1300 _splines.x.setPoints(splineTime, splineX);
1301 _splines.y.setPoints(splineTime, splineY);
1302 _splines.z.setPoints(splineTime, splineZ);
1307 csvData && csvData->v->lines.size() >= 2)
1309 if (
auto startTime =
getTimeFromCsvLine(csvData->v->lines.front(), csvData->v->description))
1311 if (!startTime) {
return false; }
1315 constexpr size_t nVirtPoints = 0;
1316 splineTime.resize(nVirtPoints);
1317 std::vector<long double> splineX(splineTime.size());
1318 std::vector<long double> splineY(splineTime.size());
1319 std::vector<long double> splineZ(splineTime.size());
1320 std::vector<long double> splineRoll(splineTime.size());
1321 std::vector<long double> splinePitch(splineTime.size());
1322 std::vector<long double> splineYaw(splineTime.size());
1324 for (
size_t i = 0; i < csvData->v->lines.size(); i++)
1329 LOG_ERROR(
"{}: Data in time column not found in line {}",
nameId(), i + 2);
1333 auto time =
static_cast<double>((*insTime -
_startTime).count());
1338 LOG_ERROR(
"{}: Data in position column not found in line {}",
nameId(), i + 2);
1346 LOG_ERROR(
"{}: Data in attitude column not found in line {}",
nameId(), i + 2);
1351 splineTime.push_back(time);
1352 splineX.push_back(e_pos->x());
1353 splineY.push_back(e_pos->y());
1354 splineZ.push_back(e_pos->z());
1358 splineRoll.push_back(i > 0 ? unwrapAngle(rpy(0), splineRoll.back(), M_PI) : rpy(0));
1359 splinePitch.push_back(i > 0 ? unwrapAngle(rpy(1), splinePitch.back(), M_PI_2) : rpy(1));
1360 splineYaw.push_back(i > 0 ? unwrapAngle(rpy(2), splineYaw.back(), M_PI) : rpy(2));
1365 auto dt =
static_cast<double>(splineTime[nVirtPoints + 1] - splineTime[nVirtPoints]);
1366 for (
size_t i = 0; i < nVirtPoints; i++)
1369 splineTime[nVirtPoints - i - 1] = splineTime[nVirtPoints - i] - h;
1370 splineX[nVirtPoints - i - 1] = splineX[nVirtPoints - i] - h * (splineX[nVirtPoints + 1] - splineX[nVirtPoints]) / dt;
1371 splineY[nVirtPoints - i - 1] = splineY[nVirtPoints - i] - h * (splineY[nVirtPoints + 1] - splineY[nVirtPoints]) / dt;
1372 splineZ[nVirtPoints - i - 1] = splineZ[nVirtPoints - i] - h * (splineZ[nVirtPoints + 1] - splineZ[nVirtPoints]) / dt;
1373 splineRoll[nVirtPoints - i - 1] = splineRoll[nVirtPoints - i] - h * (splineRoll[nVirtPoints + 1] - splineRoll[nVirtPoints]) / dt;
1374 splinePitch[nVirtPoints - i - 1] = splinePitch[nVirtPoints - i] - h * (splinePitch[nVirtPoints + 1] - splinePitch[nVirtPoints]) / dt;
1375 splineYaw[nVirtPoints - i - 1] = splineYaw[nVirtPoints - i] - h * (splineYaw[nVirtPoints + 1] - splineYaw[nVirtPoints]) / dt;
1376 splineTime.push_back(splineTime[splineX.size() - 1] + h);
1377 splineX.push_back(splineX[splineX.size() - 1] + h * (splineX[splineX.size() - 1] - splineX[splineX.size() - 2]) / dt);
1378 splineY.push_back(splineY[splineY.size() - 1] + h * (splineY[splineY.size() - 1] - splineY[splineY.size() - 2]) / dt);
1379 splineZ.push_back(splineZ[splineZ.size() - 1] + h * (splineZ[splineZ.size() - 1] - splineZ[splineZ.size() - 2]) / dt);
1380 splineRoll.push_back(splineRoll[splineRoll.size() - 1] + h * (splineRoll[splineRoll.size() - 1] - splineRoll[splineRoll.size() - 2]) / dt);
1381 splinePitch.push_back(splinePitch[splinePitch.size() - 1] + h * (splinePitch[splinePitch.size() - 1] - splinePitch[splinePitch.size() - 2]) / dt);
1382 splineYaw.push_back(splineYaw[splineYaw.size() - 1] + h * (splineYaw[splineYaw.size() - 1] - splineYaw[splineYaw.size() - 2]) / dt);
1385 _splines.x.setPoints(splineTime, splineX);
1386 _splines.y.setPoints(splineTime, splineY);
1387 _splines.z.setPoints(splineTime, splineZ);
1389 _splines.roll.setPoints(splineTime, splineRoll);
1390 _splines.pitch.setPoints(splineTime, splinePitch);
1391 _splines.yaw.setPoints(splineTime, splineYaw);
1395 LOG_ERROR(
"{}: Can't calculate the data without a connected CSV file with at least two datasets",
nameId());
1402 std::vector<long double> splineRoll(splineTime.size());
1403 std::vector<long double> splinePitch(splineTime.size());
1404 std::vector<long double> splineYaw(splineTime.size());
1406 for (uint64_t i = 0; i < splineTime.size(); i++)
1408 Eigen::Vector3d e_pos{
static_cast<double>(
_splines.x(splineTime[i])),
1409 static_cast<double>(
_splines.y(splineTime[i])),
1410 static_cast<double>(
_splines.z(splineTime[i])) };
1411 Eigen::Vector3d e_vel{
static_cast<double>(
_splines.x.derivative(1, splineTime[i])),
1412 static_cast<double>(
_splines.y.derivative(1, splineTime[i])),
1413 static_cast<double>(
_splines.z.derivative(1, splineTime[i])) };
1416 Eigen::Vector3d n_velocity =
trafo::n_Quat_e(lla_position(0), lla_position(1)) * e_vel;
1422 Eigen::Vector3d e_normalVectorCurrentPosition{ std::cos(lla_position(0)) * std::cos(lla_position(1)),
1423 std::cos(lla_position(0)) * std::sin(lla_position(1)),
1424 std::sin(lla_position(0)) };
1428 splineYaw[i] = i > 0 ? unwrapAngle(
yaw, splineYaw[i - 1], M_PI) :
yaw;
1429 splineRoll[i] = 0.0;
1434 _splines.roll.setPoints(splineTime, splineRoll);
1435 _splines.pitch.setPoints(splineTime, splinePitch);
1436 _splines.yaw.setPoints(splineTime, splineYaw);
1473 csvData && !csvData->v->lines.empty())
1475 if (
auto startTime =
getTimeFromCsvLine(csvData->v->lines.front(), csvData->v->description))
1477 if (!startTime) {
return false; }
1484 LOG_ERROR(
"{}: Can't reset the ImuSimulator without a connected CSV file",
nameId());
1490 std::time_t t = std::time(
nullptr);
1491 std::tm* now = std::localtime(&t);
1493 _startTime =
InsTime{
static_cast<uint16_t
>(now->tm_year + 1900),
static_cast<uint16_t
>(now->tm_mon),
static_cast<uint16_t
>(now->tm_mday),
1494 static_cast<uint16_t
>(now->tm_hour),
static_cast<uint16_t
>(now->tm_min),
static_cast<long double>(now->tm_sec) };
1517 lla_position(0), lla_position(1));
1518 auto distance = std::sqrt(std::pow(horizontalDistance, 2) + std::pow(
_startPosition.altitude() - lla_position(2), 2));
1525 return time > simDuration;
1547 auto obs = std::make_shared<NodeData>();
1548 obs->insTime =
_startTime + std::chrono::duration<double>(imuUpdateTime);
1552 auto obs = std::make_shared<ImuObsSimulated>(
_imuPos);
1553 obs->insTime =
_startTime + std::chrono::duration<double>(imuUpdateTime);
1554 LOG_DATA(
"{}: Simulated IMU data for time [{}] (_imuUpdateCnt {}, _imuInternalUpdateCnt {})",
nameId(), obs->insTime.toYMDHMS(),
1558 Eigen::Vector3d p_deltaVel = Eigen::Vector3d::Zero();
1559 Eigen::Vector3d p_deltaTheta = Eigen::Vector3d::Zero();
1561 double imuInternalUpdateTime = 0.0;
1564 LOG_DATA(
"{}: Simulated internal IMU data for time [{}] (_imuUpdateCnt {}, _imuInternalUpdateCnt {})",
nameId(),
1569 LOG_DATA(
"{}: [{:8.3f}] lla_position = {}°, {}°, {} m",
nameId(), imuInternalUpdateTime,
rad2deg(lla_position(0)),
rad2deg(lla_position(1)), lla_position(2));
1571 Eigen::Quaterniond n_Quat_e =
trafo::n_Quat_e(lla_position(0), lla_position(1));
1573 Eigen::Vector3d n_vel =
n_calcVelocity(imuInternalUpdateTime, n_Quat_e);
1574 LOG_DATA(
"{}: [{:8.3f}] n_vel = {} [m/s]",
nameId(), imuInternalUpdateTime, n_vel.transpose());
1582 LOG_DATA(
"{}: [{:8.3f}] n_omega_ie = {} [rad/s]",
nameId(), imuInternalUpdateTime, n_omega_ie.transpose());
1584 LOG_DATA(
"{}: [{:8.3f}] R_N = {} [m]",
nameId(), imuInternalUpdateTime, R_N);
1586 LOG_DATA(
"{}: [{:8.3f}] R_E = {} [m]",
nameId(), imuInternalUpdateTime, R_E);
1588 LOG_DATA(
"{}: [{:8.3f}] n_omega_en = {} [rad/s]",
nameId(), imuInternalUpdateTime, n_omega_en.transpose());
1593 Eigen::Vector3d n_trajectoryAccel =
n_calcTrajectoryAccel(imuInternalUpdateTime, n_Quat_e, lla_position, n_vel);
1594 LOG_DATA(
"{}: [{:8.3f}] n_trajectoryAccel = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_trajectoryAccel.transpose());
1597 Eigen::Vector3d n_accel = n_trajectoryAccel;
1601 LOG_DATA(
"{}: [{:8.3f}] n_coriolisAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_coriolisAcceleration.transpose());
1602 n_accel += n_coriolisAcceleration;
1608 n_accel -= n_gravitation;
1613 LOG_DATA(
"{}: [{:8.3f}] e_centrifugalAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, e_centrifugalAcceleration.transpose());
1614 Eigen::Vector3d n_centrifugalAcceleration = n_Quat_e * e_centrifugalAcceleration;
1615 LOG_DATA(
"{}: [{:8.3f}] n_centrifugalAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_centrifugalAcceleration.transpose());
1616 n_accel += n_centrifugalAcceleration;
1620 Eigen::Vector3d p_accel =
_imuPos.p_quat_b() * b_Quat_n * n_accel;
1621 LOG_DATA(
"{}: [{:8.3f}] p_accel = {} [m/s^2]",
nameId(), imuInternalUpdateTime, p_accel.transpose());
1625 Eigen::Vector3d n_omega_nb =
n_calcOmega_nb(imuInternalUpdateTime, Eigen::Vector3d{
roll,
pitch,
yaw }, b_Quat_n.conjugate());
1628 Eigen::Vector3d n_omega_ib = n_omega_nb;
1631 n_omega_ib += n_omega_ie;
1635 n_omega_ib += n_omega_en;
1641 Eigen::Vector3d p_omega_ip =
_imuPos.p_quat_b() * b_Quat_n * n_omega_ib;
1642 LOG_DATA(
"{}: [{:8.3f}] p_omega_ip = {} [rad/s]",
nameId(), imuInternalUpdateTime, p_omega_ip.transpose());
1646 obs->p_acceleration = p_accel.cast<
double>();
1647 obs->p_angularRate = p_omega_ip.cast<
double>();
1650 Eigen::Quaterniond e_Quat_n = n_Quat_e.conjugate();
1652 obs->n_accelDynamics = n_trajectoryAccel.cast<
double>();
1653 obs->n_angularRateDynamics = n_omega_nb.cast<
double>();
1655 obs->e_accelDynamics = (e_Quat_n * n_trajectoryAccel).cast<double>();
1656 obs->e_angularRateDynamics = (e_Quat_n * n_omega_nb).cast<double>();
1670 }
while (imuInternalUpdateTime + 1e-6 < imuUpdateTime);
1673 obs->dvel = p_deltaVel.cast<
double>();
1674 obs->dtheta = p_deltaTheta.cast<
double>();
1675 LOG_DATA(
"{}: dtime = {}, dvel = {}, dtheta = {}",
nameId(), obs->dtime, obs->dvel.transpose(), obs->dtheta.transpose());
1698 auto obs = std::make_shared<NodeData>();
1699 obs->insTime =
_startTime + std::chrono::duration<double>(gnssUpdateTime);
1702 auto obs = std::make_shared<PosVelAtt>();
1703 obs->insTime =
_startTime + std::chrono::duration<double>(gnssUpdateTime);
1704 LOG_DATA(
"{}: Simulating GNSS data for time [{}]",
nameId(), obs->insTime.toYMDHMS());
1707 LOG_DATA(
"{}: [{:8.3f}] lla_position = {}°, {}°, {} m",
nameId(), gnssUpdateTime,
rad2deg(lla_position(0)),
rad2deg(lla_position(1)), lla_position(2));
1708 Eigen::Quaterniond n_Quat_e =
trafo::n_Quat_e(lla_position(0), lla_position(1));
1709 Eigen::Vector3d n_vel =
n_calcVelocity(gnssUpdateTime, n_Quat_e);
1710 LOG_DATA(
"{}: [{:8.3f}] n_vel = {} [m/s]",
nameId(), gnssUpdateTime, n_vel.transpose());
1727 static_cast<double>(
_splines.roll(time)),
1728 static_cast<double>(
_splines.pitch(time)),
1729 static_cast<double>(
_splines.yaw(time))
1735 Eigen::Vector3d e_pos(
static_cast<double>(
_splines.x(time)),
1736 static_cast<double>(
_splines.y(time)),
1737 static_cast<double>(
_splines.z(time)));
1743 Eigen::Vector3d e_vel(
static_cast<double>(
_splines.x.derivative(1, time)),
1744 static_cast<double>(
_splines.y.derivative(1, time)),
1745 static_cast<double>(
_splines.z.derivative(1, time)));
1746 return n_Quat_e * e_vel;
1750 const Eigen::Quaterniond& n_Quat_e,
1751 const Eigen::Vector3d& lla_position,
1752 const Eigen::Vector3d& n_velocity)
const
1754 Eigen::Vector3d e_accel(
static_cast<double>(
_splines.x.derivative(2, time)),
1755 static_cast<double>(
_splines.y.derivative(2, time)),
1756 static_cast<double>(
_splines.z.derivative(2, time)));
1757 Eigen::Quaterniond e_Quat_n = n_Quat_e.conjugate();
1758 Eigen::Vector3d e_vel = e_Quat_n * n_velocity;
1761 Eigen::Matrix3d n_DCM_dot_e = e_Quat_n.toRotationMatrix()
1767 Eigen::Matrix3d e_DCM_dot_n = n_DCM_dot_e.transpose();
1770 return e_DCM_dot_n * e_vel + n_Quat_e * e_accel;
1775 const auto& R = rollPitchYaw(0);
1776 const auto& P = rollPitchYaw(1);
1780 auto R_dot =
static_cast<double>(
_splines.roll.derivative(1, time));
1781 auto Y_dot =
static_cast<double>(
_splines.yaw.derivative(1, time));
1782 auto P_dot =
static_cast<double>(
_splines.pitch.derivative(1, time));
1784 auto C_3 = [](
auto R) {
1790 return Eigen::AngleAxisd{ -R, Eigen::Vector3d::UnitX() };
1792 auto C_2 = [](
auto P) {
1798 return Eigen::AngleAxisd{ -P, Eigen::Vector3d::UnitY() };
1804 Eigen::Vector3d b_omega_nb = Eigen::Vector3d{ R_dot, 0, 0 }
1805 + C_3(R) * Eigen::Vector3d{ 0, P_dot, 0 }
1806 + C_3(R) * C_2(P) * Eigen::Vector3d{ 0, 0, Y_dot };
1808 return n_Quat_b * b_omega_nb;
1824 return "Rose Figure";
1836 return "Clockwise (CW)";
1838 return "Counterclockwise (CCW)";
Functions concerning the ellipsoid model.
nlohmann::json json
json namespace
Different Gravity Models.
Text Help Marker (?) with Tooltip.
Inertial Navigation Helper Functions.
Data storage class for simulated IMU observations.
Imu Observation Simulator.
The class is responsible for all time-related tasks.
Inertial Navigation Mechanization Functions in local navigation frame.
Utility class for logging to console and file.
#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_ERROR
Error occurred, which stops part of the program to work, but not everything.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Position, Velocity and Attitude Storage Class.
std::vector< CsvElement > CsvLine
CSV Line with splitted entries.
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
gui::widgets::PositionWithFrame _startPosition
double _roseSimDuration
Simulation duration needed for the rose figure.
CubicSpline< long double > pitch
Pitch angle [rad].
void restore(const json &j) override
Restores the node from a json object.
ImuSimulator()
Default constructor.
void deinitialize() override
Deinitialize the node.
TrajectoryType
Types of Trajectories available for simulation.
@ Linear
Linear movement with constant velocity.
@ Fixed
Static position without movement.
@ COUNT
Amount of items in the enum.
@ Csv
Get the input from the CsvData pin.
@ RoseFigure
Movement along a mathmatical rose figure.
std::shared_ptr< const NodeData > pollPosVelAtt(size_t pinIdx, bool peek)
Polls the next simulated data.
uint64_t _imuInternalUpdateCnt
Counter to calculate the internal IMU update time.
double _trajectoryRotationAngle
In the GUI selected origin angle of the circular trajectory in [rad].
CubicSpline< long double > yaw
Yaw angle [rad].
CubicSpline< long double > roll
Roll angle [rad].
@ CurrentComputerTime
Gets the current computer time as start time.
@ CustomTime
Custom time selected by the user.
Eigen::Vector3d _lla_imuLastLinearPosition
Last calculated position for the IMU in linear mode for iterative calculations as latitude,...
double _circularHarmonicAmplitudeFactor
Harmonic Oscillation Amplitude Factor of the circle radius [-].
static constexpr size_t OUTPUT_PORT_INDEX_POS_VEL_ATT
Flow (PosVelAtt)
Direction _trajectoryDirection
In the GUI selected direction of the circular trajectory (used by circular and rose figure)
CubicSpline< long double > z
ECEF Z Position [m].
double _imuInternalFrequency
Frequency to calculate the delta IMU values in [Hz].
double _csvDuration
Duration from the CSV file in [s].
double _gnssLastUpdateTime
Last time the GNSS message was calculated in [s].
json save() const override
Saves the node into a json object.
~ImuSimulator() override
Destructor.
std::optional< Eigen::Quaterniond > n_getAttitudeQuaternionFromCsvLine_b(const CsvData::CsvLine &line, const std::vector< std::string > &description) const
Get the Attitude quaternion n_quat_b from a CSV line.
int _circularHarmonicFrequency
Harmonic Oscillation Frequency on the circular trajectory [cycles/revolution].
int _rosePetNum
In the GUI selected numerator of petals (2*k for even k, k for uneven k) of the rose figure.
static constexpr size_t OUTPUT_PORT_INDEX_IMU_OBS
Flow (ImuObs)
gui::widgets::TimeEditFormat _startTimeEditFormat
Time Format to input the start time with.
InsTime _startTime
Global starttime.
double _linearTrajectoryDistanceForStop
Distance in [m] to the start position to stop the simulation.
static std::string category()
String representation of the Class Category.
Eigen::Vector3d n_calcVelocity(double time, const Eigen::Quaterniond &n_Quat_e) const
Calculates the velocity in local-navigation frame coordinates at the given time depending on the traj...
std::optional< Eigen::Vector3d > e_getPositionFromCsvLine(const CsvData::CsvLine &line, const std::vector< std::string > &description) const
Get the Position from a CSV line.
bool _angularRateEarthRotationEnabled
Apply the Earth rotation rate to the measured angular rates.
double _imuLastUpdateTime
Last time the IMU message was calculated in [s].
double _trajectoryVerticalSpeed
Vertical speed of the vehicle in the tangential plane in [m/s] (used by circular and rose figure)
static std::string typeStatic()
String representation of the Class Type.
int _rosePetDenom
In the GUI selected denominator of petals (2*k for even k, k for uneven k) of the rose figure.
static constexpr size_t INPUT_PORT_INDEX_CSV
Object (CsvData)
TrajectoryType _trajectoryType
Selected trajectory type in the GUI.
Direction
Possible directions for the circular trajectory.
@ COUNT
Amount of items in the enum.
double _roseTrajectoryCountForStop
Amount of rose figures to simulate before stopping.
double _roseStepLengthMax
Maxmimum step length for the spline points for the rose figure [m]. Points will be spaced between [L/...
void guiConfig() override
ImGui config window which is shown on double click.
CubicSpline< long double > y
ECEF Y Position [m].
bool _centrifgalAccelerationEnabled
Apply the centrifugal acceleration to the measured accelerations.
double _simulationDuration
Duration to simulate in [s].
bool resetNode() override
Resets the node. Moves the read cursor to the start.
@ DistanceOrCirclesOrRoses
Distance for Linear trajectory / Circle count for Circular / Count for rose figure trajectory.
std::array< double, 3 > calcFlightAngles(double time) const
Calculates the flight angles (roll, pitch, yaw)
bool initializeSplines()
Initializes the spline values.
double _circularTrajectoryCircleCountForStop
Amount of circles to simulate before stopping.
std::shared_ptr< const NodeData > pollImuObs(size_t pinIdx, bool peek)
Polls the next simulated data.
Eigen::Vector3d _n_linearTrajectoryStartVelocity
Start Velocity of the vehicle in local-navigation frame cooridnates in [m/s].
uint64_t _imuUpdateCnt
Counter to calculate the IMU update time.
Eigen::Vector3d n_calcOmega_nb(double time, const Eigen::Vector3d &rollPitchYaw, const Eigen::Quaterniond &n_Quat_b) const
Calculates ω_nb_n, the turn rate of the body with respect to the navigation system expressed in NED c...
Eigen::Vector3d lla_calcPosition(double time) const
Calculates the position in latLonAlt at the given time depending on the trajectoryType.
bool _angularRateTransportRateEnabled
Apply the transport rate to the measured angular rates.
static const char * to_string(TrajectoryType value)
Converts the enum to a string.
std::string type() const override
String representation of the Class Type.
struct NAV::ImuSimulator::@112323040341172005327360071040367216370163224314 _splines
Assign a variable that holds the Spline information.
GravitationModel _gravitationModel
Gravitation model selected in the GUI.
bool checkStopCondition(double time, const Eigen::Vector3d &lla_position)
Checks the selected stop condition.
uint64_t _gnssUpdateCnt
Counter to calculate the GNSS update time.
Eigen::Vector3d _lla_gnssLastLinearPosition
Last calculated position for the GNSS in linear mode for iterative calculations as latitude,...
StopCondition _simulationStopCondition
Condition which has to be met to stop the simulation.
double _trajectoryRadius
In the GUI selected radius of the circular trajectory (used by circular and rose figure)
StartTimeSource _startTimeSource
Source for the start time, selected in the GUI.
Eigen::Vector3d _p_lastImuAccelerationMeas
Last calculated acceleration measurement in platform coordinates [m/s²].
double _trajectoryHorizontalSpeed
Horizontal speed of the vehicle in the tangential plane in [m/s] (used by circular and rose figure)
bool _coriolisAccelerationEnabled
Apply the coriolis acceleration to the measured accelerations.
Eigen::Vector3d _p_lastImuAngularRateMeas
Last calculated angular rate measurement in platform coordinates [rad/s].
Eigen::Vector3d n_calcTrajectoryAccel(double time, const Eigen::Quaterniond &n_Quat_e, const Eigen::Vector3d &lla_position, const Eigen::Vector3d &n_velocity) const
Calculates the acceleration in local-navigation frame coordinates at the given time depending on the ...
bool initialize() override
Initialize the node.
std::optional< InsTime > getTimeFromCsvLine(const CsvData::CsvLine &line, const std::vector< std::string > &description) const
Get the Time from a CSV line.
CubicSpline< long double > x
ECEF X Position [m].
double _gnssFrequency
Frequency to sample the position with in [Hz].
double _imuFrequency
Frequency to sample the IMU with in [Hz].
Eigen::Vector3d _fixedTrajectoryStartOrientation
Orientation of the vehicle [roll, pitch, yaw] [rad].
json save() const override
Saves the node into a json object.
void restore(const json &j) override
Restores the node from a json object.
void guiConfig() override
ImGui config window which is shown on double click.
Imu(const Imu &)=delete
Copy constructor.
ImuPos _imuPos
Position and rotation information for conversion from platform to body frame.
static const Eigen::Vector3< double > e_omega_ie
ω_ie_e = ω_ie_i Nominal mean angular velocity of the Earth in [rad/s], in earth coordinates
The class is responsible for all time-related tasks.
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
ImVec2 _guiConfigDefaultWindowSize
std::optional< InputPin::IncomingLink::ValueWrapper< T > > getInputValue(size_t portIndex) const
Get Input Value connected on the pin. Only const data types.
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.
bool DeleteInputPin(size_t pinIndex)
Deletes the input pin. Invalidates the pin reference given.
bool _hasConfig
Flag if the config window should be shown.
static std::string type()
Returns the type of the data class.
static float windowFontRatio()
Ratio to multiply for GUI window elements.
static ImTextureID m_RoseFigure
Pointer to the texture for the rose figure (ImuSimulator node)
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 DragDouble(const char *label, double *v, float v_speed, double v_min, double v_max, const char *format, ImGuiSliderFlags flags)
Shows a Drag GUI element for 'double'.
bool InputDoubleL(const char *label, double *v, double v_min, double v_max, double step, double step_fast, const char *format, ImGuiInputTextFlags flags)
Shows a value limited InputText GUI element for 'double'.
void ApplyChanges()
Signals that there have been changes to the flow.
double calcEllipticalIntegral(double phi, double m)
Calculates the incomplete elliptical integral of the second kind.
Eigen::Matrix< typename Derived::Scalar, 3, 3 > skewSymmetricMatrix(const Eigen::MatrixBase< Derived > &a)
Calculates the skew symmetric matrix of the given vector. This is needed to perform the cross product...
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 > b_Quat_n(const Scalar &roll, const Scalar &pitch, const Scalar &yaw)
Quaternion for rotations from navigation to body frame.
Eigen::Quaternion< Scalar > e_Quat_n(const Scalar &latitude, const Scalar &longitude)
Quaternion for rotations from navigation to Earth-fixed frame.
Eigen::Quaternion< Scalar > n_Quat_e(const Scalar &latitude, const Scalar &longitude)
Quaternion for rotations from Earth-fixed to navigation frame.
Eigen::Vector3< typename Derived::Scalar > quat2eulerZYX(const Eigen::QuaternionBase< Derived > &q)
Converts the quaternion to Euler rotation angles with rotation sequence ZYX.
Eigen::Vector3< typename Derived::Scalar > lla2ecef_WGS84(const Eigen::MatrixBase< Derived > &lla_position)
Converts latitude, longitude and altitude into Earth-centered-Earth-fixed coordinates using WGS84.
Eigen::Quaternion< Scalar > n_Quat_b(Scalar roll, Scalar pitch, Scalar yaw)
Quaternion for rotations from body to navigation frame.
@ UTC
Coordinated Universal Time.
Eigen::Vector3< typename Derived::Scalar > n_calcGravitation(const Eigen::MatrixBase< Derived > &lla_position, GravitationModel gravitationModel=GravitationModel::EGM96)
Calculates the gravitation (acceleration due to mass attraction of the Earth)
Eigen::Vector3< typename DerivedA::Scalar > e_calcCentrifugalAcceleration(const Eigen::MatrixBase< DerivedA > &e_position, const Eigen::MatrixBase< DerivedB > &e_omega_ie=InsConst::e_omega_ie)
Calculates the centrifugal acceleration in [m/s^2] (acceleration that makes a body follow a curved pa...
Eigen::Vector3< typename DerivedA::Scalar > n_calcCoriolisAcceleration(const Eigen::MatrixBase< DerivedA > &n_omega_ie, const Eigen::MatrixBase< DerivedB > &n_omega_en, const Eigen::MatrixBase< DerivedC > &n_velocity)
Calculates the coriolis acceleration in [m/s^2] (acceleration due to motion in rotating reference fra...
Scalar calcGeographicalDistance(Scalar lat1, Scalar lon1, Scalar lat2, Scalar lon2)
Measure the distance between two points over an ellipsoidal-surface.
Scalar calcEarthRadius_N(const Scalar &latitude, const Scalar &a=InsConst::WGS84::a, const Scalar &e_squared=InsConst::WGS84::e_squared)
Calculates the North/South (meridian) earth radius.
const char * to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
Converts the enum to a string.
Eigen::Vector3< typename DerivedA::Scalar > n_calcTransportRate(const Eigen::MatrixBase< DerivedA > &lla_position, const Eigen::MatrixBase< DerivedB > &n_velocity, const auto &R_N, const auto &R_E)
Calculates the transport rate ω_en_n (rotation rate of the Earth frame relative to the navigation fra...
bool ComboGravitationModel(const char *label, GravitationModel &gravitationModel)
Shows a ComboBox to select the gravitation model.
Derived::Scalar calcPitchFromVelocity(const Eigen::MatrixBase< Derived > &n_velocity)
Calculates the Pitch angle from the trajectory defined by the given velocity.
constexpr auto deg2rad(const T °)
Convert Degree to Radians.
Derived::Scalar calcYawFromVelocity(const Eigen::MatrixBase< Derived > &n_velocity)
Calculates the Yaw angle from the trajectory defined by the given velocity.
Eigen::Vector3< typename Derived::Scalar > lla_calcTimeDerivativeForPosition(const Eigen::MatrixBase< Derived > &n_velocity, const auto &phi, const auto &h, const auto &R_N, const auto &R_E)
Calculates the time derivative of the curvilinear position.
constexpr auto rad2deg(const T &rad)
Convert Radians to Degree.
Scalar calcEarthRadius_E(const Scalar &latitude, const Scalar &a=InsConst::WGS84::a, const Scalar &e_squared=InsConst::WGS84::e_squared)
Calculates the East/West (prime vertical) earth radius.