Line | Branch | Exec | Source |
---|---|---|---|
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 | |||
13 | #include "Navigation/Transformations/Units.hpp" | ||
14 | |||
15 | #include "Navigation/INS/SensorCombiner/IRWKF/IRWKF.hpp" | ||
16 | #include "Navigation/INS/SensorCombiner/BsplineKF/BsplineKF.hpp" | ||
17 | #include "Navigation/INS/SensorCombiner/BsplineKF/QuadraticBsplines.hpp" | ||
18 | #include "NodeData/State/InsGnssLCKFSolution.hpp" | ||
19 | |||
20 | #include <imgui_internal.h> | ||
21 | #include "internal/gui/widgets/imgui_ex.hpp" | ||
22 | #include "internal/gui/widgets/InputWithUnit.hpp" | ||
23 | #include "internal/gui/widgets/EnumCombo.hpp" | ||
24 | #include "internal/gui/widgets/HelpMarker.hpp" | ||
25 | #include "internal/gui/NodeEditorApplication.hpp" | ||
26 | #include "util/Json.hpp" | ||
27 | |||
28 | #include "internal/NodeManager.hpp" | ||
29 | namespace nm = NAV::NodeManager; | ||
30 | #include "internal/FlowManager.hpp" | ||
31 | |||
32 | namespace 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 | ||
37 | ✗ | static 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 | ||
68 | 9 | static void from_json(const json& j, PinData& data) // NOLINT(misc-use-anonymous-namespace) | |
69 | { | ||
70 | // ------------------------------------------ Initialization --------------------------------------------- | ||
71 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initAngularRateBias")) |
72 | { | ||
73 | 9 | j.at("initAngularRateBias").get_to(data.initAngularRateBias); | |
74 | } | ||
75 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initAngularRateBiasUnit")) |
76 | { | ||
77 | 9 | j.at("initAngularRateBiasUnit").get_to(data.initAngularRateBiasUnit); | |
78 | } | ||
79 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initAccelerationBias")) |
80 | { | ||
81 | 9 | j.at("initAccelerationBias").get_to(data.initAccelerationBias); | |
82 | } | ||
83 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initAccelerationBiasUnit")) |
84 | { | ||
85 | 9 | j.at("initAccelerationBiasUnit").get_to(data.initAccelerationBiasUnit); | |
86 | } | ||
87 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceAngularRate")) |
88 | { | ||
89 | 9 | j.at("initCovarianceAngularRate").get_to(data.initCovarianceAngularRate); | |
90 | } | ||
91 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceAngularRateUnit")) |
92 | { | ||
93 | 9 | j.at("initCovarianceAngularRateUnit").get_to(data.initCovarianceAngularRateUnit); | |
94 | } | ||
95 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceAcceleration")) |
96 | { | ||
97 | 9 | j.at("initCovarianceAcceleration").get_to(data.initCovarianceAcceleration); | |
98 | } | ||
99 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceAccelerationUnit")) |
100 | { | ||
101 | 9 | j.at("initCovarianceAccelerationUnit").get_to(data.initCovarianceAccelerationUnit); | |
102 | } | ||
103 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceBiasAngRate")) |
104 | { | ||
105 | 9 | j.at("initCovarianceBiasAngRate").get_to(data.initCovarianceBiasAngRate); | |
106 | } | ||
107 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceBiasAngRateUnit")) |
108 | { | ||
109 | 9 | j.at("initCovarianceBiasAngRateUnit").get_to(data.initCovarianceBiasAngRateUnit); | |
110 | } | ||
111 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceBiasAcc")) |
112 | { | ||
113 | 9 | j.at("initCovarianceBiasAcc").get_to(data.initCovarianceBiasAcc); | |
114 | } | ||
115 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("initCovarianceBiasAccUnit")) |
116 | { | ||
117 | 9 | j.at("initCovarianceBiasAccUnit").get_to(data.initCovarianceBiasAccUnit); | |
118 | } | ||
119 | // ------------------------------------------- Process Noise --------------------------------------------- | ||
120 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("varBiasAccelerationNoise")) |
121 | { | ||
122 | 9 | j.at("varBiasAccelerationNoise").get_to(data.varBiasAccelerationNoise); | |
123 | } | ||
124 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("varBiasAccelerationNoiseUnit")) |
125 | { | ||
126 | 9 | j.at("varBiasAccelerationNoiseUnit").get_to(data.varBiasAccelerationNoiseUnit); | |
127 | } | ||
128 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("varBiasAngRateNoise")) |
129 | { | ||
130 | 9 | j.at("varBiasAngRateNoise").get_to(data.varBiasAngRateNoise); | |
131 | } | ||
132 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("varBiasAngRateNoiseUnit")) |
133 | { | ||
134 | 9 | j.at("varBiasAngRateNoiseUnit").get_to(data.varBiasAngRateNoiseUnit); | |
135 | } | ||
136 | // ----------------------------------------- Measurement Noise ------------------------------------------- | ||
137 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("measurementUncertaintyAngularRate")) |
138 | { | ||
139 | 9 | j.at("measurementUncertaintyAngularRate").get_to(data.measurementUncertaintyAngularRate); | |
140 | } | ||
141 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("measurementUncertaintyAngularRateUnit")) |
142 | { | ||
143 | 9 | j.at("measurementUncertaintyAngularRateUnit").get_to(data.measurementUncertaintyAngularRateUnit); | |
144 | } | ||
145 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("measurementUncertaintyAcceleration")) |
146 | { | ||
147 | 9 | j.at("measurementUncertaintyAcceleration").get_to(data.measurementUncertaintyAcceleration); | |
148 | } | ||
149 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | if (j.contains("measurementUncertaintyAccelerationUnit")) |
150 | { | ||
151 | 9 | j.at("measurementUncertaintyAccelerationUnit").get_to(data.measurementUncertaintyAccelerationUnit); | |
152 | } | ||
153 | 9 | } | |
154 | |||
155 | /// @brief Write info to a json object | ||
156 | /// @param[out] j Json output | ||
157 | /// @param[in] data Object to read info from | ||
158 | ✗ | static 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 | ||
185 | 2 | static void from_json(const json& j, PinDataIRWKF& data) // NOLINT(misc-use-anonymous-namespace) | |
186 | { | ||
187 | // ------------------------------------------ Initialization --------------------------------------------- | ||
188 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAngularRate")) |
189 | { | ||
190 | 2 | j.at("initAngularRate").get_to(data.initAngularRate); | |
191 | } | ||
192 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAngularRateUnit")) |
193 | { | ||
194 | 2 | j.at("initAngularRateUnit").get_to(data.initAngularRateUnit); | |
195 | } | ||
196 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAcceleration")) |
197 | { | ||
198 | 2 | j.at("initAcceleration").get_to(data.initAcceleration); | |
199 | } | ||
200 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAccelerationUnit")) |
201 | { | ||
202 | 2 | j.at("initAccelerationUnit").get_to(data.initAccelerationUnit); | |
203 | } | ||
204 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAngularAcc")) |
205 | { | ||
206 | 2 | j.at("initAngularAcc").get_to(data.initAngularAcc); | |
207 | } | ||
208 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initAngularAccUnit")) |
209 | { | ||
210 | 2 | j.at("initAngularAccUnit").get_to(data.initAngularAccUnit); | |
211 | } | ||
212 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initJerk")) |
213 | { | ||
214 | 2 | j.at("initJerk").get_to(data.initJerk); | |
215 | } | ||
216 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initJerkUnit")) |
217 | { | ||
218 | 2 | j.at("initJerkUnit").get_to(data.initJerkUnit); | |
219 | } | ||
220 | |||
221 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceAngularAcc")) |
222 | { | ||
223 | 2 | j.at("initCovarianceAngularAcc").get_to(data.initCovarianceAngularAcc); | |
224 | } | ||
225 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceAngularAccUnit")) |
226 | { | ||
227 | 2 | j.at("initCovarianceAngularAccUnit").get_to(data.initCovarianceAngularAccUnit); | |
228 | } | ||
229 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceJerk")) |
230 | { | ||
231 | 2 | j.at("initCovarianceJerk").get_to(data.initCovarianceJerk); | |
232 | } | ||
233 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceJerkUnit")) |
234 | { | ||
235 | 2 | j.at("initCovarianceJerkUnit").get_to(data.initCovarianceJerkUnit); | |
236 | } | ||
237 | |||
238 | // ------------------------------------------- Process Noise --------------------------------------------- | ||
239 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varAngularAccNoise")) |
240 | { | ||
241 | 2 | j.at("varAngularAccNoise").get_to(data.varAngularAccNoise); | |
242 | } | ||
243 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varAngularAccNoiseUnit")) |
244 | { | ||
245 | 2 | j.at("varAngularAccNoiseUnit").get_to(data.varAngularAccNoiseUnit); | |
246 | } | ||
247 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varJerkNoise")) |
248 | { | ||
249 | 2 | j.at("varJerkNoise").get_to(data.varJerkNoise); | |
250 | } | ||
251 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varJerkNoiseUnit")) |
252 | { | ||
253 | 2 | j.at("varJerkNoiseUnit").get_to(data.varJerkNoiseUnit); | |
254 | } | ||
255 | 2 | } | |
256 | |||
257 | /// @brief Write info to a json object | ||
258 | /// @param[out] j Json output | ||
259 | /// @param[in] data Object to read info from | ||
260 | ✗ | static 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 | ||
283 | 2 | static void from_json(const json& j, PinDataBsplineKF& data) // NOLINT(misc-use-anonymous-namespace) | |
284 | { | ||
285 | // ------------------------------------------ Initialization --------------------------------------------- | ||
286 | |||
287 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (j.contains("initCoeffsAngRate")) |
288 | { | ||
289 | ✗ | j.at("initCoeffsAngRate").get_to(data.initCoeffsAngRate); | |
290 | } | ||
291 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCoeffsAngularRateUnit")) |
292 | { | ||
293 | 2 | j.at("initCoeffsAngularRateUnit").get_to(data.initCoeffsAngularRateUnit); | |
294 | } | ||
295 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCoeffsAccel")) |
296 | { | ||
297 | 2 | j.at("initCoeffsAccel").get_to(data.initCoeffsAccel); | |
298 | } | ||
299 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCoeffsAccelUnit")) |
300 | { | ||
301 | 2 | j.at("initCoeffsAccelUnit").get_to(data.initCoeffsAccelUnit); | |
302 | } | ||
303 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAngRate")) |
304 | { | ||
305 | 2 | j.at("initCovarianceCoeffsAngRate").get_to(data.initCovarianceCoeffsAngRate); | |
306 | } | ||
307 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAngRateUnit")) |
308 | { | ||
309 | 2 | j.at("initCovarianceCoeffsAngRateUnit").get_to(data.initCovarianceCoeffsAngRateUnit); | |
310 | } | ||
311 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAccel")) |
312 | { | ||
313 | 2 | j.at("initCovarianceCoeffsAccel").get_to(data.initCovarianceCoeffsAccel); | |
314 | } | ||
315 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAccelUnit")) |
316 | { | ||
317 | 2 | j.at("initCovarianceCoeffsAccelUnit").get_to(data.initCovarianceCoeffsAccelUnit); | |
318 | } | ||
319 | |||
320 | // ------------------------------------------- Process Noise --------------------------------------------- | ||
321 | |||
322 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varCoeffsAngRateNoise")) |
323 | { | ||
324 | 2 | j.at("varCoeffsAngRateNoise").get_to(data.varCoeffsAngRateNoise); | |
325 | } | ||
326 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varCoeffsAngRateUnit")) |
327 | { | ||
328 | 2 | j.at("varCoeffsAngRateUnit").get_to(data.varCoeffsAngRateUnit); | |
329 | } | ||
330 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varCoeffsAccelNoise")) |
331 | { | ||
332 | 2 | j.at("varCoeffsAccelNoise").get_to(data.varCoeffsAccelNoise); | |
333 | } | ||
334 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("varCoeffsAccelUnit")) |
335 | { | ||
336 | 2 | j.at("varCoeffsAccelUnit").get_to(data.varCoeffsAccelUnit); | |
337 | } | ||
338 | 2 | } | |
339 | |||
340 | } // namespace NAV | ||
341 | |||
342 | 114 | NAV::ImuFusion::ImuFusion() | |
343 |
12/24✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 114 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 114 times.
✗ Branch 13 not taken.
✓ Branch 19 taken 114 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 114 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 114 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 114 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 114 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 114 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 114 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 114 times.
✗ Branch 41 not taken.
|
114 | : Imu(typeStatic()) |
344 | { | ||
345 | LOG_TRACE("{}: called", name); | ||
346 | |||
347 | 114 | _hasConfig = true; | |
348 | 114 | _guiConfigDefaultWindowSize = { 991, 1059 }; | |
349 | |||
350 |
4/8✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 114 times.
✓ Branch 10 taken 114 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
456 | nm::CreateOutputPin(this, "Combined ImuObs", Pin::Type::Flow, { NAV::ImuObs::type() }); |
351 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
114 | updateNumberOfInputPins(); |
352 | 228 | } | |
353 | |||
354 | 232 | NAV::ImuFusion::~ImuFusion() | |
355 | { | ||
356 | LOG_TRACE("{}: called", nameId()); | ||
357 | 232 | } | |
358 | |||
359 | 226 | std::string NAV::ImuFusion::typeStatic() | |
360 | { | ||
361 |
1/2✓ Branch 1 taken 226 times.
✗ Branch 2 not taken.
|
452 | return "ImuFusion"; |
362 | } | ||
363 | |||
364 | ✗ | std::string NAV::ImuFusion::type() const | |
365 | { | ||
366 | ✗ | return typeStatic(); | |
367 | } | ||
368 | |||
369 | 112 | std::string NAV::ImuFusion::category() | |
370 | { | ||
371 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
224 | return "Data Processor"; |
372 | } | ||
373 | |||
374 | ✗ | void NAV::ImuFusion::guiConfig() | |
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; | |
407 | ✗ | flow::ApplyChanges(); | |
408 | ✗ | updateNumberOfInputPins(); | |
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); | |
424 | ✗ | flow::ApplyChanges(); | |
425 | ✗ | updateNumberOfInputPins(); | |
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 | |||
445 | ✗ | flow::ApplyChanges(); | |
446 | ✗ | doDeinitialize(); | |
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); | |
457 | ✗ | flow::ApplyChanges(); | |
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 | |||
462 | ✗ | if (_imuFusionType == ImuFusionType::Bspline) | |
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); | |
468 | ✗ | flow::ApplyChanges(); | |
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); | |
477 | ✗ | flow::ApplyChanges(); | |
478 | } | ||
479 | ✗ | ImGui::SameLine(); | |
480 | ✗ | gui::widgets::HelpMarker("Computationally intensive - only recommended for debugging."); | |
481 | |||
482 | ✗ | if (_imuFusionType != ImuFusionType::IRWKF) | |
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); | ||
489 | ✗ | flow::ApplyChanges(); | |
490 | } | ||
491 | ✗ | if (_imuFusionType != ImuFusionType::IRWKF) | |
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); | ||
505 | ✗ | flow::ApplyChanges(); | |
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); | ||
512 | ✗ | flow::ApplyChanges(); | |
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); | |
531 | ✗ | flow::ApplyChanges(); | |
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); | ||
539 | ✗ | flow::ApplyChanges(); | |
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 | { | ||
552 | ✗ | if (_imuFusionType == ImuFusionType::IRWKF) | |
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)); | ||
561 | ✗ | flow::ApplyChanges(); | |
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)); | ||
569 | ✗ | flow::ApplyChanges(); | |
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)); | ||
579 | ✗ | flow::ApplyChanges(); | |
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)); | ||
588 | ✗ | flow::ApplyChanges(); | |
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)); | ||
599 | ✗ | flow::ApplyChanges(); | |
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)); | ||
606 | ✗ | flow::ApplyChanges(); | |
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 | { | ||
621 | ✗ | flow::ApplyChanges(); | |
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 | { | ||
628 | ✗ | flow::ApplyChanges(); | |
629 | } | ||
630 | ✗ | if (!_imuBiasesIdentical) | |
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 | { | ||
638 | ✗ | flow::ApplyChanges(); | |
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 | { | ||
645 | ✗ | flow::ApplyChanges(); | |
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 | { | ||
657 | ✗ | if (_imuFusionType == ImuFusionType::IRWKF) | |
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)); | ||
674 | ✗ | flow::ApplyChanges(); | |
675 | } | ||
676 | |||
677 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular acceleration covariance ({})##{}", | |
678 | ✗ | _pinDataIRWKF.initCovarianceAngularAccUnit == PinDataIRWKF::AngularAccVarianceUnit::rad2_s4 | |
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)); | ||
692 | ✗ | flow::ApplyChanges(); | |
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)); | ||
707 | ✗ | flow::ApplyChanges(); | |
708 | } | ||
709 | |||
710 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Jerk covariance ({})##{}", | |
711 | ✗ | _pinDataIRWKF.initCovarianceJerkUnit == PinDataIRWKF::JerkVarianceUnit::m2_s6 | |
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)); | ||
722 | ✗ | flow::ApplyChanges(); | |
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)); | ||
741 | ✗ | flow::ApplyChanges(); | |
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)); | ||
754 | ✗ | flow::ApplyChanges(); | |
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)); | ||
780 | ✗ | flow::ApplyChanges(); | |
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)); | ||
795 | ✗ | flow::ApplyChanges(); | |
796 | } | ||
797 | ✗ | if (!_imuCharacteristicsIdentical) | |
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)); | ||
816 | ✗ | flow::ApplyChanges(); | |
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)); | ||
831 | ✗ | flow::ApplyChanges(); | |
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 | |||
853 | ✗ | if (_imuFusionType == ImuFusionType::IRWKF) | |
854 | { | ||
855 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular acceleration ({})##{}", | |
856 | ✗ | _pinDataIRWKF.varAngularAccNoiseUnit == PinDataIRWKF::AngularAccVarianceUnit::rad2_s4 | |
857 | ✗ | || _pinDataIRWKF.varAngularAccNoiseUnit == PinDataIRWKF::AngularAccVarianceUnit::deg2_s4 | |
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)); | ||
870 | ✗ | flow::ApplyChanges(); | |
871 | } | ||
872 | |||
873 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Jerk ({})##{}", | |
874 | ✗ | _pinDataIRWKF.varJerkNoiseUnit == PinDataIRWKF::JerkVarianceUnit::m2_s6 | |
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)); | ||
885 | ✗ | flow::ApplyChanges(); | |
886 | } | ||
887 | } | ||
888 | else // (_imuFusionType == ImuFusionType::Bspline) | ||
889 | { | ||
890 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Angular rate B-spline coefficients ({})##{}", | |
891 | ✗ | _pinDataBsplineKF.varCoeffsAngRateUnit == PinData::AngRateVarianceUnit::rad2_s2 | |
892 | ✗ | || _pinDataBsplineKF.varCoeffsAngRateUnit == PinData::AngRateVarianceUnit::deg2_s2 | |
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)); | ||
904 | ✗ | flow::ApplyChanges(); | |
905 | } | ||
906 | ✗ | if (gui::widgets::InputDouble3WithUnit(fmt::format("Acceleration B-spline coefficients ({})##{}", | |
907 | ✗ | _pinDataBsplineKF.varCoeffsAccelUnit == PinData::AccelerationVarianceUnit::m2_s4 | |
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)); | ||
917 | ✗ | flow::ApplyChanges(); | |
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)); | ||
943 | ✗ | flow::ApplyChanges(); | |
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)); | ||
958 | ✗ | flow::ApplyChanges(); | |
959 | } | ||
960 | ✗ | if (!_imuCharacteristicsIdentical) | |
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)); | ||
979 | ✗ | flow::ApplyChanges(); | |
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)); | ||
994 | ✗ | flow::ApplyChanges(); | |
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)); | ||
1023 | ✗ | flow::ApplyChanges(); | |
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)); | ||
1038 | ✗ | flow::ApplyChanges(); | |
1039 | } | ||
1040 | ✗ | if (!_imuCharacteristicsIdentical) | |
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)); | ||
1059 | ✗ | flow::ApplyChanges(); | |
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)); | ||
1074 | ✗ | flow::ApplyChanges(); | |
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 | |||
1112 | 2 | void NAV::ImuFusion::restore(json const& j) | |
1113 | { | ||
1114 | LOG_TRACE("{}: called", nameId()); | ||
1115 | |||
1116 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("imuFusionType")) |
1117 | { | ||
1118 | 2 | j.at("imuFusionType").get_to(_imuFusionType); | |
1119 | } | ||
1120 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("checkKalmanMatricesRanks")) |
1121 | { | ||
1122 | 2 | j.at("checkKalmanMatricesRanks").get_to(_checkKalmanMatricesRanks); | |
1123 | } | ||
1124 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("nInputPins")) |
1125 | { | ||
1126 | 2 | j.at("nInputPins").get_to(_nInputPins); | |
1127 | 2 | updateNumberOfInputPins(); | |
1128 | } | ||
1129 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("imuFrequency")) |
1130 | { | ||
1131 | 2 | j.at("imuFrequency").get_to(_imuFrequency); | |
1132 | } | ||
1133 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("numStates")) |
1134 | { | ||
1135 | 2 | j.at("numStates").get_to(_numStates); | |
1136 | } | ||
1137 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("pinData")) |
1138 | { | ||
1139 | 2 | j.at("pinData").get_to(_pinData); | |
1140 | } | ||
1141 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("pinDataIRWKF")) |
1142 | { | ||
1143 | 2 | j.at("pinDataIRWKF").get_to(_pinDataIRWKF); | |
1144 | } | ||
1145 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("pinDataBsplineKF")) |
1146 | { | ||
1147 | 2 | j.at("pinDataBsplineKF").get_to(_pinDataBsplineKF); | |
1148 | } | ||
1149 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCoeffsAngRateTemp")) |
1150 | { | ||
1151 | 2 | j.at("initCoeffsAngRateTemp").get_to(_initCoeffsAngRateTemp); | |
1152 | } | ||
1153 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCoeffsAccelTemp")) |
1154 | { | ||
1155 | 2 | j.at("initCoeffsAccelTemp").get_to(_initCoeffsAccelTemp); | |
1156 | } | ||
1157 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAngRateTemp")) |
1158 | { | ||
1159 | 2 | j.at("initCovarianceCoeffsAngRateTemp").get_to(_initCovarianceCoeffsAngRateTemp); | |
1160 | } | ||
1161 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initCovarianceCoeffsAccelTemp")) |
1162 | { | ||
1163 | 2 | j.at("initCovarianceCoeffsAccelTemp").get_to(_initCovarianceCoeffsAccelTemp); | |
1164 | } | ||
1165 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("procNoiseCoeffsAngRateTemp")) |
1166 | { | ||
1167 | 2 | j.at("procNoiseCoeffsAngRateTemp").get_to(_procNoiseCoeffsAngRateTemp); | |
1168 | } | ||
1169 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("procNoiseCoeffsAccelTemp")) |
1170 | { | ||
1171 | 2 | j.at("procNoiseCoeffsAccelTemp").get_to(_procNoiseCoeffsAccelTemp); | |
1172 | } | ||
1173 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("autoInitKF")) |
1174 | { | ||
1175 | 2 | j.at("autoInitKF").get_to(_autoInitKF); | |
1176 | } | ||
1177 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("initJerkAngAcc")) |
1178 | { | ||
1179 | 2 | j.at("initJerkAngAcc").get_to(_initJerkAngAcc); | |
1180 | } | ||
1181 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (j.contains("_kfInitialized")) |
1182 | { | ||
1183 | ✗ | j.at("_kfInitialized").get_to(_kfInitialized); | |
1184 | } | ||
1185 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("averageEndTime")) |
1186 | { | ||
1187 | 2 | j.at("averageEndTime").get_to(_averageEndTime); | |
1188 | } | ||
1189 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (j.contains("splineSpacing")) |
1190 | { | ||
1191 | 2 | j.at("splineSpacing").get_to(_splineSpacing); | |
1192 | } | ||
1193 | 2 | } | |
1194 | |||
1195 | 6 | bool NAV::ImuFusion::initialize() | |
1196 | { | ||
1197 | LOG_TRACE("{}: called", nameId()); | ||
1198 | |||
1199 | 6 | _imuRotations_accel.clear(); | |
1200 | 6 | _imuRotations_gyro.clear(); | |
1201 | 6 | _biasCovariances.clear(); | |
1202 | 6 | _processNoiseVariances.clear(); | |
1203 | 6 | _measurementNoiseVariances.clear(); | |
1204 | |||
1205 | 6 | _cumulatedImuObs.clear(); | |
1206 | 6 | _cumulatedPinIds.clear(); | |
1207 | 6 | _lastFiltObs.reset(); | |
1208 | 6 | _latestTimestamp = InsTime{}; | |
1209 | 6 | _firstTimestamp.reset(); | |
1210 | |||
1211 | 6 | _imuPosSet = false; | |
1212 | 6 | _kfInitialized = false; | |
1213 | |||
1214 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 6 times.
|
33 | for (size_t pinIndex = 0; pinIndex < _pinData.size(); pinIndex++) |
1215 | { | ||
1216 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
27 | 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 | |||
1222 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | _numStatesEst = _imuFusionType == ImuFusionType::IRWKF ? _numStatesEstIRWKF : _numStatesEstBsplineKF; |
1223 | |||
1224 | 6 | _numStates = _numStatesEst + static_cast<uint8_t>((_nInputPins - 1) * _numStatesPerPin); | |
1225 | |||
1226 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | _kalmanFilter = KalmanFilter{ _numStates, _numMeasurements }; |
1227 | 6 | _kalmanFilter.setZero(); | |
1228 | |||
1229 | 6 | initializeMountingAngles(); | |
1230 | |||
1231 | // --------------------------------------------------------- KF Initializations ------------------------------------------------------------ | ||
1232 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (!_autoInitKF) // i.e. manual initialization thru inputs from the GUI |
1233 | { | ||
1234 | 3 | auto dtInit = 1.0 / _imuFrequency; // Initial state transition time in [s] | |
1235 | |||
1236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (_imuFusionType == ImuFusionType::IRWKF) |
1237 | { | ||
1238 | ✗ | _kalmanFilter = IRWKF::initializeKalmanFilterManually(_nInputPins, _pinData, _pinDataIRWKF, _numStates, dtInit, _processNoiseVariances, _kalmanFilter, _imuCharacteristicsIdentical, _imuBiasesIdentical); | |
1239 | } | ||
1240 | else // (_imuFusionType == ImuFusionType::BsplineKF) | ||
1241 | { | ||
1242 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | _kalmanFilter = BsplineKF::initializeKalmanFilterManually(_nInputPins, _pinData, _pinDataBsplineKF, _numStates, dtInit, _processNoiseVariances, _kalmanFilter, _imuCharacteristicsIdentical, _imuBiasesIdentical); |
1243 | 3 | _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 ----------------------------------------------------- | ||
1253 | 6 | _measurementNoiseVariances.resize(2 * _nInputPins); | |
1254 | |||
1255 | 6 | size_t pinDataIdx = 0; | |
1256 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 6 times.
|
33 | for (size_t pinIndex = 0; pinIndex < _nInputPins; ++pinIndex) |
1257 | { | ||
1258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | if (!_imuCharacteristicsIdentical) |
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 |
1/5✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
27 | switch (_pinData[pinDataIdx].measurementUncertaintyAngularRateUnit) |
1265 | { | ||
1266 | ✗ | case PinData::AngRateVarianceUnit::rad_s: | |
1267 | ✗ | _measurementNoiseVariances[2 * pinIndex] = (_pinData[pinDataIdx].measurementUncertaintyAngularRate).array().pow(2); | |
1268 | ✗ | break; | |
1269 | 27 | case PinData::AngRateVarianceUnit::deg_s: | |
1270 |
4/8✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 27 times.
✗ Branch 13 not taken.
|
27 | _measurementNoiseVariances[2 * pinIndex] = (deg2rad(_pinData[pinDataIdx].measurementUncertaintyAngularRate)).array().pow(2); |
1271 | 27 | break; | |
1272 | ✗ | case PinData::AngRateVarianceUnit::rad2_s2: | |
1273 | ✗ | _measurementNoiseVariances[2 * pinIndex] = _pinData[pinDataIdx].measurementUncertaintyAngularRate; | |
1274 | ✗ | break; | |
1275 | ✗ | case PinData::AngRateVarianceUnit::deg2_s2: | |
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 |
1/3✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
|
27 | switch (_pinData[pinDataIdx].measurementUncertaintyAccelerationUnit) |
1282 | { | ||
1283 | ✗ | case PinData::AccelerationVarianceUnit::m2_s4: | |
1284 | ✗ | _measurementNoiseVariances[1 + 2 * pinIndex] = _pinData[pinDataIdx].measurementUncertaintyAcceleration; | |
1285 | ✗ | break; | |
1286 | 27 | case PinData::AccelerationVarianceUnit::m_s2: | |
1287 |
3/6✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 27 times.
✗ Branch 10 not taken.
|
27 | _measurementNoiseVariances[1 + 2 * pinIndex] = (_pinData[pinDataIdx].measurementUncertaintyAcceleration).array().pow(2); |
1288 | 27 | break; | |
1289 | } | ||
1290 | } | ||
1291 | |||
1292 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (_imuCharacteristicsIdentical) |
1293 | { | ||
1294 | 6 | measurementNoiseMatrix_R(_kalmanFilter.R); | |
1295 | LOG_DATA("{}: imuCharacteristicsIdentical - kalmanFilter.R =\n{}", nameId(), _kalmanFilter.R); | ||
1296 | } | ||
1297 | |||
1298 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (!_autoInitKF) { _kfInitialized = true; } // Auto-init initializes KF at 'avgEndTime' seconds --> see 'recvSignal' |
1299 | |||
1300 |
1/2✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
12 | LOG_DEBUG("ImuFusion initialized"); |
1301 | |||
1302 | 6 | return true; | |
1303 | } | ||
1304 | |||
1305 | 2 | void NAV::ImuFusion::deinitialize() | |
1306 | { | ||
1307 | LOG_TRACE("{}: called", nameId()); | ||
1308 | 2 | } | |
1309 | |||
1310 | 116 | void NAV::ImuFusion::updateNumberOfInputPins() | |
1311 | { | ||
1312 |
2/2✓ Branch 1 taken 233 times.
✓ Branch 2 taken 116 times.
|
465 | while (inputPins.size() < _nInputPins) |
1313 | { | ||
1314 |
4/8✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 233 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 233 times.
✓ Branch 13 taken 233 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
932 | nm::CreateInputPin(this, fmt::format("Pin {}", inputPins.size() + 1).c_str(), Pin::Type::Flow, |
1315 | { NAV::ImuObs::type() }, &ImuFusion::recvSignal); | ||
1316 | 233 | _pinData.emplace_back(); | |
1317 |
2/2✓ Branch 1 taken 119 times.
✓ Branch 2 taken 114 times.
|
233 | if (outputPins.size() < _nInputPins) |
1318 | { | ||
1319 |
4/8✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 119 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 119 times.
✓ Branch 14 taken 119 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
595 | nm::CreateOutputPin(this, fmt::format("ImuBiases {}1", outputPins.size() + 1).c_str(), Pin::Type::Flow, { NAV::InsGnssLCKFSolution::type() }); |
1320 | } | ||
1321 | } | ||
1322 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
|
116 | while (inputPins.size() > _nInputPins) // TODO: while loop still necessary here? guiConfig also deletes pins |
1323 | { | ||
1324 | ✗ | nm::DeleteInputPin(inputPins.back()); | |
1325 | ✗ | nm::DeleteOutputPin(outputPins.back()); | |
1326 | ✗ | _pinData.pop_back(); | |
1327 | } | ||
1328 | 116 | _pinData.resize(_nInputPins); | |
1329 | 116 | initializeMountingAngles(); | |
1330 | 468 | } | |
1331 | |||
1332 | 122 | void NAV::ImuFusion::initializeMountingAngles() | |
1333 | { | ||
1334 | 122 | _imuRotations_accel.resize(_nInputPins); | |
1335 | 122 | _imuRotations_gyro.resize(_nInputPins); | |
1336 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 122 times.
|
386 | for (size_t i = 0; i < _nInputPins; ++i) |
1337 | { | ||
1338 |
2/4✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 264 times.
✗ Branch 6 not taken.
|
264 | _imuRotations_accel[i] = Eigen::Matrix3d::Zero(); |
1339 |
2/4✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 264 times.
✗ Branch 6 not taken.
|
264 | _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 | 264 | _imuRotations_accel[i](0, 0) = std::nan(""); | |
1343 | 264 | _imuRotations_gyro[i](0, 0) = std::nan(""); | |
1344 | } | ||
1345 | 122 | } | |
1346 | |||
1347 | 17486 | void NAV::ImuFusion::recvSignal(NAV::InputPin::NodeDataQueue& queue, size_t pinIdx) | |
1348 | { | ||
1349 |
1/2✓ Branch 1 taken 17486 times.
✗ Branch 2 not taken.
|
17486 | auto imuObs = std::static_pointer_cast<const ImuObs>(queue.extract_front()); |
1350 | |||
1351 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 17486 times.
|
17486 | 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 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 17484 times.
|
17486 | if (_latestTimestamp.empty()) |
1358 | { | ||
1359 | // Initial time step for KF prediction | ||
1360 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | InsTime dt_init = InsTime{ 0, 0, 0, 0, 0, 1.0 / _imuFrequency }; |
1361 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | _latestTimestamp = InsTime{ 0, 0, 0, 0, 0, (imuObs->insTime - dt_init).count() }; |
1362 | 2 | _firstTimestamp = imuObs->insTime; | |
1363 | |||
1364 | // Time until averaging ends and filtering starts (for auto-init of KF) | ||
1365 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | _avgEndTime = imuObs->insTime + std::chrono::milliseconds(static_cast<int>(1e3 * _averageEndTime)); |
1366 | } | ||
1367 | |||
1368 |
1/2✓ Branch 2 taken 17486 times.
✗ Branch 3 not taken.
|
17486 | _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 |
1/2✓ Branch 2 taken 17486 times.
✗ Branch 3 not taken.
|
17486 | auto dt = static_cast<double>((imuObs->insTime - _latestTimestamp).count()); |
1373 | 17486 | _latestTimestamp = imuObs->insTime; | |
1374 | LOG_DATA("{}: dt = {}", nameId(), dt); | ||
1375 | |||
1376 |
2/2✓ Branch 0 taken 17385 times.
✓ Branch 1 taken 101 times.
|
17486 | if (_kfInitialized) |
1377 | { | ||
1378 |
2/2✓ Branch 0 taken 9903 times.
✓ Branch 1 taken 7482 times.
|
17385 | if (_imuFusionType == ImuFusionType::IRWKF) |
1379 | { | ||
1380 |
1/2✓ Branch 1 taken 9903 times.
✗ Branch 2 not taken.
|
9903 | IRWKF::stateTransitionMatrix_Phi(_kalmanFilter.Phi, dt); |
1381 |
1/2✓ Branch 1 taken 9903 times.
✗ Branch 2 not taken.
|
9903 | IRWKF::processNoiseMatrix_Q(_kalmanFilter.Q, dt, _processNoiseVariances, _numStates); |
1382 | } | ||
1383 | else // (_imuFusionType == ImuFusionType::Bspline) | ||
1384 | { | ||
1385 |
1/2✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
|
7482 | BsplineKF::processNoiseMatrix_Q(_kalmanFilter.Q, dt, _processNoiseVariances, _numStates); |
1386 | |||
1387 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 7421 times.
|
7482 | if (_timeSinceStartup >= _latestKnot) |
1388 | { | ||
1389 | 61 | _latestKnot += _splineSpacing; | |
1390 | |||
1391 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | BsplineKF::rotateCoeffStates(_kalmanFilter.x); |
1392 | LOG_DATA("{}: kalmanFilter.P before B-spline coeff rotation =\n{}", nameId(), _kalmanFilter.P.block<18, 18>(0, 0)); | ||
1393 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | BsplineKF::rotateErrorCovariances(_kalmanFilter.P, _numStates); |
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 | |||
1401 |
2/2✓ Branch 0 taken 7482 times.
✓ Branch 1 taken 9903 times.
|
17385 | if (_checkKalmanMatricesRanks) |
1402 | { | ||
1403 |
3/6✓ Branch 2 taken 7482 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7482 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
|
7482 | if (inputPins.at(_pinData.size() - 1).isPinLinked()) |
1404 | { | ||
1405 |
2/4✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
|
7482 | auto rank = _kalmanFilter.P.fullPivLu().rank(); |
1406 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7482 times.
|
7482 | 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 |
3/4✓ Branch 2 taken 17486 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 17477 times.
|
17486 | if (std::isnan(_imuRotations_accel[pinIdx](0, 0))) |
1416 | { | ||
1417 | // Rotation matrix of the accelerometer platform to body frame | ||
1418 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | _imuRotations_accel[pinIdx] = imuObs->imuPos.b_quat_p().toRotationMatrix(); |
1419 | } | ||
1420 |
3/4✓ Branch 2 taken 17486 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 17477 times.
|
17486 | if (std::isnan(_imuRotations_gyro[pinIdx](0, 0))) |
1421 | { | ||
1422 | // Rotation matrix of the gyro platform to body frame | ||
1423 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | _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 |
2/4✓ Branch 1 taken 17486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17486 times.
✗ Branch 5 not taken.
|
17486 | auto DCM_accel = _imuRotations_accel.at(pinIdx); |
1428 | LOG_DATA("DCM_accel =\n{}", DCM_accel); | ||
1429 |
2/4✓ Branch 1 taken 17486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17486 times.
✗ Branch 5 not taken.
|
17486 | auto DCM_gyro = _imuRotations_gyro.at(pinIdx); |
1430 | LOG_DATA("{}: DCM_gyro =\n{}", nameId(), DCM_gyro); | ||
1431 | |||
1432 |
2/2✓ Branch 0 taken 10004 times.
✓ Branch 1 taken 7482 times.
|
17486 | if (_imuFusionType == ImuFusionType::IRWKF) |
1433 | { | ||
1434 |
1/2✓ Branch 1 taken 10004 times.
✗ Branch 2 not taken.
|
10004 | _kalmanFilter.H = IRWKF::designMatrix_H(DCM_accel, DCM_gyro, pinIdx, _numMeasurements, _numStates, _numStatesEst, _numStatesPerPin); |
1435 | LOG_DATA("{}: Sensor (pinIdx): {}, kalmanFilter.H =\n{}", nameId(), _kalmanFilter.H, pinIdx); | ||
1436 | } | ||
1437 | else // (_imuFusionType == ImuFusionType::BsplineKF) | ||
1438 | { | ||
1439 |
1/2✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
|
7482 | _kalmanFilter.H = BsplineKF::designMatrix_H(_timeSinceStartup, _splineSpacing, DCM_accel, DCM_gyro, pinIdx, _numMeasurements, _numStates, _numStatesEst, _numStatesPerPin); |
1440 | LOG_DATA("{}: timeSinceStartup: {}, Sensor (pinIdx): {}, kalmanFilter.H =\n{}", nameId(), _timeSinceStartup, pinIdx, _kalmanFilter.H); | ||
1441 | } | ||
1442 | |||
1443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17486 times.
|
17486 | if (!_imuCharacteristicsIdentical) |
1444 | { | ||
1445 | ✗ | measurementNoiseMatrix_R(_kalmanFilter.R, pinIdx); | |
1446 | LOG_DATA("{}: kalmanFilter.R =\n{}", nameId(), _kalmanFilter.R); | ||
1447 | } | ||
1448 | |||
1449 |
2/2✓ Branch 0 taken 7482 times.
✓ Branch 1 taken 10004 times.
|
17486 | if (_checkKalmanMatricesRanks) |
1450 | { | ||
1451 |
6/12✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7482 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7482 times.
✗ Branch 17 not taken.
|
7482 | auto rank = (_kalmanFilter.H * _kalmanFilter.P * _kalmanFilter.H.transpose() + _kalmanFilter.R).fullPivLu().rank(); |
1452 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7482 times.
|
7482 | if (rank != _kalmanFilter.H.rows()) |
1453 | { | ||
1454 | ✗ | LOG_WARN("{}: (HPH^T + R).rank = {}", nameId(), rank); | |
1455 | } | ||
1456 | } | ||
1457 | |||
1458 |
4/4✓ Branch 0 taken 10004 times.
✓ Branch 1 taken 7482 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 9903 times.
|
17486 | if (_autoInitKF && !_kfInitialized) |
1459 | { | ||
1460 |
2/2✓ Branch 2 taken 100 times.
✓ Branch 3 taken 1 times.
|
101 | if (imuObs->insTime < _avgEndTime) |
1461 | { | ||
1462 |
1/2✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
|
100 | _cumulatedImuObs.push_back(imuObs); |
1463 |
1/2✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
|
100 | _cumulatedPinIds.push_back(pinIdx); |
1464 | } | ||
1465 | else // if (imuObs->insTime == _avgEndTime) // <-- do auto-init, once _avgEndTime is reached | ||
1466 | { | ||
1467 | 1 | double dtInit = 1.0 / _imuFrequency; | |
1468 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | _kalmanFilter = IRWKF::initializeKalmanFilterAuto(_nInputPins, _pinData, _pinDataIRWKF, _cumulatedPinIds, _cumulatedImuObs, _initJerkAngAcc, dtInit, _numStates, _numMeasurements, _processNoiseVariances, _kalmanFilter); |
1469 | 1 | _kfInitialized = true; // Start Kalman Filter | |
1470 | } | ||
1471 | } | ||
1472 |
2/2✓ Branch 0 taken 17386 times.
✓ Branch 1 taken 100 times.
|
17486 | if (_kfInitialized) |
1473 | { | ||
1474 |
1/2✓ Branch 1 taken 17386 times.
✗ Branch 2 not taken.
|
17386 | combineSignals(imuObs); |
1475 | } | ||
1476 | 17486 | } | |
1477 | |||
1478 | 17386 | void NAV::ImuFusion::combineSignals(const std::shared_ptr<const ImuObs>& imuObs) | |
1479 | { | ||
1480 | LOG_DATA("{}: called", nameId()); | ||
1481 | |||
1482 |
1/2✓ Branch 1 taken 17386 times.
✗ Branch 2 not taken.
|
17386 | auto imuObsFiltered = std::make_shared<ImuObs>(this->_imuPos); |
1483 | |||
1484 | LOG_DATA("{}: Estimated state before prediction: x =\n{}", nameId(), _kalmanFilter.x); | ||
1485 | |||
1486 |
1/2✓ Branch 1 taken 17386 times.
✗ Branch 2 not taken.
|
17386 | _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 |
2/4✓ Branch 2 taken 17386 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 17386 times.
✗ Branch 6 not taken.
|
17386 | _kalmanFilter.z.block<3, 1>(0, 0) = imuObs->p_angularRate; |
1493 |
2/4✓ Branch 2 taken 17386 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 17386 times.
✗ Branch 6 not taken.
|
17386 | _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 |
1/2✓ Branch 1 taken 17386 times.
✗ Branch 2 not taken.
|
17386 | _kalmanFilter.correct(); |
1500 | LOG_DATA("{}: Estimated state after correction: x =\n{}", nameId(), _kalmanFilter.x); | ||
1501 | |||
1502 |
2/2✓ Branch 0 taken 7482 times.
✓ Branch 1 taken 9904 times.
|
17386 | if (_checkKalmanMatricesRanks) |
1503 | { | ||
1504 |
6/12✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7482 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7482 times.
✗ Branch 17 not taken.
|
7482 | auto rankH = (_kalmanFilter.H * _kalmanFilter.P * _kalmanFilter.H.transpose() + _kalmanFilter.R).fullPivLu().rank(); |
1505 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7482 times.
|
7482 | if (rankH != _kalmanFilter.H.rows()) |
1506 | { | ||
1507 | ✗ | LOG_WARN("{}: (HPH^T + R).rank = {}", nameId(), rankH); | |
1508 | } | ||
1509 | |||
1510 |
3/6✓ Branch 2 taken 7482 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7482 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
|
7482 | if (inputPins.at(_pinData.size() - 1).isPinLinked()) |
1511 | { | ||
1512 |
2/4✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
|
7482 | auto rankP = _kalmanFilter.P.fullPivLu().rank(); |
1513 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7482 times.
|
7482 | 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 | 17386 | imuObsFiltered->insTime = imuObs->insTime; | |
1523 |
2/2✓ Branch 0 taken 9904 times.
✓ Branch 1 taken 7482 times.
|
17386 | if (_imuFusionType == ImuFusionType::IRWKF) |
1524 | { | ||
1525 |
4/8✓ Branch 1 taken 9904 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9904 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9904 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 9904 times.
✗ Branch 11 not taken.
|
9904 | imuObsFiltered->p_acceleration = { _kalmanFilter.x(6, 0), _kalmanFilter.x(7, 0), _kalmanFilter.x(8, 0) }; |
1526 |
4/8✓ Branch 1 taken 9904 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9904 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9904 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 9904 times.
✗ Branch 11 not taken.
|
9904 | imuObsFiltered->p_angularRate = { _kalmanFilter.x(0, 0), _kalmanFilter.x(1, 0), _kalmanFilter.x(2, 0) }; |
1527 | } | ||
1528 | else // (_imuFusionType == ImuFusionType::BsplineKF) | ||
1529 | { | ||
1530 |
1/2✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
|
7482 | auto qBsplines = NAV::BsplineKF::quadraticBsplines(_timeSinceStartup, _splineSpacing); |
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 |
3/6✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
|
7482 | auto angRateEst = _kalmanFilter.x.block<3, 1>(0, 0) * qBsplines.at(0) |
1538 |
4/8✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
|
14964 | + _kalmanFilter.x.block<3, 1>(3, 0) * qBsplines.at(1) |
1539 |
4/8✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
|
14964 | + _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 |
3/6✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
|
7482 | auto accelEst = _kalmanFilter.x.block<3, 1>(9, 0) * qBsplines.at(0) |
1543 |
4/8✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
|
14964 | + _kalmanFilter.x.block<3, 1>(12, 0) * qBsplines.at(1) |
1544 |
4/8✓ Branch 1 taken 7482 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7482 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7482 times.
✗ Branch 11 not taken.
|
14964 | + _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 |
1/2✓ Branch 2 taken 7482 times.
✗ Branch 3 not taken.
|
7482 | imuObsFiltered->p_acceleration = accelEst; |
1549 |
1/2✓ Branch 2 taken 7482 times.
✗ Branch 3 not taken.
|
7482 | imuObsFiltered->p_angularRate = angRateEst; |
1550 | } | ||
1551 | |||
1552 | // Detect jumps back in time | ||
1553 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 17386 times.
|
17386 | if (imuObsFiltered->insTime < _lastFiltObs) |
1554 | { | ||
1555 | ✗ | LOG_ERROR("{}: imuObsFiltered->insTime < _lastFiltObs --> {}", nameId(), static_cast<double>((imuObsFiltered->insTime - _lastFiltObs).count())); | |
1556 | } | ||
1557 | 17386 | _lastFiltObs = imuObsFiltered->insTime; | |
1558 | |||
1559 |
1/2✓ Branch 2 taken 17386 times.
✗ Branch 3 not taken.
|
17386 | invokeCallbacks(OUTPUT_PORT_INDEX_COMBINED_SIGNAL, imuObsFiltered); |
1560 | |||
1561 |
2/2✓ Branch 0 taken 59640 times.
✓ Branch 1 taken 17386 times.
|
77026 | for (size_t OUTPUT_PORT_INDEX_BIAS = 1; OUTPUT_PORT_INDEX_BIAS < _nInputPins; ++OUTPUT_PORT_INDEX_BIAS) |
1562 | { | ||
1563 |
1/2✓ Branch 1 taken 59640 times.
✗ Branch 2 not taken.
|
59640 | auto imuRelativeBiases = std::make_shared<InsGnssLCKFSolution>(); |
1564 | 59640 | imuRelativeBiases->insTime = imuObs->insTime; | |
1565 | 59640 | auto biasIndex = _numStatesEst + static_cast<uint8_t>((OUTPUT_PORT_INDEX_BIAS - 1) * _numStatesPerPin); | |
1566 | LOG_DATA("{}: biasIndex = {}", nameId(), biasIndex); | ||
1567 | |||
1568 |
4/8✓ Branch 1 taken 59640 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59640 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59640 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59640 times.
✗ Branch 11 not taken.
|
59640 | imuRelativeBiases->b_biasGyro.value = { _kalmanFilter.x(biasIndex, 0), _kalmanFilter.x(biasIndex + 1, 0), _kalmanFilter.x(biasIndex + 2, 0) }; |
1569 |
4/8✓ Branch 1 taken 59640 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59640 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59640 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59640 times.
✗ Branch 11 not taken.
|
59640 | 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 |
1/2✓ Branch 2 taken 59640 times.
✗ Branch 3 not taken.
|
59640 | invokeCallbacks(OUTPUT_PORT_INDEX_BIAS, imuRelativeBiases); |
1575 | 59640 | } | |
1576 | 17386 | } | |
1577 | |||
1578 | // -------------------------------------- Measurement noise matrix R ----------------------------------------- | ||
1579 | |||
1580 | ✗ | Eigen::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 | |||
1585 | 6 | void NAV::ImuFusion::measurementNoiseMatrix_R(Eigen::MatrixXd& R, size_t pinIndex) const | |
1586 | { | ||
1587 |
3/6✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
|
6 | R.block<3, 3>(0, 0).diagonal() = _measurementNoiseVariances.at(2 * pinIndex); |
1588 |
3/6✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
|
6 | R.block<3, 3>(3, 3).diagonal() = _measurementNoiseVariances.at(2 * pinIndex + 1); |
1589 | 6 | } | |
1590 |