#include "MultiplicativeKalmanFilter.h" MultiplicativeKalmanFilter::MultiplicativeKalmanFilter(AcsParameters *acsParameters) { updateStandardDeviations(acsParameters); } MultiplicativeKalmanFilter::~MultiplicativeKalmanFilter() {} void MultiplicativeKalmanFilter::updateStandardDeviations(const AcsParameters *acsParameters) { sigmaSus = acsParameters->kalmanFilterParameters.sensorNoiseSus; sigmaMgm = acsParameters->kalmanFilterParameters.sensorNoiseMgm; sigmaStr = acsParameters->kalmanFilterParameters.sensorNoiseStr; sigmaGyr = acsParameters->kalmanFilterParameters.sensorNoiseGyr; sigmaGyrArw = acsParameters->kalmanFilterParameters.sensorNoiseGyrArw; sigmaGyrBs = acsParameters->kalmanFilterParameters.sensorNoiseGyrBs; MatrixOperations::multiplyScalar(*EYE3, sigmaSus * sigmaSus, *covSus, 3, 3); MatrixOperations::multiplyScalar(*EYE3, sigmaMgm * sigmaMgm, *covMgm, 3, 3); MatrixOperations::multiplyScalar(*EYE3, sigmaStr * sigmaStr, *covStr, 3, 3); } ReturnValue_t MultiplicativeKalmanFilter::reset( acsctrl::AttitudeEstimationData *attitudeEstimationData) { std::memcpy(estimatedQuaternionBI, UNIT_QUAT, sizeof(estimatedQuaternionBI)); std::memcpy(estimatedBiasGyr, ZERO_VEC3, sizeof(estimatedBiasGyr)); std::memcpy(estimatedCovarianceMatrix, ZERO_MAT66, sizeof(estimatedCovarianceMatrix)); mekfStatus = MekfStatus::UNINITIALIZED; updateDataSetWithoutData(attitudeEstimationData); return MEKF_UNINITIALIZED; } ReturnValue_t MultiplicativeKalmanFilter::init( const acsctrl::SusDataProcessed *susData, const acsctrl::MgmDataProcessed *mgmData, const acsctrl::GyrDataProcessed *gyrData, acsctrl::AttitudeEstimationData *attitudeEstimationData) { // check for valid QUEST quaternion if (attitudeEstimationData->quatQuest.isValid()) { // Initial Quaternion std::memcpy(estimatedQuaternionBI, attitudeEstimationData->quatQuest.value, sizeof(estimatedQuaternionBI)); // Initial Covariance if (susData->susVecTot.isValid() and mgmData->mgmVecTot.isValid() and gyrData->gyrVecTot.isValid()) { // QUEST Covariance double normSunI[3] = {0, 0, 0}, normMagI[3] = {0, 0, 0}, normSunEstB[3] = {0, 0, 0}, normMagEstB[3] = {0, 0, 0}; VectorOperations::normalize(susData->sunIjkModel.value, normSunI, 3); VectorOperations::normalize(mgmData->magIgrfModel.value, normMagI, 3); QuaternionOperations::multiplyVector(estimatedQuaternionBI, normSunI, normSunEstB); QuaternionOperations::multiplyVector(estimatedQuaternionBI, normMagI, normMagEstB); double matrixSus[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, matrixMgm[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, matrixSusMgm[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, matrixMgmSus[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiply(normSunEstB, normSunEstB, *matrixSus, 3, 1, 3); MatrixOperations::multiply(normMagEstB, normMagEstB, *matrixMgm, 3, 1, 3); MatrixOperations::multiply(normSunEstB, normMagEstB, *matrixSusMgm, 3, 1, 3); MatrixOperations::multiply(normMagEstB, normSunEstB, *matrixMgmSus, 3, 1, 3); double factorSus = 1. / (sigmaSus * sigmaSus); double factorMgm = 1. / (sigmaMgm * sigmaMgm); double covQuest[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiplyScalar(*matrixSus, factorSus * factorSus, *matrixSus, 3, 3); MatrixOperations::multiplyScalar(*matrixMgm, factorMgm * factorMgm, *matrixMgm, 3, 3); MatrixOperations::add(*matrixSusMgm, *matrixMgmSus, *covQuest, 3, 3); MatrixOperations::multiplyScalar( *covQuest, factorSus * factorMgm * VectorOperations::dot(normSunEstB, normMagEstB), *covQuest, 3, 3); MatrixOperations::add(*covQuest, *matrixSus, *covQuest, 3, 3); MatrixOperations::add(*covQuest, *matrixMgm, *covQuest, 3, 3); double crossSunMag[3] = {0, 0, 0}; VectorOperations::cross(normSunEstB, normMagEstB, crossSunMag); double normCrossSunMag = VectorOperations::norm(crossSunMag, 3); double factor = factorSus * factorMgm * normCrossSunMag * normCrossSunMag; MatrixOperations::multiplyScalar(*covQuest, 1. / factor, *covQuest, 3, 3); MatrixOperations::add(*EYE3, *covQuest, *covQuest, 3, 3); MatrixOperations::multiplyScalar(*covQuest, 1. / (factorSus + factorMgm), *covQuest, 3, 3); // GYR Covariance double covGyr[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiplyScalar(*EYE3, sigmaGyr, *covGyr, 3, 3); // Combine Covariances MatrixOperations::writeSubmatrix(*estimatedCovarianceMatrix, *covQuest, 3, 3, 6, 6, 0, 0); MatrixOperations::writeSubmatrix(*estimatedCovarianceMatrix, *covGyr, 3, 3, 6, 6, 3, 3); mekfStatus = MekfStatus::INITIALIZED; updateDataSetWithoutData(attitudeEstimationData); return MEKF_INITIALIZED; } } // no initialisation possible, no valid measurements mekfStatus = MekfStatus::UNINITIALIZED; updateDataSetWithoutData(attitudeEstimationData); return MEKF_UNINITIALIZED; } ReturnValue_t MultiplicativeKalmanFilter::mekfEst( const acsctrl::SusDataProcessed *susData, const acsctrl::MgmDataProcessed *mgmData, const acsctrl::GyrDataProcessed *gyrData, const double timeDelta, acsctrl::AttitudeEstimationData *attitudeEstimationData) { ReturnValue_t result = checkAvailableSensors(susData, mgmData, gyrData, attitudeEstimationData); if (result != returnvalue::OK) { reset(attitudeEstimationData); return result; } double measSensMatrix[matrixDimensionFactor][6] = {{0}}, measCovMatrix[matrixDimensionFactor][matrixDimensionFactor] = {{0}}, measVec[matrixDimensionFactor] = {0}, estVec[matrixDimensionFactor] = {0}; kfUpdate(susData, mgmData, *measSensMatrix, *measCovMatrix, measVec, estVec); double kalmanGain[6][matrixDimensionFactor] = {{0}}; result = kfGain(*measSensMatrix, *measCovMatrix, *kalmanGain, attitudeEstimationData); if (result != returnvalue::OK) { reset(attitudeEstimationData); return result; } kfCovAposteriori(*kalmanGain, *measSensMatrix); kfStateAposteriori(*kalmanGain, measVec, estVec); kfPropagate(gyrData, timeDelta); result = kfFiniteCheck(attitudeEstimationData); if (result != returnvalue::OK) { return result; } mekfStatus = MekfStatus::RUNNING; updateDataSet(attitudeEstimationData); return MEKF_RUNNING; } ReturnValue_t MultiplicativeKalmanFilter::checkAvailableSensors( const acsctrl::SusDataProcessed *susData, const acsctrl::MgmDataProcessed *mgmData, const acsctrl::GyrDataProcessed *gyrData, acsctrl::AttitudeEstimationData *attitudeEstimationData) { // Check for GYR Measurements if (not gyrData->gyrVecTot.isValid()) { mekfStatus = MekfStatus::NO_GYR_DATA; updateDataSetWithoutData(attitudeEstimationData); return MEKF_NO_GYR_DATA; } // Check for Model Calculations if (not susData->sunIjkModel.isValid() or not mgmData->magIgrfModel.isValid()) { mekfStatus = MekfStatus::NO_MODEL_VECTORS; updateDataSetWithoutData(attitudeEstimationData); return MEKF_NO_MODEL_VECTORS; } // Check Measurements available from SUS, MGM, STR if (not susData->susVecTot.isValid() and not mgmData->mgmVecTot.isValid() and not strData.strQuat.valid) { sensorsAvailable = SensorAvailability::NONE; mekfStatus = MekfStatus::NO_SUS_MGM_STR_DATA; updateDataSetWithoutData(attitudeEstimationData); return MEKF_NO_SUS_MGM_STR_DATA; } if (susData->susVecTot.isValid() and mgmData->mgmVecTot.isValid() and strData.strQuat.valid) { sensorsAvailable = SensorAvailability::SUS_MGM_STR; matrixDimensionFactor = 9; } else if (susData->susVecTot.isValid() and mgmData->mgmVecTot.isValid() and not strData.strQuat.valid) { sensorsAvailable = SensorAvailability::SUS_MGM; matrixDimensionFactor = 6; } else if (susData->susVecTot.isValid() and not mgmData->mgmVecTot.isValid() and strData.strQuat.valid) { sensorsAvailable = SensorAvailability::SUS_STR; matrixDimensionFactor = 6; } else if (not susData->susVecTot.isValid() and mgmData->mgmVecTot.isValid() and strData.strQuat.valid) { sensorsAvailable = SensorAvailability::MGM_STR; matrixDimensionFactor = 6; } else if (susData->susVecTot.isValid() and not mgmData->mgmVecTot.isValid() and not strData.strQuat.valid) { sensorsAvailable = SensorAvailability::SUS; matrixDimensionFactor = 3; } else if (not susData->susVecTot.isValid() and mgmData->mgmVecTot.isValid() and not strData.strQuat.valid) { sensorsAvailable = SensorAvailability::MGM; matrixDimensionFactor = 3; } else if (not susData->susVecTot.isValid() and not mgmData->mgmVecTot.isValid() and strData.strQuat.valid) { sensorsAvailable = SensorAvailability::STR; matrixDimensionFactor = 3; } return returnvalue::OK; } void MultiplicativeKalmanFilter::kfUpdate(const acsctrl::SusDataProcessed *susData, const acsctrl::MgmDataProcessed *mgmData, double *measSensMatrix, double *measCovMatrix, double *measVec, double *estVec) { double normMagB[3] = {0, 0, 0}, normSunB[3] = {0, 0, 0}, normMagI[3] = {0, 0, 0}, normSunI[3] = {0, 0, 0}, normSunEstB[3] = {0, 0, 0}, normMagEstB[3] = {0, 0, 0}; VectorOperations::normalize(mgmData->mgmVecTot.value, normMagB, 3); // b2 VectorOperations::normalize(susData->susVecTot.value, normSunB, 3); // b1 VectorOperations::normalize(mgmData->magIgrfModel.value, normMagI, 3); // r2 VectorOperations::normalize(susData->sunIjkModel.value, normSunI, 3); // r1 QuaternionOperations::multiplyVector(estimatedQuaternionBI, normSunI, normSunEstB); QuaternionOperations::multiplyVector(estimatedQuaternionBI, normMagI, normMagEstB); // Measurement Sensitivity Matrix double measSensMatrixSun[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; // H11 double measSensMatrixMag[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; // H22 double measSensMatrixStr[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; // H33 MatrixOperations::skewMatrix(normSunEstB, *measSensMatrixSun); MatrixOperations::skewMatrix(normMagEstB, *measSensMatrixMag); double measVecQuat[3] = {0, 0, 0}, quatEstErr[3] = {0, 0, 0}; if (strData.strQuat.valid) { double quatError[4] = {0, 0, 0, 0}; double invPropagatedQuat[4] = {0, 0, 0, 0}; QuaternionOperations::inverse(estimatedQuaternionBI, invPropagatedQuat); QuaternionOperations::multiply(strData.strQuat.value, invPropagatedQuat, quatError); for (uint8_t i = 0; i < 3; i++) { measVecQuat[i] = 2. * quatError[i] / quatError[3]; } } switch (sensorsAvailable) { case SensorAvailability::SUS_MGM_STR: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixSun, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixMag, 3, 3, matrixDimensionFactor, 6, 3, 0); MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixStr, 3, 3, matrixDimensionFactor, 6, 6, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covSus, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covMgm, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 3, 3); MatrixOperations::writeSubmatrix(measCovMatrix, *covStr, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 6, 6); std::memcpy(measVec, normSunB, sizeof(normSunB)); std::memcpy(measVec + 3, normMagB, sizeof(normMagB)); std::memcpy(measVec + 6, measVecQuat, sizeof(measVecQuat)); std::memcpy(estVec, normSunEstB, sizeof(normSunEstB)); std::memcpy(estVec + 3, normMagEstB, sizeof(normMagEstB)); std::memcpy(estVec + 6, quatEstErr, sizeof(quatEstErr)); return; case SensorAvailability::SUS_MGM: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixSun, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixMag, 3, 3, matrixDimensionFactor, 6, 3, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covSus, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covMgm, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 3, 3); std::memcpy(measVec, normSunB, sizeof(normSunB)); std::memcpy(measVec + 3, normMagB, sizeof(normMagB)); std::memcpy(estVec, normSunEstB, sizeof(normSunEstB)); std::memcpy(estVec + 3, normMagEstB, sizeof(normMagEstB)); return; case SensorAvailability::SUS_STR: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixSun, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixStr, 3, 3, matrixDimensionFactor, 6, 3, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covSus, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covStr, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 3, 3); std::memcpy(measVec, normSunB, sizeof(normSunB)); std::memcpy(measVec + 3, measVecQuat, sizeof(measVecQuat)); std::memcpy(estVec, normSunEstB, sizeof(normSunEstB)); std::memcpy(estVec + 3, quatEstErr, sizeof(quatEstErr)); return; case SensorAvailability::MGM_STR: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixMag, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixStr, 3, 3, matrixDimensionFactor, 6, 3, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covMgm, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covStr, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 3, 3); std::memcpy(measVec, normMagB, sizeof(normMagB)); std::memcpy(measVec + 3, measVecQuat, sizeof(measVecQuat)); std::memcpy(estVec, normMagEstB, sizeof(normMagEstB)); std::memcpy(estVec + 3, quatEstErr, sizeof(quatEstErr)); return; case SensorAvailability::SUS: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixSun, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covSus, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); std::memcpy(measVec, normSunB, sizeof(normSunB)); std::memcpy(estVec, normSunEstB, sizeof(normSunEstB)); return; case SensorAvailability::MGM: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixMag, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covMgm, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); std::memcpy(measVec, normMagB, sizeof(normMagB)); std::memcpy(estVec, normMagEstB, sizeof(normMagEstB)); return; case SensorAvailability::STR: MatrixOperations::writeSubmatrix(measSensMatrix, *measSensMatrixStr, 3, 3, matrixDimensionFactor, 6, 0, 0); MatrixOperations::writeSubmatrix(measCovMatrix, *covStr, 3, 3, matrixDimensionFactor, matrixDimensionFactor, 0, 0); std::memcpy(measVec, measVecQuat, sizeof(measVecQuat)); std::memcpy(estVec, quatEstErr, sizeof(quatEstErr)); return; default: sif::error << "MEKF::Invalid SensorAvailability Flag" << std::endl; } } ReturnValue_t MultiplicativeKalmanFilter::kfGain( double *measSensMatrix, double *measCovMatrix, double *kalmanGain, acsctrl::AttitudeEstimationData *attitudeEstimationData) { // Kalman Gain: K = P * H' / (H * P * H' + R) double kalmanGainDen[matrixDimensionFactor][matrixDimensionFactor] = {{0}}, invKalmanGainDen[matrixDimensionFactor][matrixDimensionFactor] = {{0}}, residualCov[6][matrixDimensionFactor] = {{0}}, measSensMatrixTransposed[6][matrixDimensionFactor] = {{0}}; MatrixOperations::transpose(measSensMatrix, *measSensMatrixTransposed, matrixDimensionFactor, 6); MatrixOperations::multiply(*estimatedCovarianceMatrix, *measSensMatrixTransposed, *residualCov, 6, 6, matrixDimensionFactor); MatrixOperations::multiply(measSensMatrix, *residualCov, *kalmanGainDen, matrixDimensionFactor, 6, matrixDimensionFactor); MatrixOperations::add(*kalmanGainDen, measCovMatrix, *kalmanGainDen, matrixDimensionFactor, matrixDimensionFactor); ReturnValue_t result = MatrixOperations::inverseMatrix(*kalmanGainDen, *invKalmanGainDen, matrixDimensionFactor); if (result != returnvalue::OK) { mekfStatus = MekfStatus::COVARIANCE_INVERSION_FAILED; updateDataSetWithoutData(attitudeEstimationData); return MEKF_COVARIANCE_INVERSION_FAILED; } MatrixOperations::multiply(*residualCov, *invKalmanGainDen, kalmanGain, 6, matrixDimensionFactor, matrixDimensionFactor); return returnvalue::OK; } void MultiplicativeKalmanFilter::kfCovAposteriori(double *kalmanGain, double *measSensMatrix) { // Covariance Matrix: P_plus [k] = (I-K*H)*P_min double helperMat[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; MatrixOperations::multiply(kalmanGain, measSensMatrix, *helperMat, 6, matrixDimensionFactor, 6); MatrixOperations::subtract(*EYE6, *helperMat, *helperMat, 6, 6); MatrixOperations::multiply(*helperMat, *estimatedCovarianceMatrix, *covAposteriori, 6, 6, 6); } void MultiplicativeKalmanFilter::kfStateAposteriori(double *kalmanGain, double *measVec, double *estVec) { double stateVecErr[6] = {0, 0, 0, 0, 0, 0}; double plantOutputDiff[matrixDimensionFactor] = {0}; VectorOperations::subtract(measVec, estVec, plantOutputDiff, matrixDimensionFactor); MatrixOperations::multiply(kalmanGain, plantOutputDiff, stateVecErr, 6, matrixDimensionFactor, 1); double quatAposteriori[3] = {stateVecErr[0], stateVecErr[1], stateVecErr[2]}; double biasAposteriori[3] = {stateVecErr[3], stateVecErr[4], stateVecErr[5]}; double quaternionIdentity[4][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double quaternionIdentityUpperMatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double quaternionIdentityUpperMatrixHelper[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double negQuatVec[3] = {0, 0, 0}; MatrixOperations::multiplyScalar(*EYE3, estimatedQuaternionBI[3], *quaternionIdentityUpperMatrix, 3, 3); MatrixOperations::skewMatrix(estimatedQuaternionBI, *quaternionIdentityUpperMatrixHelper); MatrixOperations::add(*quaternionIdentityUpperMatrix, *quaternionIdentityUpperMatrixHelper, *quaternionIdentityUpperMatrix, 3, 3); VectorOperations::mulScalar(estimatedQuaternionBI, -1, negQuatVec, 3); MatrixOperations::writeSubmatrix(*quaternionIdentity, *quaternionIdentityUpperMatrix, 3, 3, 4, 3, 0, 0); MatrixOperations::writeSubmatrix(*quaternionIdentity, negQuatVec, 1, 3, 4, 3, 3, 0); double quatCorrection[4] = {0, 0, 0, 0}; MatrixOperations::multiply(*quaternionIdentity, quatAposteriori, quatCorrection, 4, 3, 1); VectorOperations::mulScalar(quatCorrection, 0.5, quatCorrection, 4); VectorOperations::add(estimatedQuaternionBI, quatCorrection, estimatedQuaternionBI, 4); QuaternionOperations::normalize(estimatedQuaternionBI); VectorOperations::add(estimatedBiasGyr, biasAposteriori, estimatedBiasGyr, 3); } void MultiplicativeKalmanFilter::kfPropagate(const acsctrl::GyrDataProcessed *gyrData, const double timeDelta) { // Estimated Rotation Rate VectorOperations::subtract(gyrData->gyrVecTot.value, estimatedBiasGyr, estimatedRotRate); double estimatedRotRateNorm = VectorOperations::norm(estimatedRotRate, 3); double estimatedRotRateSkewed[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::skewMatrix(estimatedRotRate, *estimatedRotRateSkewed); // Estimated Quaternion double diffQuatMatrix[4][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, diffQuatMatrixHelper1[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, diffQuatMatrixHelper2[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, diffVector[3] = {0, 0, 0}, helperQuat[4] = {0, 0, 0, 0}; double diffScalar = std::cos(.5 * estimatedRotRateNorm * timeDelta); VectorOperations::mulScalar( estimatedRotRate, std::sin(.5 * estimatedRotRateNorm * timeDelta) / estimatedRotRateNorm, diffVector, 3); MatrixOperations::multiplyScalar(*EYE3, diffScalar, *diffQuatMatrixHelper1, 3, 3); MatrixOperations::skewMatrix(diffVector, *diffQuatMatrixHelper2); MatrixOperations::subtract(*diffQuatMatrixHelper1, *diffQuatMatrixHelper2, *diffQuatMatrixHelper1, 3, 3); MatrixOperations::writeSubmatrix(*diffQuatMatrix, *diffQuatMatrixHelper1, 3, 3, 4, 4, 0, 0); MatrixOperations::writeSubmatrix(*diffQuatMatrix, diffVector, 3, 1, 4, 4, 0, 3); VectorOperations::mulScalar(diffVector, -1, diffVector, 3); MatrixOperations::writeSubmatrix(*diffQuatMatrix, diffVector, 1, 3, 4, 4, 3, 0); diffQuatMatrix[3][3] = diffScalar; std::memcpy(helperQuat, estimatedQuaternionBI, sizeof(helperQuat)); MatrixOperations::multiply(*diffQuatMatrix, helperQuat, estimatedQuaternionBI, 4, 4, 1); QuaternionOperations::normalize(estimatedQuaternionBI); // Covariance Matrix: P_minus [k+1] = Phi*P_plus [k]*Phi'+G*Q*G' // Phi [Discrete Error State Transition Matrix] double errorStateTransition[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 1}}; double phi11[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, phi12[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, phi11L[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, phi11R[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, phi12L[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, phi12R[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiplyScalar( *estimatedRotRateSkewed, std::sin(estimatedRotRateNorm * timeDelta) / estimatedRotRateNorm, *phi11L, 3, 3); MatrixOperations::multiply(*estimatedRotRateSkewed, *estimatedRotRateSkewed, *phi11R, 3, 3, 3); MatrixOperations::multiplyScalar(*phi11R, (1 - std::cos(estimatedRotRateNorm * timeDelta)) / (estimatedRotRateNorm * estimatedRotRateNorm), *phi11R, 3, 3); MatrixOperations::subtract(*EYE3, *phi11L, *phi11, 3, 3); MatrixOperations::add(*phi11, *phi11R, *phi11, 3, 3); MatrixOperations::multiplyScalar(*EYE3, -timeDelta, *phi12, 3, 3); MatrixOperations::multiplyScalar(*estimatedRotRateSkewed, (1 - std::cos(estimatedRotRateNorm * timeDelta)) / (estimatedRotRateNorm * estimatedRotRateNorm), *phi12L, 3, 3); MatrixOperations::multiply(*estimatedRotRateSkewed, *estimatedRotRateSkewed, *phi12R, 3, 3, 3); MatrixOperations::multiplyScalar( *phi12R, (estimatedRotRateNorm * timeDelta - std::sin(estimatedRotRateNorm * timeDelta)) / (estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm), *phi12R, 3, 3); MatrixOperations::add(*phi12, *phi12L, *phi12, 3, 3); MatrixOperations::subtract(*phi12, *phi12R, *phi12, 3, 3); MatrixOperations::writeSubmatrix(*errorStateTransition, *phi11, 3, 3, 6, 6, 0, 0); MatrixOperations::writeSubmatrix(*errorStateTransition, *phi12, 3, 3, 6, 6, 0, 3); // G [Discrete Transfer Matrix] double transferMatrix[6][6] = {{-1, 0, 0, 0, 0, 0}, {0, -1, 0, 0, 0, 0}, {0, 0, -1, 0, 0, 0}, {0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 1}}; // Q [Discrete Time Covariance] double timeCovariance[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; double q11[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q12[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q21[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q22[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; if (estimatedRotRateNorm * timeDelta < M_PI / 10.) { MatrixOperations::multiplyScalar( *EYE3, (sigmaGyrArw * sigmaGyrArw) * timeDelta + ((sigmaGyrBs * sigmaGyrBs) * (timeDelta * timeDelta * timeDelta)) / 3., *q11, 3, 3); MatrixOperations::multiplyScalar( *EYE3, -(sigmaGyrBs * sigmaGyrBs * timeDelta * timeDelta) / 2., *q12, 3, 3); } else { double q11h1[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q11h2[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q12h1[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, q12h2[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiplyScalar(*EYE3, (sigmaGyrArw * sigmaGyrArw) * timeDelta, *q11, 3, 3); MatrixOperations::multiplyScalar(*EYE3, (timeDelta * timeDelta * timeDelta) / 3., *q11h1, 3, 3); MatrixOperations::multiply(*estimatedRotRateSkewed, *estimatedRotRateSkewed, *q11h2, 3, 3, 3); MatrixOperations::multiplyScalar( *q11h2, (2 * estimatedRotRateNorm * timeDelta - 2 * std::sin(estimatedRotRateNorm * timeDelta) - ((estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm) * (timeDelta * timeDelta * timeDelta) / .3)) / (estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm), *q11h2, 3, 3); MatrixOperations::add(*q11h1, *q11h2, *q11h1, 3, 3); MatrixOperations::multiplyScalar(*q11h1, sigmaGyrBs * sigmaGyrBs, *q11h1, 3, 3); MatrixOperations::add(*q11, *q11h1, *q11, 3, 3); MatrixOperations::multiplyScalar(*EYE3, -(timeDelta * timeDelta) / 2., *q12, 3, 3); MatrixOperations::multiplyScalar( *estimatedRotRateSkewed, (estimatedRotRateNorm * timeDelta - std::sin(estimatedRotRateNorm * timeDelta)) / (estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm), *q12h1, 3, 3); MatrixOperations::multiply(*estimatedRotRateSkewed, *estimatedRotRateSkewed, *q12h2, 3, 3, 3); MatrixOperations::multiplyScalar( *q12h2, (((estimatedRotRateNorm * estimatedRotRateNorm) * (timeDelta * timeDelta)) / 2. + std::cos(estimatedRotRateNorm * timeDelta) - 1) / (estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm * estimatedRotRateNorm), *q12h2, 3, 3); MatrixOperations::add(*q12, *q12h1, *q12, 3, 3); MatrixOperations::subtract(*q12, *q12h2, *q12, 3, 3); MatrixOperations::multiplyScalar(*q12, sigmaGyrBs * sigmaGyrBs, *q12, 3, 3); } MatrixOperations::transpose(*q12, *q21, 3); MatrixOperations::multiplyScalar(*EYE3, sigmaGyrBs * sigmaGyrBs * timeDelta, *q22, 3, 3); MatrixOperations::writeSubmatrix(*timeCovariance, *q11, 3, 3, 6, 6, 0, 0); MatrixOperations::writeSubmatrix(*timeCovariance, *q12, 3, 3, 6, 6, 0, 3); MatrixOperations::writeSubmatrix(*timeCovariance, *q21, 3, 3, 6, 6, 3, 0); MatrixOperations::writeSubmatrix(*timeCovariance, *q22, 3, 3, 6, 6, 3, 3); // Estimated Covariance double errorStateTransitionTransposed[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, estCovarianceMatrixL[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, estCovarianceMatrixR[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, estCovarianceMatrixHelp[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; MatrixOperations::transpose(*errorStateTransition, *errorStateTransitionTransposed, 6); MatrixOperations::multiply(*errorStateTransition, *covAposteriori, *estCovarianceMatrixHelp, 6, 6, 6); MatrixOperations::multiply(*estCovarianceMatrixHelp, *errorStateTransitionTransposed, *estCovarianceMatrixL, 6, 6, 6); MatrixOperations::multiply(*transferMatrix, *timeCovariance, *estCovarianceMatrixHelp, 6, 6, 6); MatrixOperations::multiply(*estCovarianceMatrixHelp, *transferMatrix, *estCovarianceMatrixR, 6, 6, 6); MatrixOperations::add(*estCovarianceMatrixL, *estCovarianceMatrixR, *estimatedCovarianceMatrix, 6, 6); } ReturnValue_t MultiplicativeKalmanFilter::kfFiniteCheck( acsctrl::AttitudeEstimationData *attitudeEstimationData) { if (not(VectorOperations::isFinite(estimatedQuaternionBI, 4)) or not(VectorOperations::isFinite(estimatedRotRate, 3)) or not(MatrixOperations::isFinite(*estimatedCovarianceMatrix, 6, 6))) { mekfStatus = MekfStatus::NOT_FINITE; updateDataSetWithoutData(attitudeEstimationData); return MEKF_NOT_FINITE; } return returnvalue::OK; } void MultiplicativeKalmanFilter::updateDataSetWithoutData( acsctrl::AttitudeEstimationData *attitudeEstimationData) { PoolReadGuard pg(attitudeEstimationData); if (pg.getReadResult() == returnvalue::OK) { std::memcpy(attitudeEstimationData->quatMekf.value, ZERO_VEC4, 4 * sizeof(double)); attitudeEstimationData->quatMekf.setValid(false); std::memcpy(attitudeEstimationData->satRotRateMekf.value, ZERO_VEC3, 3 * sizeof(double)); attitudeEstimationData->satRotRateMekf.setValid(false); attitudeEstimationData->mekfStatus.value = mekfStatus; attitudeEstimationData->mekfStatus.setValid(true); } } void MultiplicativeKalmanFilter::updateDataSet( acsctrl::AttitudeEstimationData *attitudeEstimationData) { PoolReadGuard pg(attitudeEstimationData); if (pg.getReadResult() == returnvalue::OK) { std::memcpy(attitudeEstimationData->quatMekf.value, estimatedQuaternionBI, 4 * sizeof(double)); attitudeEstimationData->quatMekf.setValid(true); std::memcpy(attitudeEstimationData->satRotRateMekf.value, estimatedRotRate, 3 * sizeof(double)); attitudeEstimationData->satRotRateMekf.setValid(true); attitudeEstimationData->mekfStatus.value = mekfStatus; attitudeEstimationData->mekfStatus.setValid(true); } } void MultiplicativeKalmanFilter::setStrData(double qX, double qY, double qZ, double qW, bool valid, bool allowStr) { strData.strQuat.value[0] = qX; strData.strQuat.value[1] = qY; strData.strQuat.value[2] = qZ; strData.strQuat.value[3] = qW; strData.strQuat.valid = (valid and allowStr); }