Da Vinci Firmware 1
Firmware for the DaVinci-M rocket avionics board.
Loading...
Searching...
No Matches
mekf.h File Reference

Multiplicative Extended Kalman Filter (MEKF) for attitude and gyroscope bias estimation. More...

#include "rtwtypes.h"
#include <stddef.h>
#include <stdlib.h>
Include dependency graph for mekf.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define HIGHEST_NUMBER   4294967294
 

Functions

void mekf (const double q[4], const double beta[3], double P[36], const double omega[3], const double b_B[3], double height_AGL, double q_new[4], double beta_new[3], double P_new[36])
 Executes one prediction and correction step of the MEKF.
 

Detailed Description

Multiplicative Extended Kalman Filter (MEKF) for attitude and gyroscope bias estimation.

Author
Francesco Abate, MSA (Originally generated by MATLAB Coder)
Version
24.2 (MATLAB Coder version)
Date
2025-05-05

This header file declares the mekf function, an auto-generated MEKF from MATLAB Coder. The filter is designed to determine the rocket's attitude (3D orientation) by fusing high-frequency gyroscope data with lower-frequency magnetometer readings.

It estimates a 6-degree-of-freedom state:

  • 3 degrees for attitude (represented by a quaternion).
  • 3 degrees for gyroscope bias.

This is a core component of the rocket's guidance, navigation, and control (GNC) system.

Definition in file mekf.h.

Macro Definition Documentation

◆ HIGHEST_NUMBER

#define HIGHEST_NUMBER   4294967294

Definition at line 34 of file mekf.h.

Function Documentation

◆ mekf()

void mekf ( const double  q[4],
const double  beta[3],
double  P[36],
const double  omega[3],
const double  b_B[3],
double  height_AGL,
double  q_new[4],
double  beta_new[3],
double  P_new[36] 
)

Executes one prediction and correction step of the MEKF.

This function propagates the state forward using gyroscope readings (prediction step) and then corrects the estimate using magnetometer data (correction step).

Parameters
[in,out]PEstimate Covariance Matrix [6x6]. Represents the uncertainty of the state estimate. Updated in place. Stored as a 36-element row-major array.
[in]qThe previous attitude state as a quaternion [w, x, y, z].
[in]betaThe previous gyroscope bias estimate vector [3x1] for x, y, z axes.
[in]omegaThe latest gyroscope measurement vector [3x1] in radians/second.
[in]b_BThe latest magnetometer measurement vector [3x1] in the body frame, in mG.
[in]height_AGLThe current altitude above ground level in meters (m), used to look up the reference magnetic field from a model.
[out]q_newThe updated attitude quaternion [w, x, y, z].
[out]beta_newThe updated gyroscope bias estimate vector [3x1].
[out]P_newThe updated estimate covariance matrix [6x6].
Returns
None

Definition at line 88 of file mekf.c.

