Skip to content

Commit

Permalink
[sample] add 2D vehicule location example
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancoisCarouge committed Apr 24, 2022
1 parent bbb1d0d commit 87f5db2
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy_test_coverage_coveralls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp source/*.cpp test/*.cpp -Iinclude -I/usr/local/include/eigen3 -O0 -g -std=c++23 -fmodules-ts --coverage -lstdc++
run: gcc-11 sample/*.cpp source/*.cpp test/*.cpp -Iinclude -I/usr/local/include/eigen3 -O0 -g -std=c++23 -fmodules-ts --coverage -lstdc++ -lm
- name: "Coverage: Base"
run: |
lcov --rc lcov_branch_coverage=1 --gcov-tool gcov-11 --capture --initial --directory . --output-file base.info
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/verify_test_memory_valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -g -O0 -std=c++23 -lstdc++
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -g -O0 -std=c++23 -lstdc++ -lm
- name: Test
run: valgrind --verbose ./a.out
2 changes: 1 addition & 1 deletion .github/workflows/verify_test_sanitizer_address.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer -lstdc++
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer -lstdc++ -lm
- name: Test
run: ASAN_OPTIONS=verbosity=2:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 ./a.out
2 changes: 1 addition & 1 deletion .github/workflows/verify_test_sanitizer_leak.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=leak -lstdc++
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=leak -lstdc++ -lm
- name: Test
run: LSAN_OPTIONS=verbosity=2 ./a.out
2 changes: 1 addition & 1 deletion .github/workflows/verify_test_sanitizer_thread.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=thread -lstdc++
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=thread -lstdc++ -lm
- name: Test
run: TSAN_OPTIONS=verbosity=2 ./a.out
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=undefined -lstdc++
run: gcc-11 sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -std=c++23 -g -fsanitize=undefined -lstdc++ -lm
- name: Test
run: UBSAN_OPTIONS=verbosity=2 ./a.out
2 changes: 1 addition & 1 deletion .github/workflows/verify_test_ubuntu-20-04_gcc-trunk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ jobs:
cmake --build . ;
sudo make install ) )
- name: Build
run: LD_LIBRARY_PATH=/opt/gcc-latest/lib64 LD_RUN_PATH=/opt/gcc-latest/lib64 /opt/gcc-latest/bin/gcc sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -Wall -Wextra -pedantic -std=c++23 -lstdc++
run: LD_LIBRARY_PATH=/opt/gcc-latest/lib64 LD_RUN_PATH=/opt/gcc-latest/lib64 /opt/gcc-latest/bin/gcc sample/*.cpp test/*.cpp source/*.cpp -Iinclude -I/usr/local/include/eigen3 -Wall -Wextra -pedantic -std=c++23 -lstdc++ -lm
- name: Run
run: ./a.out
6 changes: 4 additions & 2 deletions .github/workflows/verify_test_windows-2019_msvc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ jobs:
uses: actions/checkout@v3
- name: Install
uses: ilammy/msvc-dev-cmd@v1.10.0
- name: Version
run: cl
- name: Install Eigen
run: vcpkg install eigen3
- name: Install Eigen
run: env
- name: Build
run: cl /EHsc /std:c++latest /I include /TP sample/*.cpp source/*.cpp test/*.cpp
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ using kalman = fcarouge::kalman<double>;

kalman k;

k.state_x = kalman::state{ 60 };
k.estimate_uncertainty_p = kalman::estimate_uncertainty{ 15 * 15 };
k.transition_observation_h = []() { return kalman::observation{ 1 }; };
k.noise_observation_r = []() {
return kalman::observation_noise_uncertainty{ 5 * 5 };
k.state_x = 60;
k.estimate_uncertainty_p = 225;
k.transition_observation_h = [] { return kalman::observation{ 1 }; };
k.noise_observation_r = [] {
return kalman::observation_noise_uncertainty{ 25 };
};

k.update(48.54);
Expand All @@ -74,7 +74,7 @@ const double gravitational_acceleration{ -9.8 }; // m.s^-2
const std::chrono::milliseconds delta_time{ 250 };
kalman k;

k.state_x = kalman::state{ 0, 0 };
k.state_x = { 0, 0 };
k.estimate_uncertainty_p =
kalman::estimate_uncertainty{ { 500, 0 }, { 0, 500 } };
k.transition_state_f = [](const std::chrono::milliseconds &delta_time) {
Expand All @@ -92,8 +92,8 @@ k.transition_control_g = [](const std::chrono::milliseconds &delta_time) {
const auto dt{ std::chrono::duration<double>(delta_time).count() };
return kalman::control{ 0.0313, dt };
};
k.transition_observation_h = []() { return kalman::observation{ { 1, 0 } }; };
k.noise_observation_r = []() {
k.transition_observation_h = [] { return kalman::observation{ { 1, 0 } }; };
k.noise_observation_r = [] {
return kalman::observation_noise_uncertainty{ 400 };
};

Expand Down
4 changes: 2 additions & 2 deletions include/fcarouge/kalman.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ class kalman
// Functors could be replaced by the standard general-purpose polymorphic
// function wrapper `std::function` if lambda captures are needed.

observation (*transition_observation_h)() = []() {
observation (*transition_observation_h)() = [] {
return observation{ Identity<observation>()() };
};

observation_noise_uncertainty (*noise_observation_r)() = []() {
observation_noise_uncertainty (*noise_observation_r)() = [] {
return observation_noise_uncertainty{};
};

Expand Down
12 changes: 6 additions & 6 deletions sample/building_height.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ namespace
//! 55.01m, 55.15m, 49.89m, 40.85m, 46.72m, 50.05m, 51.27m, 49.95m.
//!
//! @example building_height.cpp
[[maybe_unused]] constexpr auto building_height{ []() {
// One-dimensional filter, constant system dynamic model.
[[maybe_unused]] constexpr auto building_height{ [] {
// A one-dimensional filter, constant system dynamic model.
using kalman = kalman<float>;
kalman k;

// Initialization
// One can estimate the building height simply by looking at it. The estimated
// building height is: 60 meters.
k.state_x = kalman::state{ 60 };
k.state_x = 60;

// Now we shall initialize the estimate uncertainty. A human’s estimation
// error (standard deviation) is about 15 meters: σ = 15. Consequently the
// variance is 225: σ^2 = 225.
k.estimate_uncertainty_p = kalman::estimate_uncertainty{ 15 * 15 };
k.estimate_uncertainty_p = 225;

// Prediction
// Now, we shall predict the next state based on the initialization values.
Expand All @@ -49,8 +49,8 @@ namespace
// The first measurement is: z1 = 48.54m. Since the standard deviation σ of
// the altimeter measurement error is 5, the variance σ^2 would be 25, thus
// the measurement uncertainty is: r1 = 25.
k.noise_observation_r = []() {
return kalman::observation_noise_uncertainty{ 5 * 5 };
k.noise_observation_r = [] {
return kalman::observation_noise_uncertainty{ 25 };
};
k.update(48.54);

Expand Down
22 changes: 12 additions & 10 deletions sample/liquid_temperature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,29 @@ namespace
//! 50.023°C, and 49.99°C.
//!
//! @example liquid_temperature.cpp
[[maybe_unused]] constexpr auto liquid_temperature{ []() {
// One-dimensional filter, constant system dynamic model.
[[maybe_unused]] constexpr auto liquid_temperature{ [] {
// A one-dimensional filter, constant system dynamic model.
using kalman = kalman<float>;
kalman k;

// Initialization
// Before the first iteration, we must initialize the Kalman filter and
// predict the next state (which is the first state). We don't know what the
// temperature of the liquid is, and our guess is 10°C.
k.state_x = kalman::state{ 10 };
k.state_x = 10;

// Our guess is very imprecise, so we set our initialization estimate error σ
// to 100. The estimate uncertainty of the initialization is the error
// variance σ^2: p0,0 = 100^2 = 10,000. This variance is very high. If we
// initialize with a more meaningful value, we will get faster Kalman filter
// convergence.
k.estimate_uncertainty_p = kalman::estimate_uncertainty{ 100 * 100 };
k.estimate_uncertainty_p = 100 * 100;

// Prediction
// Now, we shall predict the next state based on the initialization values. We
// think that we have an accurate model, thus we set the process noise
// variance q to 0.0001.
k.noise_process_q = []() {
k.noise_process_q = [] {
return kalman::process_noise_uncertainty{ 0.0001 };
};

Expand All @@ -67,13 +67,13 @@ namespace
// 0.1, the variance σ^2 would be 0.01, thus the measurement uncertainty is:
// r1 = 0.01. The measurement error (standard deviation) is 0.1 degrees
// Celsius.
k.noise_observation_r = []() {
k.noise_observation_r = [] {
return kalman::observation_noise_uncertainty{ 0.1 * 0.1 };
};

k.update(49.95);

// And so on.
// And so on, every measurements period: Δt = 5s (constant).
k.predict();
k.update(49.967);
k.predict();
Expand All @@ -92,15 +92,17 @@ namespace
k.update(50.023);
k.predict();
k.update(49.99);
k.predict();

// The estimate uncertainty quickly goes down, after 10 measurements:
assert(49.988 - 0.0001 < k.state_x && k.state_x < 49.988 + 0.0001 &&
"The filter estimates the liquid temperature at 49.988°C.");
assert(0.0013 - 0.0001 < k.estimate_uncertainty_p &&
k.estimate_uncertainty_p < 0.0013 + 0.0001 &&
"The estimate uncertainty is 0.0013, i.e. the estimate error standard "
"deviation is: 0.036°C.");

k.predict();

assert(49.988 - 0.0001 < k.state_x && k.state_x < 49.988 + 0.0001 &&
"The filter estimates the liquid temperature at 49.988°C.");
// So we can say that the liquid temperature estimate is: 49.988 ± 0.036°C.
// In this example we've measured a liquid temperature using the
// one-dimensional Kalman filter. Although the system dynamics include a
Expand Down

0 comments on commit 87f5db2

Please sign in to comment.