Sensor Fusion Library 0.6.1
Orientation sensing for Espressif (ESP32, ESP8266) processors
Loading...
Searching...
No Matches
matrix.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
15#include <stdbool.h>
16#include <stdint.h>
17#include "math.h"
18
19#include "sensor_fusion.h"
20#include "matrix.h"
21
22// compile time constants that are private to this file
23#define CORRUPTMATRIX 0.001F // column vector modulus limit for rotation matrix
24
25// function sets the 3x3 matrix A to the identity matrix
26void f3x3matrixAeqI(float A[][3])
27{
28 float *pAij; // pointer to A[i][j]
29 int8_t i,
30 j; // loop counters
31 for (i = 0; i < 3; i++)
32 {
33 // set pAij to &A[i][j=0]
34 pAij = A[i];
35 for (j = 0; j < 3; j++)
36 {
37 *(pAij++) = 0.0F;
38 }
39
40 A[i][i] = 1.0F;
41 }
42
43 return;
44}
45
46// function sets 3x3 matrix A to 3x3 matrix B
47void f3x3matrixAeqB(float A[][3], float B[][3])
48{
49 float *pAij; // pointer to A[i][j]
50 float *pBij; // pointer to B[i][j]
51 int8_t i,
52 j; // loop counters
53 for (i = 0; i < 3; i++)
54 {
55 // set pAij to &A[i][j=0] and pBij to &B[i][j=0]
56 pAij = A[i];
57 pBij = B[i];
58 for (j = 0; j < 3; j++)
59 {
60 *(pAij++) = *(pBij++);
61 }
62 }
63
64 return;
65}
66
67// function sets the matrix A to the identity matrix
68void fmatrixAeqI(float *A[], int16_t rc)
69{
70 // rc = rows and columns in A
71 float *pAij; // pointer to A[i][j]
72 int8_t i,
73 j; // loop counters
74 for (i = 0; i < rc; i++)
75 {
76 // set pAij to &A[i][j=0]
77 pAij = A[i];
78 for (j = 0; j < rc; j++)
79 {
80 *(pAij++) = 0.0F;
81 }
82
83 A[i][i] = 1.0F;
84 }
85
86 return;
87}
88
89// function sets every entry in the 3x3 matrix A to a constant scalar
90void f3x3matrixAeqScalar(float A[][3], float Scalar)
91{
92 float *pAij; // pointer to A[i][j]
93 int8_t i,
94 j; // counters
95 for (i = 0; i < 3; i++)
96 {
97 // set pAij to &A[i][j=0]
98 pAij = A[i];
99 for (j = 0; j < 3; j++)
100 {
101 *(pAij++) = Scalar;
102 }
103 }
104
105 return;
106}
107
108// function multiplies all elements of 3x3 matrix A by the specified scalar
109void f3x3matrixAeqAxScalar(float A[][3], float Scalar)
110{
111 float *pAij; // pointer to A[i][j]
112 int8_t i,
113 j; // loop counters
114 for (i = 0; i < 3; i++)
115 {
116 // set pAij to &A[i][j=0]
117 pAij = A[i];
118 for (j = 0; j < 3; j++)
119 {
120 *(pAij++) *= Scalar;
121 }
122 }
123
124 return;
125}
126
127// function negates all elements of 3x3 matrix A
128void f3x3matrixAeqMinusA(float A[][3])
129{
130 float *pAij; // pointer to A[i][j]
131 int8_t i,
132 j; // loop counters
133 for (i = 0; i < 3; i++)
134 {
135 // set pAij to &A[i][j=0]
136 pAij = A[i];
137 for (j = 0; j < 3; j++)
138 {
139 *pAij = -*pAij;
140 pAij++;
141 }
142 }
143
144 return;
145}
146
147// function directly calculates the symmetric inverse of a symmetric 3x3 matrix
148// only the on and above diagonal terms in B are used and need to be specified
149void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
150{
151 float fB11B22mB12B12; // B[1][1] * B[2][2] - B[1][2] * B[1][2]
152 float fB12B02mB01B22; // B[1][2] * B[0][2] - B[0][1] * B[2][2]
153 float fB01B12mB11B02; // B[0][1] * B[1][2] - B[1][1] * B[0][2]
154 float ftmp; // determinant and then reciprocal
155
156 // calculate useful products
157 fB11B22mB12B12 = B[1][1] * B[2][2] - B[1][2] * B[1][2];
158 fB12B02mB01B22 = B[1][2] * B[0][2] - B[0][1] * B[2][2];
159 fB01B12mB11B02 = B[0][1] * B[1][2] - B[1][1] * B[0][2];
160
161 // set ftmp to the determinant of the input matrix B
162 ftmp = B[0][0] *
163 fB11B22mB12B12 +
164 B[0][1] *
165 fB12B02mB01B22 +
166 B[0][2] *
167 fB01B12mB11B02;
168
169 // set A to the inverse of B for any determinant except zero
170 if (ftmp != 0.0F)
171 {
172 ftmp = 1.0F / ftmp;
173 A[0][0] = fB11B22mB12B12 * ftmp;
174 A[1][0] = A[0][1] = fB12B02mB01B22 * ftmp;
175 A[2][0] = A[0][2] = fB01B12mB11B02 * ftmp;
176 A[1][1] = (B[0][0] * B[2][2] - B[0][2] * B[0][2]) * ftmp;
177 A[2][1] = A[1][2] = (B[0][2] * B[0][1] - B[0][0] * B[1][2]) * ftmp;
178 A[2][2] = (B[0][0] * B[1][1] - B[0][1] * B[0][1]) * ftmp;
179 }
180 else
181 {
182 // provide the identity matrix if the determinant is zero
184 }
185
186 return;
187}
188
189// function calculates the determinant of a 3x3 matrix
190float f3x3matrixDetA(float A[][3])
191{
192 return
193 (
194 A[CHX][CHX] *
195 (
196 A[CHY][CHY] *
197 A[CHZ][CHZ] -
198 A[CHY][CHZ] *
199 A[CHZ][CHY]
200 ) +
201 A[CHX][CHY] *
202 (A[CHY][CHZ] * A[CHZ][CHX] - A[CHY][CHX] * A[CHZ][CHZ]) +
203 A[CHX][CHZ] *
204 (A[CHY][CHX] * A[CHZ][CHY] - A[CHY][CHY] * A[CHZ][CHX])
205 );
206}
207
208// function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
209// stored in the top left of a 10x10 array A[10][10]
210// A[][] is changed on output.
211// eigval[0..n-1] returns the eigenvalues of A[][].
212// eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
213// the eigenvectors are not sorted by value
214// n can vary up to and including 10 but the matrices A and eigvec must have 10 columns.
215void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8_t n)
216{
217 // maximum number of iterations to achieve convergence: in practice 6 is typical
218#define NITERATIONS 15
219 // various trig functions of the jacobi rotation angle phi
220 float cot2phi,
221 tanhalfphi,
222 tanphi,
223 sinphi,
224 cosphi;
225
226 // scratch variable to prevent over-writing during rotations
227 float ftmp;
228
229 // residue from remaining non-zero above diagonal terms
230 float residue;
231
232 // matrix row and column indices
233 int8_t i,
234 j;
235
236 // general loop counter
237 int8_t k;
238
239 // timeout ctr for number of passes of the algorithm
240 int8_t ctr;
241
242 // initialize eigenvectors matrix and eigenvalues array
243 for (i = 0; i < n; i++)
244 {
245 // loop over all columns
246 for (j = 0; j < n; j++)
247 {
248 // set on diagonal and off-diagonal elements to zero
249 eigvec[i][j] = 0.0F;
250 }
251
252 // correct the diagonal elements to 1.0
253 eigvec[i][i] = 1.0F;
254
255 // initialize the array of eigenvalues to the diagonal elements of A
256 eigval[i] = A[i][i];
257 }
258
259 // initialize the counter and loop until converged or NITERATIONS reached
260 ctr = 0;
261 do
262 {
263 // compute the absolute value of the above diagonal elements as exit criterion
264 residue = 0.0F;
265
266 // loop over rows excluding last row
267 for (i = 0; i < n - 1; i++)
268 {
269 // loop over above diagonal columns
270 for (j = i + 1; j < n; j++)
271 {
272 // accumulate the residual off diagonal terms which are being driven to zero
273 residue += fabsf(A[i][j]);
274 }
275 }
276
277 // check if we still have work to do
278 if (residue > 0.0F)
279 {
280 // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
281 for (i = 0; i < n - 1; i++)
282 {
283 // loop over columns j (where j is always greater than i since above diagonal)
284 for (j = i + 1; j < n; j++)
285 {
286 // only continue with this element if the element is non-zero
287 if (fabsf(A[i][j]) > 0.0F)
288 {
289 // calculate cot(2*phi) where phi is the Jacobi rotation angle
290 cot2phi = 0.5F * (eigval[j] - eigval[i]) / (A[i][j]);
291
292 // calculate tan(phi) correcting sign to ensure the smaller solution is used
293 tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
294 if (cot2phi < 0.0F)
295 {
296 tanphi = -tanphi;
297 }
298
299 // calculate the sine and cosine of the Jacobi rotation angle phi
300 cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
301 sinphi = tanphi * cosphi;
302
303 // calculate tan(phi/2)
304 tanhalfphi = sinphi / (1.0F + cosphi);
305
306 // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
307 ftmp = tanphi * A[i][j];
308
309 // apply the jacobi rotation to diagonal elements [i][i] and [j][j] stored in the eigenvalue array
310 // eigval[i] = eigval[i] - tan(phi) * A[i][j]
311 eigval[i] -= ftmp;
312
313 // eigval[j] = eigval[j] + tan(phi) * A[i][j]
314 eigval[j] += ftmp;
315
316 // by definition, applying the jacobi rotation on element i, j results in 0.0
317 A[i][j] = 0.0F;
318
319 // apply the jacobi rotation to all elements of the eigenvector matrix
320 for (k = 0; k < n; k++)
321 {
322 // store eigvec[k][i]
323 ftmp = eigvec[k][i];
324
325 // eigvec[k][i] = eigvec[k][i] - sin(phi) * (eigvec[k][j] + tan(phi/2) * eigvec[k][i])
326 eigvec[k][i] = ftmp - sinphi * (eigvec[k][j] + tanhalfphi * ftmp);
327
328 // eigvec[k][j] = eigvec[k][j] + sin(phi) * (eigvec[k][i] - tan(phi/2) * eigvec[k][j])
329 eigvec[k][j] = eigvec[k][j] + sinphi * (ftmp - tanhalfphi * eigvec[k][j]);
330 }
331
332 // apply the jacobi rotation only to those elements of matrix m that can change
333 for (k = 0; k <= i - 1; k++)
334 {
335 // store A[k][i]
336 ftmp = A[k][i];
337
338 // A[k][i] = A[k][i] - sin(phi) * (A[k][j] + tan(phi/2) * A[k][i])
339 A[k][i] = ftmp - sinphi * (A[k][j] + tanhalfphi * ftmp);
340
341 // A[k][j] = A[k][j] + sin(phi) * (A[k][i] - tan(phi/2) * A[k][j])
342 A[k][j] = A[k][j] + sinphi * (ftmp - tanhalfphi * A[k][j]);
343 }
344
345 for (k = i + 1; k <= j - 1; k++)
346 {
347 // store A[i][k]
348 ftmp = A[i][k];
349
350 // A[i][k] = A[i][k] - sin(phi) * (A[k][j] + tan(phi/2) * A[i][k])
351 A[i][k] = ftmp - sinphi * (A[k][j] + tanhalfphi * ftmp);
352
353 // A[k][j] = A[k][j] + sin(phi) * (A[i][k] - tan(phi/2) * A[k][j])
354 A[k][j] = A[k][j] + sinphi * (ftmp - tanhalfphi * A[k][j]);
355 }
356
357 for (k = j + 1; k < n; k++)
358 {
359 // store A[i][k]
360 ftmp = A[i][k];
361
362 // A[i][k] = A[i][k] - sin(phi) * (A[j][k] + tan(phi/2) * A[i][k])
363 A[i][k] = ftmp - sinphi * (A[j][k] + tanhalfphi * ftmp);
364
365 // A[j][k] = A[j][k] + sin(phi) * (A[i][k] - tan(phi/2) * A[j][k])
366 A[j][k] = A[j][k] + sinphi * (ftmp - tanhalfphi * A[j][k]);
367 }
368 } // end of test for matrix element A[i][j] non-zero
369 } // end of loop over columns j
370 } // end of loop over rows i
371 } // end of test for non-zero value of residue
372 } while ((residue > 0.0F) && (ctr++ < NITERATIONS));
373
374 // end of main loop
375 return;
376}
377
378// function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
379// stored in the top left of a 4x4 array A[4][4]
380// A[][] is changed on output.
381// eigval[0..n-1] returns the eigenvalues of A[][].
382// eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
383// the eigenvectors are not sorted by value
384// n can vary up to and including 4 but the matrices A and eigvec must have 4 columns.
385// this function is identical to eigencompute10 except for the workaround for 4x4 matrices since C cannot
386
387// handle functions accepting matrices with variable numbers of columns.
388void fEigenCompute4(float A[][4], float eigval[], float eigvec[][4], int8_t n)
389{
390 // maximum number of iterations to achieve convergence: in practice 6 is typical
391#define NITERATIONS 15
392 // various trig functions of the jacobi rotation angle phi
393 float cot2phi,
394 tanhalfphi,
395 tanphi,
396 sinphi,
397 cosphi;
398
399 // scratch variable to prevent over-writing during rotations
400 float ftmp;
401
402 // residue from remaining non-zero above diagonal terms
403 float residue;
404
405 // matrix row and column indices
406 int8_t ir,
407 ic;
408
409 // general loop counter
410 int8_t j;
411
412 // timeout ctr for number of passes of the algorithm
413 int8_t ctr;
414
415 // initialize eigenvectors matrix and eigenvalues array
416 for (ir = 0; ir < n; ir++)
417 {
418 // loop over all columns
419 for (ic = 0; ic < n; ic++)
420 {
421 // set on diagonal and off-diagonal elements to zero
422 eigvec[ir][ic] = 0.0F;
423 }
424
425 // correct the diagonal elements to 1.0
426 eigvec[ir][ir] = 1.0F;
427
428 // initialize the array of eigenvalues to the diagonal elements of m
429 eigval[ir] = A[ir][ir];
430 }
431
432 // initialize the counter and loop until converged or NITERATIONS reached
433 ctr = 0;
434 do
435 {
436 // compute the absolute value of the above diagonal elements as exit criterion
437 residue = 0.0F;
438
439 // loop over rows excluding last row
440 for (ir = 0; ir < n - 1; ir++)
441 {
442 // loop over above diagonal columns
443 for (ic = ir + 1; ic < n; ic++)
444 {
445 // accumulate the residual off diagonal terms which are being driven to zero
446 residue += fabsf(A[ir][ic]);
447 }
448 }
449
450 // check if we still have work to do
451 if (residue > 0.0F)
452 {
453 // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
454 for (ir = 0; ir < n - 1; ir++)
455 {
456 // loop over columns ic (where ic is always greater than ir since above diagonal)
457 for (ic = ir + 1; ic < n; ic++)
458 {
459 // only continue with this element if the element is non-zero
460 if (fabsf(A[ir][ic]) > 0.0F)
461 {
462 // calculate cot(2*phi) where phi is the Jacobi rotation angle
463 cot2phi = 0.5F *
464 (eigval[ic] - eigval[ir]) /
465 (A[ir][ic]);
466
467 // calculate tan(phi) correcting sign to ensure the smaller solution is used
468 tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
469 if (cot2phi < 0.0F)
470 {
471 tanphi = -tanphi;
472 }
473
474 // calculate the sine and cosine of the Jacobi rotation angle phi
475 cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
476 sinphi = tanphi * cosphi;
477
478 // calculate tan(phi/2)
479 tanhalfphi = sinphi / (1.0F + cosphi);
480
481 // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
482 ftmp = tanphi * A[ir][ic];
483
484 // apply the jacobi rotation to diagonal elements [ir][ir] and [ic][ic] stored in the eigenvalue array
485 // eigval[ir] = eigval[ir] - tan(phi) * A[ir][ic]
486 eigval[ir] -= ftmp;
487
488 // eigval[ic] = eigval[ic] + tan(phi) * A[ir][ic]
489 eigval[ic] += ftmp;
490
491 // by definition, applying the jacobi rotation on element ir, ic results in 0.0
492 A[ir][ic] = 0.0F;
493
494 // apply the jacobi rotation to all elements of the eigenvector matrix
495 for (j = 0; j < n; j++)
496 {
497 // store eigvec[j][ir]
498 ftmp = eigvec[j][ir];
499
500 // eigvec[j][ir] = eigvec[j][ir] - sin(phi) * (eigvec[j][ic] + tan(phi/2) * eigvec[j][ir])
501 eigvec[j][ir] = ftmp - sinphi * (eigvec[j][ic] + tanhalfphi * ftmp);
502
503 // eigvec[j][ic] = eigvec[j][ic] + sin(phi) * (eigvec[j][ir] - tan(phi/2) * eigvec[j][ic])
504 eigvec[j][ic] = eigvec[j][ic] + sinphi * (ftmp - tanhalfphi * eigvec[j][ic]);
505 }
506
507 // apply the jacobi rotation only to those elements of matrix m that can change
508 for (j = 0; j <= ir - 1; j++)
509 {
510 // store A[j][ir]
511 ftmp = A[j][ir];
512
513 // A[j][ir] = A[j][ir] - sin(phi) * (A[j][ic] + tan(phi/2) * A[j][ir])
514 A[j][ir] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
515
516 // A[j][ic] = A[j][ic] + sin(phi) * (A[j][ir] - tan(phi/2) * A[j][ic])
517 A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
518 }
519
520 for (j = ir + 1; j <= ic - 1; j++)
521 {
522 // store A[ir][j]
523 ftmp = A[ir][j];
524
525 // A[ir][j] = A[ir][j] - sin(phi) * (A[j][ic] + tan(phi/2) * A[ir][j])
526 A[ir][j] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
527
528 // A[j][ic] = A[j][ic] + sin(phi) * (A[ir][j] - tan(phi/2) * A[j][ic])
529 A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
530 }
531
532 for (j = ic + 1; j < n; j++)
533 {
534 // store A[ir][j]
535 ftmp = A[ir][j];
536
537 // A[ir][j] = A[ir][j] - sin(phi) * (A[ic][j] + tan(phi/2) * A[ir][j])
538 A[ir][j] = ftmp - sinphi * (A[ic][j] + tanhalfphi * ftmp);
539
540 // A[ic][j] = A[ic][j] + sin(phi) * (A[ir][j] - tan(phi/2) * A[ic][j])
541 A[ic][j] = A[ic][j] + sinphi * (ftmp - tanhalfphi * A[ic][j]);
542 }
543 } // end of test for matrix element already zero
544 } // end of loop over columns
545 } // end of loop over rows
546 } // end of test for non-zero residue
547 } while ((residue > 0.0F) && (ctr++ < NITERATIONS));
548
549 // end of main loop
550 return;
551}
552
553void fComputeEigSlice(float fmatA[10][10], float fmatB[10][10], float fvecA[10],
554 int8_t i, int8_t j, int8_t iMatrixSize)
555{
556 float cot2phi; // cotangent of half jacobi rotation angle
557 float tanhalfphi; // tangent of half jacobi rotation angle
558 float tanphi; // tangent of jacobi rotation angle
559 float sinphi; // sine of jacobi rotation angle
560 float cosphi; // cosine of jacobi rotation angle
561 float ftmp; // scratch
562 int8_t k; // loop counter
563
564 // calculate cot(2*phi) where phi is the Jacobi rotation angle
565 cot2phi = 0.5F * (fvecA[j] - fvecA[i]) / (fmatA[i][j]);
566
567 // calculate tan(phi) correcting sign to ensure the smaller solution is used
568 tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
569 if (cot2phi < 0.0F) tanphi = -tanphi;
570
571 // calculate the sine and cosine of the Jacobi rotation angle phi
572 cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
573 sinphi = tanphi * cosphi;
574
575 // calculate tan(phi/2)
576 tanhalfphi = sinphi / (1.0F + cosphi);
577
578 // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
579 ftmp = tanphi * fmatA[i][j];
580
581 // apply the jacobi rotation to diagonal elements [i][i] and [j][j] stored in the eigenvalue array
582 // fvecA[i] = fvecA[i] - tan(phi) * fmatA[i][j]
583 fvecA[i] -= ftmp;
584
585 // fvecA[j] = fvecA[j] + tan(phi) * fmatA[i][j]
586 fvecA[j] += ftmp;
587
588 // by definition, applying the jacobi rotation on element i, j results in 0.0
589 fmatA[i][j] = 0.0F;
590
591 // apply the jacobi rotation to all elements of the eigenvector matrix
592 for (k = 0; k < iMatrixSize; k++)
593 {
594 // store fmatB[k][i]
595 ftmp = fmatB[k][i];
596
597 // fmatB[k][i] = fmatB[k][i] - sin(phi) * (fmatB[k][j] + tan(phi/2) * fmatB[k][i])
598 fmatB[k][i] = ftmp - sinphi * (fmatB[k][j] + tanhalfphi * ftmp);
599
600 // fmatB[k][j] = fmatB[k][j] + sin(phi) * (fmatB[k][i] - tan(phi/2) * fmatB[k][j])
601 fmatB[k][j] = fmatB[k][j] + sinphi * (ftmp - tanhalfphi * fmatB[k][j]);
602 }
603
604 // apply the jacobi rotation only to those elements of matrix that can change
605 for (k = 0; k <= i - 1; k++)
606 {
607 // store fmatA[k][i]
608 ftmp = fmatA[k][i];
609
610 // fmatA[k][i] = fmatA[k][i] - sin(phi) * (fmatA[k][j] + tan(phi/2) * fmatA[k][i])
611 fmatA[k][i] = ftmp - sinphi * (fmatA[k][j] + tanhalfphi * ftmp);
612
613 // fmatA[k][j] = fmatA[k][j] + sin(phi) * (fmatA[k][i] - tan(phi/2) * fmatA[k][j])
614 fmatA[k][j] = fmatA[k][j] + sinphi * (ftmp - tanhalfphi * fmatA[k][j]);
615 }
616
617 for (k = i + 1; k <= j - 1; k++)
618 {
619 // store fmatA[i][k]
620 ftmp = fmatA[i][k];
621
622 // fmatA[i][k] = fmatA[i][k] - sin(phi) * (fmatA[k][j] + tan(phi/2) * fmatA[i][k])
623 fmatA[i][k] = ftmp - sinphi * (fmatA[k][j] + tanhalfphi * ftmp);
624
625 // fmatA[k][j] = fmatA[k][j] + sin(phi) * (fmatA[i][k] - tan(phi/2) * fmatA[k][j])
626 fmatA[k][j] = fmatA[k][j] + sinphi * (ftmp - tanhalfphi * fmatA[k][j]);
627 }
628
629 for (k = j + 1; k < iMatrixSize; k++)
630 {
631 // store fmatA[i][k]
632 ftmp = fmatA[i][k];
633
634 // fmatA[i][k] = fmatA[i][k] - sin(phi) * (fmatA[j][k] + tan(phi/2) * fmatA[i][k])
635 fmatA[i][k] = ftmp - sinphi * (fmatA[j][k] + tanhalfphi * ftmp);
636
637 // fmatA[j][k] = fmatA[j][k] + sin(phi) * (fmatA[i][k] - tan(phi/2) * fmatA[j][k])
638 fmatA[j][k] = fmatA[j][k] + sinphi * (ftmp - tanhalfphi * fmatA[j][k]);
639 }
640
641 return;
642}
643
644// function uses Gauss-Jordan elimination to compute the inverse of matrix A in situ
645
646// on exit, A is replaced with its inverse
647void fmatrixAeqInvA(float *A[], int8_t iColInd[], int8_t iRowInd[], int8_t iPivot[],
648 int8_t isize, int8_t *pierror)
649{
650 float largest; // largest element used for pivoting
651 float scaling; // scaling factor in pivoting
652 float recippiv; // reciprocal of pivot element
653 float ftmp; // temporary variable used in swaps
654 int8_t i,
655 j,
656 k,
657 l,
658 m; // index counters
659 int8_t iPivotRow,
660 iPivotCol; // row and column of pivot element
661
662 // to avoid compiler warnings
663 iPivotRow = iPivotCol = 0;
664
665 // default to successful inversion
666 *pierror = false;
667
668 // initialize the pivot array to 0
669 for (j = 0; j < isize; j++)
670 {
671 iPivot[j] = 0;
672 }
673
674 // main loop i over the dimensions of the square matrix A
675 for (i = 0; i < isize; i++)
676 {
677 // zero the largest element found for pivoting
678 largest = 0.0F;
679
680 // loop over candidate rows j
681 for (j = 0; j < isize; j++)
682 {
683 // check if row j has been previously pivoted
684 if (iPivot[j] != 1)
685 {
686 // loop over candidate columns k
687 for (k = 0; k < isize; k++)
688 {
689 // check if column k has previously been pivoted
690 if (iPivot[k] == 0)
691 {
692 // check if the pivot element is the largest found so far
693 if (fabsf(A[j][k]) >= largest)
694 {
695 // and store this location as the current best candidate for pivoting
696 iPivotRow = j;
697 iPivotCol = k;
698 largest = (float) fabsf(A[iPivotRow][iPivotCol]);
699 }
700 }
701 else if (iPivot[k] > 1)
702 {
703 // zero determinant situation: exit with identity matrix and set error flag
704 fmatrixAeqI(A, isize);
705 *pierror = true;
706 return;
707 }
708 }
709 }
710 }
711
712 // increment the entry in iPivot to denote it has been selected for pivoting
713 iPivot[iPivotCol]++;
714
715 // check the pivot rows iPivotRow and iPivotCol are not the same before swapping
716 if (iPivotRow != iPivotCol)
717 {
718 // loop over columns l
719 for (l = 0; l < isize; l++)
720 {
721 // and swap all elements of rows iPivotRow and iPivotCol
722 ftmp = A[iPivotRow][l];
723 A[iPivotRow][l] = A[iPivotCol][l];
724 A[iPivotCol][l] = ftmp;
725 }
726 }
727
728 // record that on the i-th iteration rows iPivotRow and iPivotCol were swapped
729 iRowInd[i] = iPivotRow;
730 iColInd[i] = iPivotCol;
731
732 // check for zero on-diagonal element (singular matrix) and return with identity matrix if detected
733 if (A[iPivotCol][iPivotCol] == 0.0F)
734 {
735 // zero determinant situation: exit with identity matrix and set error flag
736 fmatrixAeqI(A, isize);
737 *pierror = true;
738 return;
739 }
740
741 // calculate the reciprocal of the pivot element knowing it's non-zero
742 recippiv = 1.0F / A[iPivotCol][iPivotCol];
743
744 // by definition, the diagonal element normalizes to 1
745 A[iPivotCol][iPivotCol] = 1.0F;
746
747 // multiply all of row iPivotCol by the reciprocal of the pivot element including the diagonal element
748 // the diagonal element A[iPivotCol][iPivotCol] now has value equal to the reciprocal of its previous value
749 for (l = 0; l < isize; l++)
750 {
751 if (A[iPivotCol][l] != 0.0F) A[iPivotCol][l] *= recippiv;
752 }
753
754 // loop over all rows m of A
755 for (m = 0; m < isize; m++)
756 {
757 if (m != iPivotCol)
758 {
759 // scaling factor for this row m is in column iPivotCol
760 scaling = A[m][iPivotCol];
761
762 // zero this element
763 A[m][iPivotCol] = 0.0F;
764
765 // loop over all columns l of A and perform elimination
766 for (l = 0; l < isize; l++)
767 {
768 if ((A[iPivotCol][l] != 0.0F) && (scaling != 0.0F))
769 A[m][l] -= A[iPivotCol][l] * scaling;
770 }
771 }
772 }
773 } // end of loop i over the matrix dimensions
774
775 // finally, loop in inverse order to apply the missing column swaps
776 for (l = isize - 1; l >= 0; l--)
777 {
778 // set i and j to the two columns to be swapped
779 i = iRowInd[l];
780 j = iColInd[l];
781
782 // check that the two columns i and j to be swapped are not the same
783 if (i != j)
784 {
785 // loop over all rows k to swap columns i and j of A
786 for (k = 0; k < isize; k++)
787 {
788 ftmp = A[k][i];
789 A[k][i] = A[k][j];
790 A[k][j] = ftmp;
791 }
792 }
793 }
794
795 return;
796}
797
798// function rotates 3x1 vector u onto 3x1 vector using 3x3 rotation matrix fR.
799
800// the rotation is applied in the inverse direction if itranpose is true
801void fveqRu(float fv[], float fR[][3], float fu[], int8_t itranspose)
802{
803 if (!itranspose)
804 {
805 // normal, non-transposed rotation
806 fv[CHX] = fR[CHX][CHX] *
807 fu[CHX] +
808 fR[CHX][CHY] *
809 fu[CHY] +
810 fR[CHX][CHZ] *
811 fu[CHZ];
812 fv[CHY] = fR[CHY][CHX] *
813 fu[CHX] +
814 fR[CHY][CHY] *
815 fu[CHY] +
816 fR[CHY][CHZ] *
817 fu[CHZ];
818 fv[CHZ] = fR[CHZ][CHX] *
819 fu[CHX] +
820 fR[CHZ][CHY] *
821 fu[CHY] +
822 fR[CHZ][CHZ] *
823 fu[CHZ];
824 }
825 else
826 {
827 // transposed (inverse rotation)
828 fv[CHX] = fR[CHX][CHX] *
829 fu[CHX] +
830 fR[CHY][CHX] *
831 fu[CHY] +
832 fR[CHZ][CHX] *
833 fu[CHZ];
834 fv[CHY] = fR[CHX][CHY] *
835 fu[CHX] +
836 fR[CHY][CHY] *
837 fu[CHY] +
838 fR[CHZ][CHY] *
839 fu[CHZ];
840 fv[CHZ] = fR[CHX][CHZ] *
841 fu[CHX] +
842 fR[CHY][CHZ] *
843 fu[CHY] +
844 fR[CHZ][CHZ] *
845 fu[CHZ];
846 }
847
848 return;
849}
850
851// function multiplies the 3x1 vector V by a 3x3 matrix A
852void fVeq3x3AxV(float V[3], float A[][3])
853{
854 float ftmp[3]; // scratch vector
855
856 // set ftmp = V
857 ftmp[CHX] = V[CHX];
858 ftmp[CHY] = V[CHY];
859 ftmp[CHZ] = V[CHZ];
860
861 // set V = A * ftmp = A * V
862 V[CHX] = A[CHX][CHX] *
863 ftmp[CHX] +
864 A[CHX][CHY] *
865 ftmp[CHY] +
866 A[CHX][CHZ] *
867 ftmp[CHZ];
868 V[CHY] = A[CHY][CHX] *
869 ftmp[CHX] +
870 A[CHY][CHY] *
871 ftmp[CHY] +
872 A[CHY][CHZ] *
873 ftmp[CHZ];
874 V[CHZ] = A[CHZ][CHX] *
875 ftmp[CHX] +
876 A[CHZ][CHY] *
877 ftmp[CHY] +
878 A[CHZ][CHZ] *
879 ftmp[CHZ];
880
881 return;
882}
void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8_t n)
Definition matrix.c:215
void f3x3matrixAeqAxScalar(float A[][3], float Scalar)
function multiplies all elements of 3x3 matrix A by the specified scalar
Definition matrix.c:109
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition matrix.c:26
float f3x3matrixDetA(float A[][3])
function calculates the determinant of a 3x3 matrix
Definition matrix.c:190
void f3x3matrixAeqMinusA(float A[][3])
function negates all elements of 3x3 matrix A
Definition matrix.c:128
void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
Definition matrix.c:149
void fEigenCompute4(float A[][4], float eigval[], float eigvec[][4], int8_t n)
Definition matrix.c:388
void fmatrixAeqInvA(float *A[], int8_t iColInd[], int8_t iRowInd[], int8_t iPivot[], int8_t isize, int8_t *pierror)
Definition matrix.c:647
void f3x3matrixAeqScalar(float A[][3], float Scalar)
function sets every entry in the 3x3 matrix A to a constant scalar
Definition matrix.c:90
void f3x3matrixAeqB(float A[][3], float B[][3])
function sets 3x3 matrix A to 3x3 matrix B
Definition matrix.c:47
void fveqRu(float fv[], float fR[][3], float fu[], int8_t itranspose)
Definition matrix.c:801
void fVeq3x3AxV(float V[3], float A[][3])
function multiplies the 3x1 vector V by a 3x3 matrix A
Definition matrix.c:852
void fmatrixAeqI(float *A[], int16_t rc)
function sets the matrix A to the identity matrix
Definition matrix.c:68
Matrix manipulation functions.
The sensor_fusion.h file implements the top level programming interface.
#define CHX
Used to access X-channel entries in various data data structures.
#define CHY
Used to access Y-channel entries in various data data structures.
#define CHZ
Used to access Z-channel entries in various data data structures.