This Extended Kalman Filter library is powerful and very simple to use, but a Kalman filter is very difficult to debug. So, it is very important to follow a procedure to be sure that everything is right (code and equations). This example suggests a procedure to follow and shows how to use the library. If you are not familiar with the Kalman filter, please read this article [02].
The first thing to do is to find out the state vector you want to estimate and the inputs
of the system. After this, find the non-linear process function
that describes the evolution of the state vector through time, that is :
where is the process noise vector due to uncertainty and process modeling errors.
Then, find the non-linear relation between your state vector \form#0 and the measure vector \form#5.
where is the measure noise vector.
A plane flies in a 2D space where the x axis is the distance traveled by the plane and y axis is its altitude. This system can be represented by the following continuous equations:
where is the plane's weight (1000 kg)
is the drag coefficient (0.35 N/m²/s²)
is the lift force (3.92 N/m²/s²)
is the gravitational acceleration (9.8 m/s)
(the input) is the motor's thrust
The discrete equation is:
where and
are the random variables which represent the process noise.
A station on the ground (at the origin) mesures the angle between the plane and the ground (x axis) and the distance between the plane and the station. These measures are based on the following equation:
where and
are the random variables which represent the process noise.
Calculate the jacobian matrix A, W, H and V where : A is an n by n jacobian matrix of partial derivatives, defined as follow :
W is an n by nv jacobian matrix of partial derivatives, defined as follow :
H is an m by n jacobian matrix of partial derivatives, defined as follow :
V is an m by nv jacobian matrix of partial derivatives, defined as follow :
is the number of element in state vector
is the number of measure
is the number of process noise random variables
is the number of measure noise random variables
Set initial estimation of the state vector. After, set the covariance matrix P which represents the covariance of the error of the state vector estimation. Then, set the covariance Q and R which represent the covariance matrix of process noise and measurement noise, respectively.
The first estimation of the state vector is based on the first measures and the covariance matrix are the following:
Now, it's time to create the first version of your Kalman filter. You should not try to optimize it at this step, just create your filter and validate it. This library allows you to optimize your filter, but in your first implementation, code only the basic functions. So, code functions called makeProcess()
, makeMeasure()
, makeA()
, makeH()
, makeQ()
, makeR()
, makeV()
and makeW()
. These functions will set the value of each matrix.
The first thing to do is to create your Kalman filter class.
In this example, our Kalman filter inherits from the Extended Kalman Filter, because it's a non-linear problem ( and
are non-linear functions) The first two template parameters are respectively the floating point type used by the filter (
float
or double
) and the beginning index of vectors and matrices (0 or 1). There are three other template parameters to the EKFilter
template class. They are explained in the next section, but they can be safely set to their default values in the first version of the filter, which are false, false and true to disable optimizations and enable bound-checking.
You should declare each functions named previously in this class. You can declare variables too.
After, code the class constructor. You can call the function setDim()
here or you will call it manually in your main()
function after you created the filter object. The function setDim()
sets the number of states, the number of inputs, the number of process noise random variables, the number of measures and the number of measurement noise random variables. It can be used by advanced users to implement a Variable-Dimension Extended Kalman Filter (an EKF whose dimensions may change from one iteration to the other).
In the function makeProcess()
, you should use a temporary vector to store the new state vector like this :
In the function makeMeasure()
, you update directly the measures vector . These are the predicted measures.
Then, you code all other functions makeX()
like this:
Now, your filter is ready to be used. In this example, the measures and the inputs have been calculated by the generation.m
Matlab script. It's a good idea to test your filter with fixed measures and inputs if you want to validate it.
After you create the filter object, you should call the setDim()
function before calling the init()
function. In this example, the setDim()
function is called in the class constructor. The init()
function sets the initial state and the initial covariance matrix.
WARNING : The vectors passed to the init()
function become unusable when init()
returns ! Never use those vectors after the call.
Call the function step()
for each iteration and pass the new inputs and the new measures.
When your Kalman filter works properly, you can optimize it in many simple ways.
true
. This will minimize some calculations. Also, you will only need to fill in diagonal elements of Q, since the other values will never be read.true
. This will minimize some calculations. Also, you will only need to fill in diagonal elements of V and R, since the other values will never be read.makeBaseX()
function instead of the makeX()
function to fill these values. These functions are called only once at the beginning instead of once per iteration. You can used the makeBaseX()
function to set values that never change in a matrix and just set the other values in the makeX()
function.makeA()
, makeW()
, makeQ()
and makeProcess()
functions, then use the function makeCommonProcess()
to do those calculations and save them in member variables of your own subclass. This function is always called before the others.makeH()
, makeV()
, makeR()
, makeMeasure()
and makeDZ()
functions, then use the function makeCommonMeasure()
to do those calculations and save them in member variables of your own subclass. This function is always called before the others.makeX()
or a makeBaseX()
function, there can be some execution paths where the function does not modify any matrix (for example, if there is some condition, then modify the matrix, else don't). If this is the case, then each non-mutating execution path should call NoModification()
before returning, so that some calculations can be avoided.false
to disable bound-checking.This example have been optimized in many ways:
makeBaseX()
functions instead of makeX()
functions.makeX()
functions to makeBaseX()
functions.false
.So, the final result for this example is:
[01] Bierman, G. J. "Factorization Methods for Discrete Sequential
Estimation", Academic Press, 1977.
[02] Welch, G. and Bishop, G. "An Introduction to the %Kalman Filter", http://www.cs.unc.edu/~welch/kalman/kalmanIntro.html