OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
tracking.hpp
Go to the documentation of this file.
1#pragma once
2#include <ossia/detail/config.hpp>
3
4#include <cmath>
5
6#include <algorithm>
7#include <array>
8#include <cstdint>
9#include <vector>
10
28namespace ossia
29{
30
38{
41 {
42 float q00, q01, q11;
43 };
44
56 [[nodiscard]] static OSSIA_INLINE process_noise cwna(float sigma_a, float dt) noexcept
57 {
58 const float q = sigma_a * sigma_a;
59 const float dt2 = dt * dt;
60 return {q * dt2 * dt / 3.f, q * dt2 / 2.f, q * dt};
61 }
62
75 [[nodiscard]] static OSSIA_INLINE process_noise
76 diagonal(float std_p, float std_v, float time_ratio) noexcept
77 {
78 return {std_p * std_p * time_ratio, 0.f, std_v * std_v * time_ratio};
79 }
80
82 float p{}, v{};
83
85 float P00{}, P01{}, P11{};
86
88 OSSIA_INLINE void initiate(float p0, float var_p, float var_v) noexcept
89 {
90 p = p0;
91 v = 0.f;
92 P00 = var_p;
93 P01 = 0.f;
94 P11 = var_v;
95 }
96
98 OSSIA_INLINE void predict(float dt, const process_noise& q) noexcept
99 {
100 p += v * dt;
101 P00 += dt * (2.f * P01 + dt * P11) + q.q00;
102 P01 += dt * P11 + q.q01;
103 P11 += q.q11;
104 }
105
111 OSSIA_INLINE void update(float z, float r) noexcept
112 {
113 const float S = P00 + r;
114 if(!(S > 0.f)) [[unlikely]]
115 return; // degenerate (or NaN) innovation covariance: skip the update
116 const float K0 = P00 / S;
117 const float K1 = P01 / S;
118 const float y = z - p;
119 p += K0 * y;
120 v += K1 * y;
121 P01 -= K0 * P01;
122 P11 -= K1 * P01; // uses the already-updated P01 = (1-K0)P01: exact (I-KH)P
123 P00 -= K0 * P00;
124 }
125
128 [[nodiscard]] OSSIA_INLINE float gating_distance2(float z, float r) const noexcept
129 {
130 const float S = P00 + r;
131 const float y = z - p;
132 return S > 0.f ? (y * y) / S : 0.f;
133 }
134};
135
141template <std::size_t N>
143{
144 std::array<kalman_pv_filter, N> axes{};
145
146 OSSIA_INLINE void
147 initiate(const std::array<float, N>& p0, float var_p, float var_v) noexcept
148 {
149 for(std::size_t i = 0; i < N; i++)
150 axes[i].initiate(p0[i], var_p, var_v);
151 }
152
154 OSSIA_INLINE void predict(float dt, float sigma_a) noexcept
155 {
156 const auto q = kalman_pv_filter::cwna(sigma_a, dt);
157 for(auto& a : axes)
158 a.predict(dt, q);
159 }
160
162 OSSIA_INLINE void update(const std::array<float, N>& z, float r) noexcept
163 {
164 for(std::size_t i = 0; i < N; i++)
165 axes[i].update(z[i], r);
166 }
167
169 [[nodiscard]] OSSIA_INLINE float
170 gating_distance2(const std::array<float, N>& z, float r) const noexcept
171 {
172 float d = 0.f;
173 for(std::size_t i = 0; i < N; i++)
174 d += axes[i].gating_distance2(z[i], r);
175 return d;
176 }
177
178 [[nodiscard]] OSSIA_INLINE std::array<float, N> position() const noexcept
179 {
180 std::array<float, N> r;
181 for(std::size_t i = 0; i < N; i++)
182 r[i] = axes[i].p;
183 return r;
184 }
185
186 [[nodiscard]] OSSIA_INLINE std::array<float, N> velocity() const noexcept
187 {
188 std::array<float, N> r;
189 for(std::size_t i = 0; i < N; i++)
190 r[i] = axes[i].v;
191 return r;
192 }
193
194 OSSIA_INLINE void set_velocity(const std::array<float, N>& v) noexcept
195 {
196 for(std::size_t i = 0; i < N; i++)
197 axes[i].v = v[i];
198 }
199};
200
205{
206 float cost;
207 std::int32_t track, det;
208};
209
228 std::vector<match_candidate>& candidates, std::int32_t* track_match,
229 std::size_t n_tracks, char* det_used, std::size_t n_dets) noexcept
230{
231 std::stable_sort(
232 candidates.begin(), candidates.end(),
233 [](const match_candidate& a, const match_candidate& b) {
234 return a.cost < b.cost;
235 });
236 for(const auto& c : candidates)
237 {
238 if(c.track < 0 || std::size_t(c.track) >= n_tracks)
239 continue;
240 if(c.det < 0 || std::size_t(c.det) >= n_dets)
241 continue;
242 if(track_match[c.track] >= 0 || det_used[c.det])
243 continue;
244 track_match[c.track] = c.det;
245 det_used[c.det] = 1;
246 }
247}
248
249}
Definition git_info.h:7
void greedy_assignment(std::vector< match_candidate > &candidates, std::int32_t *track_match, std::size_t n_tracks, char *det_used, std::size_t n_dets) noexcept
Greedy bipartite matching: repeatedly take the cheapest remaining candidate whose track and detection...
Definition tracking.hpp:227
N independent position-velocity Kalman filters: a tracked N-D point.
Definition tracking.hpp:143
OSSIA_INLINE void predict(float dt, float sigma_a) noexcept
Propagate dt seconds forward with acceleration noise sigma_a.
Definition tracking.hpp:154
OSSIA_INLINE float gating_distance2(const std::array< float, N > &z, float r) const noexcept
Squared Mahalanobis distance, chi-square with N DOF.
Definition tracking.hpp:170
OSSIA_INLINE void update(const std::array< float, N > &z, float r) noexcept
Fold in a position measurement with isotropic variance r.
Definition tracking.hpp:162
Discrete process noise covariance for one predict step.
Definition tracking.hpp:41
Scalar constant-velocity Kalman filter, one axis of a tracked point.
Definition tracking.hpp:38
float p
State: position and velocity (units, units/s).
Definition tracking.hpp:82
static OSSIA_INLINE process_noise cwna(float sigma_a, float dt) noexcept
Discretised continuous-white-noise-acceleration process noise.
Definition tracking.hpp:56
OSSIA_INLINE void update(float z, float r) noexcept
Fold in a position measurement.
Definition tracking.hpp:111
float P00
Covariance, symmetric 2x2: [[P00, P01], [P01, P11]].
Definition tracking.hpp:85
OSSIA_INLINE void predict(float dt, const process_noise &q) noexcept
Propagate the state dt seconds forward.
Definition tracking.hpp:98
OSSIA_INLINE void initiate(float p0, float var_p, float var_v) noexcept
Start tracking at p0 with the given initial variances.
Definition tracking.hpp:88
OSSIA_INLINE float gating_distance2(float z, float r) const noexcept
Definition tracking.hpp:128
static OSSIA_INLINE process_noise diagonal(float std_p, float std_v, float time_ratio) noexcept
Ad-hoc diagonal process noise, dt-scaled.
Definition tracking.hpp:76
One candidate pairing for greedy bipartite assignment.
Definition tracking.hpp:205