25#include <Eigen/src/Geometry/AngleAxis.h>
26#include <Eigen/src/Geometry/Quaternion.h>
55 return "ImuSimulator";
65 return "Data Simulator";
85 std::time_t t = std::time(
nullptr);
86 std::tm* now = std::localtime(&t);
88 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);
93 if (ImGui::RadioButton(fmt::format(
"Custom Time##{}",
size_t(
id)).c_str(), &startTimeSource,
static_cast<int>(
StartTimeSource::CustomTime)))
112 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
113 if (ImGui::TreeNode(
"Output data-rate"))
115 ImGui::SetNextItemWidth(columnWidth);
123 ImGui::SetNextItemWidth(columnWidth);
129 ImGui::SetNextItemWidth(columnWidth);
130 if (ImGui::InputDouble(fmt::format(
"Trajectory output rate##{}",
size_t(
id)).c_str(), &
_gnssFrequency, 0.0, 0.0,
"%.3f Hz"))
139 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
140 if (ImGui::TreeNode(
"Scenario"))
142 ImGui::SetNextItemWidth(columnWidth);
168 ImGui::SetItemDefaultFocus();
175 auto TextColoredIfExists = [
this](
int index,
const char* text,
const char*
type) {
176 ImGui::TableSetColumnIndex(index);
177 auto displayTable = [&]() {
179 csvData && std::ranges::find(csvData->v->description, text) != csvData->v->description.end())
181 ImGui::TextUnformatted(text);
182 ImGui::TableNextColumn();
183 ImGui::TextUnformatted(
type);
187 ImGui::TextDisabled(
"%s", text);
188 ImGui::TableNextColumn();
189 ImGui::TextDisabled(
"%s",
type);
195 if (ImGui::TreeNode(fmt::format(
"Format description##{}",
size_t(
id)).c_str()))
197 ImGui::TextUnformatted(
"Time information:");
200 if (ImGui::BeginTable(fmt::format(
"##Time ({})",
size_t(
id)).c_str(), 5,
201 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
203 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
204 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
205 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
206 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
207 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
208 ImGui::TableHeadersRow();
210 ImGui::TableNextRow();
211 TextColoredIfExists(0,
"GpsCycle",
"uint");
212 TextColoredIfExists(3,
"YearUTC",
"uint");
213 ImGui::TableNextRow();
214 TextColoredIfExists(0,
"GpsWeek",
"uint");
215 TextColoredIfExists(3,
"MonthUTC",
"uint");
216 ImGui::TableNextRow();
217 TextColoredIfExists(0,
"GpsToW [s]",
"uint");
218 TextColoredIfExists(3,
"DayUTC",
"uint");
219 ImGui::TableNextRow();
220 TextColoredIfExists(3,
"HourUTC",
"uint");
221 ImGui::TableNextRow();
222 TextColoredIfExists(3,
"MinUTC",
"uint");
223 ImGui::TableNextRow();
224 TextColoredIfExists(3,
"SecUTC",
"double");
229 ImGui::TextUnformatted(
"Position information:");
231 gui::widgets::HelpMarker(
"You can either provide the position in ECEF coordinates\nor in latitude, longitude and altitude.");
232 if (ImGui::BeginTable(fmt::format(
"##Position ({})",
size_t(
id)).c_str(), 5,
233 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
235 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
236 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
237 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
238 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
239 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
240 ImGui::TableHeadersRow();
242 ImGui::TableNextRow();
243 TextColoredIfExists(0,
"Pos ECEF X [m]",
"double");
244 TextColoredIfExists(3,
"Latitude [deg]",
"double");
245 ImGui::TableNextRow();
246 TextColoredIfExists(0,
"Pos ECEF Y [m]",
"double");
247 TextColoredIfExists(3,
"Longitude [deg]",
"double");
248 ImGui::TableNextRow();
249 TextColoredIfExists(0,
"Pos ECEF Z [m]",
"double");
250 TextColoredIfExists(3,
"Altitude [m]",
"double");
255 ImGui::TextUnformatted(
"Attitude information:");
258 if (ImGui::BeginTable(fmt::format(
"##Attitude ({})",
size_t(
id)).c_str(), 5,
259 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX))
261 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
262 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
263 ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed);
264 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
265 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
266 ImGui::TableHeadersRow();
268 ImGui::TableNextRow();
269 TextColoredIfExists(0,
"Roll [deg]",
"double");
270 TextColoredIfExists(3,
"n_Quat_b w",
"double");
271 ImGui::TableNextRow();
272 TextColoredIfExists(0,
"Pitch [deg]",
"double");
273 TextColoredIfExists(3,
"n_Quat_b x",
"double");
274 ImGui::TableNextRow();
275 TextColoredIfExists(0,
"Yaw [deg]",
"double");
276 TextColoredIfExists(3,
"n_Quat_b y",
"double");
277 ImGui::TableNextRow();
278 TextColoredIfExists(3,
"n_Quat_b z",
"double");
295 ?
"Center/Tangential position"
307 ImGui::SetNextItemWidth(columnWidth);
317 ImGui::SetNextItemWidth(columnWidth);
327 ImGui::SetNextItemWidth(columnWidth);
337 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
338 ImGui::TextUnformatted(
"Orientation (Roll, Pitch, Yaw)");
342 ImGui::SetNextItemWidth(columnWidth);
350 ImGui::SetNextItemWidth(columnWidth);
358 ImGui::SetNextItemWidth(columnWidth);
366 ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x);
367 ImGui::TextUnformatted(
"Velocity (North, East, Down)");
371 if (ImGui::BeginTable(fmt::format(
"CircularOrRoseTrajectory##{}",
size_t(
id)).c_str(), 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX))
373 ImGui::TableNextColumn();
374 ImGui::SetNextItemWidth(columnWidth);
382 ImGui::TableNextColumn();
383 ImGui::SetNextItemWidth(columnWidth);
384 if (ImGui::InputDouble(fmt::format(
"Horizontal speed##{}",
size_t(
id)).c_str(), &
_trajectoryHorizontalSpeed, 0.0, 0.0,
"%.3f m/s"))
391 ImGui::TableNextColumn();
392 ImGui::SetNextItemWidth(columnWidth);
402 ImGui::TableNextColumn();
403 ImGui::SetNextItemWidth(columnWidth);
404 if (ImGui::InputDouble(fmt::format(
"Vertical speed (Up)##{}",
size_t(
id)).c_str(), &
_trajectoryVerticalSpeed, 0.0, 0.0,
"%.3f m/s"))
411 ImGui::TableNextColumn();
412 auto tableStartX = ImGui::GetCursorPosX();
429 ImGui::SetItemDefaultFocus();
434 ImGui::SetCursorPosX(tableStartX + columnWidth * 2.0F + ImGui::GetStyle().ItemSpacing.x * 1.0F);
436 ImGui::TableNextColumn();
440 ImGui::TableNextColumn();
441 ImGui::SetNextItemWidth(columnWidth);
442 if (ImGui::DragInt(fmt::format(
"Osc Frequency##{}",
size_t(
id)).c_str(), &
_circularHarmonicFrequency, 1.0F, 0, 100,
"%d [cycles/rev]"))
450 "The frequency is in units [cycles per revolution].");
452 ImGui::TableNextColumn();
453 ImGui::SetNextItemWidth(columnWidth);
462 "This factor determines the amplitude of the oscillation\n"
463 "with respect to the radius of the circle.");
467 ImGui::TableNextColumn();
468 ImGui::SetNextItemWidth(columnWidth);
469 if (
ImGui::InputIntL(fmt::format(
"n (angular freq.)##{}",
size_t(
id)).c_str(), &
_rosePetNum, 1.0, std::numeric_limits<int>::max(), 1, 1))
476 ImGui::TableNextColumn();
477 ImGui::SetNextItemWidth(columnWidth);
487 ImGui::TextUnformatted(
"Angular frequency k=n/d, n,d = natural numbers. In case of d=1,\n"
488 "for even k number of petals is 2*k, for odd k, number of petals is k.\n"
489 "Adjusts the integration limits of the incomplete elliptical integral\n"
490 "of the second kind. If k is rational (d >1), the correct limit needs \n"
491 "to be choosen depending on the symmetry (petals) of the figure.");
492 float width = 500.0F;
494 ImGui::TextUnformatted(
"Graphic by Jason Davies, CC BY-SA 3.0,\nhttps://commons.wikimedia.org/w/index.php?curid=30515231");
506 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
512 if (ImGui::RadioButton(fmt::format(
"##simulationStopConditionDuration{}",
size_t(
id)).c_str(), &simulationStopCondition,
static_cast<int>(
StopCondition::Duration)))
522 ImGui::SetNextItemWidth(columnWidth);
531 if (ImGui::RadioButton(fmt::format(
"##simulationStopConditionDistanceOrCirclesOrRoses{}",
size_t(
id)).c_str(), &simulationStopCondition,
static_cast<int>(
StopCondition::DistanceOrCirclesOrRoses)))
543 ImGui::SetNextItemWidth(columnWidth);
553 ImGui::SetNextItemWidth(columnWidth);
563 ImGui::SetNextItemWidth(columnWidth);
574 ImGui::SetNextItemOpen(
false, ImGuiCond_FirstUseEver);
575 if (ImGui::TreeNode(
"Simulation models"))
579 ImGui::TextUnformatted(fmt::format(
"Spline (current knots {})",
_splines.x.size()).c_str());
582 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
583 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"))
594 ImGui::TextUnformatted(fmt::format(
"Spline (current knots {})",
_splines.x.size()).c_str());
597 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
607 ImGui::TextUnformatted(
"Measured acceleration");
610 ImGui::SetNextItemWidth(columnWidth - ImGui::GetStyle().IndentSpacing);
629 ImGui::TextUnformatted(
"Measured angular rates");
685 j[
"splineSampleInterval"] =
_splines.sampleInterval;
702 if (j.contains(
"startTimeSource"))
706 if (j.contains(
"startTimeEditFormat"))
710 if (j.contains(
"startTime"))
715 if (j.contains(
"imuInternalFrequency"))
719 if (j.contains(
"imuFrequency"))
723 if (j.contains(
"gnssFrequency"))
728 if (j.contains(
"trajectoryType"))
741 if (j.contains(
"startPosition"))
745 if (j.contains(
"fixedTrajectoryStartOrientation"))
749 if (j.contains(
"n_linearTrajectoryStartVelocity"))
753 if (j.contains(
"circularHarmonicFrequency"))
757 if (j.contains(
"circularHarmonicAmplitudeFactor"))
761 if (j.contains(
"trajectoryHorizontalSpeed"))
765 if (j.contains(
"trajectoryVerticalSpeed"))
769 if (j.contains(
"trajectoryRadius"))
773 if (j.contains(
"trajectoryRotationAngle"))
777 if (j.contains(
"trajectoryDirection"))
781 if (j.contains(
"rosePetNum"))
785 if (j.contains(
"rosePetDenom"))
790 if (j.contains(
"simulationStopCondition"))
794 if (j.contains(
"simulationDuration"))
798 if (j.contains(
"linearTrajectoryDistanceForStop"))
802 if (j.contains(
"circularTrajectoryCircleCountForStop"))
806 if (j.contains(
"roseTrajectoryCountForStop"))
811 if (j.contains(
"splineSampleInterval"))
813 j.at(
"splineSampleInterval").get_to(
_splines.sampleInterval);
815 if (j.contains(
"roseStepLengthMax"))
819 if (j.contains(
"gravitationModel"))
823 if (j.contains(
"coriolisAccelerationEnabled"))
827 if (j.contains(
"centrifgalAccelerationEnabled"))
831 if (j.contains(
"angularRateEarthRotationEnabled"))
835 if (j.contains(
"angularRateTransportRateEnabled"))
840 if (j.contains(
"Imu"))
848 auto gpsCycleIter = std::ranges::find(description,
"GpsCycle");
849 auto gpsWeekIter = std::ranges::find(description,
"GpsWeek");
850 auto gpsTowIter = std::ranges::find(description,
"GpsToW [s]");
851 if (gpsCycleIter != description.end() && gpsWeekIter != description.end() && gpsTowIter != description.end())
853 const auto* gpsCycle = std::get_if<double>(&line.at(
static_cast<size_t>(gpsCycleIter - description.begin())));
854 const auto* gpsWeek = std::get_if<double>(&line.at(
static_cast<size_t>(gpsWeekIter - description.begin())));
855 const auto* gpsTow = std::get_if<double>(&line.at(
static_cast<size_t>(gpsTowIter - description.begin())));
856 if (gpsCycle && gpsWeek && gpsTow)
858 return InsTime{
static_cast<int32_t
>(*gpsCycle),
static_cast<int32_t
>(*gpsWeek), *gpsTow };
863 auto yearUTCIter = std::ranges::find(description,
"YearUTC");
864 auto monthUTCIter = std::ranges::find(description,
"MonthUTC");
865 auto dayUTCIter = std::ranges::find(description,
"DayUTC");
866 auto hourUTCIter = std::ranges::find(description,
"HourUTC");
867 auto minUTCIter = std::ranges::find(description,
"MinUTC");
868 auto secUTCIter = std::ranges::find(description,
"SecUTC");
869 if (yearUTCIter != description.end() && monthUTCIter != description.end() && dayUTCIter != description.end()
870 && hourUTCIter != description.end() && minUTCIter != description.end() && secUTCIter != description.end())
872 const auto* yearUTC = std::get_if<double>(&line.at(
static_cast<size_t>(yearUTCIter - description.begin())));
873 const auto* monthUTC = std::get_if<double>(&line.at(
static_cast<size_t>(monthUTCIter - description.begin())));
874 const auto* dayUTC = std::get_if<double>(&line.at(
static_cast<size_t>(dayUTCIter - description.begin())));
875 const auto* hourUTC = std::get_if<double>(&line.at(
static_cast<size_t>(hourUTCIter - description.begin())));
876 const auto* minUTC = std::get_if<double>(&line.at(
static_cast<size_t>(minUTCIter - description.begin())));
877 const auto* secUTC = std::get_if<double>(&line.at(
static_cast<size_t>(secUTCIter - description.begin())));
878 if (yearUTC && monthUTC && dayUTC && hourUTC && minUTC && secUTC)
881 static_cast<uint16_t
>(*yearUTC),
static_cast<uint16_t
>(*monthUTC),
static_cast<uint16_t
>(*dayUTC),
882 static_cast<uint16_t
>(*hourUTC),
static_cast<uint16_t
>(*minUTC), *secUTC,
UTC
888 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the time.",
nameId());
894 auto posXIter = std::ranges::find(description,
"Pos ECEF X [m]");
895 auto posYIter = std::ranges::find(description,
"Pos ECEF Y [m]");
896 auto posZIter = std::ranges::find(description,
"Pos ECEF Z [m]");
897 if (posXIter != description.end() && posYIter != description.end() && posZIter != description.end())
899 const auto* posX = std::get_if<double>(&line.at(
static_cast<size_t>(posXIter - description.begin())));
900 const auto* posY = std::get_if<double>(&line.at(
static_cast<size_t>(posYIter - description.begin())));
901 const auto* posZ = std::get_if<double>(&line.at(
static_cast<size_t>(posZIter - description.begin())));
902 if (posX && posY && posZ && !std::isnan(*posX) && !std::isnan(*posY) && !std::isnan(*posZ))
904 return Eigen::Vector3d{ *posX, *posY, *posZ };
909 auto latIter = std::ranges::find(description,
"Latitude [deg]");
910 auto lonIter = std::ranges::find(description,
"Longitude [deg]");
911 auto altIter = std::ranges::find(description,
"Altitude [m]");
912 if (latIter != description.end() && lonIter != description.end() && altIter != description.end())
914 const auto* lat = std::get_if<double>(&line.at(
static_cast<size_t>(latIter - description.begin())));
915 const auto* lon = std::get_if<double>(&line.at(
static_cast<size_t>(lonIter - description.begin())));
916 const auto* alt = std::get_if<double>(&line.at(
static_cast<size_t>(altIter - description.begin())));
917 if (lat && lon && alt && !std::isnan(*lat) && !std::isnan(*lon) && !std::isnan(*alt))
924 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the position.",
nameId());
930 auto rollIter = std::ranges::find(description,
"Roll [deg]");
931 auto pitchIter = std::ranges::find(description,
"Pitch [deg]");
932 auto yawIter = std::ranges::find(description,
"Yaw [deg]");
933 if (rollIter != description.end() && pitchIter != description.end() && yawIter != description.end())
935 const auto*
roll = std::get_if<double>(&line.at(
static_cast<size_t>(rollIter - description.begin())));
936 const auto*
pitch = std::get_if<double>(&line.at(
static_cast<size_t>(pitchIter - description.begin())));
937 const auto*
yaw = std::get_if<double>(&line.at(
static_cast<size_t>(yawIter - description.begin())));
945 auto quatWIter = std::ranges::find(description,
"n_Quat_b w");
946 auto quatXIter = std::ranges::find(description,
"n_Quat_b x");
947 auto quatYIter = std::ranges::find(description,
"n_Quat_b y");
948 auto quatZIter = std::ranges::find(description,
"n_Quat_b z");
949 if (quatWIter != description.end() && quatXIter != description.end() && quatYIter != description.end() && quatZIter != description.end())
951 const auto* w = std::get_if<double>(&line.at(
static_cast<size_t>(quatWIter - description.begin())));
952 const auto*
x = std::get_if<double>(&line.at(
static_cast<size_t>(quatXIter - description.begin())));
953 const auto*
y = std::get_if<double>(&line.at(
static_cast<size_t>(quatYIter - description.begin())));
954 const auto*
z = std::get_if<double>(&line.at(
static_cast<size_t>(quatZIter - description.begin())));
955 if (w &&
x &&
y &&
z && !std::isnan(*w) && !std::isnan(*
x) && !std::isnan(*
y) && !std::isnan(*
z))
957 return Eigen::Quaterniond{ *w, *
x, *
y, *
z };
962 LOG_ERROR(
"{}: Could not find the necessary columns in the CSV file to determine the attitude.",
nameId());
968 std::vector<long double> splineTime;
970 auto unwrapAngle = [](
auto angle,
auto prevAngle,
auto rangeMax) {
971 auto x = angle - prevAngle;
972 x = std::fmod(
x + rangeMax, 2 * rangeMax);
979 return prevAngle +
x;
984 splineTime.push_back(-30.0);
985 splineTime.push_back(-20.0);
986 splineTime.push_back(-10.0);
987 splineTime.push_back(0.0);
993 Eigen::Vector3d e_startPosition =
_startPosition.e_position.cast<
double>();
994 std::vector<long double> X(splineTime.size(), e_startPosition[0]);
995 std::vector<long double> Y(splineTime.size(), e_startPosition[1]);
996 std::vector<long double> Z(splineTime.size(), e_startPosition[2]);
1001 _splines.x.setPoints(splineTime, X);
1002 _splines.y.setPoints(splineTime, Y);
1003 _splines.z.setPoints(splineTime, Z);
1005 _splines.roll.setPoints(splineTime, Roll);
1006 _splines.pitch.setPoints(splineTime, Pitch);
1007 _splines.yaw.setPoints(splineTime, Yaw);
1016 size_t nOverhead =
static_cast<size_t>(std::round(1.0 /
_splines.sampleInterval)) + 1;
1018 splineTime = std::vector<long double>(nOverhead, 0.0);
1019 std::vector<long double> splineX(nOverhead, e_startPosition[0]);
1020 std::vector<long double> splineY(nOverhead, e_startPosition[1]);
1021 std::vector<long double> splineZ(nOverhead, e_startPosition[2]);
1022 std::vector<long double> splineRoll(nOverhead,
roll);
1023 std::vector<long double> splinePitch(nOverhead,
pitch);
1024 std::vector<long double> splineYaw(nOverhead,
yaw);
1030 auto f = [](
const Eigen::Vector<double, 6>&
y,
const Eigen::Vector3d& n_acceleration) {
1031 Eigen::Vector<double, 6> y_dot;
1043 for (
size_t i = 2; i <= nOverhead; i++)
1045 Eigen::Vector<double, 6>
y;
1046 y << lla_lastPosition,
1049 y += -
_splines.sampleInterval * f(
y, Eigen::Vector3d::Zero());
1050 lla_lastPosition =
y.head<3>();
1054 splineTime.at(nOverhead - i) = -
_splines.sampleInterval *
static_cast<double>(i - 1);
1055 splineX.at(nOverhead - i) = e_position(0);
1056 splineY.at(nOverhead - i) = e_position(1);
1057 splineZ.at(nOverhead - i) = e_position(2);
1061 for (
size_t i = 1;; i++)
1063 Eigen::Vector<double, 6>
y;
1064 y << lla_lastPosition,
1067 y +=
_splines.sampleInterval * f(
y, Eigen::Vector3d::Zero());
1068 lla_lastPosition =
y.head<3>();
1072 auto simTime =
_splines.sampleInterval *
static_cast<double>(i);
1073 splineTime.push_back(simTime);
1074 splineX.push_back(e_position(0));
1075 splineY.push_back(e_position(1));
1076 splineZ.push_back(e_position(2));
1077 splineRoll.push_back(
roll);
1078 splinePitch.push_back(
pitch);
1079 splineYaw.push_back(
yaw);
1089 lla_lastPosition(0), lla_lastPosition(1));
1090 auto distance = std::sqrt(std::pow(horizontalDistance, 2) + std::pow(
_startPosition.altitude() - lla_lastPosition(2), 2))
1099 _splines.x.setPoints(splineTime, splineX);
1100 _splines.y.setPoints(splineTime, splineY);
1101 _splines.z.setPoints(splineTime, splineZ);
1103 _splines.roll.setPoints(splineTime, splineRoll);
1104 _splines.pitch.setPoints(splineTime, splinePitch);
1105 _splines.yaw.setPoints(splineTime, splineYaw);
1109 double simDuration{};
1120 constexpr double OFFSET = 1.0;
1122 for (
size_t i = 0; i <= static_cast<size_t>(std::round((simDuration + 2.0 * OFFSET) /
_splines.sampleInterval)); i++)
1124 splineTime.push_back(
_splines.sampleInterval *
static_cast<double>(i) - OFFSET);
1126 LOG_DATA(
"{}: Sim Time [{:.3f}, {:.3f}] with dt = {:.3f} (simDuration = {:.3f})",
nameId(),
1127 static_cast<double>(splineTime.front()),
static_cast<double>(splineTime.back()),
static_cast<double>(splineTime.at(1) - splineTime.at(0)), simDuration);
1129 std::vector<long double> splineX(splineTime.size());
1130 std::vector<long double> splineY(splineTime.size());
1131 std::vector<long double> splineZ(splineTime.size());
1136 Eigen::Quaterniond e_quatCenter_n =
trafo::e_Quat_n(lla_origin(0), lla_origin(1));
1138 for (uint64_t i = 0; i < splineTime.size(); i++)
1149 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1151 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1153 splineX[i] = e_position[0];
1154 splineY[i] = e_position[1];
1155 splineZ[i] = e_position[2];
1158 _splines.x.setPoints(splineTime, splineX);
1159 _splines.y.setPoints(splineTime, splineY);
1160 _splines.z.setPoints(splineTime, splineZ);
1182 for (
int i = 2; i <= n; i++)
1184 if (n % i == 0 && d % i == 0)
1192 auto isOdd = [](
auto a) {
return static_cast<int>(a) % 2 != 0; };
1193 auto isEven = [](
auto a) {
return static_cast<int>(a) % 2 == 0; };
1195 double integrationFactor = 0.0;
1198 if (isOdd(n)) { integrationFactor =
static_cast<double>(d); }
1199 else { integrationFactor = 2.0 *
static_cast<double>(d); }
1203 if (isEven(n)) { integrationFactor =
static_cast<double>(d); }
1204 else { integrationFactor = 2.0 *
static_cast<double>(d); }
1208 splineTime.resize(nVirtPoints);
1209 std::vector<long double> splineX(splineTime.size());
1210 std::vector<long double> splineY(splineTime.size());
1211 std::vector<long double> splineZ(splineTime.size());
1218 double dPhi = 0.001;
1219 double maxPhi = std::numeric_limits<double>::infinity();
1231 for (
double phi = dPhi; phi <= maxPhi + static_cast<double>(nVirtPoints) * dPhi; phi += dPhi)
1234 double dL = length - lengthOld;
1251 splineTime.push_back(time);
1256 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1257 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1261 splineX.push_back(e_position[0]);
1262 splineY.push_back(e_position[1]);
1263 splineZ.push_back(e_position[2]);
1267 LOG_TRACE(
"{}: Rose figure simulation duration: {:8.6}s | l={:8.6}m",
nameId(), time, length);
1277 maxPhi = integrationFactor * M_PI + 1e-15;
1281 for (
size_t i = 0; i < nVirtPoints; i++)
1283 double phi = maxPhi -
static_cast<double>(i) * dPhi;
1286 splineTime[nVirtPoints - i - 1] = time;
1292 Eigen::Vector3d e_relativePosition = e_quatCenter_n * n_relativePosition;
1293 Eigen::Vector3d e_position = e_origin + e_relativePosition;
1297 splineX[nVirtPoints - i - 1] = e_position[0];
1298 splineY[nVirtPoints - i - 1] = e_position[1];
1299 splineZ[nVirtPoints - i - 1] = e_position[2];
1302 _splines.x.setPoints(splineTime, splineX);
1303 _splines.y.setPoints(splineTime, splineY);
1304 _splines.z.setPoints(splineTime, splineZ);
1309 csvData && csvData->v->lines.size() >= 2)
1311 if (
auto startTime =
getTimeFromCsvLine(csvData->v->lines.front(), csvData->v->description))
1313 if (!startTime) {
return false; }
1317 constexpr size_t nVirtPoints = 0;
1318 splineTime.resize(nVirtPoints);
1319 std::vector<long double> splineX(splineTime.size());
1320 std::vector<long double> splineY(splineTime.size());
1321 std::vector<long double> splineZ(splineTime.size());
1322 std::vector<long double> splineRoll(splineTime.size());
1323 std::vector<long double> splinePitch(splineTime.size());
1324 std::vector<long double> splineYaw(splineTime.size());
1326 for (
size_t i = 0; i < csvData->v->lines.size(); i++)
1331 LOG_ERROR(
"{}: Data in time column not found in line {}",
nameId(), i + 2);
1335 auto time =
static_cast<double>((*insTime -
_startTime).count());
1340 LOG_ERROR(
"{}: Data in position column not found in line {}",
nameId(), i + 2);
1348 LOG_ERROR(
"{}: Data in attitude column not found in line {}",
nameId(), i + 2);
1353 splineTime.push_back(time);
1354 splineX.push_back(e_pos->x());
1355 splineY.push_back(e_pos->y());
1356 splineZ.push_back(e_pos->z());
1360 splineRoll.push_back(i > 0 ? unwrapAngle(rpy(0), splineRoll.back(), M_PI) : rpy(0));
1361 splinePitch.push_back(i > 0 ? unwrapAngle(rpy(1), splinePitch.back(), M_PI_2) : rpy(1));
1362 splineYaw.push_back(i > 0 ? unwrapAngle(rpy(2), splineYaw.back(), M_PI) : rpy(2));
1367 auto dt =
static_cast<double>(splineTime[nVirtPoints + 1] - splineTime[nVirtPoints]);
1368 for (
size_t i = 0; i < nVirtPoints; i++)
1371 splineTime[nVirtPoints - i - 1] = splineTime[nVirtPoints - i] - h;
1372 splineX[nVirtPoints - i - 1] = splineX[nVirtPoints - i] - h * (splineX[nVirtPoints + 1] - splineX[nVirtPoints]) / dt;
1373 splineY[nVirtPoints - i - 1] = splineY[nVirtPoints - i] - h * (splineY[nVirtPoints + 1] - splineY[nVirtPoints]) / dt;
1374 splineZ[nVirtPoints - i - 1] = splineZ[nVirtPoints - i] - h * (splineZ[nVirtPoints + 1] - splineZ[nVirtPoints]) / dt;
1375 splineRoll[nVirtPoints - i - 1] = splineRoll[nVirtPoints - i] - h * (splineRoll[nVirtPoints + 1] - splineRoll[nVirtPoints]) / dt;
1376 splinePitch[nVirtPoints - i - 1] = splinePitch[nVirtPoints - i] - h * (splinePitch[nVirtPoints + 1] - splinePitch[nVirtPoints]) / dt;
1377 splineYaw[nVirtPoints - i - 1] = splineYaw[nVirtPoints - i] - h * (splineYaw[nVirtPoints + 1] - splineYaw[nVirtPoints]) / dt;
1378 splineTime.push_back(splineTime[splineX.size() - 1] + h);
1379 splineX.push_back(splineX[splineX.size() - 1] + h * (splineX[splineX.size() - 1] - splineX[splineX.size() - 2]) / dt);
1380 splineY.push_back(splineY[splineY.size() - 1] + h * (splineY[splineY.size() - 1] - splineY[splineY.size() - 2]) / dt);
1381 splineZ.push_back(splineZ[splineZ.size() - 1] + h * (splineZ[splineZ.size() - 1] - splineZ[splineZ.size() - 2]) / dt);
1382 splineRoll.push_back(splineRoll[splineRoll.size() - 1] + h * (splineRoll[splineRoll.size() - 1] - splineRoll[splineRoll.size() - 2]) / dt);
1383 splinePitch.push_back(splinePitch[splinePitch.size() - 1] + h * (splinePitch[splinePitch.size() - 1] - splinePitch[splinePitch.size() - 2]) / dt);
1384 splineYaw.push_back(splineYaw[splineYaw.size() - 1] + h * (splineYaw[splineYaw.size() - 1] - splineYaw[splineYaw.size() - 2]) / dt);
1387 _splines.x.setPoints(splineTime, splineX);
1388 _splines.y.setPoints(splineTime, splineY);
1389 _splines.z.setPoints(splineTime, splineZ);
1391 _splines.roll.setPoints(splineTime, splineRoll);
1392 _splines.pitch.setPoints(splineTime, splinePitch);
1393 _splines.yaw.setPoints(splineTime, splineYaw);
1397 LOG_ERROR(
"{}: Can't calculate the data without a connected CSV file with at least two datasets",
nameId());
1404 std::vector<long double> splineRoll(splineTime.size());
1405 std::vector<long double> splinePitch(splineTime.size());
1406 std::vector<long double> splineYaw(splineTime.size());
1408 for (uint64_t i = 0; i < splineTime.size(); i++)
1410 Eigen::Vector3d e_pos{
static_cast<double>(
_splines.x(splineTime[i])),
1411 static_cast<double>(
_splines.y(splineTime[i])),
1412 static_cast<double>(
_splines.z(splineTime[i])) };
1413 Eigen::Vector3d e_vel{
static_cast<double>(
_splines.x.derivative(1, splineTime[i])),
1414 static_cast<double>(
_splines.y.derivative(1, splineTime[i])),
1415 static_cast<double>(
_splines.z.derivative(1, splineTime[i])) };
1418 Eigen::Vector3d n_velocity =
trafo::n_Quat_e(lla_position(0), lla_position(1)) * e_vel;
1424 Eigen::Vector3d e_normalVectorCurrentPosition{ std::cos(lla_position(0)) * std::cos(lla_position(1)),
1425 std::cos(lla_position(0)) * std::sin(lla_position(1)),
1426 std::sin(lla_position(0)) };
1430 splineYaw[i] = i > 0 ? unwrapAngle(
yaw, splineYaw[i - 1], M_PI) :
yaw;
1431 splineRoll[i] = 0.0;
1436 _splines.roll.setPoints(splineTime, splineRoll);
1437 _splines.pitch.setPoints(splineTime, splinePitch);
1438 _splines.yaw.setPoints(splineTime, splineYaw);
1475 csvData && !csvData->v->lines.empty())
1477 if (
auto startTime =
getTimeFromCsvLine(csvData->v->lines.front(), csvData->v->description))
1479 if (!startTime) {
return false; }
1486 LOG_ERROR(
"{}: Can't reset the ImuSimulator without a connected CSV file",
nameId());
1492 std::time_t t = std::time(
nullptr);
1493 std::tm* now = std::localtime(&t);
1495 _startTime =
InsTime{
static_cast<uint16_t
>(now->tm_year + 1900),
static_cast<uint16_t
>(now->tm_mon),
static_cast<uint16_t
>(now->tm_mday),
1496 static_cast<uint16_t
>(now->tm_hour),
static_cast<uint16_t
>(now->tm_min),
static_cast<long double>(now->tm_sec) };
1519 lla_position(0), lla_position(1));
1520 auto distance = std::sqrt(std::pow(horizontalDistance, 2) + std::pow(
_startPosition.altitude() - lla_position(2), 2));
1527 return time > simDuration;
1549 auto obs = std::make_shared<NodeData>();
1550 obs->insTime =
_startTime + std::chrono::duration<double>(imuUpdateTime);
1554 auto obs = std::make_shared<ImuObsSimulated>(
_imuPos);
1555 obs->insTime =
_startTime + std::chrono::duration<double>(imuUpdateTime);
1556 LOG_DATA(
"{}: Simulated IMU data for time [{}] (_imuUpdateCnt {}, _imuInternalUpdateCnt {})",
nameId(), obs->insTime.toYMDHMS(),
1560 Eigen::Vector3d p_deltaVel = Eigen::Vector3d::Zero();
1561 Eigen::Vector3d p_deltaTheta = Eigen::Vector3d::Zero();
1563 double imuInternalUpdateTime = 0.0;
1566 LOG_DATA(
"{}: Simulated internal IMU data for time [{}] (_imuUpdateCnt {}, _imuInternalUpdateCnt {})",
nameId(),
1571 LOG_DATA(
"{}: [{:8.3f}] lla_position = {}°, {}°, {} m",
nameId(), imuInternalUpdateTime,
rad2deg(lla_position(0)),
rad2deg(lla_position(1)), lla_position(2));
1573 Eigen::Quaterniond n_Quat_e =
trafo::n_Quat_e(lla_position(0), lla_position(1));
1575 Eigen::Vector3d n_vel =
n_calcVelocity(imuInternalUpdateTime, n_Quat_e);
1576 LOG_DATA(
"{}: [{:8.3f}] n_vel = {} [m/s]",
nameId(), imuInternalUpdateTime, n_vel.transpose());
1584 LOG_DATA(
"{}: [{:8.3f}] n_omega_ie = {} [rad/s]",
nameId(), imuInternalUpdateTime, n_omega_ie.transpose());
1586 LOG_DATA(
"{}: [{:8.3f}] R_N = {} [m]",
nameId(), imuInternalUpdateTime, R_N);
1588 LOG_DATA(
"{}: [{:8.3f}] R_E = {} [m]",
nameId(), imuInternalUpdateTime, R_E);
1590 LOG_DATA(
"{}: [{:8.3f}] n_omega_en = {} [rad/s]",
nameId(), imuInternalUpdateTime, n_omega_en.transpose());
1595 Eigen::Vector3d n_trajectoryAccel =
n_calcTrajectoryAccel(imuInternalUpdateTime, n_Quat_e, lla_position, n_vel);
1596 LOG_DATA(
"{}: [{:8.3f}] n_trajectoryAccel = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_trajectoryAccel.transpose());
1599 Eigen::Vector3d n_accel = n_trajectoryAccel;
1603 LOG_DATA(
"{}: [{:8.3f}] n_coriolisAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_coriolisAcceleration.transpose());
1604 n_accel += n_coriolisAcceleration;
1610 n_accel -= n_gravitation;
1615 LOG_DATA(
"{}: [{:8.3f}] e_centrifugalAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, e_centrifugalAcceleration.transpose());
1616 Eigen::Vector3d n_centrifugalAcceleration = n_Quat_e * e_centrifugalAcceleration;
1617 LOG_DATA(
"{}: [{:8.3f}] n_centrifugalAcceleration = {} [m/s^2]",
nameId(), imuInternalUpdateTime, n_centrifugalAcceleration.transpose());
1618 n_accel += n_centrifugalAcceleration;
1622 Eigen::Vector3d p_accel =
_imuPos.p_quat_b() * b_Quat_n * n_accel;
1623 LOG_DATA(
"{}: [{:8.3f}] p_accel = {} [m/s^2]",
nameId(), imuInternalUpdateTime, p_accel.transpose());
1627 Eigen::Vector3d n_omega_nb =
n_calcOmega_nb(imuInternalUpdateTime, Eigen::Vector3d{
roll,
pitch,
yaw }, b_Quat_n.conjugate());
1630 Eigen::Vector3d n_omega_ib = n_omega_nb;
1633 n_omega_ib += n_omega_ie;
1637 n_omega_ib += n_omega_en;
1643 Eigen::Vector3d p_omega_ip =
_imuPos.p_quat_b() * b_Quat_n * n_omega_ib;
1644 LOG_DATA(
"{}: [{:8.3f}] p_omega_ip = {} [rad/s]",
nameId(), imuInternalUpdateTime, p_omega_ip.transpose());
1648 obs->p_acceleration = p_accel.cast<
double>();
1649 obs->p_angularRate = p_omega_ip.cast<
double>();
1652 Eigen::Quaterniond e_Quat_n = n_Quat_e.conjugate();
1654 obs->n_accelDynamics = n_trajectoryAccel.cast<
double>();
1655 obs->n_angularRateDynamics = n_omega_nb.cast<
double>();
1657 obs->e_accelDynamics = (e_Quat_n * n_trajectoryAccel).cast<double>();
1658 obs->e_angularRateDynamics = (e_Quat_n * n_omega_nb).cast<double>();
1672 }
while (imuInternalUpdateTime + 1e-6 < imuUpdateTime);
1675 obs->dvel = p_deltaVel.cast<
double>();
1676 obs->dtheta = p_deltaTheta.cast<
double>();
1677 LOG_DATA(
"{}: dtime = {}, dvel = {}, dtheta = {}",
nameId(), obs->dtime, obs->dvel.transpose(), obs->dtheta.transpose());
1700 auto obs = std::make_shared<NodeData>();
1701 obs->insTime =
_startTime + std::chrono::duration<double>(gnssUpdateTime);
1704 auto obs = std::make_shared<PosVelAtt>();
1705 obs->insTime =
_startTime + std::chrono::duration<double>(gnssUpdateTime);
1706 LOG_DATA(
"{}: Simulating GNSS data for time [{}]",
nameId(), obs->insTime.toYMDHMS());
1709 LOG_DATA(
"{}: [{:8.3f}] lla_position = {}°, {}°, {} m",
nameId(), gnssUpdateTime,
rad2deg(lla_position(0)),
rad2deg(lla_position(1)), lla_position(2));
1710 Eigen::Quaterniond n_Quat_e =
trafo::n_Quat_e(lla_position(0), lla_position(1));
1711 Eigen::Vector3d n_vel =
n_calcVelocity(gnssUpdateTime, n_Quat_e);
1712 LOG_DATA(
"{}: [{:8.3f}] n_vel = {} [m/s]",
nameId(), gnssUpdateTime, n_vel.transpose());
1729 static_cast<double>(
_splines.roll(time)),
1730 static_cast<double>(
_splines.pitch(time)),
1731 static_cast<double>(
_splines.yaw(time))
1737 Eigen::Vector3d e_pos(
static_cast<double>(
_splines.x(time)),
1738 static_cast<double>(
_splines.y(time)),
1739 static_cast<double>(
_splines.z(time)));
1745 Eigen::Vector3d e_vel(
static_cast<double>(
_splines.x.derivative(1, time)),
1746 static_cast<double>(
_splines.y.derivative(1, time)),
1747 static_cast<double>(
_splines.z.derivative(1, time)));
1748 return n_Quat_e * e_vel;
1752 const Eigen::Quaterniond& n_Quat_e,
1753 const Eigen::Vector3d& lla_position,
1754 const Eigen::Vector3d& n_velocity)
const
1756 Eigen::Vector3d e_accel(
static_cast<double>(
_splines.x.derivative(2, time)),
1757 static_cast<double>(
_splines.y.derivative(2, time)),
1758 static_cast<double>(
_splines.z.derivative(2, time)));
1759 Eigen::Quaterniond e_Quat_n = n_Quat_e.conjugate();
1760 Eigen::Vector3d e_vel = e_Quat_n * n_velocity;
1763 Eigen::Matrix3d n_DCM_dot_e = e_Quat_n.toRotationMatrix()
1769 Eigen::Matrix3d e_DCM_dot_n = n_DCM_dot_e.transpose();
1772 return e_DCM_dot_n * e_vel + n_Quat_e * e_accel;
1777 const auto& R = rollPitchYaw(0);
1778 const auto& P = rollPitchYaw(1);
1782 auto R_dot =
static_cast<double>(
_splines.roll.derivative(1, time));
1783 auto Y_dot =
static_cast<double>(
_splines.yaw.derivative(1, time));
1784 auto P_dot =
static_cast<double>(
_splines.pitch.derivative(1, time));
1786 auto C_3 = [](
auto R) {
1792 return Eigen::AngleAxisd{ -R, Eigen::Vector3d::UnitX() };
1794 auto C_2 = [](
auto P) {
1800 return Eigen::AngleAxisd{ -P, Eigen::Vector3d::UnitY() };
1806 Eigen::Vector3d b_omega_nb = Eigen::Vector3d{ R_dot, 0, 0 }
1807 + C_3(R) * Eigen::Vector3d{ 0, P_dot, 0 }
1808 + C_3(R) * C_2(P) * Eigen::Vector3d{ 0, 0, Y_dot };
1810 return n_Quat_b * b_omega_nb;
1826 return "Rose Figure";
1838 return "Clockwise (CW)";
1840 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.
std::string nameId() const
Node name and id.
std::string name
Name of the Node.
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
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'.
OutputPin * CreateOutputPin(Node *node, 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.
bool DeleteInputPin(InputPin &pin)
Deletes the input pin. Invalidates the pin reference given.
InputPin * CreateInputPin(Node *node, 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 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.