Skip to content

Commit 9d3f71b

Browse files
committed
🚀 [book/KF] Implementation details
1 parent fafb8b9 commit 9d3f71b

File tree

2 files changed

+119
-3
lines changed

2 files changed

+119
-3
lines changed

book/src/introduction.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,42 @@
11
# cppXplorers : Explorations in C++ for applied sciences
22

3-
`cppXplorers` is a collection of experiments and examples in modern C++, with a focus on applied sciences and engineering. The project is organized as a mono-repository, where each crate is independent and self-contained.
3+
`cppXplorers` is a collection of experiments and examples in modern C++, with a focus on applied sciences and engineering. The project is organized as a mono-repository, where each crate is independent and self-contained. All the sources can be found in the folder `crates` of the [repository](https://github.com/bstaber/cppxplorers/).
44

55
The purpose of this repository is to provide a space for exploring numerical methods, algorithms, and patterns in C++ in a practical and modular way. It is not intended as a tutorial or comprehensive learning resource, but rather as a set of working examples and references.
66

7-
Contributions are welcome. If you spot an issue, find an area that could be improved, or want to add your own example, feel free to open an issue or submit a pull request.
7+
Contributions are welcome. If you spot an issue, find an area that could be improved, or want to add your own example, feel free to open an issue or submit a pull request.
8+
9+
## Organisation and layout
10+
11+
This project has the following layout:
12+
13+
```bash
14+
├── book
15+
│ └── src
16+
└── crates
17+
├── kf_linear
18+
│ ├── include
19+
│ ├── src
20+
│ └── tests
21+
├── another_example
22+
│ ├── include
23+
│ ├── src
24+
│ └── tests
25+
├── another_example
26+
│ ├── include
27+
│ ├── src
28+
│ └── tests
29+
├── ...
30+
│ ├── include
31+
│ ├── src
32+
│ └── tests
33+
└── simple_optimizers
34+
├── include
35+
├── src
36+
└── tests
37+
```
38+
39+
* The `crates` folder contains all the examples. I apologize, I've been doing some Rust lately ([rustineers](https://github.com/bstaber/rustineers)).
40+
* Each example has its own headers, sources, and tests.
41+
* The book folder simply contains the sources for generating this book with `mdBook`.
42+
* Each chapter in the book will explain what's implemented in each example.

book/src/kf_linear.md

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,85 @@ $$
6262
K_t = P_t^{t-1} A_t^T(A_t P_t^{t-1}A_t^T + S)^{-1}\,.
6363
$$
6464

65-
Implementing the Kalman filter boils down to implement these few equations!
65+
Implementing the Kalman filter boils down to implement these few equations!
66+
67+
## C++ implementation
68+
69+
The following code provides a generic templated class `KFLinear` supporting both fixed-size and dynamic-size state and measurement vectors, using the [Eigen](https://eigen.tuxfamily.org/) linear algebra library.
70+
71+
<details>
72+
<summary>Click here to view the full implementation: <b>include/kf_linear.hpp</b>. We break into down in the sequel of this section. </summary>
73+
74+
```cpp
75+
{{#include ../../crates/kf_linear/include/kf_linear.hpp}}
76+
```
77+
</details>
78+
79+
80+
Here's the header file without the inlined implementations.
81+
82+
```cpp
83+
#pragma once
84+
85+
#include <Eigen/Dense>
86+
#include <iostream>
87+
#include <optional>
88+
#include <stdexcept>
89+
#include <vector>
90+
91+
/**
92+
* @brief Generic linear Kalman filter (templated, no control term).
93+
*
94+
* State-space model:
95+
* x_k = A x_{k-1} + w_{k-1}, w ~ N(0, Q)
96+
* z_k = H x_k + v_k, v ~ N(0, R)
97+
*
98+
* Template parameters:
99+
* Nx = state dimension (int or Eigen::Dynamic)
100+
* Ny = measurement dimension(int or Eigen::Dynamic)
101+
*/
102+
template <int Nx, int Ny> class KFLinear {
103+
public:
104+
using StateVec = Eigen::Matrix<double, Nx, 1>;
105+
using StateMat = Eigen::Matrix<double, Nx, Nx>;
106+
using MeasVec = Eigen::Matrix<double, Ny, 1>;
107+
using MeasMat = Eigen::Matrix<double, Ny, Ny>;
108+
using ObsMat = Eigen::Matrix<double, Ny, Nx>;
109+
110+
KFLinear(const StateVec &initial_state, const StateMat &initial_covariance,
111+
const StateMat &transition_matrix, const ObsMat &observation_matrix,
112+
const StateMat &process_covariance, const MeasMat &measurement_covariance);
113+
114+
void predict();
115+
void update(const MeasVec &z);
116+
void step(const std::optional<MeasVec> &measurement);
117+
std::vector<StateVec> filter(const std::vector<std::optional<MeasVec>> &measurements);
118+
119+
[[nodiscard]] const StateVec &state() const { return x_; }
120+
[[nodiscard]] const StateMat &covariance() const { return P_; }
121+
122+
void set_transition(const StateMat &A) { A_ = A; }
123+
void set_observation(const ObsMat &H) { H_ = H; }
124+
void set_process_noise(const StateMat &Q) { Q_ = Q; }
125+
void set_measurement_noise(const MeasMat &R){ R_ = R; }
126+
127+
private:
128+
StateMat A_, Q_, P_;
129+
ObsMat H_;
130+
MeasMat R_;
131+
StateVec x_;
132+
};
133+
```
134+
135+
A few comments:
136+
137+
- **Predict step**: The method `predict()` propagates the state and covariance using the transition matrix A and process noise covariance Q.
138+
139+
- **Update step**: The method `update(z)` corrects the prediction using a new measurement z. It computes the Kalman gain K efficiently by solving a linear system with LDLT factorization instead of forming the matrix inverse explicitly. The covariance update uses the Joseph form to ensure numerical stability and positive semi-definiteness.
140+
141+
- **Step and filter**: The `step()` method combines prediction with an optional update (useful when some measurements are missing). The `filter()` method processes an entire sequence of measurements, returning the sequence of estimated states.
142+
143+
- **Flexibility**:
144+
- Works with both fixed-size and dynamic-size Eigen matrices.
145+
- Provides setters to update system matrices online (e.g. if the model changes over time).
146+
- Uses `std::optional` to naturally handle missing observations.

0 commit comments

Comments
 (0)