扩展卡尔曼滤波器
kalman_filter.cpp
#include "kalman_filter.h"
#include <iostream>
using namespace std;
using Eigen::MatrixXd;
using Eigen::VectorXd;
// Please note that the Eigen library does not initialize
// VectorXd or MatrixXd objects with zeros upon creation.
const double PI = 3.1415926535;
KalmanFilter::KalmanFilter() {}
KalmanFilter::~KalmanFilter() {}
void KalmanFilter::Init(VectorXd &x_in, MatrixXd &P_in, MatrixXd &F_in,
MatrixXd &H_in, MatrixXd &R_in, MatrixXd &Q_in) {
x_ = x_in;
P_ = P_in;
F_ = F_in;
H_ = H_in;
R_ = R_in;
Q_ = Q_in;
}
void KalmanFilter::Predict() {
/**
* predict the state
*/
x_ = F_ * x_;
P_ = F_ * P_ * F_.transpose() + Q_;
}
void KalmanFilter::Update(const VectorXd &z) {
/**
* update the state by using Kalman Filter equations
*/
VectorXd y = z - H_ * x_;
MatrixXd S = H_ * P_ * H_.transpose() + R_;
MatrixXd K = P_ * H_.transpose() * S.inverse();
x_ = x_ + (K * y);
long x_size = x_.size();
MatrixXd I = MatrixXd::Identity(x_size, x_size);
P_ = (I - K * H_) * P_;
}
void KalmanFilter::UpdateEKF(const VectorXd &z) {
/**
* update the state by using Extended Kalman Filter equations
*/
double rho = sqrt(x_(0) * x_(0) + x_(1) * x_(1));
double phi = atan2(x_(1), x_(0));
double rho_dot;
if (fabs(rho) < 0.001) {
rho_dot = (x_(0) * x_(2) + x_(1)*x_(3))/.001;
} else {
rho_dot = (x_(0) * x_(2) + x_(1) * x_(3)) / rho;
}
VectorXd z_p(3);
z_p << rho, phi, rho_dot;
VectorXd y = z - z_p;
while ((y[1] < -1. * PI) || (y[1] > PI)) {
if (y[1] < -1. * PI) {
y[1] += 2. * PI;
} else {
y[1] -= 2. * PI;
}
}
MatrixXd S = H_ * P_ * H_.transpose() + R_;
MatrixXd K = P_ * H_.transpose() * S.inverse();
x_ = x_ + (K * y);
long x_size = x_.size();
MatrixXd I = MatrixXd::Identity(x_size, x_size);
P_ = (I - K * H_) * P_;
}
FusionEKF.cpp
#include "FusionEKF.h"
#include <iostream>
using namespace std;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using std::vector;
const double PI = 3.1415926535;
Tools tool = Tools();
/*
* Constructor.
*/
FusionEKF::FusionEKF() {
is_initialized_ = false;
previous_timestamp_ = 0;
// initializing matrices
R_laser_ = MatrixXd(2, 2);
R_radar_ = MatrixXd(3, 3);
H_laser_ = MatrixXd(2, 4);
Hj_ = MatrixXd(3, 4);
//measurement covariance matrix - laser
R_laser_ << 0.0225, 0,
0, 0.0225;
//measurement covariance matrix - radar
R_radar_ << 0.09, 0, 0,
0, 0.0009, 0,
0, 0, 0.09;
/**
* Finish initializing the FusionEKF.
* Set the process and measurement noises
*/
H_laser_ << 1, 0, 0, 0,
0, 1, 0, 0;
ekf_.P_ = MatrixXd(4, 4);
ekf_.P_ << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1000, 0,
0, 0, 0, 1000;
ekf_.F_ = MatrixXd(4, 4);
ekf_.F_ << 1, 0, 1, 0,
0, 1, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1;
ekf_.Q_ = MatrixXd(4, 4);
}
/**
* Destructor.
*/
FusionEKF::~FusionEKF() {}
void FusionEKF::ProcessMeasurement(const MeasurementPackage &measurement_pack) {
/*****************************************************************************
* Initialization
****************************************************************************/
if (!is_initialized_) {
/**
* Initialize the state ekf_.x_ with the first measurement.
* Create the covariance matrix.
* Remember: you'll need to convert radar from polar to cartesian coordinates.
*/
// first measurement
cout << "EKF: " << endl;
ekf_.x_ = VectorXd(4);
ekf_.x_ << 1, 1, 1, 1;
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
/**
Convert radar from polar to cartesian coordinates and initialize state.
*/
Eigen::VectorXd raw = measurement_pack.raw_measurements_;
double theta = raw(1);
double ro = raw(0);
double ro_dot = raw(2);
while ((theta < -1. * PI) || (theta > PI)) {
if (theta < -1. * PI) {
theta += 2. * PI;
} else {
theta -= 2. * PI;
}
}
double px = ro * cos(theta);
double py = ro * sin(theta);
double vx = ro_dot * cos(theta);
double vy = ro_dot * sin(theta);
ekf_.x_ << px, py, vx, vy;
} else if (measurement_pack.sensor_type_ == MeasurementPackage::LASER) {
/**
Initialize state.
*/
Eigen::VectorXd raw = measurement_pack.raw_measurements_;
ekf_.x_ << raw(0), raw(1), 0, 0;
}
// done initializing, no need to predict or update
previous_timestamp_ = measurement_pack.timestamp_;
is_initialized_ = true;
return;
}
/*****************************************************************************
* Prediction
****************************************************************************/
/**
* Update the state transition matrix F according to the new elapsed time.
- Time is measured in seconds.
* Update the process noise covariance matrix.
* Use noise_ax = 9 and noise_ay = 9 for your Q matrix.
*/
double delta_t = (measurement_pack.timestamp_ - previous_timestamp_) / 1000000.0;
previous_timestamp_ = measurement_pack.timestamp_;
ekf_.F_ << 1, 0, delta_t, 0,
0, 1, 0, delta_t,
0, 0, 1, 0,
0, 0, 0, 1;
double dt_2 = delta_t * delta_t;
double dt_3 = dt_2 * delta_t;
double dt_4 = dt_3 * delta_t;
double noise_ax = 9;
double noise_ay = 9;
ekf_.Q_ << dt_4 / 4 * noise_ax, 0, dt_3 / 2 * noise_ax, 0,
0, dt_4 / 4 * noise_ay, 0, dt_3 / 2 * noise_ay,
dt_3 / 2 * noise_ax, 0, dt_2 * noise_ax, 0,
0, dt_3 / 2 * noise_ay, 0, dt_2 * noise_ay;
ekf_.Predict();
/*****************************************************************************
* Update
****************************************************************************/
/**
* Use the sensor type to perform the update step.
* Update the state and covariance matrices.
*/
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
// Radar updates
ekf_.R_ = R_radar_;
Hj_ = tool.CalculateJacobian(ekf_.x_);
ekf_.H_ = Hj_;
ekf_.UpdateEKF(measurement_pack.raw_measurements_);
} else {
// Laser updates
ekf_.R_ = R_laser_;
ekf_.H_ = H_laser_;
ekf_.Update(measurement_pack.raw_measurements_);
}
// print the output
cout << "x_ = " << ekf_.x_ << endl;
cout << "P_ = " << ekf_.P_ << endl;
}
#include <iostream>
#include "tools.h"
using Eigen::VectorXd;
using Eigen::MatrixXd;
using std::vector;
Tools::Tools() {}
Tools::~Tools() {}
VectorXd Tools::CalculateRMSE(const vector<VectorXd> &estimations,
const vector<VectorXd> &ground_truth) {
VectorXd rmse(4);
rmse << 0,0,0,0;
//Check validation
if (estimations.size() != ground_truth.size() || estimations.size() == 0) {
cout << "Invalid data. Different size." << endl;
return rmse;
}
//accumulate squared residuals
for (int i = 0; i < estimations.size(); ++i) {
VectorXd residual = estimations[i] - ground_truth[i];
//coefficient-wise multiplication
residual = residual.array() * residual.array();
rmse += residual;
}
//calculate the mean
rmse = rmse / estimations.size();
//calculate the square root
rmse = rmse.array().sqrt();
return rmse;
}
MatrixXd Tools::CalculateJacobian(const VectorXd& x_state) {
MatrixXd Hj(3,4);
//recover state matrix
double px = x_state(0);
double py = x_state(1);
double vx = x_state(2);
double vy = x_state(3);
// pre-compute a set of terms to avoid repeated calculation
double c1 = px*px + py*py;
double c2 = sqrt(c1);
double c3 = (c1*c2);
//check division by zero
if (fabs(c1) < 0.0001) {
cout << "CalculateJacobian() -ERROR- Division by zero" << endl;
return Hj;
}
//compute the Jacobian matrix
Hj << (px/c2), (py/c2), 0, 0,
-(py/c1), (px/c1), 0, 0,
py*(vx*py - vy*px)/c3, px*(px*vy - py*vx)/c3, px/c2, py/c2;
return Hj;
}