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