@@ -42,17 +42,14 @@ For more information, please refer to <https://unlicense.org> */
42
42
// ! @file
43
43
// ! @brief The main Kalman filter class.
44
44
45
- #include " kalman_equation.hpp"
46
- #include " kalman_operator.hpp"
47
-
48
45
#include < functional>
49
46
#include < type_traits>
50
47
51
48
namespace fcarouge ::internal
52
49
{
53
50
template <typename State, typename Output, typename Input, typename Transpose,
54
51
typename Symmetrize, typename Divide, typename Identity,
55
- typename ... PredictionArguments>
52
+ typename Multiply, typename ... PredictionArguments>
56
53
struct kalman {
57
54
// ! @name Public Member Types
58
55
// ! @{
@@ -94,12 +91,18 @@ struct kalman {
94
91
// ! @details Also known as B.
95
92
using input_control = std::invoke_result_t <Divide, State, Input>;
96
93
94
+ using innovation = output;
95
+ using innovation_uncertainty = output_uncertainty;
96
+ using gain = std::invoke_result_t <Transpose, output_model>;
97
+
97
98
// ! @}
98
99
99
100
// ! @name Public Member Variables
100
101
// ! @{
101
102
102
103
// ! @brief The state estimate vector x.
104
+ // !
105
+ // ! @todo Is there a simpler, more portable way to get a zero initialization?
103
106
state x{ 0 * Identity ().template operator ()<state>() };
104
107
105
108
// ! @brief The estimate uncertainty, covariance matrix P.
@@ -167,38 +170,64 @@ struct kalman {
167
170
// ! @details
168
171
// Add prediction arguments?
169
172
std::function<state(const state &, const state_transition &)> predict_state =
170
- [](const state &x, const state_transition &f) { return state{ f * x }; };
173
+ [this ](const state &x, const state_transition &f) {
174
+ return state{ multiply (f, x) };
175
+ };
176
+
177
+ Transpose transpose;
178
+ Divide divide;
179
+ Symmetrize symmetrize;
180
+ Identity identity;
181
+ Multiply multiply;
171
182
172
183
// ! @}
173
184
174
185
// ! @name Public Member Functions
175
186
// ! @{
176
187
188
+ // ! @todo Do we want to allow the client to view the gain k? And the residual
189
+ // ! y?
190
+ // ! @todo Do we want to store i - k * h in a temporary result for reuse?
177
191
inline constexpr void update (const auto &...output_z)
178
192
{
193
+ const auto z{ output{ output_z... } };
194
+
179
195
h = transition_observation_h ();
180
196
r = noise_observation_r ();
181
- const auto z{ output{ output_z... } };
182
- internal::update<Transpose, Symmetrize, Divide, Identity>(x, p, h, r, z);
197
+
198
+ const innovation_uncertainty s{ h * p * transpose (h) + r };
199
+ const gain k{ divide (p * transpose (h), s) };
200
+ const innovation y{ z - h * x };
201
+ const auto i{ identity.template operator ()<estimate_uncertainty>() };
202
+
203
+ x = state{ x + k * y };
204
+ p = symmetrize (estimate_uncertainty{
205
+ (i - k * h) * p * transpose (i - k * h) + k * r * transpose (k) });
183
206
}
184
207
185
208
inline constexpr void predict (const PredictionArguments &...arguments,
186
209
const auto &...input_u)
187
210
{
188
211
const auto ff{ predict_state };
212
+ const auto u{ input{ input_u... } };
213
+
189
214
f = transition_state_f (arguments...);
190
215
q = noise_process_q (arguments...);
191
216
g = transition_control_g (arguments...);
192
- const auto u{ input{ input_u... } };
193
- internal::predict<Transpose, Symmetrize>(x, p, ff, f, q, g, u);
217
+
218
+ x = state{ ff (x, f) + g * u };
219
+ p = symmetrize (estimate_uncertainty{ f * p * transpose (f) + q });
194
220
}
195
221
196
222
inline constexpr void predict (const PredictionArguments &...arguments)
197
223
{
198
224
const auto ff{ predict_state };
225
+
199
226
f = transition_state_f (arguments...);
200
227
q = noise_process_q (arguments...);
201
- internal::predict<Transpose, Symmetrize>(x, p, ff, f, q);
228
+
229
+ x = state{ ff (x, f) };
230
+ p = symmetrize (estimate_uncertainty{ f * p * transpose (f) + q });
202
231
}
203
232
204
233
// ! @}
0 commit comments