0.3.0
Loading...
Searching...
No Matches
ImuFusion.cpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#include "ImuFusion.hpp"
10
11#include "util/Logger.hpp"
12
14
19
20#include <imgui_internal.h>
26#include "util/Json.hpp"
27
29namespace nm = NAV::NodeManager;
31
32namespace NAV
33{
34/// @brief Write info to a json object
35/// @param[out] j Json output
36/// @param[in] data Object to read info from
37static void to_json(json& j, const PinData& data) // NOLINT(misc-use-anonymous-namespace)
38{
39 j = json{
40 // ---------------------------------------- Initialization -------------------------------------------
41 { "initAngularRateBias", data.initAngularRateBias },
42 { "initAngularRateBiasUnit", data.initAngularRateBiasUnit },
43 { "initAccelerationBias", data.initAccelerationBias },
44 { "initAccelerationBiasUnit", data.initAccelerationBiasUnit },
45 { "initCovarianceAngularRate", data.initCovarianceAngularRate },
46 { "initCovarianceAngularRateUnit", data.initCovarianceAngularRateUnit },
47 { "initCovarianceAcceleration", data.initCovarianceAcceleration },
48 { "initCovarianceAccelerationUnit", data.initCovarianceAccelerationUnit },
49 { "initCovarianceBiasAngRate", data.initCovarianceBiasAngRate },
50 { "initCovarianceBiasAngRateUnit", data.initCovarianceBiasAngRateUnit },
51 { "initCovarianceBiasAcc", data.initCovarianceBiasAcc },
52 { "initCovarianceBiasAccUnit", data.initCovarianceBiasAccUnit },
53 // ----------------------------------------- Process Noise -------------------------------------------
54 { "varBiasAccelerationNoise", data.varBiasAccelerationNoise },
55 { "varBiasAccelerationNoiseUnit", data.varBiasAccelerationNoiseUnit },
56 { "varBiasAngRateNoise", data.varBiasAngRateNoise },
57 { "varBiasAngRateNoiseUnit", data.varBiasAngRateNoiseUnit },
58 // --------------------------------------- Measurement Noise -----------------------------------------
59 { "measurementUncertaintyAngularRateUnit", data.measurementUncertaintyAngularRateUnit },
60 { "measurementUncertaintyAngularRate", data.measurementUncertaintyAngularRate },
61 { "measurementUncertaintyAccelerationUnit", data.measurementUncertaintyAccelerationUnit },
62 { "measurementUncertaintyAcceleration", data.measurementUncertaintyAcceleration },
63 };
64}
65/// @brief Read info from a json object
66/// @param[in] j Json variable to read info from
67/// @param[out] data Output object
68static void from_json(const json& j, PinData& data) // NOLINT(misc-use-anonymous-namespace)
69{
70 // ------------------------------------------ Initialization ---------------------------------------------
71 if (j.contains("initAngularRateBias"))
72 {
73 j.at("initAngularRateBias").get_to(data.initAngularRateBias);
74 }
75 if (j.contains("initAngularRateBiasUnit"))
76 {
77 j.at("initAngularRateBiasUnit").get_to(data.initAngularRateBiasUnit);
78 }
79 if (j.contains("initAccelerationBias"))
80 {
81 j.at("initAccelerationBias").get_to(data.initAccelerationBias);
82 }
83 if (j.contains("initAccelerationBiasUnit"))
84 {
85 j.at("initAccelerationBiasUnit").get_to(data.initAccelerationBiasUnit);
86 }
87 if (j.contains("initCovarianceAngularRate"))
88 {
89 j.at("initCovarianceAngularRate").get_to(data.initCovarianceAngularRate);
90 }
91 if (j.contains("initCovarianceAngularRateUnit"))
92 {
93 j.at("initCovarianceAngularRateUnit").get_to(data.initCovarianceAngularRateUnit);
94 }
95 if (j.contains("initCovarianceAcceleration"))
96 {
97 j.at("initCovarianceAcceleration").get_to(data.initCovarianceAcceleration);
98 }
99 if (j.contains("initCovarianceAccelerationUnit"))
100 {
101 j.at("initCovarianceAccelerationUnit").get_to(data.initCovarianceAccelerationUnit);
102 }
103 if (j.contains("initCovarianceBiasAngRate"))
104 {
105 j.at("initCovarianceBiasAngRate").get_to(data.initCovarianceBiasAngRate);
106 }
107 if (j.contains("initCovarianceBiasAngRateUnit"))
108 {
109 j.at("initCovarianceBiasAngRateUnit").get_to(data.initCovarianceBiasAngRateUnit);
110 }
111 if (j.contains("initCovarianceBiasAcc"))
112 {
113 j.at("initCovarianceBiasAcc").get_to(data.initCovarianceBiasAcc);
114 }
115 if (j.contains("initCovarianceBiasAccUnit"))
116 {
117 j.at("initCovarianceBiasAccUnit").get_to(data.initCovarianceBiasAccUnit);
118 }
119 // ------------------------------------------- Process Noise ---------------------------------------------
120 if (j.contains("varBiasAccelerationNoise"))
121 {
122 j.at("varBiasAccelerationNoise").get_to(data.varBiasAccelerationNoise);
123 }
124 if (j.contains("varBiasAccelerationNoiseUnit"))
125 {
126 j.at("varBiasAccelerationNoiseUnit").get_to(data.varBiasAccelerationNoiseUnit);
127 }
128 if (j.contains("varBiasAngRateNoise"))
129 {
130 j.at("varBiasAngRateNoise").get_to(data.varBiasAngRateNoise);
131 }
132 if (j.contains("varBiasAngRateNoiseUnit"))
133 {
134 j.at("varBiasAngRateNoiseUnit").get_to(data.varBiasAngRateNoiseUnit);
135 }
136 // ----------------------------------------- Measurement Noise -------------------------------------------
137 if (j.contains("measurementUncertaintyAngularRate"))
138 {
139 j.at("measurementUncertaintyAngularRate").get_to(data.measurementUncertaintyAngularRate);
140 }
141 if (j.contains("measurementUncertaintyAngularRateUnit"))
142 {
143 j.at("measurementUncertaintyAngularRateUnit").get_to(data.measurementUncertaintyAngularRateUnit);
144 }
145 if (j.contains("measurementUncertaintyAcceleration"))
146 {
147 j.at("measurementUncertaintyAcceleration").get_to(data.measurementUncertaintyAcceleration);
148 }
149 if (j.contains("measurementUncertaintyAccelerationUnit"))
150 {
151 j.at("measurementUncertaintyAccelerationUnit").get_to(data.measurementUncertaintyAccelerationUnit);
152 }
153}
154
155/// @brief Write info to a json object
156/// @param[out] j Json output
157/// @param[in] data Object to read info from
158static void to_json(json& j, const PinDataIRWKF& data) // NOLINT(misc-use-anonymous-namespace)
159{
160 j = json{
161 // ---------------------------------------- Initialization -------------------------------------------
162 { "initAngularRate", data.initAngularRate },
163 { "initAngularRateUnit", data.initAngularRateUnit },
164 { "initAcceleration", data.initAcceleration },
165 { "initAccelerationUnit", data.initAccelerationUnit },
166 { "initAngularAcc", data.initAngularAcc },
167 { "initAngularAccUnit", data.initAngularAccUnit },
168 { "initJerk", data.initJerk },
169 { "initJerkUnit", data.initJerkUnit },
170 { "initCovarianceAngularAcc", data.initCovarianceAngularAcc },
171 { "initCovarianceAngularAccUnit", data.initCovarianceAngularAccUnit },
172 { "initCovarianceJerk", data.initCovarianceJerk },
173 { "initCovarianceJerkUnit", data.initCovarianceJerkUnit },
174
175 // ----------------------------------------- Process Noise -------------------------------------------
176 { "varAngularAccNoise", data.varAngularAccNoise },
177 { "varAngularAccNoiseUnit", data.varAngularAccNoiseUnit },
178 { "varJerkNoise", data.varJerkNoise },
179 { "varJerkNoiseUnit", data.varJerkNoiseUnit },
180 };
181}
182/// @brief Read info from a json object
183/// @param[in] j Json variable to read info from
184/// @param[out] data Output object
185static void from_json(const json& j, PinDataIRWKF& data) // NOLINT(misc-use-anonymous-namespace)
186{
187 // ------------------------------------------ Initialization ---------------------------------------------
188 if (j.contains("initAngularRate"))
189 {
190 j.at("initAngularRate").get_to(data.initAngularRate);
191 }
192 if (j.contains("initAngularRateUnit"))
193 {
194 j.at("initAngularRateUnit").get_to(data.initAngularRateUnit);
195 }
196 if (j.contains("initAcceleration"))
197 {
198 j.at("initAcceleration").get_to(data.initAcceleration);
199 }
200 if (j.contains("initAccelerationUnit"))
201 {
202 j.at("initAccelerationUnit").get_to(data.initAccelerationUnit);
203 }
204 if (j.contains("initAngularAcc"))
205 {
206 j.at("initAngularAcc").get_to(data.initAngularAcc);
207 }
208 if (j.contains("initAngularAccUnit"))
209 {
210 j.at("initAngularAccUnit").get_to(data.initAngularAccUnit);
211 }
212 if (j.contains("initJerk"))
213 {
214 j.at("initJerk").get_to(data.initJerk);
215 }
216 if (j.contains("initJerkUnit"))
217 {
218 j.at("initJerkUnit").get_to(data.initJerkUnit);
219 }
220
221 if (j.contains("initCovarianceAngularAcc"))
222 {
223 j.at("initCovarianceAngularAcc").get_to(data.initCovarianceAngularAcc);
224 }
225 if (j.contains("initCovarianceAngularAccUnit"))
226 {
227 j.at("initCovarianceAngularAccUnit").get_to(data.initCovarianceAngularAccUnit);
228 }
229 if (j.contains("initCovarianceJerk"))
230 {
231 j.at("initCovarianceJerk").get_to(data.initCovarianceJerk);
232 }
233 if (j.contains("initCovarianceJerkUnit"))
234 {
235 j.at("initCovarianceJerkUnit").get_to(data.initCovarianceJerkUnit);
236 }
237
238 // ------------------------------------------- Process Noise ---------------------------------------------
239 if (j.contains("varAngularAccNoise"))
240 {
241 j.at("varAngularAccNoise").get_to(data.varAngularAccNoise);
242 }
243 if (j.contains("varAngularAccNoiseUnit"))
244 {
245 j.at("varAngularAccNoiseUnit").get_to(data.varAngularAccNoiseUnit);
246 }
247 if (j.contains("varJerkNoise"))
248 {
249 j.at("varJerkNoise").get_to(data.varJerkNoise);
250 }
251 if (j.contains("varJerkNoiseUnit"))
252 {
253 j.at("varJerkNoiseUnit").get_to(data.varJerkNoiseUnit);
254 }
255}
256
257/// @brief Write info to a json object
258/// @param[out] j Json output
259/// @param[in] data Object to read info from
260static void to_json(json& j, const PinDataBsplineKF& data) // NOLINT(misc-use-anonymous-namespace)
261{
262 j = json{
263 // ---------------------------------------- Initialization -------------------------------------------
264 { "initAngularRate", data.initCoeffsAngRate },
265 { "initCoeffsAngularRateUnit", data.initCoeffsAngularRateUnit },
266 { "initCoeffsAccel", data.initCoeffsAccel },
267 { "initCoeffsAccelUnit", data.initCoeffsAccelUnit },
268 { "initCovarianceCoeffsAngRate", data.initCovarianceCoeffsAngRate },
269 { "initCovarianceCoeffsAngRateUnit", data.initCovarianceCoeffsAngRateUnit },
270 { "initCovarianceCoeffsAccel", data.initCovarianceCoeffsAccel },
271 { "initCovarianceCoeffsAccelUnit", data.initCovarianceCoeffsAccelUnit },
272
273 // ----------------------------------------- Process Noise -------------------------------------------
274 { "varCoeffsAngRateNoise", data.varCoeffsAngRateNoise },
275 { "varCoeffsAngRateUnit", data.varCoeffsAngRateUnit },
276 { "varCoeffsAccelNoise", data.varCoeffsAccelNoise },
277 { "varCoeffsAccelUnit", data.varCoeffsAccelUnit },
278 };
279}
280/// @brief Read info from a json object
281/// @param[in] j Json variable to read info from
282/// @param[out] data Output object
283static void from_json(const json& j, PinDataBsplineKF& data) // NOLINT(misc-use-anonymous-namespace)
284{
285 // ------------------------------------------ Initialization ---------------------------------------------
286
287 if (j.contains("initCoeffsAngRate"))
288 {
289 j.at("initCoeffsAngRate").get_to(data.initCoeffsAngRate);
290 }
291 if (j.contains("initCoeffsAngularRateUnit"))
292 {
293 j.at("initCoeffsAngularRateUnit").get_to(data.initCoeffsAngularRateUnit);
294 }
295 if (j.contains("initCoeffsAccel"))
296 {
297 j.at("initCoeffsAccel").get_to(data.initCoeffsAccel);
298 }
299 if (j.contains("initCoeffsAccelUnit"))
300 {
301 j.at("initCoeffsAccelUnit").get_to(data.initCoeffsAccelUnit);
302 }
303 if (j.contains("initCovarianceCoeffsAngRate"))
304 {
305 j.at("initCovarianceCoeffsAngRate").get_to(data.initCovarianceCoeffsAngRate);
306 }
307 if (j.contains("initCovarianceCoeffsAngRateUnit"))
308 {
309 j.at("initCovarianceCoeffsAngRateUnit").get_to(data.initCovarianceCoeffsAngRateUnit);
310 }
311 if (j.contains("initCovarianceCoeffsAccel"))
312 {
313 j.at("initCovarianceCoeffsAccel").get_to(data.initCovarianceCoeffsAccel);
314 }
315 if (j.contains("initCovarianceCoeffsAccelUnit"))
316 {
317 j.at("initCovarianceCoeffsAccelUnit").get_to(data.initCovarianceCoeffsAccelUnit);
318 }
319
320 // ------------------------------------------- Process Noise ---------------------------------------------
321
322 if (j.contains("varCoeffsAngRateNoise"))
323 {
324 j.at("varCoeffsAngRateNoise").get_to(data.varCoeffsAngRateNoise);
325 }
326 if (j.contains("varCoeffsAngRateUnit"))
327 {
328 j.at("varCoeffsAngRateUnit").get_to(data.varCoeffsAngRateUnit);
329 }
330 if (j.contains("varCoeffsAccelNoise"))
331 {
332 j.at("varCoeffsAccelNoise").get_to(data.varCoeffsAccelNoise);
333 }
334 if (j.contains("varCoeffsAccelUnit"))
335 {
336 j.at("varCoeffsAccelUnit").get_to(data.varCoeffsAccelUnit);
337 }
338}
339
340} // namespace NAV
341
343 : Imu(typeStatic())
344{
345 LOG_TRACE("{}: called", name);
346
347 _hasConfig = true;
348 _guiConfigDefaultWindowSize = { 991, 1059 };
349
350 nm::CreateOutputPin(this, "Combined ImuObs", Pin::Type::Flow, { NAV::ImuObs::type() });
352}
353
355{
356 LOG_TRACE("{}: called", nameId());
357}
358
360{
361 return "ImuFusion";
362}
363
364std::string NAV::ImuFusion::type() const
365{
366 return typeStatic();
367}
368
370{
371 return "Data Processor";
372}
373
375{
376 constexpr float configWidth = 380.0F;
377 constexpr float unitWidth = 150.0F;
378
379 if (ImGui::BeginTable(fmt::format("Pin Settings##{}", size_t(id)).c_str(), inputPins.size() > 1 ? 2 : 1,
380 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
381 {
382 ImGui::TableSetupColumn("Pin");
383 if (inputPins.size() > 2)
384 {
385 ImGui::TableSetupColumn("");
386 }
387 ImGui::TableHeadersRow();
388
389 for (size_t pinIndex = 0; pinIndex < _pinData.size(); ++pinIndex)
390 {
391 ImGui::TableNextRow();
392 ImGui::TableNextColumn(); // Pin
393
394 ImGui::TextUnformatted(fmt::format("{}", inputPins.at(pinIndex).name).c_str());
395
396 if (inputPins.size() > 2) // Minimum # of pins for the fusion to make sense is two
397 {
398 ImGui::TableNextColumn(); // Delete
399 if (!(pinIndex == 0)) // Don't delete Pin 1, it's the reference for all other sensor (biases) that follow
400 {
401 if (ImGui::Button(fmt::format("x##{} - {}", size_t(id), pinIndex).c_str()))
402 {
403 nm::DeleteInputPin(inputPins.at(pinIndex));
404 nm::DeleteOutputPin(outputPins.at(pinIndex));
405 _pinData.erase(_pinData.begin() + static_cast<int64_t>(pinIndex - 1));
406 --_nInputPins;
409 }
410 if (ImGui::IsItemHovered())
411 {
412 ImGui::SetTooltip("Delete the pin");
413 }
414 }
415 }
416 }
417
418 ImGui::TableNextRow();
419 ImGui::TableNextColumn(); // Pin
420 if (ImGui::Button(fmt::format("Add Pin##{}", size_t(id)).c_str()))
421 {
422 ++_nInputPins;
423 LOG_DEBUG("{}: # Input Pins changed to {}", nameId(), _nInputPins);
426 }
427
428 ImGui::EndTable();
429 }
430
431 float columnWidth = 130.0F * gui::NodeEditorApplication::windowFontRatio();
432
433 ImGui::Separator();
434
435 // #######################################################################################################
436 // KF config
437 // #######################################################################################################
438 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
439
440 ImGui::SetNextItemWidth(columnWidth);
441 if (gui::widgets::EnumCombo(fmt::format("IMU fusion type##{}", size_t(id)).c_str(), _imuFusionType))
442 {
443 LOG_DEBUG("{}: imuFusionType changed to {}", nameId(), fmt::underlying(_imuFusionType));
444
447 }
448 ImGui::SameLine();
449 gui::widgets::HelpMarker("IRWKF: Integrated-Random-Walk Kalman-Filter (estimates angular acceleration and jerk).\nB-spline KF: Kalman-Filter that estimates three equally spaced quadratic B-splines for angular rate and acceleration, respectively.");
450
451 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
452
453 ImGui::SetNextItemWidth(columnWidth);
454 if (ImGui::InputDoubleL(fmt::format("Highest IMU sample rate in [Hz]##{}", size_t(id)).c_str(), &_imuFrequency, 1e-3, 1e4, 0.0, 0.0, "%.0f"))
455 {
456 LOG_DEBUG("{}: imuFrequency changed to {}", nameId(), _imuFrequency);
458 }
459 ImGui::SameLine();
460 gui::widgets::HelpMarker("The inverse of this rate is used as the initial 'dt' for the Kalman Filter Prediction (Phi and Q).");
461
463 {
464 ImGui::SetNextItemWidth(columnWidth);
465 if (ImGui::InputDoubleL(fmt::format("Spacing between the quadratic B-splines in [s]##{}", size_t(id)).c_str(), &_splineSpacing, 1e-3, 1.0, 0.0, 0.0, "%.3f"))
466 {
467 LOG_DEBUG("{}: splineSpacing changed to {}", nameId(), _splineSpacing);
469 }
470 ImGui::SameLine();
471 gui::widgets::HelpMarker("Time difference between each quadratic B-spline, maximum: 1.0 second");
472 }
473
474 if (ImGui::Checkbox(fmt::format("Rank check for Kalman filter matrices##{}", size_t(id)).c_str(), &_checkKalmanMatricesRanks))
475 {
476 LOG_DEBUG("{}: checkKalmanMatricesRanks {}", nameId(), _checkKalmanMatricesRanks);
478 }
479 ImGui::SameLine();
480 gui::widgets::HelpMarker("Computationally intensive - only recommended for debugging.");
481
483 {
484 ImGui::BeginDisabled();
485 }
486 if (ImGui::Checkbox(fmt::format("Auto-initialize Kalman filter##{}", size_t(id)).c_str(), &_autoInitKF))
487 {
488 LOG_DATA("{}: auto-initialize KF: {}", nameId(), _autoInitKF);
490 }
492 {
493 if (_autoInitKF)
494 {
495 _autoInitKF = false;
496 LOG_INFO("{}: Auto-initialization for KF turned off. This is currently only available for the IRWKF.", nameId());
497 }
498 ImGui::EndDisabled();
499 }
500 ImGui::SameLine();
501 gui::widgets::HelpMarker("Initializes the KF by averaging the data over a specified time frame. Currently only available for the IRWKF fusion type.");
502 if (ImGui::Checkbox(fmt::format("Characteristics of the multiple IMUs are identical##{}", size_t(id)).c_str(), &_imuCharacteristicsIdentical))
503 {
504 LOG_DATA("{}: imuCharacteristicsIdentical: {}", nameId(), _imuCharacteristicsIdentical);
506 }
507 ImGui::SameLine();
508 gui::widgets::HelpMarker("GUI input cells can be reduced considerably.");
509 if (ImGui::Checkbox(fmt::format("Biases of the multiple IMUs are identical##{}", size_t(id)).c_str(), &_imuBiasesIdentical))
510 {
511 LOG_DATA("{}: imuBiasesIdentical: {}", nameId(), _imuBiasesIdentical);
513 }
514 ImGui::SameLine();
515 gui::widgets::HelpMarker("GUI input cells can be reduced considerably.");
516
517 ImGui::Separator();
518
519 // #######################################################################################################
520 // KF initialization
521 // #######################################################################################################
522
523 if (_autoInitKF)
524 {
525 ImGui::Text("Kalman Filter initialization (auto-init)");
526
527 ImGui::SetNextItemWidth(columnWidth);
528 if (ImGui::InputDoubleL(fmt::format("Averaging time in [s]##{}", size_t(id)).c_str(), &_averageEndTime, 1e-3, 1e4, 0.0, 0.0, "%.0f"))
529 {
530 LOG_DEBUG("{}: averageEndTime changed to {}", nameId(), _averageEndTime);
532 }
533 ImGui::SameLine();
534 gui::widgets::HelpMarker("Determines how long the data is averaged before the KF is auto-initialized");
535
536 if (ImGui::Checkbox(fmt::format("Initialize Jerk variance to acceleration variance and angular acceleration variance to angular rate variance##{}", size_t(id)).c_str(), &_initJerkAngAcc))
537 {
538 LOG_DATA("{}: initJerkAngAcc: {}", nameId(), _initJerkAngAcc);
540 }
541 ImGui::SameLine();
542 gui::widgets::HelpMarker("Otherwise zero");
543 }
544 else
545 {
546 ImGui::Text("Kalman Filter initialization (manual init)");
547
548 // ---------------------------------------- State vector x0 -------------------------------------------
549 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
550 if (ImGui::TreeNode(fmt::format("x - State vector##{}", size_t(id)).c_str()))
551 {
553 {
554 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate##{}", size_t(id)).c_str(),
555 configWidth, unitWidth, _pinDataIRWKF.initAngularRate.data(), _pinDataIRWKF.initAngularRateUnit, "deg/s\0"
556 "rad/s\0\0",
557 "%.2e", ImGuiInputTextFlags_CharsScientific))
558 {
559 LOG_DATA("{}: initAngularRate changed to {}", nameId(), _pinDataIRWKF.initAngularRate);
560 LOG_DATA("{}: AngularRateUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initAngularRateUnit));
562 }
563
564 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration##{}", size_t(id)).c_str(),
565 configWidth, unitWidth, _pinDataIRWKF.initAcceleration.data(), _pinDataIRWKF.initAccelerationUnit, "m/s²\0\0", "%.2e", ImGuiInputTextFlags_CharsScientific))
566 {
567 LOG_DATA("{}: initAcceleration changed to {}", nameId(), _pinDataIRWKF.initAcceleration);
568 LOG_DATA("{}: initAccelerationUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initAccelerationUnit));
570 }
571
572 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular Acceleration##{}", size_t(id)).c_str(),
573 configWidth, unitWidth, _pinDataIRWKF.initAngularAcc.data(), _pinDataIRWKF.initAngularAccUnit, "deg/s²\0"
574 "rad/s^2\0\0",
575 "%.2e", ImGuiInputTextFlags_CharsScientific))
576 {
577 LOG_DATA("{}: initAngularAcc changed to {}", nameId(), _pinDataIRWKF.initAngularAcc);
578 LOG_DATA("{}: initAngularAccUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initAngularAccUnit));
580 }
581
582 if (gui::widgets::InputDouble3WithUnit(fmt::format("Jerk##{}", size_t(id)).c_str(),
583 configWidth, unitWidth, _pinDataIRWKF.initJerk.data(), _pinDataIRWKF.initJerkUnit, "m/s³\0\0",
584 "%.2e", ImGuiInputTextFlags_CharsScientific))
585 {
586 LOG_DATA("{}: initJerk changed to {}", nameId(), _pinDataIRWKF.initJerk);
587 LOG_DATA("{}: PinData::JerkVarianceUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initJerkUnit));
589 }
590 }
591 else // (_imuFusionType == ImuFusionType::Bspline)
592 {
593 if (gui::widgets::InputDouble3WithUnit(fmt::format("B-spline coefficients for the angular rate##{}", size_t(id)).c_str(),
594 configWidth, unitWidth, _initCoeffsAngRateTemp.data(), _pinDataBsplineKF.initCoeffsAngularRateUnit, "deg/s\0"
595 "rad/s\0\0",
596 "%.2e", ImGuiInputTextFlags_CharsScientific))
597 {
598 LOG_DATA("{}: initCoeffsAngularRateUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.initCoeffsAngularRateUnit));
600 }
601 if (gui::widgets::InputDouble3WithUnit(fmt::format("B-spline coefficients for the acceleration##{}", size_t(id)).c_str(),
602 configWidth, unitWidth, _initCoeffsAccelTemp.data(), _pinDataBsplineKF.initCoeffsAccelUnit, "m/s²\0\0",
603 "%.2e", ImGuiInputTextFlags_CharsScientific))
604 {
605 LOG_DATA("{}: initCoeffsAccelUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.initCoeffsAccelUnit));
607 }
608 for (uint8_t i = 0; i < _numBsplines; i += 3)
609 {
610 _pinDataBsplineKF.initCoeffsAngRate.block<3, 1>(i, 0) = _initCoeffsAngRateTemp;
611 _pinDataBsplineKF.initCoeffsAccel.block<3, 1>(i, 0) = _initCoeffsAccelTemp;
612 }
613 LOG_DATA("{}: initCoeffsAngRate changed to {}", nameId(), _pinDataBsplineKF.initCoeffsAngRate);
614 LOG_DATA("{}: initCoeffsAccel changed to {}", nameId(), _pinDataBsplineKF.initCoeffsAccel);
615 }
616
617 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate bias of sensor {}##{}", 2, size_t(id)).c_str(),
618 configWidth, unitWidth, _pinData[1].initAngularRateBias.data(), _pinData[1].initAngularRateBiasUnit, "deg/s\0rad/s\0\0",
619 "%.2e", ImGuiInputTextFlags_CharsScientific))
620 {
622 }
623
624 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration bias of sensor {}##{}", 2, size_t(id)).c_str(),
625 configWidth, unitWidth, _pinData[1].initAccelerationBias.data(), _pinData[1].initAccelerationBiasUnit, "m/s^2\0\0",
626 "%.2e", ImGuiInputTextFlags_CharsScientific))
627 {
629 }
631 {
632 for (size_t pinIndex = 2; pinIndex < _nInputPins; ++pinIndex)
633 {
634 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate bias of sensor {}##{}", pinIndex + 1, size_t(id)).c_str(),
635 configWidth, unitWidth, _pinData[pinIndex].initAngularRateBias.data(), _pinData[pinIndex].initAngularRateBiasUnit, "deg/s\0rad/s\0\0",
636 "%.2e", ImGuiInputTextFlags_CharsScientific))
637 {
639 }
640
641 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration bias of sensor {}##{}", pinIndex + 1, size_t(id)).c_str(),
642 configWidth, unitWidth, _pinData[pinIndex].initAccelerationBias.data(), _pinData[pinIndex].initAccelerationBiasUnit, "m/s^2\0\0",
643 "%.2e", ImGuiInputTextFlags_CharsScientific))
644 {
646 }
647 }
648 }
649
650 ImGui::TreePop();
651 }
652
653 // ----------------------------------- Error covariance matrix P0 -------------------------------------
654 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
655 if (ImGui::TreeNode(fmt::format("P - Error covariance matrix##{}", size_t(id)).c_str()))
656 {
658 {
659 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate covariance ({})##{}",
660 _pinData[0].initCovarianceAngularRateUnit == PinData::AngRateVarianceUnit::rad2_s2
661 || _pinData[0].initCovarianceAngularRateUnit == PinData::AngRateVarianceUnit::deg2_s2
662 ? "Variance σ²"
663 : "Standard deviation σ",
664 size_t(id))
665 .c_str(),
666 configWidth, unitWidth, _pinData[0].initCovarianceAngularRate.data(), _pinData[0].initCovarianceAngularRateUnit, "(rad/s)²\0"
667 "rad/s\0"
668 "(deg/s)²\0"
669 "deg/s\0\0",
670 "%.2e", ImGuiInputTextFlags_CharsScientific))
671 {
672 LOG_DATA("{}: initCovarianceAngularRate changed to {}", nameId(), _pinData[0].initCovarianceAngularRate);
673 LOG_DATA("{}: AngRateVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[0].initCovarianceAngularRateUnit));
675 }
676
677 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular acceleration covariance ({})##{}",
679 || _pinDataIRWKF.initCovarianceAngularAccUnit == PinDataIRWKF::AngularAccVarianceUnit::deg2_s4
680 ? "Variance σ²"
681 : "Standard deviation σ",
682 size_t(id))
683 .c_str(),
684 configWidth, unitWidth, _pinDataIRWKF.initCovarianceAngularAcc.data(), _pinDataIRWKF.initCovarianceAngularAccUnit, "(rad^2)/(s^4)\0"
685 "rad/s^2\0"
686 "(deg^2)/(s^4)\0"
687 "deg/s^2\0\0",
688 "%.2e", ImGuiInputTextFlags_CharsScientific))
689 {
690 LOG_DATA("{}: initCovarianceAngularAcc changed to {}", nameId(), _pinDataIRWKF.initCovarianceAngularAcc);
691 LOG_DATA("{}: PinData::AngularAccVarianceUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initCovarianceAngularAccUnit));
693 }
694
695 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration covariance ({})##{}",
696 _pinData[0].initCovarianceAccelerationUnit == PinData::AccelerationVarianceUnit::m2_s4
697 ? "Variance σ²"
698 : "Standard deviation σ",
699 size_t(id))
700 .c_str(),
701 configWidth, unitWidth, _pinData[0].initCovarianceAcceleration.data(), _pinData[0].initCovarianceAccelerationUnit, "(m^2)/(s^4)\0"
702 "m/s^2\0\0",
703 "%.2e", ImGuiInputTextFlags_CharsScientific))
704 {
705 LOG_DATA("{}: initCovarianceAcceleration changed to {}", nameId(), _pinData[0].initCovarianceAcceleration);
706 LOG_DATA("{}: PinData::AccelerationVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[0].initCovarianceAccelerationUnit));
708 }
709
710 if (gui::widgets::InputDouble3WithUnit(fmt::format("Jerk covariance ({})##{}",
712 ? "Variance σ²"
713 : "Standard deviation σ",
714 size_t(id))
715 .c_str(),
716 configWidth, unitWidth, _pinDataIRWKF.initCovarianceJerk.data(), _pinDataIRWKF.initCovarianceJerkUnit, "(m^2)/(s^6)\0"
717 "m/s^3\0\0",
718 "%.2e", ImGuiInputTextFlags_CharsScientific))
719 {
720 LOG_DATA("{}: initCovarianceJerk changed to {}", nameId(), _pinDataIRWKF.initCovarianceJerk);
721 LOG_DATA("{}: PinData::JerkVarianceUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.initCovarianceJerkUnit));
723 }
724 }
725 else // (_imuFusionType == ImuFusionType::Bspline)
726 {
727 if (gui::widgets::InputDouble3WithUnit(fmt::format("Covariance of the B-spline coefficients of the angular rate ({})##{}",
728 _pinDataBsplineKF.initCovarianceCoeffsAngRateUnit == PinData::AngRateVarianceUnit::rad2_s2
729 || _pinDataBsplineKF.initCovarianceCoeffsAngRateUnit == PinData::AngRateVarianceUnit::deg2_s2
730 ? "Variance σ²"
731 : "Standard deviation σ",
732 size_t(id))
733 .c_str(),
734 configWidth, unitWidth, _initCovarianceCoeffsAngRateTemp.data(), _pinDataBsplineKF.initCovarianceCoeffsAngRateUnit, "(rad/s)²\0"
735 "rad/s\0"
736 "(deg/s)²\0"
737 "deg/s\0\0",
738 "%.2e", ImGuiInputTextFlags_CharsScientific))
739 {
740 LOG_DATA("{}: initCovarianceCoeffsAngRateUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.initCovarianceCoeffsAngRateUnit));
742 }
743 if (gui::widgets::InputDouble3WithUnit(fmt::format("Covariance of the B-spline coefficients of the acceleration ({})##{}",
744 _pinDataBsplineKF.initCovarianceCoeffsAccelUnit == PinData::AccelerationVarianceUnit::m2_s4
745 ? "Variance σ²"
746 : "Standard deviation σ",
747 size_t(id))
748 .c_str(),
749 configWidth, unitWidth, _initCovarianceCoeffsAccelTemp.data(), _pinDataBsplineKF.initCovarianceCoeffsAccelUnit, "(m^2)/(s^4)\0"
750 "m/s^2\0\0",
751 "%.2e", ImGuiInputTextFlags_CharsScientific))
752 {
753 LOG_DATA("{}: initCovarianceCoeffsAccelUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.initCovarianceCoeffsAccelUnit));
755 }
756 for (uint8_t i = 0; i < _numBsplines; i += 3)
757 {
758 _pinDataBsplineKF.initCovarianceCoeffsAngRate.block<3, 1>(i, 0) = _initCovarianceCoeffsAngRateTemp;
759 _pinDataBsplineKF.initCovarianceCoeffsAccel.block<3, 1>(i, 0) = _initCovarianceCoeffsAccelTemp;
760 }
761 LOG_DATA("{}: initCovarianceCoeffsAngRate changed to {}", nameId(), _pinDataBsplineKF.initCovarianceCoeffsAngRate);
762 LOG_DATA("{}: initCovarianceCoeffsAccel changed to {}", nameId(), _pinDataBsplineKF.initCovarianceCoeffsAccel);
763 }
764
765 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate bias covariance of sensor {} ({})##{}", 2,
766 _pinData[1].initCovarianceBiasAngRateUnit == PinData::AngRateVarianceUnit::rad2_s2
767 || _pinData[1].initCovarianceBiasAngRateUnit == PinData::AngRateVarianceUnit::deg2_s2
768 ? "Variance σ²"
769 : "Standard deviation σ",
770 size_t(id))
771 .c_str(),
772 configWidth, unitWidth, _pinData[1].initCovarianceBiasAngRate.data(), _pinData[1].initCovarianceBiasAngRateUnit, "(rad^2)/(s^2)\0"
773 "rad/s\0"
774 "(deg^2)/(s^2)\0"
775 "deg/s\0\0",
776 "%.2e", ImGuiInputTextFlags_CharsScientific))
777 {
778 LOG_DATA("{}: initCovarianceBiasAngRate changed to {}", nameId(), _pinData[1].initCovarianceBiasAngRate);
779 LOG_DATA("{}: PinData::AngRateVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[1].initCovarianceBiasAngRateUnit));
781 }
782
783 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration bias covariance of sensor {} ({})##{}", 2,
784 _pinData[1].initCovarianceBiasAccUnit == PinData::AccelerationVarianceUnit::m2_s4
785 ? "Variance σ²"
786 : "Standard deviation σ",
787 size_t(id))
788 .c_str(),
789 configWidth, unitWidth, _pinData[1].initCovarianceBiasAcc.data(), _pinData[1].initCovarianceBiasAccUnit, "(m^2)/(s^4)\0"
790 "m/s^2\0\0",
791 "%.2e", ImGuiInputTextFlags_CharsScientific))
792 {
793 LOG_DATA("{}: initCovarianceBiasAcc changed to {}", nameId(), _pinData[1].initCovarianceBiasAcc);
794 LOG_DATA("{}: PinData::AccelerationVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[1].initCovarianceBiasAccUnit));
796 }
798 {
799 for (size_t pinIndex = 2; pinIndex < _nInputPins; ++pinIndex)
800 {
801 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate bias covariance of sensor {} ({})##{}", pinIndex + 1,
802 _pinData[pinIndex].initCovarianceBiasAngRateUnit == PinData::AngRateVarianceUnit::rad2_s2
803 || _pinData[pinIndex].initCovarianceBiasAngRateUnit == PinData::AngRateVarianceUnit::deg2_s2
804 ? "Variance σ²"
805 : "Standard deviation σ",
806 size_t(id))
807 .c_str(),
808 configWidth, unitWidth, _pinData[pinIndex].initCovarianceBiasAngRate.data(), _pinData[pinIndex].initCovarianceBiasAngRateUnit, "(rad^2)/(s^2)\0"
809 "rad/s\0"
810 "(deg^2)/(s^2)\0"
811 "deg/s\0\0",
812 "%.2e", ImGuiInputTextFlags_CharsScientific))
813 {
814 LOG_DATA("{}: initCovarianceBiasAngRate changed to {}", nameId(), _pinData[pinIndex].initCovarianceBiasAngRate);
815 LOG_DATA("{}: PinData::AngRateVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].initCovarianceBiasAngRateUnit));
817 }
818
819 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration bias covariance of sensor {} ({})##{}", pinIndex + 1,
820 _pinData[pinIndex].initCovarianceBiasAccUnit == PinData::AccelerationVarianceUnit::m2_s4
821 ? "Variance σ²"
822 : "Standard deviation σ",
823 size_t(id))
824 .c_str(),
825 configWidth, unitWidth, _pinData[pinIndex].initCovarianceBiasAcc.data(), _pinData[pinIndex].initCovarianceBiasAccUnit, "(m^2)/(s^4)\0"
826 "m/s^2\0\0",
827 "%.2e", ImGuiInputTextFlags_CharsScientific))
828 {
829 LOG_DATA("{}: initCovarianceBiasAcc changed to {}", nameId(), _pinData[pinIndex].initCovarianceBiasAcc);
830 LOG_DATA("{}: PinData::AccelerationVarianceUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].initCovarianceBiasAccUnit));
832 }
833 }
834 }
835
836 ImGui::TreePop();
837 }
838 }
839
840 ImGui::Separator();
841
842 // #######################################################################################################
843 // KF noise setting
844 // #######################################################################################################
845 ImGui::Text("Kalman Filter noise setting");
846
847 // -------------------------------------- Process noise matrix Q -----------------------------------------
848 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
849 if (ImGui::TreeNode(fmt::format("Q - System/Process noise covariance matrix##{}", size_t(id)).c_str()))
850 {
851 ImGui::SetNextItemWidth(configWidth + ImGui::GetStyle().ItemSpacing.x);
852
854 {
855 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular acceleration ({})##{}",
858 ? "Variance σ²"
859 : "Standard deviation σ",
860 size_t(id))
861 .c_str(),
862 configWidth, unitWidth, _pinDataIRWKF.varAngularAccNoise.data(), _pinDataIRWKF.varAngularAccNoiseUnit, "(rad^2)/(s^4)\0"
863 "rad/s^2\0"
864 "(deg^2)/(s^4)\0"
865 "deg/s^2\0\0",
866 "%.2e", ImGuiInputTextFlags_CharsScientific))
867 {
868 LOG_DATA("{}: varAngularAccNoise changed to {}", nameId(), _pinDataIRWKF.varAngularAccNoise.transpose());
869 LOG_DATA("{}: varAngularAccNoiseUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.varAngularAccNoiseUnit));
871 }
872
873 if (gui::widgets::InputDouble3WithUnit(fmt::format("Jerk ({})##{}",
875 ? "Variance σ²"
876 : "Standard deviation σ",
877 size_t(id))
878 .c_str(),
879 configWidth, unitWidth, _pinDataIRWKF.varJerkNoise.data(), _pinDataIRWKF.varJerkNoiseUnit, "(m^2)/(s^6)\0"
880 "m/s^3\0\0",
881 "%.2e", ImGuiInputTextFlags_CharsScientific))
882 {
883 LOG_DATA("{}: varJerkNoise changed to {}", nameId(), _pinDataIRWKF.varJerkNoise.transpose());
884 LOG_DATA("{}: varJerkNoiseUnit changed to {}", nameId(), fmt::underlying(_pinDataIRWKF.varJerkNoiseUnit));
886 }
887 }
888 else // (_imuFusionType == ImuFusionType::Bspline)
889 {
890 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate B-spline coefficients ({})##{}",
893 ? "Variance σ²"
894 : "Standard deviation σ",
895 size_t(id))
896 .c_str(),
897 configWidth, unitWidth, _procNoiseCoeffsAngRateTemp.data(), _pinDataBsplineKF.varCoeffsAngRateUnit, "(rad^2)/(s^2)\0"
898 "rad/s\0"
899 "(deg^2)/(s^2)\0"
900 "deg/s\0\0",
901 "%.2e", ImGuiInputTextFlags_CharsScientific))
902 {
903 LOG_DATA("{}: varCoeffsAngRateUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.varCoeffsAngRateUnit));
905 }
906 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration B-spline coefficients ({})##{}",
908 ? "Variance σ²"
909 : "Standard deviation σ",
910 size_t(id))
911 .c_str(),
912 configWidth, unitWidth, _procNoiseCoeffsAccelTemp.data(), _pinDataBsplineKF.varCoeffsAccelUnit, "(m^2)/(s^4)\0"
913 "m/s^2\0\0",
914 "%.2e", ImGuiInputTextFlags_CharsScientific))
915 {
916 LOG_DATA("{}: varCoeffsAccelUnit changed to {}", nameId(), fmt::underlying(_pinDataBsplineKF.varCoeffsAccelUnit));
918 }
919 for (uint8_t i = 0; i < _numBsplines; i += 3)
920 {
921 _pinDataBsplineKF.varCoeffsAngRateNoise.block<3, 1>(i, 0) = _procNoiseCoeffsAngRateTemp;
922 _pinDataBsplineKF.varCoeffsAccelNoise.block<3, 1>(i, 0) = _procNoiseCoeffsAccelTemp;
923 }
924 LOG_DATA("{}: varCoeffsAngRateNoise changed to {}", nameId(), _pinDataBsplineKF.varCoeffsAngRateNoise.transpose());
925 LOG_DATA("{}: varCoeffsAccelNoise changed to {}", nameId(), _pinDataBsplineKF.varCoeffsAccelNoise.transpose());
926 }
927
928 if (gui::widgets::InputDouble3WithUnit(fmt::format("Bias of the angular rate of sensor {} ({})##{}", 2,
929 _pinData[1].varBiasAngRateNoiseUnit == PinData::AngRateVarianceUnit::rad2_s2
930 || _pinData[1].varBiasAngRateNoiseUnit == PinData::AngRateVarianceUnit::deg2_s2
931 ? "Variance σ²"
932 : "Standard deviation σ",
933 size_t(id))
934 .c_str(), // FIXME: adapt config window number of sensors (if pin 3 is deleted, keep 1,2,4 instead of re-counting to 1,2,3)
935 configWidth, unitWidth, _pinData[1].varBiasAngRateNoise.data(), _pinData[1].varBiasAngRateNoiseUnit, "(rad/s)^2\0"
936 "rad/s\0"
937 "(deg/s)^2\0"
938 "deg/s\0\0",
939 "%.2e", ImGuiInputTextFlags_CharsScientific))
940 {
941 LOG_DATA("{}: varBiasAngRateNoise changed to {}", nameId(), _pinData[1].varBiasAngRateNoise.transpose());
942 LOG_DATA("{}: varBiasAngRateNoiseUnit changed to {}", nameId(), fmt::underlying(_pinData[1].varBiasAngRateNoiseUnit));
944 }
945
946 if (gui::widgets::InputDouble3WithUnit(fmt::format("Bias of the acceleration of sensor {} ({})##{}", 2,
947 _pinData[1].varBiasAccelerationNoiseUnit == PinData::AccelerationVarianceUnit::m2_s4
948 ? "Variance σ²"
949 : "Standard deviation σ",
950 size_t(id))
951 .c_str(), // FIXME: adapt config window number of sensors (if pin 3 is deleted, keep 1,2,4 instead of re-counting to 1,2,3)
952 configWidth, unitWidth, _pinData[1].varBiasAccelerationNoise.data(), _pinData[1].varBiasAccelerationNoiseUnit, "(m^2)/(s^4)\0"
953 "m/s^2\0\0",
954 "%.2e", ImGuiInputTextFlags_CharsScientific))
955 {
956 LOG_DATA("{}: varBiasAccelerationNoise changed to {}", nameId(), _pinData[1].varBiasAccelerationNoise.transpose());
957 LOG_DATA("{}: varBiasAccelerationNoiseUnit changed to {}", nameId(), fmt::underlying(_pinData[1].varBiasAccelerationNoiseUnit));
959 }
961 {
962 for (size_t pinIndex = 2; pinIndex < _nInputPins; ++pinIndex)
963 {
964 if (gui::widgets::InputDouble3WithUnit(fmt::format("Bias of the angular rate of sensor {} ({})##{}", pinIndex + 1,
965 _pinData[pinIndex].varBiasAngRateNoiseUnit == PinData::AngRateVarianceUnit::rad2_s2
966 || _pinData[pinIndex].varBiasAngRateNoiseUnit == PinData::AngRateVarianceUnit::deg2_s2
967 ? "Variance σ²"
968 : "Standard deviation σ",
969 size_t(id))
970 .c_str(), // FIXME: adapt config window number of sensors (if pin 3 is deleted, keep 1,2,4 instead of re-counting to 1,2,3)
971 configWidth, unitWidth, _pinData[pinIndex].varBiasAngRateNoise.data(), _pinData[pinIndex].varBiasAngRateNoiseUnit, "(rad/s)^2\0"
972 "rad/s\0"
973 "(deg/s)^2\0"
974 "deg/s\0\0",
975 "%.2e", ImGuiInputTextFlags_CharsScientific))
976 {
977 LOG_DATA("{}: varBiasAngRateNoise changed to {}", nameId(), _pinData[pinIndex].varBiasAngRateNoise.transpose());
978 LOG_DATA("{}: varBiasAngRateNoiseUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].varBiasAngRateNoiseUnit));
980 }
981
982 if (gui::widgets::InputDouble3WithUnit(fmt::format("Bias of the acceleration of sensor {} ({})##{}", pinIndex + 1,
983 _pinData[pinIndex].varBiasAccelerationNoiseUnit == PinData::AccelerationVarianceUnit::m2_s4
984 ? "Variance σ²"
985 : "Standard deviation σ",
986 size_t(id))
987 .c_str(), // FIXME: adapt config window number of sensors (if pin 3 is deleted, keep 1,2,4 instead of re-counting to 1,2,3)
988 configWidth, unitWidth, _pinData[pinIndex].varBiasAccelerationNoise.data(), _pinData[pinIndex].varBiasAccelerationNoiseUnit, "(m^2)/(s^4)\0"
989 "m/s^2\0\0",
990 "%.2e", ImGuiInputTextFlags_CharsScientific))
991 {
992 LOG_DATA("{}: varBiasAccelerationNoise changed to {}", nameId(), _pinData[pinIndex].varBiasAccelerationNoise.transpose());
993 LOG_DATA("{}: varBiasAccelerationNoiseUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].varBiasAccelerationNoiseUnit));
995 }
996 }
997 }
998
999 ImGui::TreePop();
1000 }
1001
1002 // ------------------------------------ Measurement noise matrix R ---------------------------------------
1003 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
1004 if (ImGui::TreeNode(fmt::format("R - Measurement noise covariance matrix##{}", size_t(id)).c_str()))
1005 {
1006 ImGui::SetNextItemWidth(configWidth + ImGui::GetStyle().ItemSpacing.x);
1007
1008 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate of sensor {} ({})##{}", 1,
1009 _pinData[0].measurementUncertaintyAngularRateUnit == PinData::AngRateVarianceUnit::rad2_s2
1010 || _pinData[0].measurementUncertaintyAngularRateUnit == PinData::AngRateVarianceUnit::deg2_s2
1011 ? "Variance σ²"
1012 : "Standard deviation σ",
1013 size_t(id))
1014 .c_str(),
1015 configWidth, unitWidth, _pinData[0].measurementUncertaintyAngularRate.data(), _pinData[0].measurementUncertaintyAngularRateUnit, "(rad/s)^2\0"
1016 "rad/s\0"
1017 "(deg/s)^2\0"
1018 "deg/s\0\0",
1019 "%.2e", ImGuiInputTextFlags_CharsScientific))
1020 {
1021 LOG_DATA("{}: stdevAngularAcc changed to {}", nameId(), _pinData[0].measurementUncertaintyAngularRate.transpose());
1022 LOG_DATA("{}: stdevAngularAccUnit changed to {}", nameId(), fmt::underlying(_pinData[0].measurementUncertaintyAngularRateUnit));
1024 }
1025
1026 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration of sensor {} ({})##{}", 1,
1027 _pinData[0].measurementUncertaintyAccelerationUnit == PinData::AccelerationVarianceUnit::m2_s4
1028 ? "Variance σ²"
1029 : "Standard deviation σ",
1030 size_t(id))
1031 .c_str(),
1032 configWidth, unitWidth, _pinData[0].measurementUncertaintyAcceleration.data(), _pinData[0].measurementUncertaintyAccelerationUnit, "(m^2)/(s^4)\0"
1033 "m/s^2\0\0",
1034 "%.2e", ImGuiInputTextFlags_CharsScientific))
1035 {
1036 LOG_DATA("{}: stdevJerk changed to {}", nameId(), _pinData[0].measurementUncertaintyAcceleration.transpose());
1037 LOG_DATA("{}: stdevJerkUnit changed to {}", nameId(), fmt::underlying(_pinData[0].measurementUncertaintyAccelerationUnit));
1039 }
1041 {
1042 for (size_t pinIndex = 1; pinIndex < _nInputPins; ++pinIndex)
1043 {
1044 if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate of sensor {} ({})##{}", pinIndex + 1,
1045 _pinData[pinIndex].measurementUncertaintyAngularRateUnit == PinData::AngRateVarianceUnit::rad2_s2
1046 || _pinData[pinIndex].measurementUncertaintyAngularRateUnit == PinData::AngRateVarianceUnit::deg2_s2
1047 ? "Variance σ²"
1048 : "Standard deviation σ",
1049 size_t(id))
1050 .c_str(),
1051 configWidth, unitWidth, _pinData[pinIndex].measurementUncertaintyAngularRate.data(), _pinData[pinIndex].measurementUncertaintyAngularRateUnit, "(rad/s)^2\0"
1052 "rad/s\0"
1053 "(deg/s)^2\0"
1054 "deg/s\0\0",
1055 "%.2e", ImGuiInputTextFlags_CharsScientific))
1056 {
1057 LOG_DATA("{}: stdevAngularAcc changed to {}", nameId(), _pinData[pinIndex].measurementUncertaintyAngularRate.transpose());
1058 LOG_DATA("{}: stdevAngularAccUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].measurementUncertaintyAngularRateUnit));
1060 }
1061
1062 if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration of sensor {} ({})##{}", pinIndex + 1,
1063 _pinData[pinIndex].measurementUncertaintyAccelerationUnit == PinData::AccelerationVarianceUnit::m2_s4
1064 ? "Variance σ²"
1065 : "Standard deviation σ",
1066 size_t(id))
1067 .c_str(),
1068 configWidth, unitWidth, _pinData[pinIndex].measurementUncertaintyAcceleration.data(), _pinData[pinIndex].measurementUncertaintyAccelerationUnit, "(m^2)/(s^4)\0"
1069 "m/s^2\0\0",
1070 "%.2e", ImGuiInputTextFlags_CharsScientific))
1071 {
1072 LOG_DATA("{}: stdevJerk changed to {}", nameId(), _pinData[pinIndex].measurementUncertaintyAcceleration.transpose());
1073 LOG_DATA("{}: stdevJerkUnit changed to {}", nameId(), fmt::underlying(_pinData[pinIndex].measurementUncertaintyAccelerationUnit));
1075 }
1076 }
1077 }
1078
1079 ImGui::TreePop();
1080 }
1081}
1082
1083[[nodiscard]] json NAV::ImuFusion::save() const
1084{
1085 LOG_TRACE("{}: called", nameId());
1086
1087 json j;
1088
1089 j["imuFusionType"] = _imuFusionType;
1090 j["checkKalmanMatricesRanks"] = _checkKalmanMatricesRanks;
1091 j["nInputPins"] = _nInputPins;
1092 j["imuFrequency"] = _imuFrequency;
1093 j["numStates"] = _numStates;
1094 j["pinData"] = _pinData;
1095 j["pinDataIRWKF"] = _pinDataIRWKF;
1096 j["pinDataBsplineKF"] = _pinDataBsplineKF;
1097 j["initCoeffsAngRateTemp"] = _initCoeffsAngRateTemp;
1098 j["initCoeffsAccelTemp"] = _initCoeffsAccelTemp;
1099 j["initCovarianceCoeffsAngRateTemp"] = _initCovarianceCoeffsAngRateTemp;
1100 j["initCovarianceCoeffsAccelTemp"] = _initCovarianceCoeffsAccelTemp;
1101 j["procNoiseCoeffsAngRateTemp"] = _procNoiseCoeffsAngRateTemp;
1102 j["procNoiseCoeffsAccelTemp"] = _procNoiseCoeffsAccelTemp;
1103 j["autoInitKF"] = _autoInitKF;
1104 j["initJerkAngAcc"] = _initJerkAngAcc;
1105 j["kfInitialized"] = _kfInitialized;
1106 j["averageEndTime"] = _averageEndTime;
1107 j["splineSpacing"] = _splineSpacing;
1108
1109 return j;
1110}
1111
1113{
1114 LOG_TRACE("{}: called", nameId());
1115
1116 if (j.contains("imuFusionType"))
1117 {
1118 j.at("imuFusionType").get_to(_imuFusionType);
1119 }
1120 if (j.contains("checkKalmanMatricesRanks"))
1121 {
1122 j.at("checkKalmanMatricesRanks").get_to(_checkKalmanMatricesRanks);
1123 }
1124 if (j.contains("nInputPins"))
1125 {
1126 j.at("nInputPins").get_to(_nInputPins);
1128 }
1129 if (j.contains("imuFrequency"))
1130 {
1131 j.at("imuFrequency").get_to(_imuFrequency);
1132 }
1133 if (j.contains("numStates"))
1134 {
1135 j.at("numStates").get_to(_numStates);
1136 }
1137 if (j.contains("pinData"))
1138 {
1139 j.at("pinData").get_to(_pinData);
1140 }
1141 if (j.contains("pinDataIRWKF"))
1142 {
1143 j.at("pinDataIRWKF").get_to(_pinDataIRWKF);
1144 }
1145 if (j.contains("pinDataBsplineKF"))
1146 {
1147 j.at("pinDataBsplineKF").get_to(_pinDataBsplineKF);
1148 }
1149 if (j.contains("initCoeffsAngRateTemp"))
1150 {
1151 j.at("initCoeffsAngRateTemp").get_to(_initCoeffsAngRateTemp);
1152 }
1153 if (j.contains("initCoeffsAccelTemp"))
1154 {
1155 j.at("initCoeffsAccelTemp").get_to(_initCoeffsAccelTemp);
1156 }
1157 if (j.contains("initCovarianceCoeffsAngRateTemp"))
1158 {
1159 j.at("initCovarianceCoeffsAngRateTemp").get_to(_initCovarianceCoeffsAngRateTemp);
1160 }
1161 if (j.contains("initCovarianceCoeffsAccelTemp"))
1162 {
1163 j.at("initCovarianceCoeffsAccelTemp").get_to(_initCovarianceCoeffsAccelTemp);
1164 }
1165 if (j.contains("procNoiseCoeffsAngRateTemp"))
1166 {
1167 j.at("procNoiseCoeffsAngRateTemp").get_to(_procNoiseCoeffsAngRateTemp);
1168 }
1169 if (j.contains("procNoiseCoeffsAccelTemp"))
1170 {
1171 j.at("procNoiseCoeffsAccelTemp").get_to(_procNoiseCoeffsAccelTemp);
1172 }
1173 if (j.contains("autoInitKF"))
1174 {
1175 j.at("autoInitKF").get_to(_autoInitKF);
1176 }
1177 if (j.contains("initJerkAngAcc"))
1178 {
1179 j.at("initJerkAngAcc").get_to(_initJerkAngAcc);
1180 }
1181 if (j.contains("_kfInitialized"))
1182 {
1183 j.at("_kfInitialized").get_to(_kfInitialized);
1184 }
1185 if (j.contains("averageEndTime"))
1186 {
1187 j.at("averageEndTime").get_to(_averageEndTime);
1188 }
1189 if (j.contains("splineSpacing"))
1190 {
1191 j.at("splineSpacing").get_to(_splineSpacing);
1192 }
1193}
1194
1196{
1197 LOG_TRACE("{}: called", nameId());
1198
1199 _imuRotations_accel.clear();
1200 _imuRotations_gyro.clear();
1201 _biasCovariances.clear();
1202 _processNoiseVariances.clear();
1204
1205 _cumulatedImuObs.clear();
1206 _cumulatedPinIds.clear();
1207 _lastFiltObs.reset();
1209 _firstTimestamp.reset();
1210
1211 _imuPosSet = false;
1212 _kfInitialized = false;
1213
1214 for (size_t pinIndex = 0; pinIndex < _pinData.size(); pinIndex++)
1215 {
1216 if (!inputPins.at(pinIndex).isPinLinked())
1217 {
1218 LOG_INFO("Fewer links than input pins - Consider deleting pins that are not connected to limit KF matrices to the necessary size.");
1219 }
1220 }
1221
1223
1224 _numStates = _numStatesEst + static_cast<uint8_t>((_nInputPins - 1) * _numStatesPerPin);
1225
1227 _kalmanFilter.setZero();
1228
1230
1231 // --------------------------------------------------------- KF Initializations ------------------------------------------------------------
1232 if (!_autoInitKF) // i.e. manual initialization thru inputs from the GUI
1233 {
1234 auto dtInit = 1.0 / _imuFrequency; // Initial state transition time in [s]
1235
1237 {
1239 }
1240 else // (_imuFusionType == ImuFusionType::BsplineKF)
1241 {
1243 _latestKnot = 0.0;
1244 }
1245
1246 LOG_DATA("{}: Initial kalmanFilter.x = {}", nameId(), _kalmanFilter.x.transpose());
1247 LOG_DATA("{}: Initial kalmanFilter.P =\n{}", nameId(), _kalmanFilter.P);
1248 LOG_DATA("{}: Initial kalmanFilter.Phi =\n{}", nameId(), _kalmanFilter.Phi);
1249 LOG_DATA("{}: Initial kalmanFilter.Q =\n{}", nameId(), _kalmanFilter.Q);
1250 }
1251
1252 // -------------------------------------------------- Measurement uncertainty matrix R -----------------------------------------------------
1254
1255 size_t pinDataIdx = 0;
1256 for (size_t pinIndex = 0; pinIndex < _nInputPins; ++pinIndex)
1257 {
1259 {
1260 pinDataIdx = pinIndex;
1261 }
1262
1263 // Measurement uncertainty for the angular rate (Variance σ²) in [(rad/s)^2, (rad/s)^2, (rad/s)^2]
1264 switch (_pinData[pinDataIdx].measurementUncertaintyAngularRateUnit)
1265 {
1267 _measurementNoiseVariances[2 * pinIndex] = (_pinData[pinDataIdx].measurementUncertaintyAngularRate).array().pow(2);
1268 break;
1270 _measurementNoiseVariances[2 * pinIndex] = (deg2rad(_pinData[pinDataIdx].measurementUncertaintyAngularRate)).array().pow(2);
1271 break;
1273 _measurementNoiseVariances[2 * pinIndex] = _pinData[pinDataIdx].measurementUncertaintyAngularRate;
1274 break;
1276 _measurementNoiseVariances[2 * pinIndex] = deg2rad((_pinData[pinDataIdx].measurementUncertaintyAngularRate).cwiseSqrt()).array().pow(2);
1277 break;
1278 }
1279
1280 // Measurement uncertainty for the acceleration (Variance σ²) in [(m^2)/(s^4), (m^2)/(s^4), (m^2)/(s^4)]
1281 switch (_pinData[pinDataIdx].measurementUncertaintyAccelerationUnit)
1282 {
1284 _measurementNoiseVariances[1 + 2 * pinIndex] = _pinData[pinDataIdx].measurementUncertaintyAcceleration;
1285 break;
1287 _measurementNoiseVariances[1 + 2 * pinIndex] = (_pinData[pinDataIdx].measurementUncertaintyAcceleration).array().pow(2);
1288 break;
1289 }
1290 }
1291
1293 {
1295 LOG_DATA("{}: imuCharacteristicsIdentical - kalmanFilter.R =\n{}", nameId(), _kalmanFilter.R);
1296 }
1297
1298 if (!_autoInitKF) { _kfInitialized = true; } // Auto-init initializes KF at 'avgEndTime' seconds --> see 'recvSignal'
1299
1300 LOG_DEBUG("ImuFusion initialized");
1301
1302 return true;
1303}
1304
1306{
1307 LOG_TRACE("{}: called", nameId());
1308}
1309
1311{
1312 while (inputPins.size() < _nInputPins)
1313 {
1314 nm::CreateInputPin(this, fmt::format("Pin {}", inputPins.size() + 1).c_str(), Pin::Type::Flow,
1315 { NAV::ImuObs::type() }, &ImuFusion::recvSignal);
1316 _pinData.emplace_back();
1317 if (outputPins.size() < _nInputPins)
1318 {
1319 nm::CreateOutputPin(this, fmt::format("ImuBiases {}1", outputPins.size() + 1).c_str(), Pin::Type::Flow, { NAV::InsGnssLCKFSolution::type() });
1320 }
1321 }
1322 while (inputPins.size() > _nInputPins) // TODO: while loop still necessary here? guiConfig also deletes pins
1323 {
1326 _pinData.pop_back();
1327 }
1328 _pinData.resize(_nInputPins);
1330}
1331
1333{
1336 for (size_t i = 0; i < _nInputPins; ++i)
1337 {
1338 _imuRotations_accel[i] = Eigen::Matrix3d::Zero();
1339 _imuRotations_gyro[i] = Eigen::Matrix3d::Zero();
1340
1341 // Assigning nan for an efficient check during runtime, whether mounting angles have been read for sensor i
1342 _imuRotations_accel[i](0, 0) = std::nan("");
1343 _imuRotations_gyro[i](0, 0) = std::nan("");
1344 }
1345}
1346
1348{
1349 auto imuObs = std::static_pointer_cast<const ImuObs>(queue.extract_front());
1350
1351 if (imuObs->insTime.empty())
1352 {
1353 LOG_ERROR("{}: Can't set new imuObs__t0 because the observation has no time tag (insTime/timeSinceStartup)", nameId());
1354 return;
1355 }
1356
1357 if (_latestTimestamp.empty())
1358 {
1359 // Initial time step for KF prediction
1360 InsTime dt_init = InsTime{ 0, 0, 0, 0, 0, 1.0 / _imuFrequency };
1361 _latestTimestamp = InsTime{ 0, 0, 0, 0, 0, (imuObs->insTime - dt_init).count() };
1362 _firstTimestamp = imuObs->insTime;
1363
1364 // Time until averaging ends and filtering starts (for auto-init of KF)
1365 _avgEndTime = imuObs->insTime + std::chrono::milliseconds(static_cast<int>(1e3 * _averageEndTime));
1366 }
1367
1368 _timeSinceStartup = static_cast<double>((imuObs->insTime - _firstTimestamp).count());
1369 LOG_DATA("_timeSinceStartup = {}", _timeSinceStartup);
1370
1371 // Predict states over the time difference between the latest signal and the one before
1372 auto dt = static_cast<double>((imuObs->insTime - _latestTimestamp).count());
1373 _latestTimestamp = imuObs->insTime;
1374 LOG_DATA("{}: dt = {}", nameId(), dt);
1375
1376 if (_kfInitialized)
1377 {
1379 {
1382 }
1383 else // (_imuFusionType == ImuFusionType::Bspline)
1384 {
1386
1388 {
1390
1392 LOG_DATA("{}: kalmanFilter.P before B-spline coeff rotation =\n{}", nameId(), _kalmanFilter.P.block<18, 18>(0, 0));
1394 }
1395 }
1396
1397 LOG_DATA("{}: kalmanFilter.P (B-spline coeffs) =\n{}", nameId(), _kalmanFilter.P.block<18, 18>(0, 0));
1398 LOG_DATA("{}: kalmanFilter.Phi =\n{}", nameId(), _kalmanFilter.Phi);
1399 LOG_DATA("{}: kalmanFilter.Q =\n{}", nameId(), _kalmanFilter.Q);
1400
1402 {
1403 if (inputPins.at(_pinData.size() - 1).isPinLinked())
1404 {
1405 auto rank = _kalmanFilter.P.fullPivLu().rank();
1406 if (rank != _kalmanFilter.P.rows())
1407 {
1408 LOG_WARN("{}: P.rank = {}", nameId(), rank);
1409 }
1410 }
1411 }
1412 }
1413
1414 // Read sensor rotation info from 'imuObs'
1415 if (std::isnan(_imuRotations_accel[pinIdx](0, 0)))
1416 {
1417 // Rotation matrix of the accelerometer platform to body frame
1418 _imuRotations_accel[pinIdx] = imuObs->imuPos.b_quat_p().toRotationMatrix();
1419 }
1420 if (std::isnan(_imuRotations_gyro[pinIdx](0, 0)))
1421 {
1422 // Rotation matrix of the gyro platform to body frame
1423 _imuRotations_gyro[pinIdx] = imuObs->imuPos.b_quat_p().toRotationMatrix();
1424 }
1425
1426 // Initialize H with mounting angles (DCM) of the sensor that provided the latest measurement
1427 auto DCM_accel = _imuRotations_accel.at(pinIdx);
1428 LOG_DATA("DCM_accel =\n{}", DCM_accel);
1429 auto DCM_gyro = _imuRotations_gyro.at(pinIdx);
1430 LOG_DATA("{}: DCM_gyro =\n{}", nameId(), DCM_gyro);
1431
1433 {
1435 LOG_DATA("{}: Sensor (pinIdx): {}, kalmanFilter.H =\n{}", nameId(), _kalmanFilter.H, pinIdx);
1436 }
1437 else // (_imuFusionType == ImuFusionType::BsplineKF)
1438 {
1440 LOG_DATA("{}: timeSinceStartup: {}, Sensor (pinIdx): {}, kalmanFilter.H =\n{}", nameId(), _timeSinceStartup, pinIdx, _kalmanFilter.H);
1441 }
1442
1444 {
1446 LOG_DATA("{}: kalmanFilter.R =\n{}", nameId(), _kalmanFilter.R);
1447 }
1448
1450 {
1451 auto rank = (_kalmanFilter.H * _kalmanFilter.P * _kalmanFilter.H.transpose() + _kalmanFilter.R).fullPivLu().rank();
1452 if (rank != _kalmanFilter.H.rows())
1453 {
1454 LOG_WARN("{}: (HPH^T + R).rank = {}", nameId(), rank);
1455 }
1456 }
1457
1459 {
1460 if (imuObs->insTime < _avgEndTime)
1461 {
1462 _cumulatedImuObs.push_back(imuObs);
1463 _cumulatedPinIds.push_back(pinIdx);
1464 }
1465 else // if (imuObs->insTime == _avgEndTime) // <-- do auto-init, once _avgEndTime is reached
1466 {
1467 double dtInit = 1.0 / _imuFrequency;
1469 _kfInitialized = true; // Start Kalman Filter
1470 }
1471 }
1472 if (_kfInitialized)
1473 {
1474 combineSignals(imuObs);
1475 }
1476}
1477
1478void NAV::ImuFusion::combineSignals(const std::shared_ptr<const ImuObs>& imuObs)
1479{
1480 LOG_DATA("{}: called", nameId());
1481
1482 auto imuObsFiltered = std::make_shared<ImuObs>(this->_imuPos);
1483
1484 LOG_DATA("{}: Estimated state before prediction: x =\n{}", nameId(), _kalmanFilter.x);
1485
1486 _kalmanFilter.predict();
1487
1488 LOG_DATA("{}: kalmanFilter.P (B-spline coeffs) =\n{}", nameId(), _kalmanFilter.P.block<18, 18>(0, 0));
1489
1490 LOG_DATA("{}: kalmanFilter.P (B-spline coeffs) =\n{}", nameId(), _kalmanFilter.P.block<18, 18>(0, 0));
1491
1492 _kalmanFilter.z.block<3, 1>(0, 0) = imuObs->p_angularRate;
1493 _kalmanFilter.z.block<3, 1>(3, 0) = imuObs->p_acceleration;
1494
1495 LOG_DATA("{}: Measurements z =\n{}", nameId(), _kalmanFilter.z);
1496 LOG_DATA("{}: coeff states x =\n{}", nameId(), _kalmanFilter.x.block<18, 1>(0, 0));
1497 LOG_DATA("{}: Innovation: z - H * x =\n{}", nameId(), _kalmanFilter.z - _kalmanFilter.H * _kalmanFilter.x);
1498
1499 _kalmanFilter.correct();
1500 LOG_DATA("{}: Estimated state after correction: x =\n{}", nameId(), _kalmanFilter.x);
1501
1503 {
1504 auto rankH = (_kalmanFilter.H * _kalmanFilter.P * _kalmanFilter.H.transpose() + _kalmanFilter.R).fullPivLu().rank();
1505 if (rankH != _kalmanFilter.H.rows())
1506 {
1507 LOG_WARN("{}: (HPH^T + R).rank = {}", nameId(), rankH);
1508 }
1509
1510 if (inputPins.at(_pinData.size() - 1).isPinLinked())
1511 {
1512 auto rankP = _kalmanFilter.P.fullPivLu().rank();
1513 if (rankP != _kalmanFilter.P.rows())
1514 {
1515 LOG_WARN("{}: P.rank = {}", nameId(), rankP);
1516 LOG_DATA("{}: kalmanFilter.P =\n{}", nameId(), _kalmanFilter.P);
1517 }
1518 }
1519 }
1520
1521 // Construct imuObs
1522 imuObsFiltered->insTime = imuObs->insTime;
1524 {
1525 imuObsFiltered->p_acceleration = { _kalmanFilter.x(6, 0), _kalmanFilter.x(7, 0), _kalmanFilter.x(8, 0) };
1526 imuObsFiltered->p_angularRate = { _kalmanFilter.x(0, 0), _kalmanFilter.x(1, 0), _kalmanFilter.x(2, 0) };
1527 }
1528 else // (_imuFusionType == ImuFusionType::BsplineKF)
1529 {
1531
1532 LOG_DATA("{}: timeSinceStartup: {}, qBsplines (stacked B-spline values, cumulatively = 1) = {}, {}, {}", nameId(), _timeSinceStartup, qBsplines.at(0), qBsplines.at(1), qBsplines.at(2));
1533 LOG_DATA("{}: timeSinceStartup: {}, Angular rate B-spline coefficient estimates:\n{}", nameId(), _timeSinceStartup, _kalmanFilter.x.block<9, 1>(0, 0));
1534 LOG_DATA("{}: timeSinceStartup: {}, Acceleration B-spline coefficient estimates:\n{}", nameId(), _timeSinceStartup, _kalmanFilter.x.block<9, 1>(9, 0));
1535
1536 // Estimated angular rate: Cumulative sum of the three estimated B-spline coefficients for the angular rate
1537 auto angRateEst = _kalmanFilter.x.block<3, 1>(0, 0) * qBsplines.at(0)
1538 + _kalmanFilter.x.block<3, 1>(3, 0) * qBsplines.at(1)
1539 + _kalmanFilter.x.block<3, 1>(6, 0) * qBsplines.at(2);
1540
1541 // Estimated acceleration: Cumulative sum of the three estimated B-spline coefficients for the acceleration
1542 auto accelEst = _kalmanFilter.x.block<3, 1>(9, 0) * qBsplines.at(0)
1543 + _kalmanFilter.x.block<3, 1>(12, 0) * qBsplines.at(1)
1544 + _kalmanFilter.x.block<3, 1>(15, 0) * qBsplines.at(2);
1545
1546 LOG_DATA("{}: imuObs->insTime = {}, timeSinceStartup = {}, angRateEst = {}, accelEst = {}", nameId(), imuObs->insTime.toYMDHMS(), _timeSinceStartup, angRateEst.transpose(), accelEst.transpose());
1547
1548 imuObsFiltered->p_acceleration = accelEst;
1549 imuObsFiltered->p_angularRate = angRateEst;
1550 }
1551
1552 // Detect jumps back in time
1553 if (imuObsFiltered->insTime < _lastFiltObs)
1554 {
1555 LOG_ERROR("{}: imuObsFiltered->insTime < _lastFiltObs --> {}", nameId(), static_cast<double>((imuObsFiltered->insTime - _lastFiltObs).count()));
1556 }
1557 _lastFiltObs = imuObsFiltered->insTime;
1558
1560
1561 for (size_t OUTPUT_PORT_INDEX_BIAS = 1; OUTPUT_PORT_INDEX_BIAS < _nInputPins; ++OUTPUT_PORT_INDEX_BIAS)
1562 {
1563 auto imuRelativeBiases = std::make_shared<InsGnssLCKFSolution>();
1564 imuRelativeBiases->insTime = imuObs->insTime;
1565 auto biasIndex = _numStatesEst + static_cast<uint8_t>((OUTPUT_PORT_INDEX_BIAS - 1) * _numStatesPerPin);
1566 LOG_DATA("{}: biasIndex = {}", nameId(), biasIndex);
1567
1568 imuRelativeBiases->b_biasGyro.value = { _kalmanFilter.x(biasIndex, 0), _kalmanFilter.x(biasIndex + 1, 0), _kalmanFilter.x(biasIndex + 2, 0) };
1569 imuRelativeBiases->b_biasAccel.value = { _kalmanFilter.x(biasIndex + 3, 0), _kalmanFilter.x(biasIndex + 4, 0), _kalmanFilter.x(biasIndex + 5, 0) };
1570
1571 LOG_DATA("{}: timeSinceStartup = {}, Relative bias {}1 Gyro: {}", nameId(), _timeSinceStartup, OUTPUT_PORT_INDEX_BIAS + 1, imuRelativeBiases->b_biasGyro.value.transpose());
1572 LOG_DATA("{}: timeSinceStartup = {}, Relative bias {}1 Accel: {}", nameId(), _timeSinceStartup, OUTPUT_PORT_INDEX_BIAS + 1, imuRelativeBiases->b_biasAccel.value.transpose());
1573
1574 invokeCallbacks(OUTPUT_PORT_INDEX_BIAS, imuRelativeBiases);
1575 }
1576}
1577
1578// -------------------------------------- Measurement noise matrix R -----------------------------------------
1579
1580Eigen::MatrixXd NAV::ImuFusion::measurementNoiseMatrix_R_adaptive(double alpha, const Eigen::MatrixXd& R, const Eigen::VectorXd& e, const Eigen::MatrixXd& H, const Eigen::MatrixXd& P)
1581{
1582 return alpha * R + (1.0 - alpha) * (e * e.transpose() + H * P * H.transpose());
1583}
1584
1585void NAV::ImuFusion::measurementNoiseMatrix_R(Eigen::MatrixXd& R, size_t pinIndex) const
1586{
1587 R.block<3, 3>(0, 0).diagonal() = _measurementNoiseVariances.at(2 * pinIndex);
1588 R.block<3, 3>(3, 3).diagonal() = _measurementNoiseVariances.at(2 * pinIndex + 1);
1589}
Kalman filter matrices for the B-spline Multi-IMU fusion.
Combo representing an enumeration.
Save/Load the Nodes.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
Kalman filter matrices for the Integrated-Random-Walk (IRW) Multi-IMU fusion.
Combines signals of sensors that provide the same signal-type to one signal.
Defines Widgets which allow the input of values and the selection of the unit.
Loosely-coupled Kalman Filter INS/GNSS errors.
Defines how to save certain datatypes to json.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Manages all Nodes.
Constructs four overlapping qaudratic B-splines.
KalmanFilter _kalmanFilter
Kalman Filter representation.
void updateNumberOfInputPins()
Adds/Deletes Input Pins depending on the variable _nInputPins.
std::vector< Eigen::Matrix3d > _imuRotations_accel
Rotations of all connected accelerometers - key: pinIndex, value: Rotation matrix of the acceleromete...
uint8_t _numStatesEst
Number of estimated states (depends on imuFusionType)
const uint8_t _numStatesEstIRWKF
Number of states estimated by the IRW-KF (angular rate, angular acceleration, specific force,...
void initializeMountingAngles()
Initializes the rotation matrices used for the mounting angles of the sensors.
std::string type() const override
String representation of the Class Type.
bool initialize() override
Initialize the node.
Eigen::Vector3d _procNoiseCoeffsAccelTemp
Temporary vector for the initial coefficients' process noise for the acceleration.
bool _kfInitialized
flag to check whether KF has been auto-initialized
bool _checkKalmanMatricesRanks
Check the rank of the Kalman matrices every iteration (computationally expensive)
bool _imuCharacteristicsIdentical
If the multiple IMUs have the same characteristics, GUI input cells can be reduced considerably.
std::vector< Eigen::Matrix3d > _imuRotations_gyro
Rotations of all connected gyros - key: pinIndex, value: Rotation matrix of the gyro platform to body...
Eigen::Vector3d _initCovarianceCoeffsAngRateTemp
Temporary vector for the initial coefficients' initial covariance for the angular rate.
std::vector< Eigen::Vector3d > _measurementNoiseVariances
Container for measurement noises of each sensor.
const uint8_t _numBsplines
Number of quadratic B-splines that make up the entire 3D stacked B-spline.
json save() const override
Saves the node into a json object.
void recvSignal(InputPin::NodeDataQueue &queue, size_t pinIdx)
Receive Function for the signal at the time tₖ
const uint8_t _numMeasurements
Number of measurements overall.
size_t _nInputPins
Number of input pins.
InsTime _lastFiltObs
Previous observation (for timestamp)
~ImuFusion() override
Destructor.
void measurementNoiseMatrix_R(Eigen::MatrixXd &R, size_t pinIndex=0) const
Calculates the initial measurement noise matrix R.
ImuPos _imuPos
Position and rotation information for conversion from platform to body frame.
Definition ImuFusion.hpp:66
InsTime _firstTimestamp
Saves the first timestamp in [s].
PinDataIRWKF _pinDataIRWKF
Stores IRW-KF specific parameter data.
Eigen::Vector3d _initCoeffsAccelTemp
Temporary vector for the initial coefficients for acceleration.
double _imuFrequency
Highest IMU sample rate in [Hz] (for time step in KF prediction)
std::vector< Eigen::Vector3d > _biasCovariances
Container for the bias covariances.
double _averageEndTime
Time until averaging ends and filtering starts in [s].
static std::string typeStatic()
String representation of the Class Type.
bool _imuPosSet
Check whether the combined solution has an '_imuPos' set.
static Eigen::MatrixXd measurementNoiseMatrix_R_adaptive(double alpha, const Eigen::MatrixXd &R, const Eigen::VectorXd &e, const Eigen::MatrixXd &H, const Eigen::MatrixXd &P)
Calculates the adaptive measurement noise matrix R.
static constexpr size_t OUTPUT_PORT_INDEX_COMBINED_SIGNAL
Flow (ImuObs)
Definition ImuFusion.hpp:69
void guiConfig() override
ImGui config window which is shown on double click.
ImuFusion()
Default constructor.
std::vector< std::shared_ptr< const NAV::ImuObs > > _cumulatedImuObs
Container that collects all imuObs for averaging for auto-init of the KF.
void restore(const json &j) override
Restores the node from a json object.
static std::string category()
String representation of the Class Category.
Eigen::Vector3d _initCovarianceCoeffsAccelTemp
Temporary vector for the initial coefficients' initial covariance for the acceleration.
std::vector< size_t > _cumulatedPinIds
Container that collects all pinIds for averaging for auto-init of the KF.
uint8_t _numStates
Number of states overall.
const uint8_t _numStatesEstBsplineKF
Number of states estimated by the B-spline KF (3 stacked B-splines in 3D for angular rate and specifi...
double _timeSinceStartup
Time since startup in [s].
bool _initJerkAngAcc
flag to determine how jerk and angular acceleration states are initialized if '_autoInitKF = true'
std::vector< Eigen::VectorXd > _processNoiseVariances
Container for process noise of each state.
void deinitialize() override
Deinitialize the node.
double _latestKnot
Latest knot in [s].
const uint8_t _numStatesPerPin
Number of states per pin (biases of accel and gyro)
ImuFusionType _imuFusionType
KF-type for the IMU fusion, selected in the GUI.
bool _autoInitKF
Auto-initialize the Kalman Filter - GUI setting.
@ Bspline
B-spline Kalman filter.
@ IRWKF
IRW Kalman filter.
double _splineSpacing
Time difference between two quadratic B-splines in the stacked B-spline.
std::vector< PinData > _pinData
Stores parameter data for each connected sensor.
Eigen::Vector3d _procNoiseCoeffsAngRateTemp
Temporary vector for the initial coefficients' process noise for the angular rate.
void combineSignals(const std::shared_ptr< const ImuObs > &imuObs)
Combines the signals.
PinDataBsplineKF _pinDataBsplineKF
Stores Bspline-KF specific parameter data.
bool _imuBiasesIdentical
If the multiple IMUs have the same bias, GUI input cells can be reduced considerably.
InsTime _latestTimestamp
Saves the timestamp of the measurement before in [s].
InsTime _avgEndTime
Time until averaging ends and filtering starts as 'InsTime'.
Eigen::Vector3d _initCoeffsAngRateTemp
Temporary vector for the initial coefficients for angular rate.
static std::string type()
Returns the type of the data class.
Definition ImuObs.hpp:33
Imu(const Imu &)=delete
Copy constructor.
TsDeque< std::shared_ptr< const NAV::NodeData > > NodeDataQueue
Node data queue type.
Definition Pin.hpp:707
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
Generalized Kalman Filter class.
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:395
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:410
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:399
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:397
std::string nameId() const
Node name and id.
Definition Node.cpp:253
std::string name
Name of the Node.
Definition Node.hpp:395
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
Definition Node.cpp:180
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:413
auto extract_front()
Returns a copy of the first element in the container and removes it from the container.
Definition TsDeque.hpp:494
static float windowFontRatio()
Ratio to multiply for GUI window elements.
ImGui extensions.
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'.
Definition imgui_ex.cpp:294
void rotateErrorCovariances(Eigen::MatrixXd &P, uint8_t &numStates, const double &sigmaScalingFactorAngRate=3.0, const double &sigmaScalingFactorAccel=3.0)
Rotates the B-spline coefficient error covariances in P, once a new B-spline is introduced.
Definition BsplineKF.cpp:62
std::array< double, 3 > quadraticBsplines(const double &ti, const double &splineSpacing=1.0)
Set the points/knots of the four B-splines.
void processNoiseMatrix_Q(Eigen::MatrixXd &Q, const double &dt, const std::vector< Eigen::VectorXd > &processNoiseVariances, const uint8_t &numStates, const bool &imuCharacteristicsIdentical=false)
Calculates the process noise matrix Q.
Definition BsplineKF.cpp:38
void rotateCoeffStates(Eigen::MatrixXd &x)
Rotates the B-spline coefficient states in the state vector x, once a new B-spline is introduced.
Definition BsplineKF.cpp:56
KalmanFilter initializeKalmanFilterManually(const size_t &numInputPins, const std::vector< PinData > &pinData, const PinDataBsplineKF &pinDataBsplineKF, const uint8_t &numStates, const double &dtInit, std::vector< Eigen::VectorXd > &processNoiseVariances, KalmanFilter &kalmanFilter, const bool &imuCharacteristicsIdentical, const bool &imuBiasesIdentical)
Initializes the BsplineKF manually (i.e. using GUI inputs instead of averaging)
Eigen::MatrixXd designMatrix_H(const double &ti, const double &splineSpacing, const Eigen::Matrix3d &DCM_accel, const Eigen::Matrix3d &DCM_gyro, const size_t &pinIndex, const uint8_t &numMeasurements, const uint8_t &numStates, const uint8_t &numStatesEst, const uint8_t &numStatesPerPin)
Calculates the design matrix H.
Definition BsplineKF.cpp:91
void stateTransitionMatrix_Phi(Eigen::MatrixXd &Phi, const double &dt)
Calculates the state-transition-matrix 𝚽
Definition IRWKF.cpp:76
Eigen::MatrixXd designMatrix_H(const Eigen::Matrix3d &DCM_accel, const Eigen::Matrix3d &DCM_gyro, const size_t &pinIndex, const uint8_t &numMeasurements, const uint8_t &numStates, const uint8_t &numStatesEst, const uint8_t &numStatesPerPin)
Calculates the design matrix H.
Definition IRWKF.cpp:82
void processNoiseMatrix_Q(Eigen::MatrixXd &Q, const double &dt, const std::vector< Eigen::VectorXd > &processNoiseVariances, const uint8_t &numStates, const bool &imuCharacteristicsIdentical=false)
Calculates the process noise matrix Q.
Definition IRWKF.cpp:49
KalmanFilter initializeKalmanFilterManually(const size_t &numInputPins, const std::vector< PinData > &pinData, const PinDataIRWKF &pinDataIRWKF, const uint8_t &numStates, const double &dtInit, std::vector< Eigen::VectorXd > &processNoiseVariances, KalmanFilter &kalmanFilter, const bool &imuCharacteristicsIdentical, const bool &imuBiasesIdentical)
Initializes the IRWKF manually (i.e. using GUI inputs instead of averaging)
Definition IRWKF.cpp:102
KalmanFilter initializeKalmanFilterAuto(const size_t &nInputPins, const std::vector< PinData > &pinData, const PinDataIRWKF &pinDataIRWKF, const std::vector< size_t > &cumulatedPinIds, const std::vector< std::shared_ptr< const NAV::ImuObs > > &cumulatedImuObs, const bool &initJerkAngAcc, const double &dtInit, const uint8_t &numStates, const uint8_t &numMeasurements, std::vector< Eigen::VectorXd > &processNoiseVariances, KalmanFilter &kalmanFilter)
Initializes the IRWKF automatically, i.e. init values are calculated by averaging the data in the fir...
Definition IRWKF.cpp:357
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 DeleteOutputPin(OutputPin &pin)
Deletes the output pin. Invalidates the pin reference given.
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.
InputWithUnitChange InputDouble3WithUnit(const char *label, float itemWidth, float unitWidth, double v[3], U &combo_current_item, const char *combo_items_separated_by_zeros, const char *format="%.6f", ImGuiInputTextFlags flags=0, int combo_popup_max_height_in_items=-1)
Shows an InputText GUI element to modify the provided value and also set its unit.
bool EnumCombo(const char *label, T &enumeration, size_t startIdx=0)
Combo representing an enumeration.
Definition EnumCombo.hpp:30
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
void to_json(json &j, const Node &node)
Converts the provided node into a json object.
Definition Node.cpp:990
void from_json(const json &j, Node &node)
Converts the provided json object into a node object.
Definition Node.cpp:1007
constexpr auto deg2rad(const T &deg)
Convert Degree to Radians.
Definition Units.hpp:21
Sensor information specific to the Bspline-KF.
Definition PinData.hpp:179
Eigen::VectorXd initCovarianceCoeffsAngRate
GUI selection for the initial covariance of the B-spline coefficients of the angular rate.
Definition PinData.hpp:205
PinData::AccelerationUnit initCoeffsAccelUnit
Gui selection for the unit of the initial coefficients of the acceleration B-splines.
Definition PinData.hpp:185
PinData::AccelerationVarianceUnit initCovarianceCoeffsAccelUnit
Gui selection for the unit of the initial covariance for the coefficients of acceleration.
Definition PinData.hpp:190
Eigen::VectorXd initCoeffsAngRate
GUI selection for the initial B-spline coefficients of the angular rate.
Definition PinData.hpp:200
PinData::AngRateVarianceUnit initCovarianceCoeffsAngRateUnit
Gui selection for the unit of the initial covariance for the coefficients of angular rate.
Definition PinData.hpp:188
Eigen::VectorXd varCoeffsAccelNoise
GUI selection for the coeffs of the acceleration process noise (diagonal values)
Definition PinData.hpp:212
Eigen::VectorXd initCoeffsAccel
GUI selection for the initial B-spline coefficients of the acceleration.
Definition PinData.hpp:202
Eigen::VectorXd initCovarianceCoeffsAccel
GUI selection for the initial covariance of the B-spline coefficients of the acceleration.
Definition PinData.hpp:207
Eigen::VectorXd varCoeffsAngRateNoise
GUI selection for the coeffs of the angular rate process noise (diagonal values)
Definition PinData.hpp:210
PinData::AngRateVarianceUnit varCoeffsAngRateUnit
GUI selection for the B-spline coeffs of the angular rate process noise (diagonal values)
Definition PinData.hpp:193
PinData::AccelerationVarianceUnit varCoeffsAccelUnit
GUI selection for the B-spline coeffs of the acceleration process noise (diagonal values)
Definition PinData.hpp:195
PinData::AngRateUnit initCoeffsAngularRateUnit
Gui selection for the unit of the initial coefficients of the angular rate B-splines.
Definition PinData.hpp:183
Sensor information specific to the IRW-KF.
Definition PinData.hpp:105
JerkVarianceUnit initCovarianceJerkUnit
Gui selection for the unit of the initial covariance for the jerk.
Definition PinData.hpp:148
PinData::AccelerationUnit initAccelerationUnit
Gui selection for the unit of the initial acceleration.
Definition PinData.hpp:141
Eigen::Vector3d initAcceleration
GUI selection for the initial acceleration.
Definition PinData.hpp:162
AngularAccUnit initAngularAccUnit
Gui selection for the unit of the initial angular acceleration.
Definition PinData.hpp:139
Eigen::Vector3d initCovarianceAngularAcc
GUI selection for the initial covariance diagonal values for angular acceleration (standard deviation...
Definition PinData.hpp:167
Eigen::Vector3d initAngularRate
GUI selection for the initial angular rate.
Definition PinData.hpp:158
Eigen::Vector3d initCovarianceJerk
GUI selection for the initial covariance diagonal values for jerk (standard deviation σ or Variance σ...
Definition PinData.hpp:169
Eigen::Vector3d varJerkNoise
GUI selection for the jerk process noise diagonal values.
Definition PinData.hpp:174
AngularAccVarianceUnit varAngularAccNoiseUnit
Gui selection for the unit of the angular acceleration process noise.
Definition PinData.hpp:151
Eigen::Vector3d initJerk
GUI selection for the initial jerk.
Definition PinData.hpp:164
Eigen::Vector3d varAngularAccNoise
GUI selection for the angular acceleration process noise diagonal values.
Definition PinData.hpp:172
@ m2_s6
Variance [(m^2)/(s^6), (m^2)/(s^6), (m^2)/(s^6)].
Definition PinData.hpp:130
AngularAccVarianceUnit initCovarianceAngularAccUnit
Gui selection for the unit of the initial covariance for the angular acceleration.
Definition PinData.hpp:146
PinData::AngRateUnit initAngularRateUnit
Gui selection for the unit of the initial angular rate.
Definition PinData.hpp:137
Eigen::Vector3d initAngularAcc
GUI selection for the initial angular acceleration.
Definition PinData.hpp:160
JerkVarianceUnit varJerkNoiseUnit
Gui selection for the unit of the jerk process noise.
Definition PinData.hpp:153
JerkUnit initJerkUnit
Gui selection for the Unit of the initial jerk.
Definition PinData.hpp:143
@ deg2_s4
Variance [(deg^2)/(s^4), (deg^2)/(s^4), (deg^2)/(s^4)].
Definition PinData.hpp:124
@ rad2_s4
Variance [(rad^2)/(s^4), (rad^2)/(s^4), (rad^2)/(s^4)].
Definition PinData.hpp:122
Information about a sensor which is connected to a certain pin (i.e. sensor characteristics defined i...
Definition PinData.hpp:23
AccelerationVarianceUnit measurementUncertaintyAccelerationUnit
Gui selection for the unit of the acceleration's measurement uncertainty.
Definition PinData.hpp:76
Eigen::Vector3d initCovarianceAngularRate
GUI selection for the initial covariance diagonal values for angular rate (standard deviation σ or Va...
Definition PinData.hpp:86
Eigen::Vector3d measurementUncertaintyAngularRate
Gui selection for the angular rate measurement uncertainty diagonal values.
Definition PinData.hpp:98
@ m2_s4
Variance [(m^2)/(s^4), (m^2)/(s^4), (m^2)/(s^4)].
Definition PinData.hpp:50
@ m_s2
Standard deviation [m/s², m/s², m/s²].
Definition PinData.hpp:51
AccelerationVarianceUnit initCovarianceBiasAccUnit
Gui selection for the Unit of the initial covariance for the acceleration biases.
Definition PinData.hpp:68
Eigen::Vector3d varBiasAngRateNoise
GUI selection for the process noise of the angular rate diagonal values (standard deviation σ or Vari...
Definition PinData.hpp:94
Eigen::Vector3d initCovarianceBiasAcc
GUI selection for the initial covariance diagonal values for acceleration biases (standard deviation ...
Definition PinData.hpp:92
Eigen::Vector3d initCovarianceAcceleration
GUI selection for the initial covariance diagonal values for acceleration (standard deviation σ or Va...
Definition PinData.hpp:88
Eigen::Vector3d measurementUncertaintyAcceleration
Gui selection for the acceleration measurement uncertainty diagonal values.
Definition PinData.hpp:100
AngRateVarianceUnit varBiasAngRateNoiseUnit
Gui selection for the Unit of the process noise of the angular rate.
Definition PinData.hpp:70
AccelerationUnit initAccelerationBiasUnit
GUI selection for the unit of the initial angular acceleration bias.
Definition PinData.hpp:59
AngRateVarianceUnit measurementUncertaintyAngularRateUnit
Gui selection for the unit of the angular rate's measurement uncertainty.
Definition PinData.hpp:74
@ rad2_s2
Variance [rad²/s², rad²/s², rad²/s²].
Definition PinData.hpp:41
@ deg2_s2
Variance [deg²/s², deg²/s², deg²/s²].
Definition PinData.hpp:43
@ deg_s
Standard deviation [deg/s, deg/s, deg/s].
Definition PinData.hpp:44
@ rad_s
Standard deviation [rad/s, rad/s, rad/s].
Definition PinData.hpp:42
Eigen::Vector3d initAccelerationBias
GUI selection for the initial acceleration bias.
Definition PinData.hpp:83
Eigen::Vector3d initAngularRateBias
GUI selection for the initial angular rate bias.
Definition PinData.hpp:81
AngRateVarianceUnit initCovarianceAngularRateUnit
Gui selection for the Unit of the initial covariance for the angular rate.
Definition PinData.hpp:62
Eigen::Vector3d initCovarianceBiasAngRate
GUI selection for the initial covariance diagonal values for angular rate biases (standard deviation ...
Definition PinData.hpp:90
AccelerationVarianceUnit initCovarianceAccelerationUnit
Gui selection for the Unit of the initial covariance for the acceleration.
Definition PinData.hpp:64
Eigen::Vector3d varBiasAccelerationNoise
GUI selection for the process noise of the acceleration diagonal values (standard deviation σ or Vari...
Definition PinData.hpp:96
AngRateVarianceUnit initCovarianceBiasAngRateUnit
Gui selection for the Unit of the initial covariance for the angular rate biases.
Definition PinData.hpp:66
AccelerationVarianceUnit varBiasAccelerationNoiseUnit
Gui selection for the Unit of the process noise of the acceleration.
Definition PinData.hpp:72
AngRateUnit initAngularRateBiasUnit
GUI selection for the unit of the initial angular rate bias.
Definition PinData.hpp:57
@ Flow
NodeData Trigger.
Definition Pin.hpp:52