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 | /// @file LooselyCoupledKF.hpp | ||
10 | /// @brief Kalman Filter class for the loosely coupled INS/GNSS integration | ||
11 | /// @author T. Topp (topp@ins.uni-stuttgart.de) | ||
12 | /// @author M. Maier (marcel.maier@ins.uni-stuttgart.de) | ||
13 | /// @date 2021-08-04 | ||
14 | |||
15 | #pragma once | ||
16 | |||
17 | #include <cstdint> | ||
18 | #include "internal/Node/Node.hpp" | ||
19 | #include "internal/gui/widgets/DynamicInputPins.hpp" | ||
20 | |||
21 | #include "Navigation/INS/Units.hpp" | ||
22 | #include "Navigation/Time/InsTime.hpp" | ||
23 | #include "Navigation/INS/InertialIntegrator.hpp" | ||
24 | |||
25 | #include "NodeData/IMU/ImuObs.hpp" | ||
26 | #include "NodeData/State/PosVelAtt.hpp" | ||
27 | #include "NodeData/Baro/BaroHgt.hpp" | ||
28 | |||
29 | #include "Navigation/Math/KeyedKalmanFilter.hpp" | ||
30 | |||
31 | namespace NAV | ||
32 | { | ||
33 | /// @brief Loosely-coupled Kalman Filter for INS/GNSS integration | ||
34 | class LooselyCoupledKF : public Node | ||
35 | { | ||
36 | public: | ||
37 | /// @brief Default constructor | ||
38 | LooselyCoupledKF(); | ||
39 | /// @brief Destructor | ||
40 | ~LooselyCoupledKF() override; | ||
41 | /// @brief Copy constructor | ||
42 | LooselyCoupledKF(const LooselyCoupledKF&) = delete; | ||
43 | /// @brief Move constructor | ||
44 | LooselyCoupledKF(LooselyCoupledKF&&) = delete; | ||
45 | /// @brief Copy assignment operator | ||
46 | LooselyCoupledKF& operator=(const LooselyCoupledKF&) = delete; | ||
47 | /// @brief Move assignment operator | ||
48 | LooselyCoupledKF& operator=(LooselyCoupledKF&&) = delete; | ||
49 | /// @brief String representation of the class type | ||
50 | [[nodiscard]] static std::string typeStatic(); | ||
51 | |||
52 | /// @brief String representation of the class type | ||
53 | [[nodiscard]] std::string type() const override; | ||
54 | |||
55 | /// @brief String representation of the class category | ||
56 | [[nodiscard]] static std::string category(); | ||
57 | |||
58 | /// @brief ImGui config window which is shown on double click | ||
59 | /// @attention Don't forget to set _hasConfig to true in the constructor of the node | ||
60 | void guiConfig() override; | ||
61 | |||
62 | /// @brief Saves the node into a json object | ||
63 | [[nodiscard]] json save() const override; | ||
64 | |||
65 | /// @brief Restores the node from a json object | ||
66 | /// @param[in] j Json object with the node state | ||
67 | void restore(const json& j) override; | ||
68 | |||
69 | /// @brief State Keys of the Kalman filter | ||
70 | enum KFStates : uint8_t | ||
71 | { | ||
72 | Roll = 0, ///< Roll | ||
73 | Pitch = 1, ///< Pitch | ||
74 | Yaw = 2, ///< Yaw | ||
75 | VelN = 3, ///< Velocity North | ||
76 | VelE = 4, ///< Velocity East | ||
77 | VelD = 5, ///< Velocity Down | ||
78 | PosLat = 6, ///< Latitude | ||
79 | PosLon = 7, ///< Longitude | ||
80 | PosAlt = 8, ///< Altitude | ||
81 | AccBiasX = 9, ///< Accelerometer Bias X | ||
82 | AccBiasY = 10, ///< Accelerometer Bias Y | ||
83 | AccBiasZ = 11, ///< Accelerometer Bias Z | ||
84 | GyrBiasX = 12, ///< Gyroscope Bias X | ||
85 | GyrBiasY = 13, ///< Gyroscope Bias Y | ||
86 | GyrBiasZ = 14, ///< Gyroscope Bias Z | ||
87 | HeightBias = 15, ///< Baro Height Bias | ||
88 | HeightScale = 16, ///< Baro Height Scale | ||
89 | KFStates_COUNT = 17, ///< Amount of states | ||
90 | |||
91 | Psi_eb_1 = Roll, ///< Angle between Earth and Body frame around 1. axis | ||
92 | Psi_eb_2 = Pitch, ///< Angle between Earth and Body frame around 2. axis | ||
93 | Psi_eb_3 = Yaw, ///< Angle between Earth and Body frame around 3. axis | ||
94 | VelX = VelN, ///< ECEF Velocity X | ||
95 | VelY = VelE, ///< ECEF Velocity Y | ||
96 | VelZ = VelD, ///< ECEF Velocity Z | ||
97 | PosX = PosLat, ///< ECEF Position X | ||
98 | PosY = PosLon, ///< ECEF Position Y | ||
99 | PosZ = PosAlt, ///< ECEF Position Z | ||
100 | }; | ||
101 | |||
102 | /// @brief Measurement Keys of the Kalman filter | ||
103 | enum KFMeas : uint8_t | ||
104 | { | ||
105 | dPosLat = 0, ///< Latitude difference | ||
106 | dPosLon = 1, ///< Longitude difference | ||
107 | dPosAlt = 2, ///< Altitude difference | ||
108 | dVelN = 3, ///< Velocity North difference | ||
109 | dVelE = 4, ///< Velocity East difference | ||
110 | dVelD = 5, ///< Velocity Down difference | ||
111 | dHgt = 6, ///< height difference | ||
112 | |||
113 | dPosX = dPosLat, ///< ECEF Position X difference | ||
114 | dPosY = dPosLon, ///< ECEF Position Y difference | ||
115 | dPosZ = dPosAlt, ///< ECEF Position Z difference | ||
116 | dVelX = dVelN, ///< ECEF Velocity X difference | ||
117 | dVelY = dVelE, ///< ECEF Velocity Y difference | ||
118 | dVelZ = dVelD, ///< ECEF Velocity Z difference | ||
119 | }; | ||
120 | |||
121 | private: | ||
122 | constexpr static size_t INPUT_PORT_INDEX_IMU = 0; ///< @brief Flow (ImuObs) | ||
123 | constexpr static size_t INPUT_PORT_INDEX_POS_VEL_ATT_INIT = 1; ///< @brief Flow (PosVelAtt) | ||
124 | constexpr static size_t OUTPUT_PORT_INDEX_SOLUTION = 0; ///< @brief Flow (InsGnssLCKFSolution) | ||
125 | |||
126 | /// @brief Initialize the node | ||
127 | bool initialize() override; | ||
128 | |||
129 | /// @brief Deinitialize the node | ||
130 | void deinitialize() override; | ||
131 | |||
132 | /// @brief Checks wether there is an input pin with the same time | ||
133 | /// @param[in] insTime Time to check | ||
134 | bool hasInputPinWithSameTime(const InsTime& insTime) const; | ||
135 | |||
136 | /// @brief Invoke the callback with a PosVelAtt solution (without LCKF specific output) | ||
137 | /// @param[in] posVelAtt PosVelAtt solution | ||
138 | void invokeCallbackWithPosVelAtt(const PosVelAtt& posVelAtt); | ||
139 | |||
140 | /// @brief Receive Function for the IMU observation | ||
141 | /// @param[in] queue Queue with all the received data messages | ||
142 | /// @param[in] pinIdx Index of the pin the data is received on | ||
143 | void recvImuObservation(InputPin::NodeDataQueue& queue, size_t pinIdx); | ||
144 | |||
145 | /// @brief Receive Function for the PosVel observation | ||
146 | /// @param[in] queue Queue with all the received data messages | ||
147 | /// @param[in] pinIdx Index of the pin the data is received on | ||
148 | void recvPosVelObservation(InputPin::NodeDataQueue& queue, size_t pinIdx); | ||
149 | |||
150 | /// @brief Receive Function for the PosVelAtt observation | ||
151 | /// @param[in] queue Queue with all the received data messages | ||
152 | /// @param[in] pinIdx Index of the pin the data is received on | ||
153 | void recvPosVelAttInit(InputPin::NodeDataQueue& queue, size_t pinIdx); | ||
154 | |||
155 | /// @brief Receive Function for the BaroHgt observation | ||
156 | /// @param[in] queue Queue with all the received data messages | ||
157 | /// @param[in] pinIdx Index of the pin the data is received on | ||
158 | void recvBaroHeight(InputPin::NodeDataQueue& queue, size_t pinIdx); | ||
159 | |||
160 | /// @brief Predicts the state from the InertialNavSol | ||
161 | /// @param[in] inertialNavSol Inertial navigation solution triggering the prediction | ||
162 | /// @param[in] tau_i Time since the last prediction in [s] | ||
163 | /// @param[in] imuPos IMU platform frame position with respect to body frame | ||
164 | void looselyCoupledPrediction(const std::shared_ptr<const PosVelAtt>& inertialNavSol, double tau_i, const ImuPos& imuPos); | ||
165 | |||
166 | /// @brief Updates the predicted state from the InertialNavSol with the PosVel observation | ||
167 | /// @param[in] posVelObs PosVel measurement triggering the update | ||
168 | void looselyCoupledUpdate(const std::shared_ptr<const PosVel>& posVelObs); | ||
169 | |||
170 | /// @brief Updates the predicted state from the InertialNavSol with the Baro observation | ||
171 | /// @param[in] baroHgtObs Barometric height measurement triggering the update | ||
172 | void looselyCoupledUpdate(const std::shared_ptr<const BaroHgt>& baroHgtObs); | ||
173 | |||
174 | /// @brief Sets the covariance matrix P of the LCKF (and does the necessary unit conversions) | ||
175 | /// @param[in] lckfSolution LCKF solution from prediction or update | ||
176 | /// @param[in] R_N Prime vertical radius of curvature (East/West) [m] | ||
177 | /// @param[in] R_E Meridian radius of curvature in [m] | ||
178 | void setSolutionPosVelAttAndCov(const std::shared_ptr<PosVelAtt>& lckfSolution, double R_N, double R_E); | ||
179 | |||
180 | /// @brief Inertial Integrator | ||
181 | InertialIntegrator _inertialIntegrator; | ||
182 | /// Prefer the raw acceleration measurements over the deltaVel & deltaTheta values | ||
183 | bool _preferAccelerationOverDeltaMeasurements = false; | ||
184 | |||
185 | /// Last received IMU observation (to get ImuPos) | ||
186 | std::shared_ptr<const ImuObs> _lastImuObs = nullptr; | ||
187 | |||
188 | /// Accumulator for height bias [m] | ||
189 | double _heightBiasTotal = 0.0; | ||
190 | /// Accumulator for height scale [m/m] | ||
191 | double _heightScaleTotal = 1.0; | ||
192 | |||
193 | /// Accumulator for acceleration bias [m/s²] | ||
194 | Eigen::Vector3d _accelBiasTotal = Eigen::Vector3d::Zero(); | ||
195 | /// Accumulator gyro bias [rad/s] | ||
196 | Eigen::Vector3d _gyroBiasTotal = Eigen::Vector3d::Zero(); | ||
197 | |||
198 | /// Roll, Pitch and Yaw angles in [deg] used for initialization if not taken from separate pin | ||
199 | std::array<double, 3> _initalRollPitchYaw{}; | ||
200 | /// Whether to initialize the state over an external pin | ||
201 | bool _initializeStateOverExternalPin{}; | ||
202 | |||
203 | /// Whether to enable barometric height (including the corresponding pin) | ||
204 | bool _enableBaroHgt{}; | ||
205 | |||
206 | /// Time from the external init | ||
207 | InsTime _externalInitTime; | ||
208 | |||
209 | /// Whether the accumulated biases have been initialized in the 'inertialIntegrator' | ||
210 | bool _initialSensorBiasesApplied = false; | ||
211 | |||
212 | /// @brief Vector with all state keys | ||
213 | inline static const std::vector<KFStates> States = { KFStates::Roll, KFStates::Pitch, KFStates::Yaw, | ||
214 | KFStates::VelN, KFStates::VelE, KFStates::VelD, | ||
215 | KFStates::PosLat, KFStates::PosLon, KFStates::PosAlt, | ||
216 | KFStates::AccBiasX, KFStates::AccBiasY, KFStates::AccBiasZ, | ||
217 | KFStates::GyrBiasX, KFStates::GyrBiasY, KFStates::GyrBiasZ, | ||
218 | KFStates::HeightBias, KFStates::HeightScale }; | ||
219 | /// @brief All position keys | ||
220 | inline static const std::vector<KFStates> KFPos = { KFStates::PosLat, KFStates::PosLon, KFStates::PosAlt }; | ||
221 | /// @brief All velocity keys | ||
222 | inline static const std::vector<KFStates> KFVel = { KFStates::VelN, KFStates::VelE, KFStates::VelD }; | ||
223 | /// @brief All attitude keys | ||
224 | inline static const std::vector<KFStates> KFAtt = { KFStates::Roll, KFStates::Pitch, KFStates::Yaw }; | ||
225 | /// @brief All acceleration bias keys | ||
226 | inline static const std::vector<KFStates> KFAccBias = { KFStates::AccBiasX, KFStates::AccBiasY, KFStates::AccBiasZ }; | ||
227 | /// @brief All gyroscope bias keys | ||
228 | inline static const std::vector<KFStates> KFGyrBias = { KFStates::GyrBiasX, KFStates::GyrBiasY, KFStates::GyrBiasZ }; | ||
229 | |||
230 | /// @brief All position and velocity keys | ||
231 | inline static const std::vector<KFStates> KFPosVel = { KFStates::PosLat, KFStates::PosLon, KFStates::PosAlt, | ||
232 | KFStates::VelN, KFStates::VelE, KFStates::VelD }; | ||
233 | /// @brief All position, velocity and attitude keys | ||
234 | inline static const std::vector<KFStates> KFPosVelAtt = { KFStates::PosLat, KFStates::PosLon, KFStates::PosAlt, | ||
235 | KFStates::VelN, KFStates::VelE, KFStates::VelD, | ||
236 | KFStates::Roll, KFStates::Pitch, KFStates::Yaw }; | ||
237 | |||
238 | /// @brief Vector with all measurement keys | ||
239 | inline static const std::vector<KFMeas> Meas = { KFMeas::dPosLat, KFMeas::dPosLon, KFMeas::dPosAlt, KFMeas::dVelN, KFMeas::dVelE, KFMeas::dVelD }; | ||
240 | /// @brief All position difference keys | ||
241 | inline static const std::vector<KFMeas> dPos = { KFMeas::dPosLat, KFMeas::dPosLon, KFMeas::dPosAlt }; | ||
242 | /// @brief All velocity difference keys | ||
243 | inline static const std::vector<KFMeas> dVel = { KFMeas::dVelN, KFMeas::dVelE, KFMeas::dVelD }; | ||
244 | |||
245 | /// Kalman Filter representation | ||
246 | KeyedKalmanFilterD<KFStates, KFMeas> _kalmanFilter{ States, Meas }; | ||
247 | |||
248 | // ######################################################################################################################################### | ||
249 | // GUI settings | ||
250 | // ######################################################################################################################################### | ||
251 | |||
252 | /// @brief Check the rank of the Kalman matrices every iteration (computational expensive) | ||
253 | bool _checkKalmanMatricesRanks = true; | ||
254 | |||
255 | // ########################################################################################################### | ||
256 | // Parameters | ||
257 | // ########################################################################################################### | ||
258 | |||
259 | /// Gui selection for the Unit of the input stdev_ra parameter | ||
260 | Units::ImuAccelerometerFilterNoiseUnits _stdevAccelNoiseUnits = Units::ImuAccelerometerFilterNoiseUnits::mg_sqrtHz; | ||
261 | |||
262 | /// @brief 𝜎_ra Standard deviation of the noise on the accelerometer specific-force measurements | ||
263 | /// @note Value from VN-310 Datasheet but verify with values from Brown (2012) table 9.3 for 'High quality' | ||
264 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _stdev_ra = 0.04 /* [mg/√(Hz)] */ * Eigen::Vector3d::Ones(); |
265 | |||
266 | // ########################################################################################################### | ||
267 | |||
268 | /// Gui selection for the Unit of the input stdev_rg parameter | ||
269 | Units::ImuGyroscopeFilterNoiseUnits _stdevGyroNoiseUnits = Units::ImuGyroscopeFilterNoiseUnits::deg_hr_sqrtHz; | ||
270 | |||
271 | /// @brief 𝜎_rg Standard deviation of the noise on the gyro angular-rate measurements | ||
272 | /// @note Value from VN-310 Datasheet but verify with values from Brown (2012) table 9.3 for 'High quality' | ||
273 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _stdev_rg = 5 /* [deg/hr/√(Hz)]^2 */ * Eigen::Vector3d::Ones(); |
274 | |||
275 | // ########################################################################################################### | ||
276 | |||
277 | /// Gui selection for the Unit of the input variance_bad parameter | ||
278 | Units::ImuAccelerometerFilterBiasUnits _stdevAccelBiasUnits = Units::ImuAccelerometerFilterBiasUnits::microg; | ||
279 | |||
280 | /// @brief 𝜎²_bad Variance of the accelerometer dynamic bias | ||
281 | /// @note Value from VN-310 Datasheet (In-Run Bias Stability (Allan Variance)) | ||
282 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _stdev_bad = 10 /* [µg] */ * Eigen::Vector3d::Ones(); |
283 | |||
284 | /// @brief Correlation length of the accelerometer dynamic bias in [s] | ||
285 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _tau_bad = 0.1 * Eigen::Vector3d::Ones(); |
286 | |||
287 | // ########################################################################################################### | ||
288 | |||
289 | /// Gui selection for the Unit of the input variance_bad parameter | ||
290 | Units::ImuGyroscopeFilterBiasUnits _stdevGyroBiasUnits = Units::ImuGyroscopeFilterBiasUnits::deg_h; | ||
291 | |||
292 | /// @brief 𝜎²_bgd Variance of the gyro dynamic bias | ||
293 | /// @note Value from VN-310 Datasheet (In-Run Bias Stability (Allan Variance)) | ||
294 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _stdev_bgd = 1 /* [°/h] */ * Eigen::Vector3d::Ones(); |
295 | |||
296 | /// @brief Correlation length of the gyro dynamic bias in [s] | ||
297 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _tau_bgd = 0.1 * Eigen::Vector3d::Ones(); |
298 | |||
299 | // ########################################################################################################### | ||
300 | |||
301 | /// Possible Units for the Variance of the barometric height bias | ||
302 | enum class StdevBaroHeightBiasUnits : uint8_t | ||
303 | { | ||
304 | m, ///< [m] | ||
305 | }; | ||
306 | /// Gui selection for the Unit of the barometric height bias uncertainty | ||
307 | StdevBaroHeightBiasUnits _stdevBaroHeightBiasUnits = StdevBaroHeightBiasUnits::m; | ||
308 | |||
309 | /// Uncertainty of the barometric height bias | ||
310 | double _stdevBaroHeightBias = 1e-6; | ||
311 | |||
312 | // ########################################################################################################### | ||
313 | |||
314 | /// Possible Units for the Variance of the barometric height scale | ||
315 | enum class StdevBaroHeightScaleUnits : uint8_t | ||
316 | { | ||
317 | m_m, ///< [m/m] | ||
318 | }; | ||
319 | /// Gui selection for the Unit of the barometric height scale uncertainty | ||
320 | StdevBaroHeightScaleUnits _stdevBaroHeightScaleUnits = StdevBaroHeightScaleUnits::m_m; | ||
321 | |||
322 | /// Uncertainty of the barometric height scale | ||
323 | double _stdevBaroHeightScale = 1e-8; | ||
324 | |||
325 | // ########################################################################################################### | ||
326 | |||
327 | /// @brief Available Random processes | ||
328 | enum class RandomProcess : uint8_t | ||
329 | { | ||
330 | // WhiteNoise, ///< White noise | ||
331 | // RandomConstant, ///< Random constant | ||
332 | |||
333 | RandomWalk, ///< Random Walk | ||
334 | GaussMarkov1, ///< Gauss-Markov 1st Order | ||
335 | |||
336 | // GaussMarkov2, ///< Gauss-Markov 2nd Order | ||
337 | // GaussMarkov3, ///< Gauss-Markov 3rd Order | ||
338 | }; | ||
339 | |||
340 | /// @brief Random Process used to estimate the accelerometer biases | ||
341 | RandomProcess _randomProcessAccel = RandomProcess::RandomWalk; | ||
342 | /// @brief Random Process used to estimate the gyroscope biases | ||
343 | RandomProcess _randomProcessGyro = RandomProcess::RandomWalk; | ||
344 | |||
345 | // ########################################################################################################### | ||
346 | |||
347 | /// Possible Units for the GNSS measurement uncertainty for the position (standard deviation σ or Variance σ²) | ||
348 | enum class GnssMeasurementUncertaintyPositionUnit : uint8_t | ||
349 | { | ||
350 | meter2, ///< Variance [m^2, m^2, m^2] | ||
351 | meter, ///< Standard deviation [m, m, m] | ||
352 | }; | ||
353 | /// Gui selection for the Unit of the GNSS measurement uncertainty for the position | ||
354 | GnssMeasurementUncertaintyPositionUnit _gnssMeasurementUncertaintyPositionUnit = GnssMeasurementUncertaintyPositionUnit::meter; | ||
355 | |||
356 | /// @brief GUI selection of the GNSS position measurement uncertainty (standard deviation σ or Variance σ²). | ||
357 | /// SPP accuracy approx. 3m in horizontal direction and 3 times worse in vertical direction | ||
358 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _gnssMeasurementUncertaintyPosition{ 0.3, 0.3, 0.3 * 3 }; |
359 | |||
360 | /// Whether to override the position uncertainty or use the one included in the measurement | ||
361 | bool _gnssMeasurementUncertaintyPositionOverride = false; | ||
362 | |||
363 | // ########################################################################################################### | ||
364 | |||
365 | /// Possible Units for the GNSS measurement uncertainty for the velocity (standard deviation σ or Variance σ²) | ||
366 | enum class GnssMeasurementUncertaintyVelocityUnit : uint8_t | ||
367 | { | ||
368 | m2_s2, ///< Variance [m^2/s^2] | ||
369 | m_s, ///< Standard deviation [m/s] | ||
370 | }; | ||
371 | /// Gui selection for the Unit of the GNSS measurement uncertainty for the velocity | ||
372 | GnssMeasurementUncertaintyVelocityUnit _gnssMeasurementUncertaintyVelocityUnit = GnssMeasurementUncertaintyVelocityUnit::m_s; | ||
373 | |||
374 | /// GUI selection of the GNSS NED velocity measurement uncertainty (standard deviation σ or Variance σ²) | ||
375 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _gnssMeasurementUncertaintyVelocity{ 0.5, 0.5, 0.5 }; |
376 | |||
377 | /// Whether to override the velocity uncertainty or use the one included in the measurement | ||
378 | bool _gnssMeasurementUncertaintyVelocityOverride = false; | ||
379 | |||
380 | // ########################################################################################################### | ||
381 | |||
382 | /// Possible Units for the barometric height measurement uncertainty (standard deviation σ or Variance σ²) | ||
383 | enum class BaroHeightMeasurementUncertaintyUnit : uint8_t | ||
384 | { | ||
385 | m2, ///< Variance [m²] | ||
386 | m, ///< Standard deviation [m] | ||
387 | }; | ||
388 | /// Gui selection for the Unit of the barometric height measurement uncertainty | ||
389 | BaroHeightMeasurementUncertaintyUnit _barometricHeightMeasurementUncertaintyUnit = BaroHeightMeasurementUncertaintyUnit::m; | ||
390 | |||
391 | /// GUI selection of the barometric height measurement uncertainty (standard deviation σ or Variance σ²) | ||
392 | double _barometricHeightMeasurementUncertainty = 1.0; | ||
393 | |||
394 | /// Whether to override the barometric height uncertainty or use the one included in the measurement | ||
395 | bool _baroHeightMeasurementUncertaintyOverride = false; | ||
396 | |||
397 | // ########################################################################################################### | ||
398 | |||
399 | /// Possible Units for the initial covariance for the position (standard deviation σ or Variance σ²) | ||
400 | enum class InitCovariancePositionUnit : uint8_t | ||
401 | { | ||
402 | rad2_rad2_m2, ///< Variance LatLonAlt^2 [rad^2, rad^2, m^2] | ||
403 | rad_rad_m, ///< Standard deviation LatLonAlt [rad, rad, m] | ||
404 | meter2, ///< Variance NED [m^2, m^2, m^2] | ||
405 | meter, ///< Standard deviation NED [m, m, m] | ||
406 | }; | ||
407 | /// Gui selection for the Unit of the initial covariance for the position | ||
408 | InitCovariancePositionUnit _initCovariancePositionUnit = InitCovariancePositionUnit::meter; | ||
409 | |||
410 | /// GUI selection of the initial covariance diagonal values for position (standard deviation σ or Variance σ²) | ||
411 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initCovariancePosition{ 100.0, 100.0, 100.0 }; |
412 | |||
413 | // ########################################################################################################### | ||
414 | |||
415 | /// Possible Units for the initial covariance for the velocity (standard deviation σ or Variance σ²) | ||
416 | enum class InitCovarianceVelocityUnit : uint8_t | ||
417 | { | ||
418 | m2_s2, ///< Variance [m^2/s^2] | ||
419 | m_s, ///< Standard deviation [m/s] | ||
420 | }; | ||
421 | /// Gui selection for the Unit of the initial covariance for the velocity | ||
422 | InitCovarianceVelocityUnit _initCovarianceVelocityUnit = InitCovarianceVelocityUnit::m_s; | ||
423 | |||
424 | /// GUI selection of the initial covariance diagonal values for velocity (standard deviation σ or Variance σ²) | ||
425 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initCovarianceVelocity{ 10.0, 10.0, 10.0 }; |
426 | |||
427 | // ########################################################################################################### | ||
428 | |||
429 | /// Possible Units for the initial covariance for the attitude angles (standard deviation σ or Variance σ²) | ||
430 | enum class InitCovarianceAttitudeAnglesUnit : uint8_t | ||
431 | { | ||
432 | rad2, ///< Variance [rad^2] | ||
433 | deg2, ///< Variance [deg^2] | ||
434 | rad, ///< Standard deviation [rad] | ||
435 | deg, ///< Standard deviation [deg] | ||
436 | }; | ||
437 | /// Gui selection for the Unit of the initial covariance for the attitude angles | ||
438 | InitCovarianceAttitudeAnglesUnit _initCovarianceAttitudeAnglesUnit = InitCovarianceAttitudeAnglesUnit::deg; | ||
439 | |||
440 | /// GUI selection of the initial covariance diagonal values for attitude angles (standard deviation σ or Variance σ²) | ||
441 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initCovarianceAttitudeAngles{ 10.0, 10.0, 10.0 }; |
442 | |||
443 | // ########################################################################################################### | ||
444 | |||
445 | /// Possible Units for the initial covariance for the accelerometer biases (standard deviation σ or Variance σ²) | ||
446 | enum class InitCovarianceBiasAccelUnit : uint8_t | ||
447 | { | ||
448 | m2_s4, ///< Variance [m^2/s^4] | ||
449 | m_s2, ///< Standard deviation [m/s^2] | ||
450 | }; | ||
451 | /// Gui selection for the Unit of the initial covariance for the accelerometer biases | ||
452 | InitCovarianceBiasAccelUnit _initCovarianceBiasAccelUnit = InitCovarianceBiasAccelUnit::m_s2; | ||
453 | |||
454 | /// GUI selection of the initial covariance diagonal values for accelerometer biases (standard deviation σ or Variance σ²) | ||
455 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initCovarianceBiasAccel{ 1.0, 1.0, 1.0 }; |
456 | |||
457 | // ########################################################################################################### | ||
458 | |||
459 | /// Possible Units for the initial covariance for the gyroscope biases (standard deviation σ or Variance σ²) | ||
460 | enum class InitCovarianceBiasGyroUnit : uint8_t | ||
461 | { | ||
462 | rad2_s2, ///< Variance [rad²/s²] | ||
463 | deg2_s2, ///< Variance [deg²/s²] | ||
464 | rad_s, ///< Standard deviation [rad/s] | ||
465 | deg_s, ///< Standard deviation [deg/s] | ||
466 | }; | ||
467 | /// Gui selection for the Unit of the initial covariance for the gyroscope biases | ||
468 | InitCovarianceBiasGyroUnit _initCovarianceBiasGyroUnit = InitCovarianceBiasGyroUnit::deg_s; | ||
469 | |||
470 | /// GUI selection of the initial covariance diagonal values for gyroscope biases (standard deviation σ or Variance σ²) | ||
471 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initCovarianceBiasGyro{ 0.5, 0.5, 0.5 }; |
472 | |||
473 | // ########################################################################################################### | ||
474 | |||
475 | /// Possible Units for the initial covariance for the height bias (standard deviation σ or Variance σ²) | ||
476 | enum class InitCovarianceBiasHeightUnit : uint8_t | ||
477 | { | ||
478 | m2, ///< Variance [m²] | ||
479 | m, ///< Standard deviation [m] | ||
480 | }; | ||
481 | /// Gui selection for the Unit of the initial covariance for the height bias | ||
482 | InitCovarianceBiasHeightUnit _initCovarianceBiasHeightUnit = InitCovarianceBiasHeightUnit::m2; | ||
483 | |||
484 | /// GUI selection of the initial covariance diagonal values for the height bias (standard deviation σ or Variance σ²) | ||
485 | double _initCovarianceBiasHeight{ 100.0 }; | ||
486 | |||
487 | // ########################################################################################################### | ||
488 | |||
489 | /// Possible Units for the initial covariance for the height scale (standard deviation σ or Variance σ²) | ||
490 | enum class InitCovarianceScaleHeight : uint8_t | ||
491 | { | ||
492 | m2_m2, ///< Variance [m²/m²] | ||
493 | m_m, ///< Standard devation [m/m] | ||
494 | }; | ||
495 | /// Gui selection for the Unit of the initial covariance for the height scale | ||
496 | InitCovarianceScaleHeight _initCovarianceScaleHeightUnit = InitCovarianceScaleHeight::m2_m2; | ||
497 | |||
498 | /// GUI selection of the initial covariance diagonal values for the height scale (standard deviation σ or Variance σ²) | ||
499 | double _initCovarianceScaleHeight{ 0.01 }; | ||
500 | |||
501 | // ########################################################################################################### | ||
502 | |||
503 | /// Possible Units for the initial accelerometer biases | ||
504 | enum class InitBiasAccelUnit : uint8_t | ||
505 | { | ||
506 | microg, ///< [µg] | ||
507 | m_s2, ///< acceleration [m/s^2] | ||
508 | }; | ||
509 | /// Gui selection for the unit of the initial accelerometer biases | ||
510 | InitBiasAccelUnit _initBiasAccelUnit = InitBiasAccelUnit::m_s2; | ||
511 | |||
512 | /// GUI selection of the initial accelerometer biases | ||
513 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initBiasAccel{ 0.0, 0.0, 0.0 }; |
514 | |||
515 | // ########################################################################################################### | ||
516 | |||
517 | /// Possible Units for the initial gyroscope biases | ||
518 | enum class InitBiasGyroUnit : uint8_t | ||
519 | { | ||
520 | rad_s, ///< angular rate [rad/s] | ||
521 | deg_s, ///< angular rate [deg/s] | ||
522 | }; | ||
523 | /// Gui selection for the unit of the initial gyroscope biases | ||
524 | InitBiasGyroUnit _initBiasGyroUnit = InitBiasGyroUnit::deg_s; | ||
525 | |||
526 | /// GUI selection of the initial gyroscope biases | ||
527 |
1/2✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
|
129 | Eigen::Vector3d _initBiasGyro{ 0.0, 0.0, 0.0 }; |
528 | |||
529 | // ########################################################################################################### | ||
530 | |||
531 | /// GUI option for the Phi calculation algorithm | ||
532 | enum class PhiCalculationAlgorithm : uint8_t | ||
533 | { | ||
534 | Exponential, ///< Van-Loan | ||
535 | Taylor, ///< Taylor | ||
536 | }; | ||
537 | /// GUI option for the Phi calculation algorithm | ||
538 | PhiCalculationAlgorithm _phiCalculationAlgorithm = PhiCalculationAlgorithm::Taylor; | ||
539 | |||
540 | /// GUI option for the order of the Taylor polynom to calculate the Phi matrix | ||
541 | int _phiCalculationTaylorOrder = 2; | ||
542 | |||
543 | /// GUI option for the Q calculation algorithm | ||
544 | enum class QCalculationAlgorithm : uint8_t | ||
545 | { | ||
546 | VanLoan, ///< Van-Loan | ||
547 | Taylor1, ///< Taylor | ||
548 | }; | ||
549 | /// GUI option for the Q calculation algorithm | ||
550 | QCalculationAlgorithm _qCalculationAlgorithm = QCalculationAlgorithm::Taylor1; | ||
551 | |||
552 | // ########################################################################################################### | ||
553 | // Dynamic Input Pins | ||
554 | // ########################################################################################################### | ||
555 | // | ||
556 | /// @brief Function to call to add a new pin | ||
557 | /// @param[in, out] node Pointer to this node | ||
558 | static void pinAddCallback(Node* node); | ||
559 | /// @brief Function to call to delete a pin | ||
560 | /// @param[in, out] node Pointer to this node | ||
561 | /// @param[in] pinIdx Input pin index to delete | ||
562 | static void pinDeleteCallback(Node* node, size_t pinIdx); | ||
563 | |||
564 | /// Update the input pins depending on the GUI | ||
565 | void updateInputPins(); | ||
566 | |||
567 | /// @brief Dynamic input pins | ||
568 | /// @attention This should always be the last variable in the header, because it accesses others through the function callbacks | ||
569 | gui::widgets::DynamicInputPins _dynamicInputPins{ 1, this, pinAddCallback, pinDeleteCallback }; | ||
570 | |||
571 | // ########################################################################################################### | ||
572 | // Prediction | ||
573 | // ########################################################################################################### | ||
574 | |||
575 | // ########################################################################################################### | ||
576 | // System matrix 𝐅 | ||
577 | // ########################################################################################################### | ||
578 | |||
579 | /// @brief Calculates the system matrix 𝐅 for the local navigation frame | ||
580 | /// @param[in] n_Quat_b Attitude of the body with respect to n-system | ||
581 | /// @param[in] b_specForce_ib Specific force of the body with respect to inertial frame in [m / s^2], resolved in body coordinates | ||
582 | /// @param[in] n_omega_in Angular rate of navigation system with respect to the inertial system [rad / s], resolved in navigation coordinates. | ||
583 | /// @param[in] n_velocity Velocity in n-system in [m / s] | ||
584 | /// @param[in] lla_position Position as Lat Lon Alt in [rad rad m] | ||
585 | /// @param[in] R_N Meridian radius of curvature in [m] | ||
586 | /// @param[in] R_E Prime vertical radius of curvature (East/West) [m] | ||
587 | /// @param[in] g_0 Magnitude of the gravity vector in [m/s^2] (see \cite Groves2013 Groves, ch. 2.4.7, eq. 2.135, p. 70) | ||
588 | /// @param[in] r_eS_e Geocentric radius. The distance of a point on the Earth's surface from the center of the Earth in [m] | ||
589 | /// @param[in] tau_bad Correlation length for the accelerometer in [s] | ||
590 | /// @param[in] tau_bgd Correlation length for the gyroscope in [s] | ||
591 | /// @note See Groves (2013) chapter 14.2.4, equation (14.63) | ||
592 | [[nodiscard]] KeyedMatrix<double, KFStates, KFStates, 17, 17> n_systemMatrix_F(const Eigen::Quaterniond& n_Quat_b, | ||
593 | const Eigen::Vector3d& b_specForce_ib, | ||
594 | const Eigen::Vector3d& n_omega_in, | ||
595 | const Eigen::Vector3d& n_velocity, | ||
596 | const Eigen::Vector3d& lla_position, | ||
597 | double R_N, | ||
598 | double R_E, | ||
599 | double g_0, | ||
600 | double r_eS_e, | ||
601 | const Eigen::Vector3d& tau_bad, | ||
602 | const Eigen::Vector3d& tau_bgd) const; | ||
603 | |||
604 | /// @brief Calculates the system matrix 𝐅 for the ECEF frame | ||
605 | /// @param[in] e_Quat_b Attitude of the body with respect to e-system | ||
606 | /// @param[in] b_specForce_ib Specific force of the body with respect to inertial frame in [m / s^2], resolved in body coordinates | ||
607 | /// @param[in] e_position Position in ECEF coordinates in [m] | ||
608 | /// @param[in] e_gravitation Gravitational acceleration in [m/s^2] | ||
609 | /// @param[in] r_eS_e Geocentric radius. The distance of a point on the Earth's surface from the center of the Earth in [m] | ||
610 | /// @param[in] e_omega_ie Angular velocity of Earth with respect to inertial system, represented in e-sys in [rad/s] | ||
611 | /// @param[in] tau_bad Correlation length for the accelerometer in [s] | ||
612 | /// @param[in] tau_bgd Correlation length for the gyroscope in [s] | ||
613 | /// @note See Groves (2013) chapter 14.2.3, equation (14.48) | ||
614 | [[nodiscard]] KeyedMatrix<double, KFStates, KFStates, 17, 17> e_systemMatrix_F(const Eigen::Quaterniond& e_Quat_b, | ||
615 | const Eigen::Vector3d& b_specForce_ib, | ||
616 | const Eigen::Vector3d& e_position, | ||
617 | const Eigen::Vector3d& e_gravitation, | ||
618 | double r_eS_e, | ||
619 | const Eigen::Vector3d& e_omega_ie, | ||
620 | const Eigen::Vector3d& tau_bad, | ||
621 | const Eigen::Vector3d& tau_bgd) const; | ||
622 | |||
623 | // ########################################################################################################### | ||
624 | // Noise input matrix 𝐆 & Noise scale matrix 𝐖 | ||
625 | // System noise covariance matrix 𝐐 | ||
626 | // ########################################################################################################### | ||
627 | |||
628 | /// @brief Calculates the noise input matrix 𝐆 | ||
629 | /// @param[in] ien_Quat_b Quaternion from body frame to {i,e,n} frame | ||
630 | /// @note See \cite Groves2013 Groves, ch. 14.2.6, eq. 14.79, p. 590 | ||
631 | [[nodiscard]] static KeyedMatrix<double, KFStates, KFStates, 17, 17> noiseInputMatrix_G(const Eigen::Quaterniond& ien_Quat_b); | ||
632 | |||
633 | /// @brief Calculates the noise scale matrix 𝐖 | ||
634 | /// @param[in] sigma_ra Standard deviation of the noise on the accelerometer specific-force measurements | ||
635 | /// @param[in] sigma_rg Standard deviation of the noise on the gyro angular-rate measurements | ||
636 | /// @param[in] sigma_bad Standard deviation of the accelerometer dynamic bias | ||
637 | /// @param[in] sigma_bgd Standard deviation of the gyro dynamic bias | ||
638 | /// @param[in] tau_bad Correlation length for the accelerometer in [s] | ||
639 | /// @param[in] tau_bgd Correlation length for the gyroscope in [s] | ||
640 | /// @param[in] sigma_heightBias Standard deviation of the height bias | ||
641 | /// @param[in] sigma_heightScale Standard deviation of the height scale | ||
642 | /// @note See \cite Groves2013 Groves, ch. 14.2.6, eq. 14.79, p. 590 | ||
643 | [[nodiscard]] Eigen::Matrix<double, 17, 17> noiseScaleMatrix_W(const Eigen::Vector3d& sigma_ra, const Eigen::Vector3d& sigma_rg, | ||
644 | const Eigen::Vector3d& sigma_bad, const Eigen::Vector3d& sigma_bgd, | ||
645 | const Eigen::Vector3d& tau_bad, const Eigen::Vector3d& tau_bgd, | ||
646 | const double& sigma_heightBias, const double& sigma_heightScale); | ||
647 | |||
648 | /// @brief System noise covariance matrix 𝐐_{k-1} | ||
649 | /// @param[in] sigma2_ra Variance of the noise on the accelerometer specific-force measurements | ||
650 | /// @param[in] sigma2_rg Variance of the noise on the gyro angular-rate measurements | ||
651 | /// @param[in] sigma2_bad Variance of the accelerometer dynamic bias | ||
652 | /// @param[in] sigma2_bgd Variance of the gyro dynamic bias | ||
653 | /// @param[in] sigma_heightBias Standard deviation of the height bias | ||
654 | /// @param[in] sigma_heightScale Standard deviation of the height scale | ||
655 | /// @param[in] tau_bad Correlation length for the accelerometer in [s] | ||
656 | /// @param[in] tau_bgd Correlation length for the gyroscope in [s] | ||
657 | /// @param[in] n_F_21 Submatrix 𝐅_21 of the system matrix 𝐅 | ||
658 | /// @param[in] T_rn_p Conversion matrix between cartesian and curvilinear perturbations to the position | ||
659 | /// @param[in] n_Dcm_b Direction Cosine Matrix from body to navigation coordinates | ||
660 | /// @param[in] tau_s Time interval in [s] | ||
661 | /// @return The 17x17 matrix of system noise covariances | ||
662 | [[nodiscard]] static KeyedMatrix<double, KFStates, KFStates, 17, 17> n_systemNoiseCovarianceMatrix_Q(const Eigen::Vector3d& sigma2_ra, const Eigen::Vector3d& sigma2_rg, | ||
663 | const Eigen::Vector3d& sigma2_bad, const Eigen::Vector3d& sigma2_bgd, | ||
664 | const double& sigma_heightBias, const double& sigma_heightScale, | ||
665 | const Eigen::Vector3d& tau_bad, const Eigen::Vector3d& tau_bgd, | ||
666 | const Eigen::Matrix3d& n_F_21, const Eigen::Matrix3d& T_rn_p, | ||
667 | const Eigen::Matrix3d& n_Dcm_b, const double& tau_s); | ||
668 | |||
669 | /// @brief System noise covariance matrix 𝐐_{k-1} | ||
670 | /// @param[in] sigma2_ra Variance of the noise on the accelerometer specific-force measurements | ||
671 | /// @param[in] sigma2_rg Variance of the noise on the gyro angular-rate measurements | ||
672 | /// @param[in] sigma2_bad Variance of the accelerometer dynamic bias | ||
673 | /// @param[in] sigma2_bgd Variance of the gyro dynamic bias | ||
674 | /// @param[in] sigma_heightBias Standard deviation of the height bias | ||
675 | /// @param[in] sigma_heightScale Standard deviation of the height scale | ||
676 | /// @param[in] tau_bad Correlation length for the accelerometer in [s] | ||
677 | /// @param[in] tau_bgd Correlation length for the gyroscope in [s] | ||
678 | /// @param[in] e_F_21 Submatrix 𝐅_21 of the system matrix 𝐅 | ||
679 | /// @param[in] e_Dcm_b Direction Cosine Matrix from body to Earth coordinates | ||
680 | /// @param[in] tau_s Time interval in [s] | ||
681 | /// @return The 17x17 matrix of system noise covariances | ||
682 | [[nodiscard]] static KeyedMatrix<double, KFStates, KFStates, 17, 17> e_systemNoiseCovarianceMatrix_Q(const Eigen::Vector3d& sigma2_ra, const Eigen::Vector3d& sigma2_rg, | ||
683 | const Eigen::Vector3d& sigma2_bad, const Eigen::Vector3d& sigma2_bgd, | ||
684 | const double& sigma_heightBias, const double& sigma_heightScale, | ||
685 | const Eigen::Vector3d& tau_bad, const Eigen::Vector3d& tau_bgd, | ||
686 | const Eigen::Matrix3d& e_F_21, | ||
687 | const Eigen::Matrix3d& e_Dcm_b, const double& tau_s); | ||
688 | |||
689 | // ########################################################################################################### | ||
690 | // Error covariance matrix P | ||
691 | // ########################################################################################################### | ||
692 | |||
693 | /// @brief Initial error covariance matrix P_0 | ||
694 | /// @param[in] variance_angles Initial Covariance of the attitude angles in [rad²] | ||
695 | /// @param[in] variance_vel Initial Covariance of the velocity in [m²/s²] | ||
696 | /// @param[in] variance_pos Initial Covariance of the position in [rad² rad² m²] n-frame / [m²] i,e-frame | ||
697 | /// @param[in] variance_accelBias Initial Covariance of the accelerometer biases in [m^2/s^4] | ||
698 | /// @param[in] variance_gyroBias Initial Covariance of the gyroscope biases in [rad^2/s^2] | ||
699 | /// @param[in] variance_heightBias Initial Covariance of the height bias [m^2] | ||
700 | /// @param[in] variance_heightScale Initial Covariance of the height scale in [m^2 / m^2] | ||
701 | /// @return The 17x17 matrix of initial state variances | ||
702 | [[nodiscard]] KeyedMatrix<double, KFStates, KFStates, 17, 17> initialErrorCovarianceMatrix_P0(const Eigen::Vector3d& variance_angles, | ||
703 | const Eigen::Vector3d& variance_vel, | ||
704 | const Eigen::Vector3d& variance_pos, | ||
705 | const Eigen::Vector3d& variance_accelBias, | ||
706 | const Eigen::Vector3d& variance_gyroBias, | ||
707 | const double& variance_heightBias, | ||
708 | const double& variance_heightScale) const; | ||
709 | |||
710 | // ########################################################################################################### | ||
711 | // Correction | ||
712 | // ########################################################################################################### | ||
713 | |||
714 | /// @brief Measurement matrix for GNSS measurements at timestep k, represented in navigation coordinates | ||
715 | /// @param[in] T_rn_p Conversion matrix between cartesian and curvilinear perturbations to the position | ||
716 | /// @param[in] n_Dcm_b Direction Cosine Matrix from body to navigation coordinates | ||
717 | /// @param[in] b_omega_ib Angular rate of body with respect to inertial system in body-frame coordinates in [rad/s] | ||
718 | /// @param[in] b_leverArm_InsGnss l_{ba}^b lever arm from the INS to the GNSS antenna in body-frame coordinates [m] | ||
719 | /// @param[in] n_Omega_ie Skew-symmetric matrix of the Earth-rotation vector in local navigation frame axes | ||
720 | /// @return The 6x17 measurement matrix 𝐇 | ||
721 | [[nodiscard]] static KeyedMatrix<double, KFMeas, KFStates, 6, 17> n_measurementMatrix_H(const Eigen::Matrix3d& T_rn_p, | ||
722 | const Eigen::Matrix3d& n_Dcm_b, | ||
723 | const Eigen::Vector3d& b_omega_ib, | ||
724 | const Eigen::Vector3d& b_leverArm_InsGnss, | ||
725 | const Eigen::Matrix3d& n_Omega_ie); | ||
726 | |||
727 | /// @brief Measurement matrix for baro height measurements at timestep k, represented in navigation coordinates | ||
728 | /// @param[in] height predicted height | ||
729 | /// @param[in] scale height scale | ||
730 | /// @return The 6x17 measurement matrix 𝐇 | ||
731 | [[nodiscard]] static KeyedMatrix<double, KFMeas, KFStates, 1, 17> n_measurementMatrix_H(const double& height, const double& scale); | ||
732 | |||
733 | /// @brief Measurement matrix for GNSS measurements at timestep k, represented in Earth frame coordinates | ||
734 | /// @param[in] e_Dcm_b Direction Cosine Matrix from body to Earth coordinates | ||
735 | /// @param[in] b_omega_ib Angular rate of body with respect to inertial system in body-frame coordinates in [rad/s] | ||
736 | /// @param[in] b_leverArm_InsGnss l_{ba}^b lever arm from the INS to the GNSS antenna in body-frame coordinates [m] | ||
737 | /// @param[in] e_Omega_ie Skew-symmetric matrix of the Earth-rotation vector in Earth frame axes | ||
738 | /// @return The 6x17 measurement matrix 𝐇 | ||
739 | [[nodiscard]] static KeyedMatrix<double, KFMeas, KFStates, 6, 17> e_measurementMatrix_H(const Eigen::Matrix3d& e_Dcm_b, | ||
740 | const Eigen::Vector3d& b_omega_ib, | ||
741 | const Eigen::Vector3d& b_leverArm_InsGnss, | ||
742 | const Eigen::Matrix3d& e_Omega_ie); | ||
743 | |||
744 | /// @brief Measurement matrix for barometric height measurements at timestep k, represented in Earth frame coordinates | ||
745 | /// @param[in] e_positionEstimate predicted position | ||
746 | /// @param[in] height predicted height (assuming that the KF internally converts to LLA at every epoch) | ||
747 | /// @param[in] scale height scale | ||
748 | /// @return The 1x17 measurement matrix 𝐇 | ||
749 | [[nodiscard]] static KeyedMatrix<double, KFMeas, KFStates, 1, 17> e_measurementMatrix_H(const Eigen::Vector3d& e_positionEstimate, | ||
750 | const double& height, | ||
751 | const double& scale); | ||
752 | |||
753 | /// @brief Measurement noise covariance matrix 𝐑 | ||
754 | /// @param[in] posVelObs Position and velocity observation | ||
755 | /// @param[in] lla_position Position as Lat Lon Alt in [rad rad m] | ||
756 | /// @param[in] R_N Meridian radius of curvature in [m] | ||
757 | /// @param[in] R_E Prime vertical radius of curvature (East/West) [m] | ||
758 | /// @return The 6x6 measurement covariance matrix 𝐑 | ||
759 | [[nodiscard]] KeyedMatrix<double, KFMeas, KFMeas, 6, 6> n_measurementNoiseCovariance_R(const std::shared_ptr<const PosVel>& posVelObs, | ||
760 | const Eigen::Vector3d& lla_position, | ||
761 | double R_N, | ||
762 | double R_E) const; | ||
763 | |||
764 | /// @brief Measurement noise covariance matrix 𝐑 | ||
765 | /// @param[in] baroVarianceHeight Variance of height in [m²] | ||
766 | /// @return The 1x1 measurement covariance matrix 𝐑 | ||
767 | [[nodiscard]] static KeyedMatrix<double, KFMeas, KFMeas, 1, 1> n_measurementNoiseCovariance_R(const double& baroVarianceHeight); | ||
768 | |||
769 | /// @brief Measurement noise covariance matrix 𝐑 | ||
770 | /// @param[in] posVelObs Position and velocity observation | ||
771 | /// @return The 6x6 measurement covariance matrix 𝐑 | ||
772 | [[nodiscard]] KeyedMatrix<double, KFMeas, KFMeas, 6, 6> e_measurementNoiseCovariance_R(const std::shared_ptr<const PosVel>& posVelObs) const; | ||
773 | |||
774 | /// @brief Measurement innovation vector 𝜹𝐳 | ||
775 | /// @param[in] lla_positionMeasurement Position measurement as Lat Lon Alt in [rad rad m] | ||
776 | /// @param[in] lla_positionEstimate Position estimate as Lat Lon Alt in [rad rad m] | ||
777 | /// @param[in] n_velocityMeasurement Velocity measurement in the n frame in [m/s] | ||
778 | /// @param[in] n_velocityEstimate Velocity estimate in the n frame in [m/s] | ||
779 | /// @param[in] T_rn_p Conversion matrix between cartesian and curvilinear perturbations to the position | ||
780 | /// @param[in] n_Quat_b Rotation quaternion from body to navigation coordinates | ||
781 | /// @param[in] b_leverArm_InsGnss l_{ba}^b lever arm from the INS to the GNSS antenna in body-frame coordinates [m] | ||
782 | /// @param[in] b_omega_ib Angular rate of body with respect to inertial system in body-frame coordinates in [rad/s] | ||
783 | /// @param[in] n_Omega_ie Skew-symmetric matrix of the Earth-rotation vector in local navigation frame axes | ||
784 | /// @return The 6x1 measurement innovation vector 𝜹𝐳 | ||
785 | [[nodiscard]] static KeyedVector<double, KFMeas, 6> n_measurementInnovation_dz(const Eigen::Vector3d& lla_positionMeasurement, const Eigen::Vector3d& lla_positionEstimate, | ||
786 | const Eigen::Vector3d& n_velocityMeasurement, const Eigen::Vector3d& n_velocityEstimate, | ||
787 | const Eigen::Matrix3d& T_rn_p, const Eigen::Quaterniond& n_Quat_b, const Eigen::Vector3d& b_leverArm_InsGnss, | ||
788 | const Eigen::Vector3d& b_omega_ib, const Eigen::Matrix3d& n_Omega_ie); | ||
789 | |||
790 | /// @brief Measurement innovation vector 𝜹𝐳 | ||
791 | /// @param[in] baroheight barometric height measurement in [m] | ||
792 | /// @param[in] height predicted height in [m] | ||
793 | /// @param[in] heightbias height bias in [m] | ||
794 | /// @param[in] heightscale height scale [m/m] | ||
795 | /// @return The 1x1 measurement innovation vector 𝜹𝐳 | ||
796 | [[nodiscard]] static KeyedVector<double, KFMeas, 1> n_measurementInnovation_dz(const double& baroheight, const double& height, | ||
797 | const double& heightbias, const double& heightscale); | ||
798 | |||
799 | /// @brief Measurement innovation vector 𝜹𝐳 | ||
800 | /// @param[in] e_positionMeasurement Position measurement in ECEF coordinates in [m] | ||
801 | /// @param[in] e_positionEstimate Position estimate in ECEF coordinates in [m] | ||
802 | /// @param[in] e_velocityMeasurement Velocity measurement in the e frame in [m/s] | ||
803 | /// @param[in] e_velocityEstimate Velocity estimate in the e frame in [m/s] | ||
804 | /// @param[in] e_Quat_b Rotation quaternion from body to Earth coordinates | ||
805 | /// @param[in] b_leverArm_InsGnss l_{ba}^b lever arm from the INS to the GNSS antenna in body-frame coordinates [m] | ||
806 | /// @param[in] b_omega_ib Angular rate of body with respect to inertial system in body-frame coordinates in [rad/s] | ||
807 | /// @param[in] e_Omega_ie Skew-symmetric matrix of the Earth-rotation vector in Earth frame axes | ||
808 | /// @return The 6x1 measurement innovation vector 𝜹𝐳 | ||
809 | [[nodiscard]] static KeyedVector<double, KFMeas, 6> e_measurementInnovation_dz(const Eigen::Vector3d& e_positionMeasurement, const Eigen::Vector3d& e_positionEstimate, | ||
810 | const Eigen::Vector3d& e_velocityMeasurement, const Eigen::Vector3d& e_velocityEstimate, | ||
811 | const Eigen::Quaterniond& e_Quat_b, const Eigen::Vector3d& b_leverArm_InsGnss, | ||
812 | const Eigen::Vector3d& b_omega_ib, const Eigen::Matrix3d& e_Omega_ie); | ||
813 | }; | ||
814 | |||
815 | } // namespace NAV | ||
816 | |||
817 | #ifndef DOXYGEN_IGNORE | ||
818 | |||
819 | template<> | ||
820 | struct fmt::formatter<NAV::LooselyCoupledKF::KFStates> : fmt::formatter<const char*> | ||
821 | { | ||
822 | /// @brief Defines how to format structs | ||
823 | /// @param[in] st Struct to format | ||
824 | /// @param[in, out] ctx Format context | ||
825 | /// @return Output iterator | ||
826 | template<typename FormatContext> | ||
827 | ✗ | auto format(const NAV::LooselyCoupledKF::KFStates& st, FormatContext& ctx) const | |
828 | { | ||
829 | ✗ | switch (st) | |
830 | { | ||
831 | ✗ | case NAV::LooselyCoupledKF::KFStates::Roll: | |
832 | ✗ | return fmt::formatter<const char*>::format("Roll/Psi_eb_1", ctx); | |
833 | ✗ | case NAV::LooselyCoupledKF::KFStates::Pitch: | |
834 | ✗ | return fmt::formatter<const char*>::format("Pitch/Psi_eb_2", ctx); | |
835 | ✗ | case NAV::LooselyCoupledKF::KFStates::Yaw: | |
836 | ✗ | return fmt::formatter<const char*>::format("Yaw/Psi_eb_3", ctx); | |
837 | ✗ | case NAV::LooselyCoupledKF::KFStates::VelN: | |
838 | ✗ | return fmt::formatter<const char*>::format("VelN/VelX", ctx); | |
839 | ✗ | case NAV::LooselyCoupledKF::KFStates::VelE: | |
840 | ✗ | return fmt::formatter<const char*>::format("VelE/VelY", ctx); | |
841 | ✗ | case NAV::LooselyCoupledKF::KFStates::VelD: | |
842 | ✗ | return fmt::formatter<const char*>::format("VelD/VelZ", ctx); | |
843 | ✗ | case NAV::LooselyCoupledKF::KFStates::PosLat: | |
844 | ✗ | return fmt::formatter<const char*>::format("PosLat/PosX", ctx); | |
845 | ✗ | case NAV::LooselyCoupledKF::KFStates::PosLon: | |
846 | ✗ | return fmt::formatter<const char*>::format("PosLon/PosY", ctx); | |
847 | ✗ | case NAV::LooselyCoupledKF::KFStates::PosAlt: | |
848 | ✗ | return fmt::formatter<const char*>::format("PosAlt/PosZ", ctx); | |
849 | ✗ | case NAV::LooselyCoupledKF::KFStates::AccBiasX: | |
850 | ✗ | return fmt::formatter<const char*>::format("AccBiasX", ctx); | |
851 | ✗ | case NAV::LooselyCoupledKF::KFStates::AccBiasY: | |
852 | ✗ | return fmt::formatter<const char*>::format("AccBiasY", ctx); | |
853 | ✗ | case NAV::LooselyCoupledKF::KFStates::AccBiasZ: | |
854 | ✗ | return fmt::formatter<const char*>::format("AccBiasZ", ctx); | |
855 | ✗ | case NAV::LooselyCoupledKF::KFStates::GyrBiasX: | |
856 | ✗ | return fmt::formatter<const char*>::format("GyrBiasX", ctx); | |
857 | ✗ | case NAV::LooselyCoupledKF::KFStates::GyrBiasY: | |
858 | ✗ | return fmt::formatter<const char*>::format("GyrBiasY", ctx); | |
859 | ✗ | case NAV::LooselyCoupledKF::KFStates::GyrBiasZ: | |
860 | ✗ | return fmt::formatter<const char*>::format("GyrBiasZ", ctx); | |
861 | ✗ | case NAV::LooselyCoupledKF::KFStates::HeightBias: | |
862 | ✗ | return fmt::formatter<const char*>::format("HeightBias", ctx); | |
863 | ✗ | case NAV::LooselyCoupledKF::KFStates::HeightScale: | |
864 | ✗ | return fmt::formatter<const char*>::format("HeightScale", ctx); | |
865 | ✗ | case NAV::LooselyCoupledKF::KFStates::KFStates_COUNT: | |
866 | ✗ | return fmt::formatter<const char*>::format("COUNT", ctx); | |
867 | } | ||
868 | |||
869 | ✗ | return fmt::formatter<const char*>::format("ERROR", ctx); | |
870 | } | ||
871 | }; | ||
872 | template<> | ||
873 | struct fmt::formatter<NAV::LooselyCoupledKF::KFMeas> : fmt::formatter<const char*> | ||
874 | { | ||
875 | /// @brief Defines how to format structs | ||
876 | /// @param[in] st Struct to format | ||
877 | /// @param[in, out] ctx Format context | ||
878 | /// @return Output iterator | ||
879 | template<typename FormatContext> | ||
880 | ✗ | auto format(const NAV::LooselyCoupledKF::KFMeas& st, FormatContext& ctx) const | |
881 | { | ||
882 | ✗ | switch (st) | |
883 | { | ||
884 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dPosLat: | |
885 | ✗ | return fmt::formatter<const char*>::format("dPosLat/dPosX", ctx); | |
886 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dPosLon: | |
887 | ✗ | return fmt::formatter<const char*>::format("dPosLon/dPosY", ctx); | |
888 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dPosAlt: | |
889 | ✗ | return fmt::formatter<const char*>::format("dPosAlt/dPosZ", ctx); | |
890 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dVelN: | |
891 | ✗ | return fmt::formatter<const char*>::format("dVelN/dVelX", ctx); | |
892 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dVelE: | |
893 | ✗ | return fmt::formatter<const char*>::format("dVelE/dVelY", ctx); | |
894 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dVelD: | |
895 | ✗ | return fmt::formatter<const char*>::format("dVelD/dVelZ", ctx); | |
896 | ✗ | case NAV::LooselyCoupledKF::KFMeas::dHgt: | |
897 | ✗ | return fmt::formatter<const char*>::format("dHgt", ctx); | |
898 | } | ||
899 | |||
900 | ✗ | return fmt::formatter<const char*>::format("ERROR", ctx); | |
901 | } | ||
902 | }; | ||
903 | |||
904 | #endif | ||
905 | |||
906 | /// @brief Stream insertion operator overload | ||
907 | /// @param[in, out] os Output stream object to stream the time into | ||
908 | /// @param[in] obj Object to print | ||
909 | /// @return Returns the output stream object in order to chain stream insertions | ||
910 | std::ostream& operator<<(std::ostream& os, const NAV::LooselyCoupledKF::KFStates& obj); | ||
911 | |||
912 | /// @brief Stream insertion operator overload | ||
913 | /// @param[in, out] os Output stream object to stream the time into | ||
914 | /// @param[in] obj Object to print | ||
915 | /// @return Returns the output stream object in order to chain stream insertions | ||
916 | std::ostream& operator<<(std::ostream& os, const NAV::LooselyCoupledKF::KFMeas& obj); | ||
917 |