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