11#define FCN_XUW [=]( arma::mat x, arma::mat u, arma::mat w )
12using fcn_t = std::function<double( arma::mat, arma::mat, arma::mat )>;
13using fcn_v = std::vector<fcn_t>;
14using fcn_m = std::vector<fcn_v>;
24arma_inline arma::mat
eval_fcn(
const fcn_v f,
const arma::mat& x,
const arma::mat& u,
const arma::mat& w )
26 arma::mat y( ( arma::uword )( f.size() ), 1, arma::fill::zeros );
27 for( arma::uword n = 0; n < y.n_rows; n++ )
28 y( n, 0 ) = f[n]( x, u, w );
39arma_inline arma::mat
eval_fcn(
const fcn_v f,
const arma::mat& x,
const arma::mat& u )
41 arma::mat w0( 0, 0, arma::fill::zeros );
53 arma::mat w0( 0, 0, arma::fill::zeros );
79arma_inline
void lti2discr(
const arma::mat& F,
const arma::mat& W,
const arma::mat& Qc,
const double dT, arma::mat& A, arma::mat& Q )
81 arma::uword M = F.n_rows;
84 A = arma::expmat( F * dT );
87 arma::mat AB = arma::zeros( 2 * M, M );
88 arma::mat CD = arma::zeros( 2 * M, 2 * M );
89 arma::mat EF = arma::zeros( 2 * M, M );
90 EF.submat( M, 0, 2 * M - 1, M - 1 ) = arma::eye( M, M );
91 CD.submat( 0, 0, M - 1, M - 1 ) = F;
92 CD.submat( M, M, 2 * M - 1, 2 * M - 1 ) = -F.t();
93 CD.submat( 0, M, M - 1, 2 * M - 1 ) = W * Qc * W.t();
95 AB = arma::expmat( CD * dT ) * EF;
97 Q = AB.rows( 0, M - 1 ) * arma::inv( AB.rows( M, 2 * M - 1 ) );
147 KF( arma::uword _N, arma::uword _M, arma::uword _L )
273 P =
A *
P *
A.t() +
Q;
281 arma::mat u0(
L, 1, arma::fill::zeros );
291 K =
P *
H.t() * inv(
H *
P *
H.t() +
R );
298 arma::mat Jf = arma::eye<arma::mat>(
N,
N ) -
K *
H;
299 P = Jf *
P * Jf.t() +
K *
R *
K.t();
307 void rts_smooth(
const arma::mat& Xf,
const arma::cube& Pf, arma::mat& Xs, arma::cube& Ps )
309 arma::uword Nf = Xf.n_cols;
310 arma::mat X_pred(
N, 1 );
311 arma::mat P_pred(
N,
N );
319 for( arma::uword n = Nf - 2; n > 0; n-- )
322 X_pred =
A * Xf.col( n );
323 P_pred =
A * Pf.slice( n ) *
A.t() +
Q;
326 C = Pf.slice( n ) *
A.t() * inv( P_pred );
327 Xs.col( n ) += C * ( Xs.col( n + 1 ) - X_pred );
328 Ps.slice( n ) += C * ( Ps.slice( n + 1 ) - P_pred ) * C.t();
362 EKF( arma::uword _N, arma::uword _M, arma::uword _L ) :
KF( _N, _M, _L )
397 arma::uword nC = _F.n_cols;
398 arma::uword nR =
static_cast<arma::uword
>( _f.size() );
399 arma::mat z0( nC, 1, arma::fill::zeros );
401 if( nR == 0 || nR != _F.n_rows )
402 err_handler(
"Function list is empty or wrong size" );
404 for( arma::uword c = 0; c < nC; c++ )
412 for( arma::uword r = 0; r < nR; r++ )
413 _F( r, c ) = ( _f[r]( xp, z0, z0 ) - _f[r]( xm, z0, z0 ) ) / ( 2 *
dx );
436 arma::uword nC = _F.n_cols;
437 arma::uword nR =
static_cast<arma::uword
>( _f_m.size() );
439 if( nR == 0 || nR != _F.n_rows )
440 err_handler(
"Function list is empty or wrong size" );
442 arma::mat z0( nC, 1, arma::fill::zeros );
443 for( arma::uword c = 0; c < nC; c++ )
445 for( arma::uword r = 0; r < nR; r++ )
446 _F( r, c ) = _f_m[r][c]( _x, z0, z0 );
469 if(
f_jac.size() > 0 )
481 P =
A *
P *
A.t() +
Q;
489 arma::mat u0(
L, 1, arma::fill::zeros );
498 arma::mat z_hat(
M, 1 );
503 if(
h_jac.size() > 0 )
518 K =
P *
H.t() * inv(
H *
P *
H.t() +
R );
524 arma::mat Jf = arma::eye<arma::mat>(
N,
N ) -
K *
H;
525 P = Jf *
P * Jf.t() +
K *
R *
K.t();
533 void rts_smooth(
const arma::mat& Xf,
const arma::cube& Pf, arma::mat& Xs, arma::cube& Ps )
535 arma::uword Nf = Xf.n_cols;
536 arma::mat X_pred(
N, 1 );
537 arma::mat P_pred(
N,
N );
545 for( arma::uword n = Nf - 2; n > 0; n-- )
550 if(
f_jac.size() > 0 )
561 X_pred =
A * Xf.col( n );
565 P_pred =
A * Pf.slice( n ) *
A.t() +
Q;
568 C = Pf.slice( n ) *
A.t() * inv( P_pred );
569 Xs.col( n ) += C * ( Xs.col( n + 1 ) - X_pred );
570 Ps.slice( n ) += C * ( Ps.slice( n + 1 ) - P_pred ) * C.t();
604 UKF( arma::uword _N, arma::uword _M, arma::uword _L ) :
KF( _N, _M, _L )
610 X.set_size( _N, 2 * _N + 1 );
612 Wx.set_size( 2 * _N + 1 );
614 Wp.set_size( 2 * _N + 1 );
653 for( arma::uword n = 1; n <= 2 *
N; n++ )
668 arma::mat _A = sqrt(
N +
lambda ) * arma::chol( ( _P + _P.t() ) / 2,
"lower" );
670 X = arma::repmat( _x, 1, 2 *
N + 1 );
671 X.cols( 1,
N ) += _A;
672 X.cols(
N + 1, 2 *
N ) -= _A;
678 arma::mat
ut(
const arma::mat& _x,
const arma::mat& _P,
const fcn_v _f )
680 arma::uword Ny =
static_cast<arma::uword
>( _f.size() );
681 arma::mat y( Ny, 1 );
682 S.set_size( Ny, Ny );
689 arma::mat Xy( Ny, 2 *
N + 1 );
690 for( arma::uword n = 0; n < 2 *
N + 1; n++ )
691 Xy.col( n ) =
eval_fcn( _f,
X.col( n ) );
697 S = ( Xy - arma::repmat( y, 1, 2 *
N + 1 ) ) * arma::diagmat(
Wp ) * ( Xy - arma::repmat( y, 1, 2 *
N + 1 ) ).t();
700 C = (
X - arma::repmat( _x, 1, 2 *
N + 1 ) ) * arma::diagmat(
Wp ) * ( Xy - arma::repmat( y, 1, 2 *
N + 1 ) ).t();
725 P =
A *
P *
A.t() +
Q;
734 arma::mat u0(
L, 1, arma::fill::zeros );
743 arma::mat z_hat(
M, 1 );
747 z_hat =
ut(
x,
P,
h );
753 K =
C * arma::inv(
S );
760 P =
P -
K *
S *
K.t();
768 K =
P *
H.t() * inv(
H *
P *
H.t() +
R );
774 arma::mat Jf = arma::eye<arma::mat>(
N,
N ) -
K *
H;
775 P = Jf *
P * Jf.t() +
K *
R *
K.t();
784 void rts_smooth(
const arma::mat& Xf,
const arma::cube& Pf, arma::mat& Xs, arma::cube& Ps )
786 arma::uword Nf = Xf.n_cols;
787 arma::mat X_pred(
N, 1, arma::fill::zeros );
788 arma::mat P_pred(
N,
N, arma::fill::zeros );
789 arma::mat D_pred(
N,
N, arma::fill::zeros );
796 for( arma::uword k = Nf - 2; k > 0; k-- )
801 X_pred =
ut( Xf.col( k ), Pf.slice( k ),
f );
805 D_pred =
C * inv( P_pred );
806 Xs.col( k ) += D_pred * ( Xs.col( k + 1 ) - X_pred );
807 Ps.slice( k ) += D_pred * ( Ps.slice( k + 1 ) - P_pred ) * D_pred.t();
812 X_pred =
A * Xf.col( k );
815 P_pred =
A * Pf.slice( k ) *
A.t() +
Q;
818 D_pred = Pf.slice( k ) *
A.t() * inv( P_pred );
819 Xs.col( k ) += D_pred * ( Xs.col( k + 1 ) - X_pred );
820 Ps.slice( k ) += D_pred * ( Ps.slice( k + 1 ) - P_pred ) * D_pred.t();
First order Extended Kalman filter class.
Unscented Kalman filter class.
void predict(void)
Predict the internal states, no control. Convenient function.
void predict(const arma::mat u)
Predict the internal states using a control input.
void rts_smooth(const arma::mat &Xf, const arma::cube &Pf, arma::mat &Xs, arma::cube &Ps)
Rauch-Tung-Striebel smoother. See https://users.aalto.fi/~ssarkka/course_k2012/full_course_booklet_20...
arma::mat A
State transition matrix.
arma::mat get_err_cov(void)
arma::vec Wx
Weights states.
arma::mat H
Measurement matrix.
arma::uword L
Number of measurements/observations.
bool lin_proc
Linearity flag for process.
void rts_smooth(const arma::mat &Xf, const arma::cube &Pf, arma::mat &Xs, arma::cube &Ps)
Rauch-Tung-Striebel smoother. See https://users.aalto.fi/~ssarkka/course_k2012/full_course_booklet_20...
double alpha
Spread factor of sigma points.
void jacobian_analytical(arma::mat &_F, fcn_m _f_m)
Evaluate Jacobian matrix using analytical jacobian.
arma::mat C
Cross covariance input-output.
void set_meas_jac(fcn_m _h)
bool lin_meas
Linearity flag for measurement.
arma::mat Q
Process noise.
arma::mat K
Kalman gain vector.
KF(arma::uword _N, arma::uword _M, arma::uword _L)
Constructor.
arma::mat get_state_vec(void)
UKF(arma::uword _N, arma::uword _M, arma::uword _L)
void update(const arma::mat z)
Correct and update the internal states. EKF.
void set_state_jac(fcn_m _f)
void clear(void)
Clear the internal states and pointer.
fcn_m h_jac
Matrix of Extended Kalman measurement transition jacobian.
void set_meas_noise(const arma::mat &_R)
void set_state_vec(const arma::mat &_x)
void rts_smooth(const arma::mat &Xf, const arma::cube &Pf, arma::mat &Xs, arma::cube &Ps)
Rauch-Tung-Striebel smoother. See https://users.aalto.fi/~ssarkka/course_k2012/full_course_booklet_20...
void set_diff_step(double _dx)
void set_meas_mat(const arma::mat &_H)
void set_meas_fcn(fcn_v _h)
void predict(void)
Predict the internal states, no control.
void set_err_cov(const arma::mat &_P)
void jacobian_diff(arma::mat &_F, fcn_v _f, const arma::mat &_x)
Calculate and evaluate Jacobian matrix using finite difference approximation.
void set_control_mat(const arma::mat &_B)
void set_trans_mat(const arma::mat &_A)
fcn_m f_jac
Matrix of Extended Kalman state transition jacobian.
void jacobian_diff(arma::mat &_F, fcn_v _f)
Calculate and evaluate Jacobian matrix using finite difference approximation.
double beta
x distr. prior knowledge factor
void set_trans_fcn(fcn_v _f)
arma::mat R
Measurement noise.
void update(const arma::mat z)
Correct and update the internal states. UKF.
void predict(void)
Predict the internal states, no control.
void jacobian_analytical(arma::mat &_F, fcn_m _f_m, const arma::mat &_x)
Evaluate Jacobian matrix using analytical jacobian.
fcn_v h
Vector of Kalman measurement functions.
arma::mat get_kalman_gain(void)
arma::uword M
Number of inputs.
void set_lambda(double _l)
arma::uword N
Number of states.
void update_sigma(const arma::mat &_x, const arma::mat &_P)
Calculate sigma points around a reference point.
void set_kalman_gain(const arma::mat &_K)
void set_proc_noise(const arma::mat &_Q)
void update_weights(void)
Calculate sigma point weights.
EKF(arma::uword _N, arma::uword _M, arma::uword _L)
void predict(const arma::mat u)
Predict the internal states using a control input.
arma::mat z_err
Prediction error.
void set_kappa(double _k)
arma::mat P
Error covariance matrix (estimated accuracy)
double dx
Finite difference approximation step size.
arma::mat ut(const arma::mat &_x, const arma::mat &_P, const fcn_v _f)
Calculate unscented transform.
void predict(const arma::mat u)
Predict the internal states using a control input.
arma::vec Wp
Weights covariance.
fcn_v f
Vector of Kalman state transition functions.
void update(const arma::mat z)
Correct and update the internal states.
arma::mat S
Output covariance.
void set_alpha(double _a)
arma_inline void lti2discr(const arma::mat &F, const arma::mat &W, const arma::mat &Qc, const double dT, arma::mat &A, arma::mat &Q)
Discretize to a state transition and state noise cov matrix from an LTI system.
std::vector< fcn_v > fcn_m
std::function< double(arma::mat, arma::mat, arma::mat)> fcn_t
std::vector< fcn_t > fcn_v
arma_inline arma::mat eval_fcn(const fcn_v f, const arma::mat &x, const arma::mat &u, const arma::mat &w)
Evaluate function f(x,u,w)