16 const auto nStates =
static_cast<Eigen::Index
>(numStates);
17 Eigen::MatrixXd Phi = Eigen::MatrixXd::Identity(nStates, nStates);
19 Phi.block<3, 3>(0, 3).diagonal().setConstant(dt);
20 Phi.block<3, 3>(6, 9).diagonal().setConstant(dt);
27 Eigen::MatrixXd P = Eigen::MatrixXd::Zero(numStates, numStates);
29 P.block<3, 3>(0, 0).diagonal() = initCovariances.at(0);
30 P.block<3, 3>(3, 3).diagonal() = initCovariances.at(1);
31 P.block<3, 3>(6, 6).diagonal() = initCovariances.at(2);
32 P.block<3, 3>(9, 9).diagonal() = initCovariances.at(3);
35 for (uint32_t i = 12; i < numStates; i += 6)
37 if (!imuCharacteristicsIdentical)
42 P.block<3, 3>(i, i).diagonal() = initCovariances.at(j);
43 P.block<3, 3>(i + 3, i + 3).diagonal() = initCovariances.at(j + 1);
49void NAV::IRWKF::processNoiseMatrix_Q(Eigen::MatrixXd& Q,
const double& dt,
const std::vector<Eigen::VectorXd>& processNoiseVariances,
const uint8_t& numStates,
const bool& imuCharacteristicsIdentical)
52 Q.block<3, 3>(0, 0).diagonal() = processNoiseVariances.at(0) / 3. * std::pow(dt, 3);
53 Q.block<3, 3>(0, 3).diagonal() = processNoiseVariances.at(0) / 2. * std::pow(dt, 2);
54 Q.block<3, 3>(3, 0).diagonal() = processNoiseVariances.at(0) / 2. * std::pow(dt, 2);
55 Q.block<3, 3>(3, 3).diagonal() = processNoiseVariances.at(0) * dt;
58 Q.block<3, 3>(6, 6).diagonal() = processNoiseVariances.at(1) / 3. * std::pow(dt, 3);
59 Q.block<3, 3>(6, 9).diagonal() = processNoiseVariances.at(1) / 2. * std::pow(dt, 2);
60 Q.block<3, 3>(9, 6).diagonal() = processNoiseVariances.at(1) / 2. * std::pow(dt, 2);
61 Q.block<3, 3>(9, 9).diagonal() = processNoiseVariances.at(1) * dt;
65 for (uint32_t i = 12; i < numStates; i += 6)
67 if (!imuCharacteristicsIdentical)
71 Q.block<3, 3>(i, i).diagonal() = processNoiseVariances.at(j) * dt;
72 Q.block<3, 3>(i + 3, i + 3).diagonal() = processNoiseVariances.at(j + 1) * dt;
78 Phi.block<3, 3>(0, 3).diagonal().setConstant(dt);
79 Phi.block<3, 3>(6, 9).diagonal().setConstant(dt);
82Eigen::MatrixXd
NAV::IRWKF::designMatrix_H(
const Eigen::Matrix3d& DCM_accel,
const Eigen::Matrix3d& DCM_gyro,
const size_t& pinIndex,
const uint8_t& numMeasurements,
const uint8_t& numStates,
const uint8_t& numStatesEst,
const uint8_t& numStatesPerPin)
84 Eigen::MatrixXd H = Eigen::MatrixXd::Zero(numMeasurements, numStates);
87 H.block<3, 3>(0, 0) = DCM_accel.transpose();
88 H.block<3, 3>(3, 6) = DCM_gyro.transpose();
93 const auto stateIndex =
static_cast<uint8_t
>(numStatesEst + numStatesPerPin * (pinIndex - 1));
94 LOG_DATA(
"stateIndex = {}", stateIndex);
96 H.block<6, 6>(0, stateIndex) = Eigen::MatrixXd::Identity(6, 6);
106 std::vector<Eigen::Vector3d> initStates;
107 initStates.resize(6 + 2 * numInputPins);
138 initStates[3] = pinDataIRWKF.
initJerk;
141 size_t pinDataBiasesIdenticalIdx = 1;
142 for (
size_t pinIndex = 1; pinIndex < numInputPins; ++pinIndex)
144 if (!imuBiasesIdentical)
146 pinDataBiasesIdenticalIdx = pinIndex;
152 initStates[2 + 2 * pinIndex] = pinData[pinDataBiasesIdenticalIdx].initAngularRateBias.array();
156 initStates[2 + 2 * pinIndex] =
deg2rad(pinData[pinDataBiasesIdenticalIdx].initAngularRateBias).array();
162 initStates[3 + 2 * pinIndex] = pinData[pinDataBiasesIdenticalIdx].initAccelerationBias.array();
166 kalmanFilter.
x.block<3, 1>(0, 0) = initStates[0];
167 kalmanFilter.
x.block<3, 1>(3, 0) = initStates[1];
168 kalmanFilter.
x.block<3, 1>(6, 0) = initStates[2];
169 kalmanFilter.
x.block<3, 1>(9, 0) = initStates[3];
171 uint32_t containerIndex = 4;
172 for (uint32_t pinIndex = 0; pinIndex < numInputPins - 1UL; ++pinIndex)
174 if (!imuBiasesIdentical)
176 containerIndex = 4 + 2 * pinIndex;
178 kalmanFilter.
x.block<3, 1>(12 + 6 * pinIndex, 0) = initStates[containerIndex];
179 kalmanFilter.
x.block<3, 1>(15 + 6 * pinIndex, 0) = initStates[1 + containerIndex];
187 std::vector<Eigen::Vector3d> initErrorCovariances;
188 initErrorCovariances.resize(6 + 2 * numInputPins);
193 initErrorCovariances[0] = pinData[0].initCovarianceAngularRate;
197 initErrorCovariances[0] =
deg2rad(pinData[0].initCovarianceAngularRate);
201 initErrorCovariances[0] = pinData[0].initCovarianceAngularRate.array().pow(2);
205 initErrorCovariances[0] =
deg2rad(pinData[0].initCovarianceAngularRate).array().pow(2);
229 initErrorCovariances[2] = pinData[0].initCovarianceAcceleration;
233 initErrorCovariances[2] = pinData[0].initCovarianceAcceleration.array().pow(2);
246 size_t pinDataIdx = 1;
247 for (
size_t pinIndex = 1; pinIndex < numInputPins; ++pinIndex)
249 if (!imuCharacteristicsIdentical)
251 pinDataIdx = pinIndex;
257 initErrorCovariances[2 + 2 * pinIndex] = pinData[pinDataIdx].initCovarianceBiasAngRate;
261 initErrorCovariances[2 + 2 * pinIndex] =
deg2rad(pinData[pinDataIdx].initCovarianceBiasAngRate);
265 initErrorCovariances[2 + 2 * pinIndex] = pinData[pinDataIdx].initCovarianceBiasAngRate.array().pow(2);
269 initErrorCovariances[2 + 2 * pinIndex] =
deg2rad(pinData[pinDataIdx].initCovarianceBiasAngRate).array().pow(2);
275 initErrorCovariances[3 + 2 * pinIndex] = pinData[pinDataIdx].initCovarianceBiasAcc;
279 initErrorCovariances[3 + 2 * pinIndex] = pinData[pinDataIdx].initCovarianceBiasAcc.array().pow(2);
286 processNoiseVariances.resize(2 * numInputPins);
312 processNoiseVariances[1] = pinDataIRWKF.
varJerkNoise.array().pow(2);
316 for (
size_t pinIndex = 1; pinIndex < numInputPins; ++pinIndex)
318 if (!imuCharacteristicsIdentical)
320 pinDataIdx = pinIndex;
324 switch (pinData[pinDataIdx].varBiasAngRateNoiseUnit)
327 processNoiseVariances[2 * pinIndex] = pinData[pinDataIdx].varBiasAngRateNoise;
330 processNoiseVariances[2 * pinIndex] =
deg2rad(pinData[pinDataIdx].varBiasAngRateNoise);
333 processNoiseVariances[2 * pinIndex] =
deg2rad(pinData[pinDataIdx].varBiasAngRateNoise).array().pow(2);
336 processNoiseVariances[2 * pinIndex] = pinData[pinDataIdx].varBiasAngRateNoise.array().pow(2);
341 switch (pinData[pinIndex].varBiasAccelerationNoiseUnit)
344 processNoiseVariances[1 + 2 * pinIndex] = pinData[pinDataIdx].varBiasAccelerationNoise;
347 processNoiseVariances[1 + 2 * pinIndex] = pinData[pinDataIdx].varBiasAccelerationNoise.array().pow(2);
357NAV::KalmanFilter NAV::IRWKF::initializeKalmanFilterAuto(
const size_t& nInputPins,
const std::vector<PinData>& pinData,
const PinDataIRWKF& pinDataIRWKF,
const std::vector<size_t>& cumulatedPinIds,
const std::vector<std::shared_ptr<const NAV::ImuObs>>& cumulatedImuObs,
const bool& initJerkAngAcc,
const double& dtInit,
const uint8_t& numStates,
const uint8_t& numMeasurements, std::vector<Eigen::VectorXd>& processNoiseVariances,
KalmanFilter& kalmanFilter)
361 std::vector<std::vector<std::shared_ptr<const NAV::ImuObs>>> sensorMeasurements;
362 sensorMeasurements.resize(nInputPins);
364 std::vector<Eigen::Vector3d> initStates;
365 initStates.resize(6 + 2 * nInputPins);
368 for (
size_t msgIndex = 0; msgIndex < cumulatedImuObs.size(); msgIndex++)
370 sensorMeasurements[cumulatedPinIds[msgIndex]].push_back(cumulatedImuObs[msgIndex]);
373 std::vector<std::vector<std::vector<double>>> sensorComponents;
374 sensorComponents.resize(nInputPins);
376 for (
size_t pinIndex = 0; pinIndex < nInputPins; pinIndex++)
378 sensorComponents[pinIndex].resize(numMeasurements);
379 for (
size_t axisIndex = 0; axisIndex < numMeasurements; axisIndex++)
381 for (
size_t msgIndex = 0; msgIndex < sensorMeasurements[pinIndex].size(); msgIndex++)
385 sensorComponents[pinIndex][axisIndex].push_back(sensorMeasurements[pinIndex][msgIndex]->p_acceleration(
static_cast<uint32_t
>(axisIndex)));
389 sensorComponents[pinIndex][axisIndex].push_back(sensorMeasurements[pinIndex][msgIndex]->p_angularRate(
static_cast<uint32_t
>(axisIndex - 3)));
397 initStates[2] =
mean(sensorComponents[0], 0);
399 initStates[3] = Eigen::Vector3d::Zero();
401 initStates[0] =
mean(sensorComponents[0], 3);
403 initStates[1] = Eigen::Vector3d::Zero();
406 for (
size_t pinIndex = 0; pinIndex < nInputPins - 1; pinIndex++)
408 auto stateIndex = 4 + 2 * pinIndex;
409 initStates[stateIndex + 1] =
mean(sensorComponents[pinIndex + 1], 0) - initStates[2];
410 initStates[stateIndex] =
mean(sensorComponents[pinIndex + 1], 3) - initStates[0];
419 std::vector<Eigen::Vector3d> initErrorCovariances;
420 initErrorCovariances.resize(6 + 2 * nInputPins);
423 initErrorCovariances[2] =
variance(sensorComponents[0], 0);
425 initErrorCovariances[0] =
variance(sensorComponents[0], 3);
430 initErrorCovariances[3] = initErrorCovariances[2];
432 initErrorCovariances[1] = initErrorCovariances[0];
437 initErrorCovariances[3] = Eigen::Vector3d::Zero();
439 initErrorCovariances[1] = Eigen::Vector3d::Zero();
443 for (
size_t pinIndex = 0; pinIndex < nInputPins - 1; pinIndex++)
445 auto stateIndex = 4 + 2 * pinIndex;
446 initErrorCovariances[stateIndex + 1] =
variance(sensorComponents[pinIndex + 1], 0);
447 initErrorCovariances[stateIndex] =
variance(sensorComponents[pinIndex + 1], 3);
450 for (
int axisIndex = 0; axisIndex < 3; axisIndex++)
453 initErrorCovariances[stateIndex + 1](axisIndex) = std::max(initErrorCovariances[stateIndex + 1](axisIndex),
454 initErrorCovariances[2](axisIndex));
456 initErrorCovariances[stateIndex](axisIndex) = std::max(initErrorCovariances[stateIndex](axisIndex),
457 initErrorCovariances[0](axisIndex));
461 kalmanFilter.
x.block<3, 1>(0, 0) = initStates[0];
462 kalmanFilter.
x.block<3, 1>(3, 0) = initStates[1];
463 kalmanFilter.
x.block<3, 1>(6, 0) = initStates[2];
464 kalmanFilter.
x.block<3, 1>(9, 0) = initStates[3];
465 for (uint32_t pinIndex = 0; pinIndex < nInputPins - 1UL; ++pinIndex)
467 auto containerIndex = 4 + 2 * pinIndex;
468 kalmanFilter.
x.block<3, 1>(12 + 6 * pinIndex, 0) = initStates[containerIndex];
469 kalmanFilter.
x.block<3, 1>(15 + 6 * pinIndex, 0) = initStates[1 + containerIndex];
475 processNoiseVariances.resize(2 * nInputPins);
501 processNoiseVariances[1] = pinDataIRWKF.
varJerkNoise.array().pow(2);
505 for (
size_t pinIndex = 0; pinIndex < nInputPins - 1; ++pinIndex)
508 switch (pinData[1 + pinIndex].varBiasAngRateNoiseUnit)
511 processNoiseVariances[2 + 2 * pinIndex] = pinData[1 + pinIndex].varBiasAngRateNoise;
514 processNoiseVariances[2 + 2 * pinIndex] =
deg2rad(pinData[1 + pinIndex].varBiasAngRateNoise);
517 processNoiseVariances[2 + 2 * pinIndex] =
deg2rad(pinData[1 + pinIndex].varBiasAngRateNoise).array().pow(2);
520 processNoiseVariances[2 + 2 * pinIndex] = pinData[1 + pinIndex].varBiasAngRateNoise.array().pow(2);
525 switch (pinData[pinIndex].varBiasAccelerationNoiseUnit)
528 processNoiseVariances[3 + 2 * pinIndex] = pinData[1 + pinIndex].varBiasAccelerationNoise;
531 processNoiseVariances[3 + 2 * pinIndex] = pinData[1 + pinIndex].varBiasAccelerationNoise.array().pow(2);
541Eigen::Vector3d
NAV::IRWKF::mean(
const std::vector<std::vector<double>>& sensorType,
const size_t& containerPos)
543 Eigen::Vector3d meanVector = Eigen::Vector3d::Zero();
545 for (
size_t axisIndex = 0; axisIndex < 3; axisIndex++)
547 meanVector(
static_cast<int>(axisIndex)) = std::accumulate(sensorType[axisIndex + containerPos].begin(),
548 sensorType[axisIndex + containerPos].end(), 0.)
549 /
static_cast<double>(sensorType[axisIndex + containerPos].size());
555Eigen::Vector3d
NAV::IRWKF::variance(
const std::vector<std::vector<double>>& sensorType,
const size_t& containerPos)
557 Eigen::Vector3d varianceVector = Eigen::Vector3d::Zero();
559 auto means =
mean(sensorType, containerPos);
561 for (
size_t axisIndex = 0; axisIndex < 3; axisIndex++)
563 auto N = sensorType.at(axisIndex + containerPos).size();
565 std::vector<double> absolSquared(N, 0.);
567 for (
size_t msgIndex = 0; msgIndex < N; msgIndex++)
569 absolSquared[msgIndex] = std::pow(std::abs(sensorType[axisIndex + containerPos][msgIndex] - means(
static_cast<int>(axisIndex))), 2);
572 varianceVector(
static_cast<int>(axisIndex)) = (1. / (
static_cast<double>(N) - 1.)) * std::accumulate(absolSquared.begin(), absolSquared.end(), 0.);
575 return varianceVector;
Kalman filter matrices for the Integrated-Random-Walk (IRW) Multi-IMU fusion.
Utility class for logging to console and file.
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Generalized Kalman Filter class.
Eigen::MatrixXd x
x̂ State vector
Eigen::MatrixXd P
𝐏 Error covariance matrix
Eigen::MatrixXd Q
𝐐 System/Process noise covariance matrix
Eigen::MatrixXd Phi
𝚽 State transition matrix
void stateTransitionMatrix_Phi(Eigen::MatrixXd &Phi, const double &dt)
Calculates the state-transition-matrix 𝚽
Eigen::MatrixXd initialStateTransitionMatrix_Phi(const double &dt, const uint8_t &numStates)
Calculates the state-transition-matrix 𝚽
Eigen::MatrixXd designMatrix_H(const Eigen::Matrix3d &DCM_accel, const Eigen::Matrix3d &DCM_gyro, const size_t &pinIndex, const uint8_t &numMeasurements, const uint8_t &numStates, const uint8_t &numStatesEst, const uint8_t &numStatesPerPin)
Calculates the design matrix H.
void processNoiseMatrix_Q(Eigen::MatrixXd &Q, const double &dt, const std::vector< Eigen::VectorXd > &processNoiseVariances, const uint8_t &numStates, const bool &imuCharacteristicsIdentical=false)
Calculates the process noise matrix Q.
Eigen::Vector3d mean(const std::vector< std::vector< double > > &sensorType, const size_t &containerPos)
Calculates the mean values of each axis in a vector that contains 3d measurements of a certain sensor...
KalmanFilter initializeKalmanFilterManually(const size_t &numInputPins, const std::vector< PinData > &pinData, const PinDataIRWKF &pinDataIRWKF, const uint8_t &numStates, const double &dtInit, std::vector< Eigen::VectorXd > &processNoiseVariances, KalmanFilter &kalmanFilter, const bool &imuCharacteristicsIdentical, const bool &imuBiasesIdentical)
Initializes the IRWKF manually (i.e. using GUI inputs instead of averaging)
Eigen::Vector3d variance(const std::vector< std::vector< double > > &sensorType, const size_t &containerPos)
Calculates the variance of each axis in a vector that contains 3d measurements of a certain sensor ty...
Eigen::MatrixXd initialErrorCovarianceMatrix_P0(const std::vector< Eigen::Vector3d > &initCovariances, const uint8_t &numStates, const bool &imuCharacteristicsIdentical=false)
Initial error covariance matrix P_0.
KalmanFilter initializeKalmanFilterAuto(const size_t &nInputPins, const std::vector< PinData > &pinData, const PinDataIRWKF &pinDataIRWKF, const std::vector< size_t > &cumulatedPinIds, const std::vector< std::shared_ptr< const NAV::ImuObs > > &cumulatedImuObs, const bool &initJerkAngAcc, const double &dtInit, const uint8_t &numStates, const uint8_t &numMeasurements, std::vector< Eigen::VectorXd > &processNoiseVariances, KalmanFilter &kalmanFilter)
Initializes the IRWKF automatically, i.e. init values are calculated by averaging the data in the fir...
constexpr auto deg2rad(const T °)
Convert Degree to Radians.
Sensor information specific to the IRW-KF.
JerkVarianceUnit initCovarianceJerkUnit
Gui selection for the unit of the initial covariance for the jerk.
PinData::AccelerationUnit initAccelerationUnit
Gui selection for the unit of the initial acceleration.
Eigen::Vector3d initAcceleration
GUI selection for the initial acceleration.
AngularAccUnit initAngularAccUnit
Gui selection for the unit of the initial angular acceleration.
Eigen::Vector3d initCovarianceAngularAcc
GUI selection for the initial covariance diagonal values for angular acceleration (standard deviation...
Eigen::Vector3d initAngularRate
GUI selection for the initial angular rate.
Eigen::Vector3d initCovarianceJerk
GUI selection for the initial covariance diagonal values for jerk (standard deviation σ or Variance σ...
Eigen::Vector3d varJerkNoise
GUI selection for the jerk process noise diagonal values.
AngularAccVarianceUnit varAngularAccNoiseUnit
Gui selection for the unit of the angular acceleration process noise.
Eigen::Vector3d initJerk
GUI selection for the initial jerk.
Eigen::Vector3d varAngularAccNoise
GUI selection for the angular acceleration process noise diagonal values.
@ m2_s6
Variance [(m^2)/(s^6), (m^2)/(s^6), (m^2)/(s^6)].
@ m_s3
Standard deviation [m/s³, m/s³, m/s³].
@ m_s3
in [m/s³, m/s³, m/s³]
AngularAccVarianceUnit initCovarianceAngularAccUnit
Gui selection for the unit of the initial covariance for the angular acceleration.
PinData::AngRateUnit initAngularRateUnit
Gui selection for the unit of the initial angular rate.
Eigen::Vector3d initAngularAcc
GUI selection for the initial angular acceleration.
JerkVarianceUnit varJerkNoiseUnit
Gui selection for the unit of the jerk process noise.
@ deg_s2
in [deg/s², deg/s², deg/s²]
@ rad_s2
in [rad/s², rad/s², rad/s²]
JerkUnit initJerkUnit
Gui selection for the Unit of the initial jerk.
@ deg_s2
Standard deviation [deg/s², deg/s², deg/s²].
@ deg2_s4
Variance [(deg^2)/(s^4), (deg^2)/(s^4), (deg^2)/(s^4)].
@ rad2_s4
Variance [(rad^2)/(s^4), (rad^2)/(s^4), (rad^2)/(s^4)].
@ rad_s2
Standard deviation [rad/s², rad/s², rad/s²].
@ m2_s4
Variance [(m^2)/(s^4), (m^2)/(s^4), (m^2)/(s^4)].
@ m_s2
Standard deviation [m/s², m/s², m/s²].
@ rad2_s2
Variance [rad²/s², rad²/s², rad²/s²].
@ deg2_s2
Variance [deg²/s², deg²/s², deg²/s²].
@ deg_s
Standard deviation [deg/s, deg/s, deg/s].
@ rad_s
Standard deviation [rad/s, rad/s, rad/s].
@ m_s2
in [m/s², m/s², m/s²]
@ deg_s
in [deg/s, deg/s, deg/s]
@ rad_s
in [rad/s, rad/s, rad/s]