16static void mmul(
float *
C,
const float *
A, uint16_t ar, uint16_t ac,
17 const float *
B, uint16_t bc)
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);
26static void mtrans(
float *At,
const float *
A, uint16_t r, uint16_t c)
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);
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]);
76 memset(f, 0,
sizeof *f);
79 memcpy(f->
R,
s->R0,
sizeof f->
R);
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;
93 for (
int i = 0; i < 3; ++i) {
101 float phi[3], E[9], Rn[9];
102 for (
int i = 0; i < 3; ++i) phi[i] = dtheta[i] - f->
b[i] * h;
107 memcpy(f->
R, Rn,
sizeof Rn);
109 memcpy(f->
E_last, E,
sizeof E);
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];
127 for (
int i = 0; i < 3; ++i) {
128 f->
P[i*
NX + i] += qg;
129 f->
P[(i + 3)*
NX + (i + 3)] += qb;
136 const float dth[3] = { gyro[0]*h, gyro[1]*h, gyro[2]*h };
143 float J[9], S[9],
A[9], T[9], Jt[9];
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]; }
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];
154 for (
int c = 0; c < 3; ++c) {
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;
171 for (
int i = 0; i < 3; ++i)
174 for (
int i = 3; i < 6; ++i)
187 for (
int i = 0; i < 3; ++i) e[i] -= d * u[i];
202 for (
int blk = 0; blk < 2; ++blk) {
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);
210 *k0 -= d*a[0]; *k1 -= d*a[1]; *k2 -= d*a[2];
212 *k0 = d*a[0]; *k1 = d*a[1]; *k2 = d*a[2];
227 float nis_gate,
float *infl,
proj_t proj)
229 float S0[9], S3[9], Si[9], S[9], innov[3], dx[
NX];
231 memset(f->
wH, 0,
sizeof f->
wH);
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];
239 for (
int i = 0; i < 3; ++i) innov[i] = y[i] - yhat[i];
244 memcpy(S3, S0,
sizeof S3);
245 for (
int i = 0; i < 3; ++i) S3[i*3 + i] += r;
253 if (nis_gate > 0.0f && infl) {
254 const float inst = nis / nis_gate;
256 if (g < 1.0f) g = 1.0f;
257 if (inst > g) g = inst;
262 const float re = r * k;
264 memcpy(S3, S0,
sizeof S3);
265 for (
int i = 0; i < 3; ++i) S3[i*3 + i] += re;
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];
278 memcpy(f->
R, Rn,
sizeof Rn);
281 f->
b[0] += dx[3]; f->
b[1] += dx[4]; f->
b[2] += dx[5];
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;
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]);
306static float adaptive_var(
float r0,
float n,
float nom,
float tol,
int adaptive,
float *dev_out)
308 const float dev = fabsf(
n - nom) / nom;
310 if (!adaptive)
return r0;
311 const float x = dev / tol;
312 return r0 * (1.0f + x*x);
318 if (na < 1e-9f)
return 0;
319 float y[3] = { acc[0]/na, acc[1]/na, acc[2]/na }, yhat[3];
374 if (nm < 1e-9f)
return 0;
375 float y[3] = { mag[0]/nm, mag[1]/nm, mag[2]/nm }, yhat[3];
382 bw[0] = sqrtf(hw[0]*hw[0] + hw[1]*hw[1]);
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;
420 f->
P[c*
NX + r] = (r == c) ? p0_att : 0.0f;
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)
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.
static void reset_covariance(iekf_t *f, const float dth[3])
static float adaptive_var(float r0, float n, float nom, float tol, int adaptive, float *dev_out)
int iekf_update_mag(iekf_t *f, const float mag[3])
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.
void iekf_propagate(iekf_t *f, const float gyro[3], float h)
Single-sample case: dtheta = gyro*dt (compatible with the previous port)
static void mmul(float *C, const float *A, uint16_t ar, uint16_t ac, const float *B, uint16_t bc)
void iekf_init(iekf_t *f, const iekf_config_t *cfg, const iekf_seed_t *s)
void iekf_get_quat(const iekf_t *f, float q[4])
int iekf_update_acc(iekf_t *f, const float acc[3])
Return 1 if the measurement was "gated" (de-weighted), 0 otherwise.
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,...
static void project_gain(iekf_t *f, proj_t proj)
void iekf_default_config(iekf_config_t *c)
static void symmetrize(float *P)
static void condition_covariance(iekf_t *f)
static void tangent_part(float e[3], const float u[3])
static void mtrans(float *At, const float *A, uint16_t r, uint16_t c)
Attitude IEKF on SO(3), C port of iekfAttitude.m.
#define IEKF_P_ATT_MIN
rad^2 : floor on the diagonal of P
#define IEKF_P_BIAS_MIN
(rad/s)^2
void so3_exp(const float phi[3], float R[9])
int mat3_inv(const float A[9], float B[9])
0 = OK
void mat3_vec(const float A[9], const float x[3], float y[3])
y = A*x
void so3_to_quat(const float R[9], float q[4])
void mat3t_vec(const float A[9], const float x[3], float y[3])
y = A'*x
float vec3_norm(const float v[3])
void mat3_mul(const float A[9], const float B[9], float C[9])
C = A*B
void so3_orthonormalize(float R[9])
float vec3_dot(const float a[3], const float b[3])
int vec3_normalize(float v[3])
0 = OK
void so3_skew(const float v[3], float S[9])
Single-precision SO(3) Lie-group utilities (port of expSO3.m / skewSym.m + firmware helpers).
uint8_t decouple
1: acc corrects only roll/pitch, mag only yaw
float infl_max
— protection against "lockout" of the NIS inflation — If the estimate is truly wrong,...
uint8_t reset_jacobian
1: transport P after the retraction (default)
float sigma_bias
rad/s^2, bias random walk
float p0_att
initial attitude variance [rad^2]
uint16_t grace_updates
e.g.
float acc_nis_gate
— robustness to external accelerations / magnetic disturbances —
float persist_ratio
|mean|^2 / mean(|e|^2) above which it is persistent, e.g.
float sigma_acc
per-component std of the normalised vector
float p0_bias
initial bias variance [(rad/s)^2]
float sigma_gyro
rad/s, gyro white noise
float persist_decay
moving mean of the innovation: exp(-dt/tau), tau ~ 1 s
uint16_t lockout_updates
e.g.
float acc_tol
relative tolerance on the magnitude (gating)
float lockout_p_bump
rad^2, e.g.
float persist_min
minimum |mean| (sine of the error), e.g.
Initial conditions, typically from calib_finish()
float E_last[9]
rotation of the last propagation step
uint16_t acc_grace
remaining acc updates without inflation
float last_mag_dev
relative magnitude deviation
uint16_t acc_gated_run
consecutive acc updates with inflation > 2
float last_acc_innov_b[3]
acc innovation (body) before the update
float mag_infl
current inflation of R (>= 1)
float last_acc_dir[3]
last measured acc direction (for dip)
float innov_w_pow
moving mean of |innovation|^2
uint32_t lockouts
how many times the protection fired
float innov_w_mean[3]
moving mean of acc innovation, world frame
float P[IEKF_NX *IEKF_NX]
float dip_ref
g_ref-m_ref angle, rad
float wF[36]
static workspace: no large matrices on the RTOS task stack