LCOV - code coverage report
Current view: top level - src - ekf.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 76 82 92.7 %
Date: 2024-11-26 20:23:51 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2024 robinAZERTY [https://github.com/robinAZERTY]
       3             :  *
       4             :  * This file is part of ESP32AlgebraFilters library.
       5             :  *
       6             :  * ESP32AlgebraFilters library is free software: you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * ESP32AlgebraFilters library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with ESP32AlgebraFilters library. If not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #define EKF_CPP
      21             : #include "ekf.hpp"
      22             : 
      23             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      24          20 : Ekf<x_dim, u_dim, c_dim, z_num, T>::Ekf()
      25             : {
      26           2 :     X.fill(0);
      27           2 :     P.fill(0);
      28           2 :     Cov_U.fill(0);
      29           2 :     dx.fill(1e-4);
      30           2 :     du.fill(1e-4);
      31           2 :     dc.fill(1e-4);
      32           2 : }
      33             : 
      34             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      35        4496 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::finite_diff_Fx(const size_t i)
      36             : {
      37        4496 :     const T eps = dx[i];
      38        4496 :     prev_X[i] += eps;
      39        4496 :     Vector<T> dX(&Fx_val_T[i * x_dim], x_dim, true);
      40        4496 :     dX.holdSub(*f(prev_X, U, C).release(), X);
      41        4496 :     dX /= eps;
      42        4496 :     prev_X[i] -= eps;
      43        4496 : }
      44             : 
      45             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      46        2498 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::finite_diff_Fu(const size_t i)
      47             : {
      48        2498 :     const T eps = du[i];
      49        2498 :     U[i] += eps;
      50        2498 :     Vector<T> dX(&Fu_val_T[i * x_dim], x_dim, true);
      51        2498 :     dX.holdSub(*f(prev_X, U, C).release(), X);
      52        2498 :     dX /= eps;
      53        2498 :     U[i] -= eps;
      54        2498 : }
      55             : 
      56             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      57         422 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::finite_diff_H(const size_t z_idx, const size_t i)
      58             : {
      59         422 :     const T eps = dx[i];
      60         422 :     X[i] += eps;
      61         422 :     Vector<T> dz(&H_val[z_idx][i * z_dim[z_idx]], z_dim[z_idx], true);
      62         422 :     dz.holdSub(*h[z_idx](X, C).release(), h_val[z_idx]);
      63         422 :     dz /= eps;
      64         422 :     X[i] -= eps;
      65         422 : }
      66             : 
      67             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      68           5 : void Ekf<x_dim, u_dim, c_dim, z_num, T>::setMeasurementFunction(Vector_f2<T> h, size_t z_dim, size_t z_idx)
      69             : {
      70           5 :     this->h[z_idx] = h;
      71           5 :     this->z_dim[z_idx] = z_dim;
      72           5 :     this->H_val[z_idx].resize(x_dim, z_dim);
      73           5 :     this->S_inv[z_idx].resize(z_dim);
      74           5 : }
      75             : 
      76             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
      77        1499 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::predict()
      78             : {
      79             : 
      80        1499 :     if (f == nullptr)
      81           0 :         throw "Ekf::predict() state transition function not set";
      82             : 
      83             : 
      84        1499 :     prev_X = X;
      85             : 
      86        1499 :     X = f(prev_X, U, C);
      87             : 
      88        1499 :     if (Fx != nullptr)
      89           0 :         Fx_val_T = Fx(prev_X, U, C);
      90             :     else
      91        1499 :         this->finite_diff_Fx();
      92        1499 :     if (Fu != nullptr)
      93           0 :         Fu_val_T = Fu(prev_X, U, C);
      94             :     else
      95        1499 :         this->finite_diff_Fu();
      96             : 
      97        1499 :     P.holdMul(*(Fx_val_T.T * P).release(), Fx_val_T);
      98        1499 :     P.addMul(*(Fu_val_T.T * Cov_U).release(), Fu_val_T);
      99        1499 : }
     100             : 
     101             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
     102         143 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::update(const Vector<T> &Z, const symMatrix<T> &R, const size_t z_idx)
     103             : {
     104         143 :     compute_H_P(z_idx);
     105         143 :     computeResidualPrecision(R, z_idx);
     106         143 :     computeResidual(Z, z_idx);
     107         143 :     updateStateCovariance(z_idx);
     108         143 : }
     109             : 
     110             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
     111         143 : void Ekf<x_dim, u_dim, c_dim, z_num, T>::compute_H_P(const size_t z_idx)
     112             : {
     113         143 :     if (h[z_idx] == nullptr)
     114           0 :         throw "Ekf::update() measurement function not set";
     115             : 
     116         143 :     h_val[z_idx] = h[z_idx](X, C); //  measurement prediction
     117             : 
     118             :     // measurement function Jacobian computation
     119         143 :     if (H[z_idx] == nullptr)
     120         143 :         this->finite_diff_H(z_idx);
     121             :     else
     122           0 :         H_val[z_idx] = H[z_idx](X, C);
     123             : 
     124         143 :     H_P[z_idx].holdMul(H_val[z_idx].T, P);          // common expression (calculus factorisation)
     125         143 :     pre_S[z_idx].holdMul(H_P[z_idx], H_val[z_idx]); // pre computation of residual covariance (R not added yet)
     126         143 : }
     127             : 
     128             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
     129         143 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::computeResidualPrecision(const symMatrix<T> &R, const size_t z_idx)
     130             : {
     131             :     // residual precision
     132         143 :     S_inv[z_idx].holdAdd(pre_S[z_idx], R);
     133         143 :     S_inv[z_idx].holdInv(S_inv[z_idx], false);
     134         143 : }
     135             : 
     136             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
     137         143 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::computeResidual(const Vector<T> &Z, const size_t z_idx)
     138             : {
     139         143 :     if (z_dim[z_idx] != Z.size())
     140           0 :         throw "Ekf::update() measurement dimension mismatch";
     141             : 
     142         143 :     y[z_idx].holdSub(Z, h_val[z_idx]);
     143         143 : }
     144             : 
     145             : template <size_t x_dim, size_t u_dim, size_t c_dim, size_t z_num, typename T>
     146         143 : inline void Ekf<x_dim, u_dim, c_dim, z_num, T>::updateStateCovariance(const size_t z_idx)
     147             : {
     148         143 :     K.holdMul(H_P[z_idx].T, S_inv[z_idx]); // Kalman gains
     149         143 :     X.addMul(K, y[z_idx]);                 // update the state
     150         143 :     P.subMul(K, H_P[z_idx]);               // update the state covariance
     151         143 : }

Generated by: LCOV version 1.14