ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
iekf.c
Go to the documentation of this file.
1
5#include "iekf.h"
6#include "so3.h"
7#include "arm_math.h"
8#include <string.h>
9#include <math.h>
10
11#define NX IEKF_NX
12
13static void condition_covariance(iekf_t *f);
14
15/* ---- CMSIS-DSP wrappers (dst always distinct from the sources) ---------- */
16static void mmul(float *C, const float *A, uint16_t ar, uint16_t ac,
17 const float *B, uint16_t bc)
18{
19 arm_matrix_instance_f32 mA, mB, mC;
20 arm_mat_init_f32(&mA, ar, ac, (float32_t *)A);
21 arm_mat_init_f32(&mB, ac, bc, (float32_t *)B);
22 arm_mat_init_f32(&mC, ar, bc, C);
23 (void)arm_mat_mult_f32(&mA, &mB, &mC);
24}
25
26static void mtrans(float *At, const float *A, uint16_t r, uint16_t c)
27{
28 arm_matrix_instance_f32 mA, mT;
29 arm_mat_init_f32(&mA, r, c, (float32_t *)A);
30 arm_mat_init_f32(&mT, c, r, At);
31 (void)arm_mat_trans_f32(&mA, &mT);
32}
33
34static void symmetrize(float *P)
35{
36 for (int r = 0; r < NX; ++r)
37 for (int c = r + 1; c < NX; ++c) {
38 const float m = 0.5f * (P[r*NX + c] + P[c*NX + r]);
39 P[r*NX + c] = m;
40 P[c*NX + r] = m;
41 }
42}
43
44/* ------------------------------------------------------------------------ */
46{
47 c->sigma_gyro = 0.5f * 0.017453293f;
48 c->sigma_bias = 1e-4f;
49 c->sigma_acc = 0.05f;
50 c->sigma_mag = 0.05f;
51 c->acc_tol = 0.08f;
52 c->mag_tol = 0.08f;
53 c->p0_att = 1e-2f;
54 c->p0_bias = 1e-4f;
55 c->estimate_bias = 1;
56 c->adaptive = 1;
57 c->tilt_comp_mag = 0;
58 c->acc_nis_gate = 0.0f;
59 c->mag_nis_gate = 0.0f;
60 c->infl_decay = 0.0f;
61 c->decouple = 0;
62 c->dip_tol = 0.0f;
63 c->reset_jacobian = 1;
64 c->tangent_innov = 1;
65 c->infl_max = 1e4f;
66 c->lockout_updates = 0;
67 c->lockout_p_bump = 0.0f;
68 c->grace_updates = 0;
69 c->persist_decay = 0.0f;
70 c->persist_ratio = 0.6f;
71 c->persist_min = 0.02f;
72}
73
74void iekf_init(iekf_t *f, const iekf_config_t *cfg, const iekf_seed_t *s)
75{
76 memset(f, 0, sizeof *f);
77 f->cfg = *cfg;
78 f->E_last[0] = f->E_last[4] = f->E_last[8] = 1.0f;
79 memcpy(f->R, s->R0, sizeof f->R);
81 if (cfg->estimate_bias) memcpy(f->b, s->b0, sizeof f->b);
82
83 memcpy(f->g_ref, s->g_ref, sizeof f->g_ref); (void)vec3_normalize(f->g_ref);
84 memcpy(f->m_ref, s->m_ref, sizeof f->m_ref); (void)vec3_normalize(f->m_ref);
85 f->nom_acc = (s->nom_acc > 1e-6f) ? s->nom_acc : 1.0f;
86 f->nom_mag = (s->nom_mag > 1e-6f) ? s->nom_mag : 1.0f;
87 f->acc_infl = f->mag_infl = 1.0f;
88 f->dip_ref = acosf(fmaxf(-1.0f, fminf(1.0f, vec3_dot(f->g_ref, f->m_ref))));
89 mat3t_vec(f->R, f->g_ref, f->last_acc_dir);
90
91 /* Without bias estimation the bias block stays identically zero:
92 * the filter reduces exactly to the 3-state MATLAB version. */
93 for (int i = 0; i < 3; ++i) {
94 f->P[i*NX + i] = cfg->p0_att;
95 f->P[(i + 3)*NX + (i + 3)] = cfg->estimate_bias ? cfg->p0_bias : 0.0f;
96 }
97}
98
99void iekf_propagate_dtheta(iekf_t *f, const float dtheta[3], float h)
100{
101 float phi[3], E[9], Rn[9];
102 for (int i = 0; i < 3; ++i) phi[i] = dtheta[i] - f->b[i] * h;
103
104 /* Exact integration on the group */
105 so3_exp(phi, E);
106 mat3_mul(f->R, E, Rn);
107 memcpy(f->R, Rn, sizeof Rn);
109 memcpy(f->E_last, E, sizeof E);
110
111 /* F does not depend on R_hat (group-affine propagation): it depends on the
112 * measured rate and on the bias estimate, through phi = dtheta - b*h */
113 memset(f->wF, 0, sizeof f->wF);
114 for (int i = 0; i < NX; ++i) f->wF[i*NX + i] = 1.0f;
115 for (int r = 0; r < 3; ++r) {
116 for (int c = 0; c < 3; ++c) f->wF[r*NX + c] = E[c*3 + r]; /* exp(-phi) = E' */
117 if (f->cfg.estimate_bias) f->wF[r*NX + 3 + r] = -h;
118 }
119
120 /* P = F P F' + Q */
121 mmul(f->wA, f->wF, NX, NX, f->P, NX);
122 mtrans(f->wB, f->wF, NX, NX);
123 mmul(f->P, f->wA, NX, NX, f->wB, NX);
124
125 const float qg = f->cfg.sigma_gyro * f->cfg.sigma_gyro * h;
126 const float qb = f->cfg.estimate_bias ? f->cfg.sigma_bias * f->cfg.sigma_bias * h : 0.0f;
127 for (int i = 0; i < 3; ++i) {
128 f->P[i*NX + i] += qg;
129 f->P[(i + 3)*NX + (i + 3)] += qb;
130 }
132}
133
134void iekf_propagate(iekf_t *f, const float gyro[3], float h)
135{
136 const float dth[3] = { gyro[0]*h, gyro[1]*h, gyro[2]*h };
137 iekf_propagate_dtheta(f, dth, h);
138}
139
140/* P_aa <- J P_aa J', P_ab <- J P_ab, P_ba <- P_ab', J = I - 1/2 [dth]x */
141static void reset_covariance(iekf_t *f, const float dth[3])
142{
143 float J[9], S[9], A[9], T[9], Jt[9];
144 so3_skew(dth, S);
145 for (int i = 0; i < 9; ++i) J[i] = -0.5f * S[i];
146 J[0] += 1.0f; J[4] += 1.0f; J[8] += 1.0f;
147 for (int r = 0; r < 3; ++r)
148 for (int c = 0; c < 3; ++c) { A[3*r + c] = f->P[r*NX + c]; Jt[3*c + r] = J[3*r + c]; }
149 mat3_mul(J, A, T);
150 mat3_mul(T, Jt, A);
151 for (int r = 0; r < 3; ++r)
152 for (int c = 0; c < 3; ++c) f->P[r*NX + c] = A[3*r + c];
153 if (f->cfg.estimate_bias) {
154 for (int c = 0; c < 3; ++c) { /* columns of the P_ab block */
155 const float b0 = f->P[0*NX + 3 + c], b1 = f->P[1*NX + 3 + c], b2 = f->P[2*NX + 3 + c];
156 for (int r = 0; r < 3; ++r) {
157 const float v = J[3*r]*b0 + J[3*r + 1]*b1 + J[3*r + 2]*b2;
158 f->P[r*NX + 3 + c] = v;
159 f->P[(3 + c)*NX + r] = v; /* P_ba = P_ab' */
160 }
161 }
162 }
163}
164
165/* Single-precision numerical hygiene: exact symmetry and a diagonal never
166 * below a minimum floor (the Joseph form guarantees P >= 0 in exact arithmetic,
167 * not in float32). The bias block stays zero when not estimated. */
169{
170 symmetrize(f->P);
171 for (int i = 0; i < 3; ++i)
172 if (f->P[i*NX + i] < IEKF_P_ATT_MIN) f->P[i*NX + i] = IEKF_P_ATT_MIN;
173 if (f->cfg.estimate_bias)
174 for (int i = 3; i < 6; ++i)
175 if (f->P[i*NX + i] < IEKF_P_BIAS_MIN) f->P[i*NX + i] = IEKF_P_BIAS_MIN;
176}
177
178typedef enum { PROJ_NONE = 0, PROJ_TILT_ONLY = 1, PROJ_YAW_ONLY = 2 } proj_t;
179
180/* Keeps only the part of e orthogonal to the unit vector u: the radial part of a
181 * normalised-vector innovation, (1 - cos eps) along yhat, is not in the range of
182 * H = [[yhat]x 0], so it carries no correction and would be weighted by R alone
183 * in the NIS (spurious inflation for large errors). */
184static void tangent_part(float e[3], const float u[3])
185{
186 const float d = vec3_dot(e, u);
187 for (int i = 0; i < 3; ++i) e[i] -= d * u[i];
188}
189
190/* Projects the columns of K (attitude and bias rows) w.r.t. the vertical axis
191 * expressed in the body frame, a = R' * g_ref:
192 * TILT_ONLY: removes the component along a -> the measurement cannot touch yaw
193 * YAW_ONLY : keeps only the component along a -> the measurement touches only yaw
194 * The gain is no longer optimal, but the Joseph form keeps P consistent with
195 * ANY gain: the covariance stays correct. */
196static void project_gain(iekf_t *f, proj_t proj)
197{
198 if (proj == PROJ_NONE) return;
199 float a[3];
200 mat3t_vec(f->R, f->g_ref, a);
201 (void)vec3_normalize(a);
202 for (int blk = 0; blk < 2; ++blk) {
203 if (blk == 1 && !f->cfg.estimate_bias) break;
204 for (int col = 0; col < 3; ++col) {
205 float *k0 = &f->wK[(3*blk + 0)*3 + col];
206 float *k1 = &f->wK[(3*blk + 1)*3 + col];
207 float *k2 = &f->wK[(3*blk + 2)*3 + col];
208 const float d = a[0]*(*k0) + a[1]*(*k1) + a[2]*(*k2);
209 if (proj == PROJ_TILT_ONLY) {
210 *k0 -= d*a[0]; *k1 -= d*a[1]; *k2 -= d*a[2];
211 } else {
212 *k0 = d*a[0]; *k1 = d*a[1]; *k2 = d*a[2];
213 }
214 }
215 }
216}
217
218/* Common vector correction (MATLAB applyUpdate) with:
219 * - robust inflation of R driven by the normalised innovation (NIS):
220 * an external acceleration perpendicular to gravity barely changes |a|
221 * but rotates the measured direction a lot: NIS sees it, the magnitude does not;
222 * - memory of the inflation (*infl decays slowly towards 1), because real
223 * disturbances oscillate and cross zero;
224 * - optional gain projection (yaw / tilt decoupling).
225 * Returns the NIS computed with the nominal R. */
226static float vector_update(iekf_t *f, const float y[3], const float yhat[3], float r,
227 float nis_gate, float *infl, proj_t proj)
228{
229 float S0[9], S3[9], Si[9], S[9], innov[3], dx[NX];
230
231 memset(f->wH, 0, sizeof f->wH);
232 so3_skew(yhat, S);
233 for (int rr = 0; rr < 3; ++rr)
234 for (int c = 0; c < 3; ++c) f->wH[rr*NX + c] = S[rr*3 + c];
235
236 mtrans(f->wHt, f->wH, 3, NX); /* H' 6x3 */
237 mmul(f->wPHt, f->P, NX, NX, f->wHt, 3); /* P H' 6x3 */
238 mmul(S0, f->wH, 3, NX, f->wPHt, 3); /* H P H' 3x3 */
239 for (int i = 0; i < 3; ++i) innov[i] = y[i] - yhat[i];
240 if (f->cfg.tangent_innov) tangent_part(innov, yhat);
241
242 /* NIS with the nominal R */
243 float nis = 0.0f;
244 memcpy(S3, S0, sizeof S3);
245 for (int i = 0; i < 3; ++i) S3[i*3 + i] += r;
246 if (mat3_inv(S3, Si)) return 0.0f;
247 float t[3];
248 mat3_vec(Si, innov, t);
249 nis = vec3_dot(innov, t);
250
251 /* inflation: instantaneous NIS/gate, with memory */
252 float k = 1.0f;
253 if (nis_gate > 0.0f && infl) {
254 const float inst = nis / nis_gate;
255 float g = *infl * f->cfg.infl_decay;
256 if (g < 1.0f) g = 1.0f;
257 if (inst > g) g = inst;
258 if (g > f->cfg.infl_max) g = f->cfg.infl_max;
259 *infl = g;
260 k = g;
261 }
262 const float re = r * k;
263 if (k != 1.0f) {
264 memcpy(S3, S0, sizeof S3);
265 for (int i = 0; i < 3; ++i) S3[i*3 + i] += re;
266 if (mat3_inv(S3, Si)) return nis;
267 }
268 mmul(f->wK, f->wPHt, NX, 3, Si, 3); /* K = P H' S^-1 6x3 */
269 project_gain(f, proj);
270
271 for (int i = 0; i < NX; ++i)
272 dx[i] = f->wK[i*3]*innov[0] + f->wK[i*3 + 1]*innov[1] + f->wK[i*3 + 2]*innov[2];
273
274 /* Retraction onto SO(3) */
275 float E[9], Rn[9];
276 so3_exp(dx, E);
277 mat3_mul(f->R, E, Rn);
278 memcpy(f->R, Rn, sizeof Rn);
280 if (f->cfg.estimate_bias) { /* dx(4:6) estimates b_true - b_hat */
281 f->b[0] += dx[3]; f->b[1] += dx[4]; f->b[2] += dx[5];
282 }
283
284 /* Joseph form: P = (I-KH) P (I-KH)' + re K K' (valid for any K) */
285 mmul(f->wA, f->wK, NX, 3, f->wH, NX); /* KH */
286 for (int i = 0; i < NX*NX; ++i) f->wA[i] = -f->wA[i];
287 for (int i = 0; i < NX; ++i) f->wA[i*NX + i] += 1.0f;
288 mmul(f->wB, f->wA, NX, NX, f->P, NX); /* (I-KH) P */
289 mtrans(f->wF, f->wA, NX, NX); /* (I-KH)' (wF reused) */
290 mmul(f->P, f->wB, NX, NX, f->wF, NX);
291 for (int rr = 0; rr < NX; ++rr)
292 for (int c = 0; c < NX; ++c)
293 f->P[rr*NX + c] += re * (f->wK[rr*3]*f->wK[c*3] + f->wK[rr*3 + 1]*f->wK[c*3 + 1]
294 + f->wK[rr*3 + 2]*f->wK[c*3 + 2]);
295 symmetrize(f->P);
296
297 /* Error reset: after R <- R*exp(dtheta) the error is defined w.r.t. the NEW
298 * estimate, delta' ~ delta - dtheta - 1/2 [dtheta]x delta, hence
299 * P_aa <- J P_aa J', P_ab <- J P_ab with J = I - 1/2 [dtheta]x.
300 * Negligible at steady state, relevant for large corrections (convergence). */
301 if (f->cfg.reset_jacobian) reset_covariance(f, dx);
303 return nis;
304}
305
306static float adaptive_var(float r0, float n, float nom, float tol, int adaptive, float *dev_out)
307{
308 const float dev = fabsf(n - nom) / nom;
309 *dev_out = dev;
310 if (!adaptive) return r0;
311 const float x = dev / tol;
312 return r0 * (1.0f + x*x);
313}
314
315int iekf_update_acc(iekf_t *f, const float acc[3])
316{
317 const float na = vec3_norm(acc);
318 if (na < 1e-9f) return 0;
319 float y[3] = { acc[0]/na, acc[1]/na, acc[2]/na }, yhat[3];
320 memcpy(f->last_acc_dir, y, sizeof y);
321 mat3t_vec(f->R, f->g_ref, yhat);
322
323 const float r = adaptive_var(f->cfg.sigma_acc * f->cfg.sigma_acc, na, f->nom_acc,
324 f->cfg.acc_tol, f->cfg.adaptive, &f->last_acc_dev);
325 for (int i = 0; i < 3; ++i) f->last_acc_innov_b[i] = y[i] - yhat[i];
326 if (f->cfg.tangent_innov) tangent_part(f->last_acc_innov_b, yhat); /* as in vector_update */
327 const int trusted = f->acc_trusted || f->acc_grace > 0;
328 if (f->acc_grace > 0) f->acc_grace--;
329 if (trusted) f->acc_infl = 1.0f;
330 f->last_acc_nis = vector_update(f, y, yhat, r,
331 trusted ? 0.0f : f->cfg.acc_nis_gate, &f->acc_infl,
333 f->acc_trusted = 0;
334
335 /* persistence of the innovation in the world frame (the innovation is the one
336 * computed BEFORE the update, i.e. independent of the correction just applied) */
337 {
338 float ew[3];
339 mat3_vec(f->R, f->last_acc_innov_b, ew);
340 const float a = f->cfg.persist_decay;
341 for (int i = 0; i < 3; ++i) f->innov_w_mean[i] = a*f->innov_w_mean[i] + (1.0f - a)*ew[i];
342 f->innov_w_pow = a*f->innov_w_pow + (1.0f - a)*vec3_dot(ew, ew);
343 }
344
345 /* lockout protection */
346 if (f->cfg.lockout_updates > 0) {
347 const float m2 = vec3_dot(f->innov_w_mean, f->innov_w_mean);
348 const int persistent = (f->innov_w_pow > 0.0f) &&
349 (m2 > f->cfg.persist_ratio * f->innov_w_pow) &&
350 (m2 > f->cfg.persist_min * f->cfg.persist_min);
351 if (f->acc_infl > 2.0f) {
352 if (++f->acc_gated_run >= f->cfg.lockout_updates && persistent) {
353 for (int i = 0; i < 3; ++i) f->P[i*NX + i] += f->cfg.lockout_p_bump;
354 f->acc_infl = 1.0f;
355 f->acc_gated_run = 0;
357 f->lockouts++;
358 }
359 } else {
360 f->acc_gated_run = 0;
361 }
362 }
363 return (f->last_acc_dev > f->cfg.acc_tol) || (f->acc_infl > 2.0f);
364}
365
366int iekf_update_mag(iekf_t *f, const float mag[3])
367{
368 return iekf_update_mag_ex(f, mag, 0.0f);
369}
370
371int iekf_update_mag_ex(iekf_t *f, const float mag[3], float extra_var)
372{
373 const float nm = vec3_norm(mag);
374 if (nm < 1e-9f) return 0;
375 float y[3] = { mag[0]/nm, mag[1]/nm, mag[2]/nm }, yhat[3];
376
377 if (f->cfg.tilt_comp_mag) {
378 /* Tilt-compensated compass: only the horizontal component matters.
379 * Requires a world frame with vertical z -> guaranteed by calib.c. */
380 float hw[3], bw[3];
381 mat3_vec(f->R, y, hw);
382 bw[0] = sqrtf(hw[0]*hw[0] + hw[1]*hw[1]);
383 bw[1] = 0.0f;
384 bw[2] = hw[2];
385 mat3t_vec(f->R, bw, yhat);
386 } else {
387 mat3t_vec(f->R, f->m_ref, yhat);
388 }
389
390 float r = adaptive_var(f->cfg.sigma_mag * f->cfg.sigma_mag, nm, f->nom_mag,
391 f->cfg.mag_tol, f->cfg.adaptive, &f->last_mag_dev);
392 /* Magnetic dip check: angle between the measured field and gravity,
393 * independent of the attitude estimate (a yaw error does not change it). */
394 f->last_dip_dev = 0.0f;
395 if (f->cfg.dip_tol > 0.0f) {
396 const float dip = acosf(fmaxf(-1.0f, fminf(1.0f, vec3_dot(y, f->last_acc_dir))));
397 f->last_dip_dev = fabsf(dip - f->dip_ref);
398 const float x = f->last_dip_dev / f->cfg.dip_tol;
399 r *= 1.0f + x*x;
400 }
401 r += extra_var;
402 f->last_mag_nis = vector_update(f, y, yhat, r, f->cfg.mag_nis_gate, &f->mag_infl,
404 return (f->last_mag_dev > f->cfg.mag_tol) || (f->mag_infl > 2.0f)
405 || (f->cfg.dip_tol > 0.0f && f->last_dip_dev > f->cfg.dip_tol);
406}
407
408void iekf_get_quat(const iekf_t *f, float q[4])
409{
410 so3_to_quat(f->R, q);
411}
412
413void iekf_reset_attitude(iekf_t *f, const float R0[9], float p0_att)
414{
415 memcpy(f->R, R0, sizeof f->R);
417 for (int r = 0; r < 3; ++r)
418 for (int c = 0; c < NX; ++c) {
419 f->P[r*NX + c] = (r == c) ? p0_att : 0.0f; /* attitude rows */
420 f->P[c*NX + r] = (r == c) ? p0_att : 0.0f; /* attitude columns */
421 }
422 f->acc_infl = f->mag_infl = 1.0f;
423 f->acc_gated_run = 0;
425 memset(f->innov_w_mean, 0, sizeof f->innov_w_mean);
426 f->innov_w_pow = 0.0f;
428}
static batt_state_t s
Definition battery.c:21
static struct @10 B
uint32_t n
Definition calib_mgr.c:35
static struct @7 A
static struct @11 C
static float vector_update(iekf_t *f, const float y[3], const float yhat[3], float r, float nis_gate, float *infl, proj_t proj)
Definition iekf.c:226
int iekf_update_mag_ex(iekf_t *f, const float mag[3], float extra_var)
As above, with an additional per-component variance (e.g.
Definition iekf.c:371
static void reset_covariance(iekf_t *f, const float dth[3])
Definition iekf.c:141
static float adaptive_var(float r0, float n, float nom, float tol, int adaptive, float *dev_out)
Definition iekf.c:306
int iekf_update_mag(iekf_t *f, const float mag[3])
Definition iekf.c:366
void iekf_propagate_dtheta(iekf_t *f, const float dtheta[3], float h)
Propagation with a measured angle increment (bias NOT yet removed): phi = dtheta - b*dt.
Definition iekf.c:99
#define NX
Definition iekf.c:11
void iekf_propagate(iekf_t *f, const float gyro[3], float h)
Single-sample case: dtheta = gyro*dt (compatible with the previous port)
Definition iekf.c:134
static void mmul(float *C, const float *A, uint16_t ar, uint16_t ac, const float *B, uint16_t bc)
Definition iekf.c:16
proj_t
Definition iekf.c:178
@ PROJ_TILT_ONLY
Definition iekf.c:178
@ PROJ_YAW_ONLY
Definition iekf.c:178
@ PROJ_NONE
Definition iekf.c:178
void iekf_init(iekf_t *f, const iekf_config_t *cfg, const iekf_seed_t *s)
Definition iekf.c:74
void iekf_get_quat(const iekf_t *f, float q[4])
Definition iekf.c:408
int iekf_update_acc(iekf_t *f, const float acc[3])
Return 1 if the measurement was "gated" (de-weighted), 0 otherwise.
Definition iekf.c:315
void iekf_reset_attitude(iekf_t *f, const float R0[9], float p0_att)
Re-initialisation of the attitude away from rest (estimator reset after a failsafe,...
Definition iekf.c:413
static void project_gain(iekf_t *f, proj_t proj)
Definition iekf.c:196
void iekf_default_config(iekf_config_t *c)
Definition iekf.c:45
static void symmetrize(float *P)
Definition iekf.c:34
static void condition_covariance(iekf_t *f)
Definition iekf.c:168
static void tangent_part(float e[3], const float u[3])
Definition iekf.c:184
static void mtrans(float *At, const float *A, uint16_t r, uint16_t c)
Definition iekf.c:26
Attitude IEKF on SO(3), C port of iekfAttitude.m.
#define IEKF_P_ATT_MIN
rad^2 : floor on the diagonal of P
Definition iekf.h:30
#define IEKF_P_BIAS_MIN
(rad/s)^2
Definition iekf.h:31
void so3_exp(const float phi[3], float R[9])
Definition so3.c:22
int mat3_inv(const float A[9], float B[9])
0 = OK
Definition so3.c:127
void mat3_vec(const float A[9], const float x[3], float y[3])
y = A*x
Definition so3.c:113
void so3_to_quat(const float R[9], float q[4])
Definition so3.c:80
void mat3t_vec(const float A[9], const float x[3], float y[3])
y = A'*x
Definition so3.c:120
float vec3_norm(const float v[3])
Definition so3.c:47
void mat3_mul(const float A[9], const float B[9], float C[9])
C = A*B
Definition so3.c:106
void so3_orthonormalize(float R[9])
Definition so3.c:65
float vec3_dot(const float a[3], const float b[3])
Definition so3.c:46
int vec3_normalize(float v[3])
0 = OK
Definition so3.c:56
void so3_skew(const float v[3], float S[9])
Definition so3.c:15
Single-precision SO(3) Lie-group utilities (port of expSO3.m / skewSym.m + firmware helpers).
float mag_tol
Definition iekf.h:38
float sigma_mag
Definition iekf.h:36
uint8_t adaptive
Definition iekf.h:42
uint8_t decouple
1: acc corrects only roll/pitch, mag only yaw
Definition iekf.h:56
float infl_max
— protection against "lockout" of the NIS inflation — If the estimate is truly wrong,...
Definition iekf.h:77
uint8_t reset_jacobian
1: transport P after the retraction (default)
Definition iekf.h:57
float sigma_bias
rad/s^2, bias random walk
Definition iekf.h:34
float p0_att
initial attitude variance [rad^2]
Definition iekf.h:39
uint16_t grace_updates
e.g.
Definition iekf.h:80
float acc_nis_gate
— robustness to external accelerations / magnetic disturbances —
Definition iekf.h:45
float dip_tol
Definition iekf.h:50
float persist_ratio
|mean|^2 / mean(|e|^2) above which it is persistent, e.g.
Definition iekf.h:82
float sigma_acc
per-component std of the normalised vector
Definition iekf.h:35
uint8_t tilt_comp_mag
Definition iekf.h:43
float p0_bias
initial bias variance [(rad/s)^2]
Definition iekf.h:40
float sigma_gyro
rad/s, gyro white noise
Definition iekf.h:33
float persist_decay
moving mean of the innovation: exp(-dt/tau), tau ~ 1 s
Definition iekf.h:81
uint16_t lockout_updates
e.g.
Definition iekf.h:78
uint8_t estimate_bias
Definition iekf.h:41
uint8_t tangent_innov
Definition iekf.h:58
float acc_tol
relative tolerance on the magnitude (gating)
Definition iekf.h:37
float mag_nis_gate
Definition iekf.h:47
float lockout_p_bump
rad^2, e.g.
Definition iekf.h:79
float infl_decay
Definition iekf.h:54
float persist_min
minimum |mean| (sine of the error), e.g.
Definition iekf.h:83
Initial conditions, typically from calib_finish()
Definition iekf.h:87
Definition iekf.h:96
float nom_acc
Definition iekf.h:102
float g_ref[3]
Definition iekf.h:101
float E_last[9]
rotation of the last propagation step
Definition iekf.h:117
float last_dip_dev
Definition iekf.h:108
uint16_t acc_grace
remaining acc updates without inflation
Definition iekf.h:112
float last_mag_dev
relative magnitude deviation
Definition iekf.h:103
float wHt[18]
Definition iekf.h:120
uint16_t acc_gated_run
consecutive acc updates with inflation > 2
Definition iekf.h:111
float m_ref[3]
Definition iekf.h:101
float last_acc_dev
Definition iekf.h:103
uint8_t acc_trusted
Definition iekf.h:109
float R[9]
Definition iekf.h:98
float last_acc_innov_b[3]
acc innovation (body) before the update
Definition iekf.h:116
float nom_mag
Definition iekf.h:102
float last_acc_nis
Definition iekf.h:105
float acc_infl
Definition iekf.h:104
iekf_config_t cfg
Definition iekf.h:97
float b[3]
Definition iekf.h:99
float mag_infl
current inflation of R (>= 1)
Definition iekf.h:104
float last_mag_nis
Definition iekf.h:105
float last_acc_dir[3]
last measured acc direction (for dip)
Definition iekf.h:106
float wPHt[18]
Definition iekf.h:120
float innov_w_pow
moving mean of |innovation|^2
Definition iekf.h:115
uint32_t lockouts
how many times the protection fired
Definition iekf.h:113
float wK[18]
Definition iekf.h:120
float innov_w_mean[3]
moving mean of acc innovation, world frame
Definition iekf.h:114
float P[IEKF_NX *IEKF_NX]
Definition iekf.h:100
float dip_ref
g_ref-m_ref angle, rad
Definition iekf.h:107
float wH[18]
Definition iekf.h:120
float wB[36]
Definition iekf.h:119
float wA[36]
Definition iekf.h:119
float wF[36]
static workspace: no large matrices on the RTOS task stack
Definition iekf.h:119