Estimating the vehicle location.
Estimating the vehicle location.
In this example, we would like to estimate the location of the vehicle in the XY plane. The vehicle has an onboard location sensor that reports X and Y coordinates of the system. We assume constant acceleration dynamics. In this example we don't have a control variable u since we don't have control input. Let us assume a vehicle moving in a straight line in the X direction with a constant velocity. After traveling 400 meters the vehicle turns right, with a turning radius of 300 meters. During the turning maneuver, the vehicle experiences acceleration due to the circular motion (an angular acceleration). The measurements period: Δt = 1s (constant).
The initial guess, at the origin, lies some 500 m from the vehicle, far beyond its 22 m standard deviation: the first innovations are inconsistent until the estimate converges. The turn, from the seventeenth measurement, surprises the constant acceleration model again. The acceleration is never measured, yet through the turn its estimate tracks the centripetal acceleration v²/R of a 25 m/s vehicle on a 300 m radius.
#include "fcarouge/linalg.hpp"
#include <cassert>
#include <cmath>
namespace {
template <auto Size> using vector = column_vector<double, Size>;
template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
using state = fcarouge::state<vector<6>>;
[[maybe_unused]] const auto sample{[] -> int {
state{0., 0., 0., 0., 0., 0.},
output<vector<2>>,
estimate_uncertainty{{500., 0., 0., 0., 0., 0.},
{0., 500., 0., 0., 0., 0.},
{0., 0., 500., 0., 0., 0.},
{0., 0., 0., 500., 0., 0.},
{0., 0., 0., 0., 500., 0.},
{0., 0., 0., 0., 0., 500.}},
process_uncertainty{0.2 * 0.2 *
matrix<6, 6>{{0.25, 0.5, 0.5, 0., 0., 0.},
{0.5, 1., 1., 0., 0., 0.},
{0.5, 1., 1., 0., 0., 0.},
{0., 0., 0., 0.25, 0.5, 0.5},
{0., 0., 0., 0.5, 1., 1.},
{0., 0., 0., 0.5, 1., 1.}}},
output_uncertainty{{9., 0.}, {0., 9.}},
output_model{{1., 0., 0., 0., 0., 0.}, {0., 0., 0., 1., 0., 0.}},
state_transition{{1., 1., 0.5, 0., 0., 0.},
{0., 1., 1., 0., 0., 0.},
{0., 0., 1., 0., 0., 0.},
{0., 0., 0., 1., 1., 0.5},
{0., 0., 0., 0., 1., 1.},
{0., 0., 0., 0., 0., 1.}}};
filter.
update(-393.66, 300.4);
const auto step{[&filter](double position_x, double position_y) -> void {
filter.
update(position_x, position_y);
}};
step(-375.93, 301.78);
assert(std::abs(1 - (filter.
x()[0] / -277.8)) < 0.001 &&
std::abs(1 - (filter.
x()[1] / 148.3)) < 0.001 &&
std::abs(1 - (filter.
x()[2] / 94.5)) < 0.001 &&
std::abs(1 - (filter.
x()[3] / 249.8)) < 0.001 &&
std::abs(1 - (filter.
x()[4] / -85.9)) < 0.001 &&
std::abs(1 - (filter.
x()[5] / -63.6)) < 0.001 &&
"The state estimates expected at 0.1% accuracy.");
step(-351.04, 295.1);
step(-328.96, 305.19);
step(-299.35, 301.06);
step(-273.36, 302.05);
step(-245.89, 300);
step(-222.58, 303.57);
step(-198.03, 296.33);
step(-174.17, 297.65);
step(-146.32, 297.41);
step(-123.72, 299.61);
step(-103.47, 299.6);
step(-78.23, 302.39);
step(-52.63, 295.04);
step(-23.34, 300.09);
step(25.96, 294.72);
step(49.72, 298.61);
step(76.94, 294.64);
step(95.38, 284.88);
step(119.83, 272.82);
step(144.01, 264.93);
step(161.84, 251.46);
step(180.56, 241.27);
step(201.42, 222.98);
step(222.62, 203.73);
step(239.4, 184.1);
step(252.51, 166.12);
step(266.26, 138.71);
step(271.75, 119.71);
step(277.4, 100.41);
step(294.12, 79.76);
step(301.23, 50.62);
step(291.8, 32.99);
step(299.89, 2.14);
assert(std::abs(1 - (filter.
x()[0] / 298.5)) < 0.006 &&
std::abs(1 - (filter.
x()[1] / -1.65)) < 0.006 &&
std::abs(1 - (filter.
x()[2] / -1.9)) < 0.006 &&
std::abs(1 - (filter.
x()[3] / -22.5)) < 0.006 &&
std::abs(1 - (filter.
x()[4] / -26.1)) < 0.006 &&
std::abs(1 - (filter.
x()[5] / -0.64)) < 0.006 &&
"The state estimates expected at 0.6% accuracy.");
assert(std::abs(1 - (filter.
p()(0, 0) / 11.25)) < 0.001 &&
std::abs(1 - (filter.
p()(0, 1) / 4.5)) < 0.001 &&
std::abs(1 - (filter.
p()(0, 2) / 0.9)) < 0.001 &&
std::abs(1 - (filter.
p()(1, 1) / 2.4)) < 0.001 &&
std::abs(1 - (filter.
p()(2, 2) / 0.2)) < 0.001 &&
std::abs(1 - (filter.
p()(3, 3) / 11.25)) < 0.001 &&
"The estimate uncertainty expected at 0.1% accuracy."
"At this point, the position uncertainty px = py = 5, which means "
"that the standard deviation of the prediction is square root of 5m.");
return 0;
}()};
}
}
constexpr void predict(const auto &...arguments)
Produces estimates of the state variables and uncertainties.
constexpr decltype(auto) p(this auto &&self, const auto &...values)
Read, write the estimated covariance matrix P.
constexpr decltype(auto) x(this auto &&self, const auto &...values)
Read, write the estimated state column vector X.
constexpr void update(const auto &...arguments)
Updates the estimates with the outcome of a measurement.
The Kalman filter class and library top-level header.
Examples, tutorials, demonstrators of the library.
kalman(Arguments... arguments) -> kalman< kf::deduce_filter< Arguments... > >
Deduces the filter type from its declared configuration.