#include <stdio.h>
#include <rc/math/algebra.h>
#include <rc/math/kalman.h>
#include "algebra_common.h"
rc_kalman_t rc_kalman_empty(void)
{
rc_kalman_t kf = RC_KALMAN_INITIALIZER;
return kf;
}
int rc_kalman_alloc_lin(rc_kalman_t* kf, rc_matrix_t F, rc_matrix_t G, rc_matrix_t H, rc_matrix_t Q, rc_matrix_t R, rc_matrix_t Pi)
{
int Nx;
if(kf==NULL){
fprintf(stderr, "ERROR in rc_kalman_alloc_lin, received NULL pointer\n");
return -1;
}
if(!F.initialized || !H.initialized){
fprintf(stderr, "ERROR in rc_kalman_alloc, received uninitialized F or H\n");
return -1;
}
if(!Q.initialized || !R.initialized){
fprintf(stderr, "ERROR in rc_kalman_alloc, received initialized P or Q\n");
return -1;
}
if(F.rows != F.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc, F must be square\n");
return -1;
}
if(H.cols != F.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc, F and H must have same number of columns\n");
return -1;
}
if(G.rows != F.rows){
fprintf(stderr, "ERROR in rc_kalman_alloc, F and G must have same number of rows\n");
return -1;
}
if(Q.rows != Q.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, Q must be square\n");
return -1;
}
if(R.rows != R.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, R must be square\n");
return -1;
}
if(rc_kalman_free(kf)==-1) return -1;
Nx = F.cols;
if(rc_matrix_duplicate(F, &kf->F)==-1) return -1;
if(rc_matrix_duplicate(G, &kf->G)==-1) return -1;
if(rc_matrix_duplicate(H, &kf->H)==-1) return -1;
if(rc_matrix_duplicate(Q, &kf->Q)==-1) return -1;
if(rc_matrix_duplicate(R, &kf->R)==-1) return -1;
if(rc_matrix_duplicate(Pi, &kf->P)==-1) return -1;
if(rc_matrix_duplicate(Pi, &kf->Pi)==-1) return -1;
if(rc_vector_zeros(&kf->x_est, Nx)==-1) return -1;
if(rc_vector_zeros(&kf->x_pre, Nx)==-1) return -1;
kf->initialized = 1;
return 0;
}
int rc_kalman_alloc_ekf(rc_kalman_t* kf, rc_matrix_t Q, rc_matrix_t R, rc_matrix_t Pi)
{
if(kf==NULL){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, received NULL pointer\n");
return -1;
}
if(!Q.initialized || !R.initialized || !Pi.initialized){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, received uninitialized matrix\n");
return -1;
}
if(Q.rows != Q.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, Q must be square\n");
return -1;
}
if(R.rows != R.cols){
fprintf(stderr, "ERROR in rc_kalman_alloc_ekf, R must be square\n");
return -1;
}
rc_kalman_free(kf);
rc_matrix_duplicate(Q, &kf->Q);
rc_matrix_duplicate(R, &kf->R);
rc_matrix_duplicate(Pi, &kf->Pi);
rc_matrix_duplicate(Pi, &kf->P);
rc_vector_zeros(&kf->x_est, Q.rows);
rc_vector_zeros(&kf->x_pre, Q.rows);
kf->initialized = 1;
return 0;
}
int rc_kalman_free(rc_kalman_t* kf)
{
rc_kalman_t new = RC_KALMAN_INITIALIZER;
if(kf==NULL){
fprintf(stderr, "ERROR in rc_kalman_free, received NULL pointer\n");
return -1;
}
rc_matrix_free(&kf->F);
rc_matrix_free(&kf->G);
rc_matrix_free(&kf->H);
rc_matrix_free(&kf->Q);
rc_matrix_free(&kf->R);
rc_matrix_free(&kf->P);
rc_matrix_free(&kf->Pi);
rc_vector_free(&kf->x_est);
rc_vector_free(&kf->x_pre);
*kf = new;
return 0;
}
int rc_kalman_reset(rc_kalman_t* kf)
{
if(kf==NULL){
fprintf(stderr, "ERROR in rc_kalman_reset, received NULL pointer\n");
return -1;
}
if(kf->initialized !=1){
fprintf(stderr, "ERROR in rc_kalman_reset, kf uninitialized\n");
return -1;
}
rc_matrix_duplicate(kf->Pi, &kf->P);
rc_vector_zero_out(&kf->x_est);
rc_vector_zero_out(&kf->x_pre);
kf->step = 0;
return 0;
}
int rc_kalman_update_lin(rc_kalman_t* kf, rc_vector_t u, rc_vector_t y)
{
rc_matrix_t L = RC_MATRIX_INITIALIZER;
rc_matrix_t newP = RC_MATRIX_INITIALIZER;
rc_matrix_t S = RC_MATRIX_INITIALIZER;
rc_matrix_t FT = RC_MATRIX_INITIALIZER;
rc_vector_t h = RC_VECTOR_INITIALIZER;
rc_vector_t z = RC_VECTOR_INITIALIZER;
rc_vector_t tmp1 = RC_VECTOR_INITIALIZER;
rc_vector_t tmp2 = RC_VECTOR_INITIALIZER;
if(unlikely(kf==NULL)){
fprintf(stderr, "ERROR in rc_kalman_lin_update, received NULL pointer\n");
return -1;
}
if(unlikely(kf->initialized !=1)){
fprintf(stderr, "ERROR in rc_kalman_lin_update, kf uninitialized\n");
return -1;
}
if(unlikely(u.initialized!=1 || y.initialized!=1)){
fprintf(stderr, "ERROR in rc_kalman_lin_update received uninitialized vector\n");
return -1;
}
if(unlikely(u.len != kf->G.cols)){
fprintf(stderr, "ERROR in rc_kalman_lin_update u must have same dimension as columns of G\n");
return -1;
}
if(unlikely(y.len != kf->H.rows)){
fprintf(stderr, "ERROR in rc_kalman_lin_update y must have same dimension as rows of H\n");
return -1;
}
rc_matrix_times_col_vec(kf->F, kf->x_est, &tmp1);
rc_matrix_times_col_vec(kf->G, u, &tmp2);
rc_vector_sum(tmp1, tmp2, &kf->x_pre);
rc_matrix_multiply(kf->F, kf->P, &newP); rc_matrix_transpose(kf->F, &FT);
rc_matrix_right_multiply_inplace(&newP, FT); rc_matrix_add_inplace(&newP, kf->Q); rc_matrix_symmetrize(&newP);
rc_matrix_times_col_vec(kf->H,kf->x_pre,&h);
rc_matrix_transpose(kf->H, &S); rc_matrix_multiply(newP, S, &L); rc_matrix_left_multiply_inplace(newP, &S); rc_matrix_left_multiply_inplace(kf->H, &S); rc_matrix_add_inplace(&S, kf->R);
rc_algebra_invert_matrix_inplace(&S); rc_matrix_right_multiply_inplace(&L, S);
rc_vector_subtract(y,h,&z); rc_matrix_times_col_vec(L, z, &tmp1); rc_vector_sum(kf->x_pre, tmp1, &kf->x_est);
rc_matrix_multiply(kf->H, newP, &S); rc_matrix_left_multiply_inplace(L, &S); rc_matrix_subtract_inplace(&newP, S); rc_matrix_symmetrize(&newP); rc_matrix_duplicate(newP,&kf->P);
rc_matrix_free(&L);
rc_matrix_free(&newP);
rc_matrix_free(&S);
rc_matrix_free(&FT);
rc_vector_free(&h);
rc_vector_free(&z);
rc_vector_free(&tmp1);
rc_vector_free(&tmp2);
kf->step++;
return 0;
}
int rc_kalman_update_ekf(rc_kalman_t* kf, rc_matrix_t F, rc_matrix_t H, rc_vector_t x_pre, rc_vector_t y, rc_vector_t h)
{
rc_matrix_t L = RC_MATRIX_INITIALIZER;
rc_matrix_t newP = RC_MATRIX_INITIALIZER;
rc_matrix_t S = RC_MATRIX_INITIALIZER;
rc_matrix_t FT = RC_MATRIX_INITIALIZER;
rc_vector_t z = RC_VECTOR_INITIALIZER;
rc_vector_t tmp1 = RC_VECTOR_INITIALIZER;
rc_vector_t tmp2 = RC_VECTOR_INITIALIZER;
if(unlikely(kf==NULL)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update, received NULL pointer\n");
return -1;
}
if(unlikely(kf->initialized !=1)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update, kf uninitialized\n");
return -1;
}
if(unlikely(F.initialized!=1 || H.initialized!=1)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update received uninitialized matrix\n");
return -1;
}
if(unlikely(x_pre.initialized!=1 || y.initialized!=1 || h.initialized!=1)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update received uninitialized vector\n");
return -1;
}
if(unlikely(F.rows != F.cols)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update F must be square\n");
return -1;
}
if(unlikely(x_pre.len != F.rows)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update x_pre must have same dimension as rows of F\n");
return -1;
}
if(unlikely(x_pre.len != H.cols)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update x_pre must have same dimension as columns of H\n");
return -1;
}
if(unlikely(y.len != H.rows)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update y must have same dimension as rows of H\n");
return -1;
}
if(unlikely(y.len != h.len)){
fprintf(stderr, "ERROR in rc_kalman_ekf_update y must have same dimension h\n");
return -1;
}
rc_matrix_duplicate(F, &kf->F);
rc_vector_duplicate(x_pre, &kf->x_pre);
rc_matrix_duplicate(H, &kf->H);
rc_matrix_multiply(kf->F, kf->P, &newP); rc_matrix_transpose(kf->F, &FT);
rc_matrix_right_multiply_inplace(&newP, FT); rc_matrix_add(newP, kf->Q, &kf->P); rc_matrix_symmetrize(&kf->P);
rc_matrix_transpose(kf->H, &S); rc_matrix_multiply(kf->P, S, &L); rc_matrix_left_multiply_inplace(kf->P, &S); rc_matrix_left_multiply_inplace(kf->H, &S); rc_matrix_add_inplace(&S, kf->R);
rc_algebra_invert_matrix_inplace(&S); rc_matrix_right_multiply_inplace(&L, S);
rc_vector_subtract(y,h,&z); rc_matrix_times_col_vec(L, z, &tmp1); rc_vector_sum(kf->x_pre, tmp1, &kf->x_est);
rc_matrix_multiply(kf->H, newP, &S); rc_matrix_left_multiply_inplace(L, &S); rc_matrix_subtract_inplace(&newP, S); rc_matrix_symmetrize(&newP); rc_matrix_duplicate(newP,&kf->P);
rc_matrix_free(&L);
rc_matrix_free(&newP);
rc_matrix_free(&S);
rc_matrix_free(&FT);
rc_vector_free(&z);
rc_vector_free(&tmp1);
rc_vector_free(&tmp2);
kf->step++;
return 0;
}