PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

449 lines
15KB

  1. // Copyright (c) 2014, Freescale Semiconductor, Inc.
  2. // All rights reserved.
  3. // vim: set ts=4:
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of Freescale Semiconductor, Inc. nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. // DISCLAIMED. IN NO EVENT SHALL FREESCALE SEMICONDUCTOR, INC. BE LIABLE FOR ANY
  20. // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. //
  27. // This file contains matrix manipulation functions.
  28. //
  29. #include <inttypes.h>
  30. #include <math.h>
  31. // compile time constants that are private to this file
  32. #define CORRUPTMATRIX 0.001F // column vector modulus limit for rotation matrix
  33. // vector components
  34. #define X 0
  35. #define Y 1
  36. #define Z 2
  37. // function sets the 3x3 matrix A to the identity matrix
  38. void f3x3matrixAeqI(float A[][3])
  39. {
  40. float *pAij; // pointer to A[i][j]
  41. int8_t i, j; // loop counters
  42. for (i = 0; i < 3; i++) {
  43. // set pAij to &A[i][j=0]
  44. pAij = A[i];
  45. for (j = 0; j < 3; j++) {
  46. *(pAij++) = 0.0F;
  47. }
  48. A[i][i] = 1.0F;
  49. }
  50. }
  51. // function sets the matrix A to the identity matrix
  52. void fmatrixAeqI(float *A[], int16_t rc)
  53. {
  54. // rc = rows and columns in A
  55. float *pAij; // pointer to A[i][j]
  56. int8_t i, j; // loop counters
  57. for (i = 0; i < rc; i++) {
  58. // set pAij to &A[i][j=0]
  59. pAij = A[i];
  60. for (j = 0; j < rc; j++) {
  61. *(pAij++) = 0.0F;
  62. }
  63. A[i][i] = 1.0F;
  64. }
  65. }
  66. // function sets every entry in the 3x3 matrix A to a constant scalar
  67. void f3x3matrixAeqScalar(float A[][3], float Scalar)
  68. {
  69. float *pAij; // pointer to A[i][j]
  70. int8_t i, j; // counters
  71. for (i = 0; i < 3; i++) {
  72. // set pAij to &A[i][j=0]
  73. pAij = A[i];
  74. for (j = 0; j < 3; j++) {
  75. *(pAij++) = Scalar;
  76. }
  77. }
  78. }
  79. // function multiplies all elements of 3x3 matrix A by the specified scalar
  80. void f3x3matrixAeqAxScalar(float A[][3], float Scalar)
  81. {
  82. float *pAij; // pointer to A[i][j]
  83. int8_t i, j; // loop counters
  84. for (i = 0; i < 3; i++) {
  85. // set pAij to &A[i][j=0]
  86. pAij = A[i];
  87. for (j = 0; j < 3; j++) {
  88. *(pAij++) *= Scalar;
  89. }
  90. }
  91. }
  92. // function negates all elements of 3x3 matrix A
  93. void f3x3matrixAeqMinusA(float A[][3])
  94. {
  95. float *pAij; // pointer to A[i][j]
  96. int8_t i, j; // loop counters
  97. for (i = 0; i < 3; i++) {
  98. // set pAij to &A[i][j=0]
  99. pAij = A[i];
  100. for (j = 0; j < 3; j++) {
  101. *pAij = -*pAij;
  102. pAij++;
  103. }
  104. }
  105. }
  106. // function directly calculates the symmetric inverse of a symmetric 3x3 matrix
  107. // only the on and above diagonal terms in B are used and need to be specified
  108. void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
  109. {
  110. float fB11B22mB12B12; // B[1][1] * B[2][2] - B[1][2] * B[1][2]
  111. float fB12B02mB01B22; // B[1][2] * B[0][2] - B[0][1] * B[2][2]
  112. float fB01B12mB11B02; // B[0][1] * B[1][2] - B[1][1] * B[0][2]
  113. float ftmp; // determinant and then reciprocal
  114. // calculate useful products
  115. fB11B22mB12B12 = B[1][1] * B[2][2] - B[1][2] * B[1][2];
  116. fB12B02mB01B22 = B[1][2] * B[0][2] - B[0][1] * B[2][2];
  117. fB01B12mB11B02 = B[0][1] * B[1][2] - B[1][1] * B[0][2];
  118. // set ftmp to the determinant of the input matrix B
  119. ftmp = B[0][0] * fB11B22mB12B12 + B[0][1] * fB12B02mB01B22 + B[0][2] * fB01B12mB11B02;
  120. // set A to the inverse of B for any determinant except zero
  121. if (ftmp != 0.0F) {
  122. ftmp = 1.0F / ftmp;
  123. A[0][0] = fB11B22mB12B12 * ftmp;
  124. A[1][0] = A[0][1] = fB12B02mB01B22 * ftmp;
  125. A[2][0] = A[0][2] = fB01B12mB11B02 * ftmp;
  126. A[1][1] = (B[0][0] * B[2][2] - B[0][2] * B[0][2]) * ftmp;
  127. A[2][1] = A[1][2] = (B[0][2] * B[0][1] - B[0][0] * B[1][2]) * ftmp;
  128. A[2][2] = (B[0][0] * B[1][1] - B[0][1] * B[0][1]) * ftmp;
  129. } else {
  130. // provide the identity matrix if the determinant is zero
  131. f3x3matrixAeqI(A);
  132. }
  133. }
  134. // function calculates the determinant of a 3x3 matrix
  135. float f3x3matrixDetA(float A[][3])
  136. {
  137. return (A[X][X] * (A[Y][Y] * A[Z][Z] - A[Y][Z] * A[Z][Y]) +
  138. A[X][Y] * (A[Y][Z] * A[Z][X] - A[Y][X] * A[Z][Z]) +
  139. A[X][Z] * (A[Y][X] * A[Z][Y] - A[Y][Y] * A[Z][X]));
  140. }
  141. // function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
  142. // stored in the top left of a 10x10 array A[10][10]
  143. // A[][] is changed on output.
  144. // eigval[0..n-1] returns the eigenvalues of A[][].
  145. // eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
  146. // the eigenvectors are not sorted by value
  147. void eigencompute(float A[][10], float eigval[], float eigvec[][10], int8_t n)
  148. {
  149. // maximum number of iterations to achieve convergence: in practice 6 is typical
  150. #define NITERATIONS 15
  151. // various trig functions of the jacobi rotation angle phi
  152. float cot2phi, tanhalfphi, tanphi, sinphi, cosphi;
  153. // scratch variable to prevent over-writing during rotations
  154. float ftmp;
  155. // residue from remaining non-zero above diagonal terms
  156. float residue;
  157. // matrix row and column indices
  158. int8_t ir, ic;
  159. // general loop counter
  160. int8_t j;
  161. // timeout ctr for number of passes of the algorithm
  162. int8_t ctr;
  163. // initialize eigenvectors matrix and eigenvalues array
  164. for (ir = 0; ir < n; ir++) {
  165. // loop over all columns
  166. for (ic = 0; ic < n; ic++) {
  167. // set on diagonal and off-diagonal elements to zero
  168. eigvec[ir][ic] = 0.0F;
  169. }
  170. // correct the diagonal elements to 1.0
  171. eigvec[ir][ir] = 1.0F;
  172. // initialize the array of eigenvalues to the diagonal elements of m
  173. eigval[ir] = A[ir][ir];
  174. }
  175. // initialize the counter and loop until converged or NITERATIONS reached
  176. ctr = 0;
  177. do {
  178. // compute the absolute value of the above diagonal elements as exit criterion
  179. residue = 0.0F;
  180. // loop over rows excluding last row
  181. for (ir = 0; ir < n - 1; ir++) {
  182. // loop over above diagonal columns
  183. for (ic = ir + 1; ic < n; ic++) {
  184. // accumulate the residual off diagonal terms which are being driven to zero
  185. residue += fabsf(A[ir][ic]);
  186. }
  187. }
  188. // check if we still have work to do
  189. if (residue > 0.0F) {
  190. // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
  191. for (ir = 0; ir < n - 1; ir++) {
  192. // loop over columns ic (where ic is always greater than ir since above diagonal)
  193. for (ic = ir + 1; ic < n; ic++) {
  194. // only continue with this element if the element is non-zero
  195. if (fabsf(A[ir][ic]) > 0.0F) {
  196. // calculate cot(2*phi) where phi is the Jacobi rotation angle
  197. cot2phi = 0.5F * (eigval[ic] - eigval[ir]) / (A[ir][ic]);
  198. // calculate tan(phi) correcting sign to ensure the smaller solution is used
  199. tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
  200. if (cot2phi < 0.0F) {
  201. tanphi = -tanphi;
  202. }
  203. // calculate the sine and cosine of the Jacobi rotation angle phi
  204. cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
  205. sinphi = tanphi * cosphi;
  206. // calculate tan(phi/2)
  207. tanhalfphi = sinphi / (1.0F + cosphi);
  208. // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
  209. ftmp = tanphi * A[ir][ic];
  210. // apply the jacobi rotation to diagonal elements [ir][ir] and [ic][ic] stored in the eigenvalue array
  211. // eigval[ir] = eigval[ir] - tan(phi) * A[ir][ic]
  212. eigval[ir] -= ftmp;
  213. // eigval[ic] = eigval[ic] + tan(phi) * A[ir][ic]
  214. eigval[ic] += ftmp;
  215. // by definition, applying the jacobi rotation on element ir, ic results in 0.0
  216. A[ir][ic] = 0.0F;
  217. // apply the jacobi rotation to all elements of the eigenvector matrix
  218. for (j = 0; j < n; j++) {
  219. // store eigvec[j][ir]
  220. ftmp = eigvec[j][ir];
  221. // eigvec[j][ir] = eigvec[j][ir] - sin(phi) * (eigvec[j][ic] + tan(phi/2) * eigvec[j][ir])
  222. eigvec[j][ir] = ftmp - sinphi * (eigvec[j][ic] + tanhalfphi * ftmp);
  223. // eigvec[j][ic] = eigvec[j][ic] + sin(phi) * (eigvec[j][ir] - tan(phi/2) * eigvec[j][ic])
  224. eigvec[j][ic] = eigvec[j][ic] + sinphi * (ftmp - tanhalfphi * eigvec[j][ic]);
  225. }
  226. // apply the jacobi rotation only to those elements of matrix m that can change
  227. for (j = 0; j <= ir - 1; j++) {
  228. // store A[j][ir]
  229. ftmp = A[j][ir];
  230. // A[j][ir] = A[j][ir] - sin(phi) * (A[j][ic] + tan(phi/2) * A[j][ir])
  231. A[j][ir] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
  232. // A[j][ic] = A[j][ic] + sin(phi) * (A[j][ir] - tan(phi/2) * A[j][ic])
  233. A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
  234. }
  235. for (j = ir + 1; j <= ic - 1; j++) {
  236. // store A[ir][j]
  237. ftmp = A[ir][j];
  238. // A[ir][j] = A[ir][j] - sin(phi) * (A[j][ic] + tan(phi/2) * A[ir][j])
  239. A[ir][j] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
  240. // A[j][ic] = A[j][ic] + sin(phi) * (A[ir][j] - tan(phi/2) * A[j][ic])
  241. A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
  242. }
  243. for (j = ic + 1; j < n; j++) {
  244. // store A[ir][j]
  245. ftmp = A[ir][j];
  246. // A[ir][j] = A[ir][j] - sin(phi) * (A[ic][j] + tan(phi/2) * A[ir][j])
  247. A[ir][j] = ftmp - sinphi * (A[ic][j] + tanhalfphi * ftmp);
  248. // A[ic][j] = A[ic][j] + sin(phi) * (A[ir][j] - tan(phi/2) * A[ic][j])
  249. A[ic][j] = A[ic][j] + sinphi * (ftmp - tanhalfphi * A[ic][j]);
  250. }
  251. } // end of test for matrix element already zero
  252. } // end of loop over columns
  253. } // end of loop over rows
  254. } // end of test for non-zero residue
  255. } while ((residue > 0.0F) && (ctr++ < NITERATIONS)); // end of main loop
  256. }
  257. // function uses Gauss-Jordan elimination to compute the inverse of matrix A in situ
  258. // on exit, A is replaced with its inverse
  259. void fmatrixAeqInvA(float *A[], int8_t iColInd[], int8_t iRowInd[], int8_t iPivot[], int8_t isize)
  260. {
  261. float largest; // largest element used for pivoting
  262. float scaling; // scaling factor in pivoting
  263. float recippiv; // reciprocal of pivot element
  264. float ftmp; // temporary variable used in swaps
  265. int8_t i, j, k, l, m; // index counters
  266. int8_t iPivotRow, iPivotCol; // row and column of pivot element
  267. // to avoid compiler warnings
  268. iPivotRow = iPivotCol = 0;
  269. // initialize the pivot array to 0
  270. for (j = 0; j < isize; j++) {
  271. iPivot[j] = 0;
  272. }
  273. // main loop i over the dimensions of the square matrix A
  274. for (i = 0; i < isize; i++) {
  275. // zero the largest element found for pivoting
  276. largest = 0.0F;
  277. // loop over candidate rows j
  278. for (j = 0; j < isize; j++) {
  279. // check if row j has been previously pivoted
  280. if (iPivot[j] != 1) {
  281. // loop over candidate columns k
  282. for (k = 0; k < isize; k++) {
  283. // check if column k has previously been pivoted
  284. if (iPivot[k] == 0) {
  285. // check if the pivot element is the largest found so far
  286. if (fabsf(A[j][k]) >= largest) {
  287. // and store this location as the current best candidate for pivoting
  288. iPivotRow = j;
  289. iPivotCol = k;
  290. largest = (float) fabsf(A[iPivotRow][iPivotCol]);
  291. }
  292. } else if (iPivot[k] > 1) {
  293. // zero determinant situation: exit with identity matrix
  294. fmatrixAeqI(A, isize);
  295. return;
  296. }
  297. }
  298. }
  299. }
  300. // increment the entry in iPivot to denote it has been selected for pivoting
  301. iPivot[iPivotCol]++;
  302. // check the pivot rows iPivotRow and iPivotCol are not the same before swapping
  303. if (iPivotRow != iPivotCol) {
  304. // loop over columns l
  305. for (l = 0; l < isize; l++) {
  306. // and swap all elements of rows iPivotRow and iPivotCol
  307. ftmp = A[iPivotRow][l];
  308. A[iPivotRow][l] = A[iPivotCol][l];
  309. A[iPivotCol][l] = ftmp;
  310. }
  311. }
  312. // record that on the i-th iteration rows iPivotRow and iPivotCol were swapped
  313. iRowInd[i] = iPivotRow;
  314. iColInd[i] = iPivotCol;
  315. // check for zero on-diagonal element (singular matrix) and return with identity matrix if detected
  316. if (A[iPivotCol][iPivotCol] == 0.0F) {
  317. // zero determinant situation: exit with identity matrix
  318. fmatrixAeqI(A, isize);
  319. return;
  320. }
  321. // calculate the reciprocal of the pivot element knowing it's non-zero
  322. recippiv = 1.0F / A[iPivotCol][iPivotCol];
  323. // by definition, the diagonal element normalizes to 1
  324. A[iPivotCol][iPivotCol] = 1.0F;
  325. // multiply all of row iPivotCol by the reciprocal of the pivot element including the diagonal element
  326. // the diagonal element A[iPivotCol][iPivotCol] now has value equal to the reciprocal of its previous value
  327. for (l = 0; l < isize; l++) {
  328. A[iPivotCol][l] *= recippiv;
  329. }
  330. // loop over all rows m of A
  331. for (m = 0; m < isize; m++) {
  332. if (m != iPivotCol) {
  333. // scaling factor for this row m is in column iPivotCol
  334. scaling = A[m][iPivotCol];
  335. // zero this element
  336. A[m][iPivotCol] = 0.0F;
  337. // loop over all columns l of A and perform elimination
  338. for (l = 0; l < isize; l++) {
  339. A[m][l] -= A[iPivotCol][l] * scaling;
  340. }
  341. }
  342. }
  343. } // end of loop i over the matrix dimensions
  344. // finally, loop in inverse order to apply the missing column swaps
  345. for (l = isize - 1; l >= 0; l--) {
  346. // set i and j to the two columns to be swapped
  347. i = iRowInd[l];
  348. j = iColInd[l];
  349. // check that the two columns i and j to be swapped are not the same
  350. if (i != j) {
  351. // loop over all rows k to swap columns i and j of A
  352. for (k = 0; k < isize; k++) {
  353. ftmp = A[k][i];
  354. A[k][i] = A[k][j];
  355. A[k][j] = ftmp;
  356. }
  357. }
  358. }
  359. }
  360. // function re-orthonormalizes a 3x3 rotation matrix
  361. void fmatrixAeqRenormRotA(float A[][3])
  362. {
  363. float ftmp; // scratch variable
  364. // normalize the X column of the low pass filtered orientation matrix
  365. ftmp = sqrtf(A[X][X] * A[X][X] + A[Y][X] * A[Y][X] + A[Z][X] * A[Z][X]);
  366. if (ftmp > CORRUPTMATRIX) {
  367. // normalize the x column vector
  368. ftmp = 1.0F / ftmp;
  369. A[X][X] *= ftmp;
  370. A[Y][X] *= ftmp;
  371. A[Z][X] *= ftmp;
  372. } else {
  373. // set x column vector to {1, 0, 0}
  374. A[X][X] = 1.0F;
  375. A[Y][X] = A[Z][X] = 0.0F;
  376. }
  377. // force the y column vector to be orthogonal to x using y = y-(x.y)x
  378. ftmp = A[X][X] * A[X][Y] + A[Y][X] * A[Y][Y] + A[Z][X] * A[Z][Y];
  379. A[X][Y] -= ftmp * A[X][X];
  380. A[Y][Y] -= ftmp * A[Y][X];
  381. A[Z][Y] -= ftmp * A[Z][X];
  382. // normalize the y column vector
  383. ftmp = sqrtf(A[X][Y] * A[X][Y] + A[Y][Y] * A[Y][Y] + A[Z][Y] * A[Z][Y]);
  384. if (ftmp > CORRUPTMATRIX) {
  385. // normalize the y column vector
  386. ftmp = 1.0F / ftmp;
  387. A[X][Y] *= ftmp;
  388. A[Y][Y] *= ftmp;
  389. A[Z][Y] *= ftmp;
  390. } else {
  391. // set y column vector to {0, 1, 0}
  392. A[Y][Y] = 1.0F;
  393. A[X][Y] = A[Z][Y] = 0.0F;
  394. }
  395. // finally set the z column vector to x vector cross y vector (automatically normalized)
  396. A[X][Z] = A[Y][X] * A[Z][Y] - A[Z][X] * A[Y][Y];
  397. A[Y][Z] = A[Z][X] * A[X][Y] - A[X][X] * A[Z][Y];
  398. A[Z][Z] = A[X][X] * A[Y][Y] - A[Y][X] * A[X][Y];
  399. }