Kalman Filter Implementation for 3D Position using Eigen
Asked Answered
A

2

6

I wrote a kalman Filter implementation using the Eigen Library in C++ and also using the implementation at this link to test my filter: My prediction step looks like this:

void KalmanFilter::Predict()
{
    // state Estimate = state transition matrix * previous state
    // No control input present.
    x = A * x;


   // State Covariance Matrix = (State Transition Matrix * Previous State 
   Covariance matrix * (State Transition Matrix)^T ) + Process Noise

   P = A * P * A.transpose() + Q;
}

while my update step is:

void KalmanFilter::Update(VectorXd z)
{
    //Kalman Gain = (State Covariance Matrix * Measurement matrix.transpose) * (H*P*H^T + Measurement Noise)^-1
    K = (P * H.transpose()) * (H * P * H.transpose()+ R).inverse();

    //Estimated Stated = Estimated state + Kalman Gain (Measurement Innovation)
    x = x + K*(z - H * x);

   //State Covariance matrix = (Identity Matrix of the size of  x.size * x.size) - K* H * P;
    long x_size = x.size();
    MatrixXd I = MatrixXd::Identity(x_size, x_size);
    P = (I - K * H) * P ;

}

My initial values are:

pos_x = 0.0;
pos_y = 0.0;
pos_z = 1.0;
vel_x = 10.0;
vel_y = 0.0;
vel_z = 0.0;
acc_x = 0.0;
acc_y = 0.0;
acc_z = -9.81;

and I'm generating "fake data" by doing the following in a loop:

double c = 0.1; // Drag resistance coefficient
double damping = 0.9 ; // Damping

double sigma_position = 0.1 ; // position_noise

// Create simulated position data
for (int i = 0; i < N; i ++)
{
    acc_x = -c * pow(vel_x, 2);  // calculate acceleration ( Drag Resistance)

    vel_x += acc_x * dt;  // Integrate acceleration to give you velocity in the x axis.

    pos_x += vel_x * dt; // Integrate velocity to return the position in the x axis

    acc_z = -9.806 + c * pow(vel_z, 2); // Gravitation + Drag

    vel_z += acc_z * dt;   // z axis velocity

    pos_z += vel_z * dt;  // position in z axis

    // generate y position here later.

    if(pos_z < 0.01)
    {
        vel_z = -vel_z * damping;
        pos_z += vel_z * dt;
    }

    if (vel_x < 0.1)
    {
        acc_x = 0.0;
        acc_z = 0.0;
    }

    // add some noise
    pos_x = pos_x + sigma_position * process_noise(generator); 
    pos_y = pos_y + sigma_position * process_noise(generator);
    pos_z = pos_z + sigma_position * process_noise(generator);

I then run my prediction and update step by:

// Prediction Step
kalmanFilter.Predict();

// Correction Step
kalmanFilter.Update(z);

where z is a 3 x 1 vector containing pos_x, pos_y and pos_z

My State Transition Matrix A looks like this:

A <<    1, 0, 0, dt, 0, 0, dt_squared, 0 , 0,
        0, 1, 0, 0,  dt, 0, 0, dt_squared, 0,
        0, 0, 1, 0, 0, dt, 0, 0, dt_squared,
        0, 0, 0, 1, 0, 0, dt, 0, 0,
        0, 0, 0, 0, 1, 0, 0 , dt, 0,
        0, 0, 0, 0, 0, 1, 0, 0, dt,
        0, 0, 0, 0, 0, 0, 1, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 1, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 1;

where dt_squared is (dt * dt) /2;

P is  

P<< 100, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 100, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 100, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 100, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 100, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 100, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 100, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 100, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 100;

and

   R << 1, 0, 0,
         0, 1, 0,
         0, 0, 1;

and

Q = G * G.transpose()* a * a;  

where G is a 9 x 1 Matrix of

G << dt_squared, dt_squared, dt_squared, dt, dt, dt, 1, 1, 1;

a =  0.1 //( acceleration process noise)

My issue is my estimated position for y and z are off and diverge from the "real" positions. If you look at the following graphs,

This is what pos_x looks like: X

This is what pos_y looks like: Y

And finally Z: Z

This is my first foray with Kalman filters and I'm not sure what I'm doing wrong here. My final goal would be to use this to estimate the position of a drone. Additionally, I have the following questions:

In a real life situation for a drone for example, how do you about choosing your Process Noise if you can't directly observe the process? Do you simply just pick arbitrary values?

My apologies for the long post. Any help is appreciated.

Alyosha answered 23/5, 2018 at 15:13 Comment(1)
I am curious about your implementation. could you point me to on your github! thanksTracheitis
I
2

I am not sure if it's a code related issue, an algorithm implementation issue, or an expectation issue.

You do realize that a filter like this will NOT reproduce truth data, or even anything close to it, if the fake data has too much maneuvering in it.

Also, your graphs are not present.

I know my response doesn't follow community standards but I cannot comment or I'd do that.

Until you provide the plots and check the curvature of the path against the update rate I would not attempt to go into detail. Also filters need to be "tuned" to a specific system. You may need to play with noise parameters to tune it better. For maneuvering tracks one may need to go to higher order filters, Singer, or Jerk filters... The filter needs to model the system well enough. Based on your update matrix it looks like you have a parabolic (second order) estimate. You may also want to ask about this in other forums that are not s/w or code specific.

Imbroglio answered 24/5, 2018 at 23:0 Comment(3)
I didn't have a high enough score to attach images to posts which is why I provided them as links instead. They were there but not obvious enough. But after applying the same dataset to other kalman filter implementations I found online, the results were similar to mine. My concusion is I believe the noise parameters and my initial state covariance matrix just needs some tuningAlyosha
What is the actual system you are estimating? Looks like the z-position variable has a jump discontinuity in the derivative. There is no way, in all likelihood, that a simple white noise filter will catch that. You have applied your first attempt to a difficult system to track! It looks like it did damn good until the first "bounce". You have what we might call a maneuvering target. You need a Jerk filter to catch that point, or an MMI - a lib or maneuvering filters and the logic to branch off into a new filter when such a maneuver is detected.Imbroglio
In short I'd say your filter works where it should but you applied a simple filter to a complex moving target. Keep at it.Imbroglio
H
0

Every System has variances. Let's say the Filter has a variance of +-1% and the real value has +-5%; If you predict a value you have to make a choice for the update to use the predicted or the meassures value. Depending on which one you believe more. Otherwise your filter does develop always based on it's own values...

Heliochrome answered 12/9, 2018 at 7:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.