Skip to content

Instantly share code, notes, and snippets.

@pablovela5620
Created August 10, 2017 20:50
Show Gist options
  • Save pablovela5620/2d56018f8c98df40033b99a4a5a6154b to your computer and use it in GitHub Desktop.
Save pablovela5620/2d56018f8c98df40033b99a4a5a6154b to your computer and use it in GitHub Desktop.
#include "FusionEKF.h"
#include "tools.h"
#include "Eigen/Dense"
#include <iostream>
using namespace std;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using std::vector;
/*
* 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);
H_radar = 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;
/**
TODO:
* Finish initializing the FusionEKF.
* Set the process and measurement noises
*/
H_laser_ << 1, 0, 0, 0, //from section 10 lesson 5
0, 1, 0, 0;
H_radar << 1, 1, 0, 0,
1, 1, 0, 0,
1, 1, 1, 1;
ekf_.F_ = MatrixXd(4, 4); // 4x4 matrix (initial state transition)
ekf_.F_ << 1, 0, 1, 0,
0, 1, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1;
ekf_.P_ = MatrixXd(4, 4);// 4x4 matrix (covariance)
ekf_.P_ << 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1000, 0,
0, 0, 0, 1000;
//set the acceleration noise components
noise_ax = 9;//provided in quiz as 9 in seciont 13 lesson 5 (sigmax^2)
noise_ay = 9;//provided in quiz as 9
}
/**
* Destructor.
*/
FusionEKF::~FusionEKF() {}
void FusionEKF::ProcessMeasurement(const MeasurementPackage &measurement_pack) {
/*****************************************************************************
* Initialization
****************************************************************************/
if (!is_initialized_) {
/**
TODO:
* 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;// this value is important for the RMSE
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
/**
Convert radar from polar to cartesian coordinates and initialize state.
*/
//just set ekf_.x_(0) to ro*cos(theta)
float rho = measurement_pack.raw_measurements_(0);
float theta = measurement_pack.raw_measurements_(1);
float rho_dot = measurement_pack.raw_measurements_(2);
ekf_.x_(0) = rho * cos(theta);
ekf_.x_(1) = rho * sin(theta);
ekf_.x_(2) = rho_dot * cos(theta);
ekf_.x_(3) = rho_dot * sin(theta);
} else if (measurement_pack.sensor_type_ == MeasurementPackage::LASER) {
/**
Initialize state.
*/
//set ekf_.x_(0) to x
ekf_.x_(0) = measurement_pack.raw_measurements_(0);
//set ekf_.x_(1) to y
ekf_.x_(1) = measurement_pack.raw_measurements_(1);
}
previous_timestamp_ = measurement_pack.timestamp_;
// done initializing, no need to predict or update
is_initialized_ = true;
return;
}
/*****************************************************************************
* Prediction
****************************************************************************/
/**
TODO: FOUND IN SECTION 8 LESSON 5
* 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.
*/
float dt = (measurement_pack.timestamp_ - previous_timestamp_) / 1000000.0; //dt - expressed in seconds
previous_timestamp_ = measurement_pack.timestamp_;
float dt_2 = dt * dt;
float dt_3 = dt_2 * dt;
float dt_4 = dt_3 * dt;
//Modify the F matrix so that the time is integrated
ekf_.F_(0, 2) = dt;
ekf_.F_(1, 3) = dt;
//set the process covariance matrix Q Section 9 Lesson 5
ekf_.Q_ = MatrixXd(4, 4);
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
****************************************************************************/
/**
TODO:
* Use the sensor type to perform the update step.
* Update the state and covariance matrices.
*/
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
// Radar updates
//set ekf_.H_ by setting to Hj which is the calculated the jacobian
Tools tools;
H_radar = tools.CalculateJacobian(ekf_.x_);
ekf_.H_ = H_radar;
//set ekf_.R_ by just using R_radar_
ekf_.R_ = R_radar_;
ekf_.UpdateEKF(measurement_pack.raw_measurements_);
} else {
// Laser updates
// set ekf_.H_ by just using H_laser_;
ekf_.H_ = H_laser_;
// set ekf_.R_ by just using R_laser_;
ekf_.R_ = R_laser_;
ekf_.Update(measurement_pack.raw_measurements_);
}
// print the output
cout << "x_ = " << ekf_.x_ << endl;
cout << "P_ = " << ekf_.P_ << endl;
}
#include "kalman_filter.h"
using Eigen::MatrixXd;
using Eigen::VectorXd;
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() {
/**
TODO:
* predict the state
*/
x_ = F_ * x_;
MatrixXd Ft = F_.transpose();
P_ = F_ * P_ * Ft + Q_;
}
void KalmanFilter::Update(const VectorXd &z) {
/**
TODO:
* update the state by using Kalman Filter equations
*/
VectorXd y = z - H_ * x_; //z_pred = H_ * x_
MatrixXd Ht = H_.transpose();
MatrixXd S = H_ * P_ * Ht + R_;
MatrixXd Si = S.inverse();
MatrixXd K = P_ * Ht * Si;
long x_size = x_.size();
MatrixXd I = MatrixXd::Identity(x_size, x_size);
//new state
x_ = x_ + (K * y);
P_ = (I - K * H_) * P_;
}
void KalmanFilter::UpdateEKF(const VectorXd &z) {
/**
TODO:
* update the state by using Extended Kalman Filter equations
*/
float px = x_(0);
float py = x_(1);
float vx = x_(2);
float vy = x_(3);
float rho = sqrt(px*px+py*py);
float phi = atan2(py,px);
float rho_dot;
if(fabs(rho)<0.0001){
rho_dot =0;
} else{
rho_dot = ((px*vx)+(py*vy))/rho;
}
VectorXd z_radar(3);
z_radar << rho, phi, rho_dot;
VectorXd y = z - z_radar;
MatrixXd Ht = H_.transpose();
MatrixXd S = H_ * P_ * Ht + R_;
MatrixXd Si = S.inverse();
MatrixXd K = P_ * Ht * Si;
long x_size = x_.size();
MatrixXd I = MatrixXd::Identity(x_size, x_size);
//new state
x_ = x_ + (K * y);
P_ = (I - K * H_) * P_;
}
#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) {
/**
TODO:
* Calculate the RMSE here.
*/
VectorXd rmse(4);
rmse << 0, 0, 0, 0;
// check the validity of the following inputs:
// * the estimation vector size should not be zero
// * the estimation vector size should equal ground truth vector size
if (estimations.size() != ground_truth.size()
|| estimations.size() == 0) {
cout << "Invalid estimation or ground_truth data" << endl;
return rmse;
}
//accumulate sqared residuals
for (unsigned 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 squared root
rmse = rmse.array().sqrt();
//return the result
return rmse;
}
MatrixXd Tools::CalculateJacobian(const VectorXd &x_state) {
/**
TODO:
* Calculate a Jacobian here.
*/
MatrixXd Hj(3, 4);
//recover state parameters
float px = x_state(0);
float py = x_state(1);
float vx = x_state(2);
float vy = x_state(3);
//pre-compute a set of terms to avoid repeated calculations
float c1 = px * px + py * py;
float c2 = sqrt(c1);
float 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment