| 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 131 times.
✗ Branch 2 not taken.
|
131 | 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 |