Skip to content

Commit

Permalink
[filter] declarative paradigm
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancoisCarouge committed Feb 18, 2024
1 parent 657b7d9 commit 31194af
Show file tree
Hide file tree
Showing 39 changed files with 650 additions and 437 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Kalman Filter

The Kalman filter is a Bayesian filter that uses multivariate Gaussians, a recursive state estimator, a linear quadratic estimator (LQE), and an Infinite Impulse Response (IIR) filter. It is a control theory tool applicable to signal estimation, sensor fusion, or data assimilation problems. The filter is applicable for unimodal and uncorrelated uncertainties. The filter assumes white noise, propagation and measurement functions are differentiable, and that the uncertainty stays centered on the state estimate. The filter is the optimal linear filter under assumptions. The filter updates estimates by multiplying Gaussians rather than integrating differential equations. The filter predicts estimates by adding Gaussians. The filter maintains an estimate of the state and its uncertainty over the sequential estimation process. The filter is named after Rudolf E. Kálmán, who was one of the primary developers of its theory in 1960.

Designing a filter is as much art as science, with the following recipe. Model the real world in state-space notation. Then, compute and select the fundamental matrices, select the states *X*, *P*, the processes *F*, *Q*, the measurements *Z*, *R*, the measurement function *H*, and if the system has control inputs *U*, *G*. Evaluate the performance and iterate.
Expand Down
4 changes: 1 addition & 3 deletions benchmark/predict_1x1x0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ namespace fcarouge::benchmark {
namespace {
//! @benchmark Measure predict, empty benchmark performance.
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<float, float>;

kalman filter;
kalman filter{state{0.F}, output<float>};

for (auto _ : benchmark_state) {
::benchmark::ClobberMemory();
Expand Down
6 changes: 3 additions & 3 deletions benchmark/predict_1x1x1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ namespace fcarouge::benchmark {
namespace {
//! @benchmark Measure predict, empty benchmark performance.
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<float, float, float>;

kalman filter;
kalman filter{state{0.F}, output<float>, input<float>};
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

using kalman = decltype(filter);

for (auto _ : benchmark_state) {
const typename kalman::output u{uniformly_distributed(random_generator)};

Expand Down
7 changes: 4 additions & 3 deletions benchmark/predict_linalg_x1x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,14 @@ template <auto Size> using vector = column_vector<float, Size>;
//! states and inputs with the Eigen linear algebra backend.
template <auto StateSize, auto InputSize>
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<vector<StateSize>, float, vector<InputSize>>;

kalman filter;
kalman filter{state{vector<StateSize>{}}, output<float>,
input<vector<InputSize>>};
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

using kalman = decltype(filter);

for (auto _ : benchmark_state) {
float uv[InputSize];

Expand Down
6 changes: 3 additions & 3 deletions benchmark/update_1x1x0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ namespace fcarouge::benchmark {
namespace {
//! @benchmark Measure update, empty benchmark performance.
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<float, float>;

kalman filter;
kalman filter{state{0.F}, output<float>};
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

using kalman = decltype(filter);

for (auto _ : benchmark_state) {
const typename kalman::output z{uniformly_distributed(random_generator)};

Expand Down
6 changes: 3 additions & 3 deletions benchmark/update_1x1x1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ namespace fcarouge::benchmark {
namespace {
//! @benchmark Measure update, empty benchmark performance.
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<float, float, float>;

kalman filter;
kalman filter{state{0.F}, output<float>, input<float>};
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

using kalman = decltype(filter);

for (auto _ : benchmark_state) {
const typename kalman::output z{uniformly_distributed(random_generator)};

Expand Down
6 changes: 3 additions & 3 deletions benchmark/update_linalg_xx0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ template <auto Size> using vector = column_vector<float, Size>;
//! states and outputs with the Eigen linear algebra backend.
template <auto StateSize, auto OutputSize>
void bench(::benchmark::State &benchmark_state) {
using kalman = kalman<vector<StateSize>, vector<OutputSize>, void>;

kalman filter;
kalman filter{state{vector<StateSize>{}}, output<vector<OutputSize>>};
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

using kalman = decltype(filter);

for (auto _ : benchmark_state) {
float zv[OutputSize];

Expand Down
30 changes: 13 additions & 17 deletions include/fcarouge/internal/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,49 +45,44 @@ For more information, please refer to <https://unlicense.org> */
#include <type_traits>

namespace fcarouge {
template <typename, typename, typename, typename, typename> class kalman;
template <typename> class kalman;
} // namespace fcarouge

template <typename State, typename Output, typename Input, typename UpdateTypes,
typename PredictionTypes, typename Char>
template <typename Filter, typename Char>
// It is allowed to add template specializations for any standard library class
// template to the namespace std only if the declaration depends on at least one
// program-defined type and the specialization satisfies all requirements for
// the original template, except where such specializations are prohibited.
// NOLINTNEXTLINE(cert-dcl58-cpp)
struct std::formatter<
fcarouge::kalman<State, Output, Input, UpdateTypes, PredictionTypes>,
Char> {
using kalman =
fcarouge::kalman<State, Output, Input, UpdateTypes, PredictionTypes>;

struct std::formatter<fcarouge::kalman<Filter>, Char> {
constexpr auto parse(std::basic_format_parse_context<Char> &parse_context) {
return parse_context.begin();
}

//! @todo P2585 may be useful in simplifying and standardizing the support.
template <typename OutputIt>
auto format(const kalman &filter,
auto format(const fcarouge::kalman<Filter> &filter,
std::basic_format_context<OutputIt, Char> &format_context) const
-> OutputIt {
format_context.advance_to(
format_to(format_context.out(), R"({{"f": {}, )", filter.f()));

if constexpr (fcarouge::internal::has_input_control_method<kalman>) {
if constexpr (fcarouge::has_input_control<Filter>) {
format_context.advance_to(
format_to(format_context.out(), R"("g": {}, )", filter.g()));
}

if constexpr (fcarouge::internal::has_output_model_method<kalman>) {
if constexpr (fcarouge::has_output_model<Filter>) {
format_context.advance_to(
format_to(format_context.out(), R"("h": {}, )", filter.h()));
}

format_context.advance_to(format_to(
format_context.out(), R"("k": {}, "p": {}, )", filter.k(), filter.p()));

{
constexpr auto end{fcarouge::internal::repack_s<PredictionTypes>};
if constexpr (fcarouge::internal::has_prediction_types<Filter>) {
constexpr auto end{
fcarouge::internal::repack_s<typename Filter::prediction_types>};
constexpr decltype(end) begin{0};
constexpr decltype(end) next{1};
fcarouge::internal::for_constexpr<begin, end, next>(
Expand All @@ -104,13 +99,14 @@ struct std::formatter<

//! @todo Generalize out internal method concept when MSVC has better
//! if-constexpr-requires support.
if constexpr (fcarouge::internal::has_input_method<kalman>) {
if constexpr (fcarouge::has_input<Filter>) {
format_context.advance_to(
format_to(format_context.out(), R"("u": {}, )", filter.u()));
}

{
constexpr auto end{fcarouge::internal::repack_s<UpdateTypes>};
if constexpr (fcarouge::internal::has_update_types<Filter>) {
constexpr auto end{
fcarouge::internal::repack_s<typename Filter::update_types>};
constexpr decltype(end) begin{0};
constexpr decltype(end) next{1};
fcarouge::internal::for_constexpr<begin, end, next>(
Expand Down
Loading

0 comments on commit 31194af

Please sign in to comment.