91{
92 static const double Q[36] = {4.3956900000000333E-11,
93 0.0,
94 0.0,
95 -5.0000000000000008E-23,
96 -0.0,
97 -0.0,
98 0.0,
99 4.3956900000000333E-11,
100 0.0,
101 -0.0,
102 -5.0000000000000008E-23,
103 -0.0,
104 0.0,
105 0.0,
106 4.3956900000000333E-11,
107 -0.0,
108 -0.0,
109 -5.0000000000000008E-23,
110 -5.0000000000000008E-23,
111 -0.0,
112 -0.0,
113 1.0000000000000001E-20,
114 0.0,
115 0.0,
116 -0.0,
117 -5.0000000000000008E-23,
118 -0.0,
119 0.0,
120 1.0000000000000001E-20,
121 0.0,
122 -0.0,
123 -0.0,
124 -5.0000000000000008E-23,
125 0.0,
126 0.0,
127 1.0000000000000001E-20};
128 static const double dv[11] = {23950.03, 23938.16, 23926.3, 23914.44,
129 23902.6, 23890.76, 23878.93, 23867.11,
130 23855.29, 23843.49, 23831.69};
131 static const double dv1[11] = {2585.64, 2583.71, 2581.78, 2579.85,
132 2577.92, 2576.0, 2574.08, 2572.15,
133 2570.24, 2568.32, 2566.4};
134 static const double dv2[11] = {39593.08, 39573.32, 39553.57, 39533.84,
135 39514.11, 39494.41, 39474.71, 39455.03,
136 39435.36, 39415.7, 39396.06};
137 static const double b_y[9] = {0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01};
138 static const int R[9] = {HIGHEST_NUMBER, 0, 0, 0, HIGHEST_NUMBER, 0, 0, 0, HIGHEST_NUMBER};
139 static const signed char iv[18] = {0, 0, 0, 0, 0, 0, 0, 0, 0,
140 1, 0, 0, 0, 1, 0, 0, 0, 1};
141 static const signed char b[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
142 double Phi[36];
143 double b_Phi[36];
144 double H[18];
145 double K[18];
146 double b_H[18];
147 double cos_term[16];
148 double A[9];
149 double dv3[9];
150 double skew_omega_sq[9];
151 double delta_x[6];
152 double delta_q[4];
153 double axis[3];
154 double b_W[3] = {0};
155 double A_tmp;
156 double a;
157 double angle;
158 double b_a;
159 double d;
160 double omega_norm;
161 double sin_term;
162 double x;
163 double y;
164 int H_tmp;
165 int b_i;
166 int cos_term_tmp;
167 int i;
168 /* Input parameters: */
169 /* q Attitude quaternion [qx,qy,qz,qw] */
170 /* beta Gyro bias estimate (3x1) */
171 /* P Covariance matrix (6x6) */
172 /* omega Gyroscope measurement (3x1) */
173 /* b_B Measured magnetic field vector (3x1) */
174 /* height_AGL Height Above Ground Level */
175 /* Output parameters: */
176 /* q_new Updated quaternion */
177 /* beta_new Updated gyro bias estimate */
178 /* P_new Updated covariance matrix */
179 /* PARAMETERS INITIALIZATION */
180 /* sigma_v Gyro noise standard deviation */
181 /* sigma_u Gyro bias random walk noise standard deviation */
182 /* sigma_b Magnetometer noise standard deviation */
183 /* dt Time step */
184 /* spec-sheet */
185 /* placeholder */
186 /* spec-sheet */
187 /* MEASUREMENT UPDATE */
188 /* Normalize b_B and b_W */
189 y = floor(height_AGL / 1000.0);
190 omega_norm = ceil(height_AGL / 1000.0);
191 //-----------------------------------------------------------------------------------------------------------------------------------
192 //x = (height_AGL / 1000.0 - (y + 1.0)) + 1.0;
193 // sin_term = dv[(int)(y + 1.0) - 1];
194 // b_W[0] = (dv[(int)(omega_norm + 1.0) - 1] - sin_term) * x + sin_term;
195 // sin_term = dv1[(int)(y + 1.0) - 1];
196 // b_W[1] = (dv1[(int)(omega_norm + 1.0) - 1] - sin_term) * x + sin_term;
197 // sin_term = dv2[(int)(y + 1.0) - 1];
198 // b_W[2] = (dv2[(int)(omega_norm + 1.0) - 1] - sin_term) * x + sin_term;
199 //---------------------------------------------------------------------------------------------------------------------------------- commented because of the magnetometers question
200 /* Assemble point-rotation matrix for q */
201 y = 2.0 * (q[2] * q[2]);
202 omega_norm = 2.0 * (q[1] * q[1]);
203 A[0] = (1.0 - omega_norm) - y;
204 x = q[0] * q[1];
205 sin_term = q[2] * q[3];
206 A[3] = 2.0 * (x - sin_term);
207 A_tmp = q[0] * q[2];
208 angle = q[1] * q[3];
209 A[6] = 2.0 * (A_tmp + angle);
210 A[1] = 2.0 * (x + sin_term);
211 x = 1.0 - 2.0 * (q[0] * q[0]);
212 A[4] = x - y;
213 y = q[1] * q[2];
214 sin_term = q[0] * q[3];
215 A[7] = 2.0 * (y - sin_term);
216 A[2] = 2.0 * (A_tmp - angle);
217 A[5] = 2.0 * (y + sin_term);
218 A[8] = x - omega_norm;
219 /* Calculate predicted measurement */
220 /* Define sensitivity matrix */
221 /* Create skew-symmetric matrix from a 3x1 vector */
222 H[0] = 0.0;
223 H[4] = 0.0;
224 H[8] = 0.0;
225 d = b_W[0];
226 A_tmp = b_W[1];
227 y = b_W[2];
228 for (i = 0; i < 3; i++) {
229 H_tmp = 3 * (i + 3);
230 H[H_tmp] = 0.0;
231 H[H_tmp + 1] = 0.0;
232 H[H_tmp + 2] = 0.0;
233 axis[i] = (A[i] * d + A[i + 3] * A_tmp) + A[i + 6] * y;
234 }
235 H[3] = -axis[2];
236 H[6] = axis[1];
237 H[1] = axis[2];
238 H[7] = -axis[0];
239 H[2] = -axis[1];
240 H[5] = axis[0];
241 /* Calculate Kalman gain */
242 for (i = 0; i < 3; i++) {
243 for (cos_term_tmp = 0; cos_term_tmp < 6; cos_term_tmp++) {
244 d = 0.0;
245 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
246 d += H[i + 3 * H_tmp] * P[H_tmp + 6 * cos_term_tmp];
247 }
248 b_H[i + 3 * cos_term_tmp] = d;
249 }
250 for (cos_term_tmp = 0; cos_term_tmp < 3; cos_term_tmp++) {
251 d = 0.0;
252 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
253 d += b_H[i + 3 * H_tmp] * H[cos_term_tmp + 3 * H_tmp];
254 }
255 H_tmp = i + 3 * cos_term_tmp;
256 skew_omega_sq[H_tmp] = d + (double)R[H_tmp];
257 }
258 }
259 mpower(skew_omega_sq, dv3);
260 for (i = 0; i < 6; i++) {
261 for (cos_term_tmp = 0; cos_term_tmp < 3; cos_term_tmp++) {
262 d = 0.0;
263 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
264 d += P[i + 6 * H_tmp] * H[cos_term_tmp + 3 * H_tmp];
265 }
266 b_H[i + 6 * cos_term_tmp] = d;
267 }
268 d = b_H[i];
269 A_tmp = b_H[i + 6];
270 y = b_H[i + 12];
271 for (cos_term_tmp = 0; cos_term_tmp < 3; cos_term_tmp++) {
272 K[i + 6 * cos_term_tmp] =
273 (d * dv3[3 * cos_term_tmp] + A_tmp * dv3[3 * cos_term_tmp + 1]) +
274 y * dv3[3 * cos_term_tmp + 2];
275 }
276 }
277 /* Update error state */
278 d = b_norm(b_B);
279 A_tmp = b_norm(b_W);
280 //-----------------------------------------TODO SETTATO A 0 PER VIA DEL TINKERING, EVITARE 0/0
281 omega_norm = 0;// b_W[0] / A_tmp;
282 x = 0;//b_W[1] / A_tmp;
283 y = 0;//b_W[2] / A_tmp;
284 //for (i = 0; i < 3; i++) {
285 //b_W[i] = b_B[i] / d - ((A[i] * omega_norm + A[i + 3] * x) + A[i + 6] * y);
286 //}
287 //-----------------------------------------TODO SETTATO A 0 PER VIA DEL TINKERING, EVITARE 0/0
288 /* Update global states */
289 /* QUATERNION UPDATE */
290 /* delta_q quaternion definition */
291 /* Small angle approx */
292 /* Scalar part */
293 /* Multiply delta_q with the current quaternion */
294 /* Normalize the result */
295 /* BIAS UPDATE */
296 /* COVARIANCE MATRIX UPDATE */
297 b_eye(Phi);
298 for (i = 0; i < 6; i++) {
299 d = K[i];
300 A_tmp = K[i + 6];
301 y = K[i + 12];
302 delta_x[i] = (d * b_W[0] + A_tmp * b_W[1]) + y * b_W[2];
303 for (cos_term_tmp = 0; cos_term_tmp < 6; cos_term_tmp++) {
304 H_tmp = i + 6 * cos_term_tmp;
305 b_Phi[H_tmp] =
306 Phi[H_tmp] -
307 ((d * H[3 * cos_term_tmp] + A_tmp * H[3 * cos_term_tmp + 1]) +
308 y * H[3 * cos_term_tmp + 2]);
309 }
310 for (cos_term_tmp = 0; cos_term_tmp < 6; cos_term_tmp++) {
311 d = 0.0;
312 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
313 d += b_Phi[i + 6 * H_tmp] * P[H_tmp + 6 * cos_term_tmp];
314 }
315 Phi[i + 6 * cos_term_tmp] = d;
316 }
317 }
318 delta_q[0] = 0.5 * delta_x[0];
319 delta_q[1] = 0.5 * delta_x[1];
320 delta_q[2] = 0.5 * delta_x[2];
321 q_new[0] =
322 ((delta_q[0] * q[3] + q[0]) + q[1] * delta_q[2]) - delta_q[1] * q[2];
323 q_new[1] =
324 ((delta_q[1] * q[3] - q[0] * delta_q[2]) + q[1]) + delta_q[0] * q[2];
325 q_new[2] =
326 ((delta_q[2] * q[3] + q[0] * delta_q[1]) - delta_q[0] * q[1]) + q[2];
327 q_new[3] =
328 ((q[3] - q[0] * delta_q[0]) - q[1] * delta_q[1]) - q[2] * delta_q[2];
329 d = c_norm(q_new);
330 q_new[0] /= d;
331 q_new[1] /= d;
332 q_new[2] /= d;
333 q_new[3] /= d;
334 beta_new[0] = beta[0] + delta_x[3];
335 beta_new[1] = beta[1] + delta_x[4];
336 beta_new[2] = beta[2] + delta_x[5];
337 memcpy(&P[0], &Phi[0], 36U * sizeof(double));
338 /* STATE PROPAGATION */
339 /* Calculate the gyroscope measurement without the bias */
340 b_W[0] = omega[0] - beta_new[0];
341 b_W[1] = omega[1] - beta_new[1];
342 b_W[2] = omega[2] - beta_new[2];
343 /* Calculate the magnitude of the angular velocity */
344 omega_norm = b_norm(b_W);
345 /* Calculate the angle and axis of rotation */
346 angle = omega_norm * 0.01;
347 /* Compute the matrix exponential */
348 x = cos(angle);
349 sin_term = sin(angle);
350 /* Define the skew symmetric matrix for omega_hat */
351 /* Create skew-symmetric matrix from a 3x1 vector */
352 A[0] = 0.0;
353 A[3] = -b_W[2];
354 A[6] = b_W[1];
355 A[1] = b_W[2];
356 A[4] = 0.0;
357 A[7] = -b_W[0];
358 A[2] = -b_W[1];
359 A[5] = b_W[0];
360 A[8] = 0.0;
361 /* Calculate the squared product of the skew matrix of omega_hat */
362 for (b_i = 0; b_i < 3; b_i++) {
363 axis[b_i] = b_W[b_i] / omega_norm;
364 for (i = 0; i < 3; i++) {
365 skew_omega_sq[b_i + 3 * i] =
366 (A[b_i] * A[3 * i] + A[b_i + 3] * A[3 * i + 1]) +
367 A[b_i + 6] * A[3 * i + 2];
368 }
369 }
370 /* Calculate the elements of the first row of the phi matrix */
371 a = sin_term / omega_norm;
372 y = omega_norm * omega_norm;
373 b_a = x / y;
374 x = (1.0 - x) / y;
375 y = (angle - sin_term) / rt_powd_snf(omega_norm, 3.0);
376 /* Assemble phi matrix */
377 eye(dv3);
378 for (i = 0; i < 3; i++) {
379 d = A[3 * i];
380 A_tmp = skew_omega_sq[3 * i];
381 Phi[6 * i] = (dv3[3 * i] - a * d) + b_a * A_tmp;
382 H_tmp = 6 * (i + 3);
383 Phi[H_tmp] = (x * d - y * A_tmp) - b_y[3 * i];
384 cos_term_tmp = 3 * i + 1;
385 d = A[cos_term_tmp];
386 A_tmp = skew_omega_sq[cos_term_tmp];
387 Phi[6 * i + 1] = (dv3[cos_term_tmp] - a * d) + b_a * A_tmp;
388 Phi[H_tmp + 1] = (x * d - y * A_tmp) - b_y[cos_term_tmp];
389 cos_term_tmp = 3 * i + 2;
390 d = A[cos_term_tmp];
391 A_tmp = skew_omega_sq[cos_term_tmp];
392 Phi[6 * i + 2] = (dv3[cos_term_tmp] - a * d) + b_a * A_tmp;
393 Phi[H_tmp + 2] = (x * d - y * A_tmp) - b_y[cos_term_tmp];
394 }
395 for (i = 0; i < 6; i++) {
396 Phi[6 * i + 3] = iv[3 * i];
397 Phi[6 * i + 4] = iv[3 * i + 1];
398 Phi[6 * i + 5] = iv[3 * i + 2];
399 }
400 /* Calculate the elements of Q_k */
401 /* Assemble Q_k */
402 /* Covariance propagation */
403 for (i = 0; i < 6; i++) {
404 for (cos_term_tmp = 0; cos_term_tmp < 6; cos_term_tmp++) {
405 d = 0.0;
406 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
407 d += Phi[i + 6 * H_tmp] * P[H_tmp + 6 * cos_term_tmp];
408 }
409 b_Phi[i + 6 * cos_term_tmp] = d;
410 }
411 for (cos_term_tmp = 0; cos_term_tmp < 6; cos_term_tmp++) {
412 d = 0.0;
413 for (H_tmp = 0; H_tmp < 6; H_tmp++) {
414 d += b_Phi[i + 6 * H_tmp] * Phi[cos_term_tmp + 6 * H_tmp];
415 }
416 H_tmp = i + 6 * cos_term_tmp;
417 P_new[H_tmp] = d + Q[H_tmp];
418 }
419 }
420 /* Compute the skew-symmetric matrix for the axis */
421 /* Create skew-symmetric matrix from a 3x1 vector */
422 /* Recompute the sine and cosine terms */
423 x = cos(0.5 * angle);
424 sin_term = sin(0.5 * angle);
425 /* Construct the Theta matrix */
426 /* Propagate the quaternion */
427 skew_omega_sq[0] = sin_term * 0.0;
428 skew_omega_sq[3] = sin_term * -axis[2];
429 skew_omega_sq[6] = sin_term * axis[1];
430 skew_omega_sq[1] = sin_term * axis[2];
431 skew_omega_sq[4] = sin_term * 0.0;
432 skew_omega_sq[7] = sin_term * -axis[0];
433 skew_omega_sq[2] = sin_term * -axis[1];
434 skew_omega_sq[5] = sin_term * axis[0];
435 skew_omega_sq[8] = sin_term * 0.0;
436 for (b_i = 0; b_i < 3; b_i++) {
437 d = sin_term * axis[b_i];
438 H_tmp = b_i << 2;
439 cos_term[H_tmp] = x * (double)b[3 * b_i] - skew_omega_sq[3 * b_i];
440 cos_term_tmp = 3 * b_i + 1;
441 cos_term[H_tmp + 1] =
442 x * (double)b[cos_term_tmp] - skew_omega_sq[cos_term_tmp];
443 cos_term_tmp = 3 * b_i + 2;
444 cos_term[H_tmp + 2] =
445 x * (double)b[cos_term_tmp] - skew_omega_sq[cos_term_tmp];
446 cos_term[b_i + 12] = d;
447 cos_term[H_tmp + 3] = -d;
448 }
449 cos_term[15] = x;
450 d = q_new[0];
451 A_tmp = q_new[1];
452 y = q_new[2];
453 omega_norm = q_new[3];
454 for (i = 0; i < 4; i++) {
455 delta_q[i] =
456 ((cos_term[i] * d + cos_term[i + 4] * A_tmp) + cos_term[i + 8] * y) +
457 cos_term[i + 12] * omega_norm;
458 }
459 /* Normalize the propagated quaternion */
460 d = c_norm(delta_q);
461 q_new[0] = delta_q[0] / d;
462 q_new[1] = delta_q[1] / d;
463 q_new[2] = delta_q[2] / d;
464 q_new[3] = delta_q[3] / d;
465}
void b_eye(double b_I[36])
Creates a 6x6 identity matrix.
Definition eye.c:21
void eye(double b_I[9])
Creates a 3x3 identity matrix.
Definition eye.c:34
double b_B[]
Definition main.c:241
double beta[]
Definition main.c:238
double q_new[]
Definition main.c:243
double omega[]
Definition main.c:240
const double R[]
Definition main.c:253
double beta_new[]
Definition main.c:244
double q[]
Definition main.c:237
const double Q[]
Definition main.c:252
static double rt_powd_snf(double u0, double u1)
Definition mekf.c:30
#define HIGHEST_NUMBER
Definition mekf.h:34
void mpower(const double a[9], double c[9])
Calculates the inverse of a 3x3 matrix.
Definition mpower.c:24
double b_norm(const double x[3])
Calculates the Euclidean norm (magnitude) of a 3-element vector.
Definition norm.c:21
double c_norm(const double x[4])
Calculates the Euclidean norm (magnitude) of a 4-element vector.
Definition norm.c:61

References b_B, b_eye(), b_norm(), beta, beta_new, c_norm(), eye(), HIGHEST_NUMBER, mpower(), omega, q, Q, q_new, R, and rt_powd_snf().

Here is the call graph for this function: