load "matrix.5c" /* * Copyright © 2011 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ namespace kalman { import matrix; public typedef struct { vec_t x; /* state */ mat_t p; /* error estimate */ mat_t k; /* kalman factor */ } state_t; public typedef struct { mat_t a; /* model */ mat_t q; /* model error covariance */ mat_t r; /* measurement error covariance */ mat_t h; /* measurement from model */ } parameters_t; public typedef struct { mat_t a; /* model */ mat_t k; /* kalman coefficient */ mat_t h; /* measurement from model */ } parameters_fast_t; vec_t measurement_from_state(vec_t x, mat_t h) { return multiply_mat_vec(h, x); } void print_state(string name, state_t s) { print_vec(sprintf("%s state", name), s.x); print_mat(sprintf("%s error", name), s.p); } public bool debug = false; public state_t predict (state_t s, parameters_t p) { state_t n; if (debug) { printf ("--------PREDICT--------\n"); print_state("current", s); } /* Predict state * * x': predicted state * a: model * x: previous state * * x' = a * x; */ n.x = multiply_mat_vec(p.a, s.x); /* t0 = a * p */ mat_t t0 = multiply (p.a, s.p); if (debug) print_mat("t0", t0); /* t1 = a * p * transpose(a) */ mat_t t1 = multiply (t0, transpose(p.a)); /* Predict error * * p': predicted error * a: model * p: previous error * q: model error * * p' = a * p * transpose(a) + q */ n.p = add(t1, p.q); if (debug) print_state("predict", n); return n; } public vec_t predict_fast(vec_t x, parameters_fast_t p) { if (debug) { printf ("--------FAST PREDICT--------\n"); print_vec("current", x); } vec_t new = multiply_mat_vec(p.a, x); if (debug) print_vec("predict", new); return new; } public vec_t correct_fast(vec_t x, vec_t z, parameters_fast_t p) { if (debug) { printf ("--------FAST CORRECT--------\n"); print_vec("measure", z); print_vec("current", x); } vec_t model = multiply_mat_vec(p.h, x); if (debug) print_vec("extract model", model); vec_t diff = vec_subtract(z, model); if (debug) print_vec("difference", diff); vec_t adjust = multiply_mat_vec(p.k, diff); if (debug) print_vec("adjust", adjust); vec_t new = vec_add(x, multiply_mat_vec(p.k, vec_subtract(z, multiply_mat_vec(p.h, x)))); if (debug) print_vec("correct", new); return new; } public state_t correct(state_t s, vec_t z, parameters_t p) { state_t n; if (debug) { printf ("--------CORRECT--------\n"); print_vec("measure", z); print_state("current", s); } /* t0 = p * T(h) */ /* 3x2 = 3x3 * 3x2 */ mat_t t0 = multiply(s.p, transpose(p.h)); if (debug) print_mat("t0", t0); /* t1 = h * p */ /* 2x3 = 2x3 * 3x3 */ mat_t t1 = multiply(p.h, s.p); if (debug) print_mat("t1", t1); /* t2 = h * p * transpose(h) */ /* 2x2 = 2x3 * 3x2 */ mat_t t2 = multiply(t1, transpose(p.h)); if (debug) print_mat("t2", t2); /* t3 = h * p * transpose(h) + r */ /* 2x2 = 2x2 + 2x2 */ mat_t t3 = add(t2, p.r); if (debug) print_mat("t3", t3); /* t4 = inverse(h * p * transpose(h) + r) */ /* 2x2 = 2x2 */ mat_t t4 = inverse(t3); if (debug) print_mat("t4", t4); /* Kalman value */ /* k: Kalman value * p: error estimate * h: state to measurement matrix * r: measurement error covariance * * k = p * transpose(h) * inverse(h * p * transpose(h) + r) * * k = K(p) */ /* 3x2 = 3x2 * 2x2 */ mat_t k = multiply(t0, t4); if (debug) print_mat("k", k); n.k = k; /* t5 = h * x */ /* 2 = 2x3 * 3 */ vec_t t5 = multiply_mat_vec(p.h, s.x); if (debug) print_vec("t5", t5); /* t6 = z - h * x */ /* 2 = 2 - 2 */ vec_t t6 = vec_subtract(z, t5); if (debug) print_vec("t6", t6); /* t7 = k * (z - h * x) */ /* 3 = 3x2 * 2 */ vec_t t7 = multiply_mat_vec(k, t6); if (debug) print_vec("t7", t7); /* Correct state * * x: predicted state * k: kalman value * z: measurement * h: state to measurement matrix * x': corrected state * * x' = x + k * (z - h * x) */ n.x = vec_add(s.x, t7); if (debug) print_vec("n->x", n.x); /* t8 = k * h */ /* 3x3 = 3x2 * 2x3 */ mat_t t8 = multiply(k, p.h); if (debug) print_mat("t8", t8); /* t9 = 1 - k * h */ /* 3x3 = 3x3 - 3x3 */ mat_t t9 = subtract(identity(dim(s.x)), t8); if (debug) print_mat("t9", t9); /* Correct error * * p: predicted error * k: kalman value * h: state to measurement matrix * p': corrected error * * p' = (1 - k * h) * p * * p' = P(k,p) */ /* 3x3 = 3x3 * 3x3 */ n.p = multiply(t9, s.p); if (debug) { print_mat("n->p", n.p); # print_state("correct", n); } return n; } real distance(mat_t a, mat_t b) { int[2] d = dims(a); int i_max = d[0]; int j_max = d[1]; real s = 0; for (int i = 0; i < i_max; i++) for (int j = 0; j < j_max; j++) s += (a[i,j] - b[i,j]) ** 2; return sqrt(s); } public mat_t converge(parameters_t p) { int model = dims(p.a)[0]; int measure = dims(p.r)[0]; int reps = 0; state_t s = { .x = (real[model]) { 0 ... }, .p = (real[model,model]) { { 0 ... } ... }, .k = (real[model,measure]) { { 0 ... } ... } }; vec_t z = (real [measure]) { 0 ... }; for (;;) { state_t s_pre = predict(s, p); state_t s_post = correct(s_pre, z, p); real d = distance(s.k, s_post.k); s = s_post; reps++; if (d < 1e-10 && reps > 10) break; } return s.k; } public parameters_fast_t convert_to_fast(parameters_t p) { return (parameters_fast_t) { .a = p.a, .k = converge(p), .h = p.h }; } }