/* $License: Copyright 2011 InvenSense, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. $ */ #include "mlmath.h" #include "mlMathFunc.h" #include "mlinclude.h" /** Performs a multiply and shift by 29. These are good functions to write in assembly on * with devices with small memory where you want to get rid of the long long which some * assemblers don't handle well * @param[in] a * @param[in] b * @return ((long long)a*b)>>29 */ long inv_q29_mult(long a, long b) { long long temp; long result; temp = (long long)a *b; result = (long)(temp >> 29); return result; } /** Performs a multiply and shift by 30. These are good functions to write in assembly on * with devices with small memory where you want to get rid of the long long which some * assemblers don't handle well * @param[in] a * @param[in] b * @return ((long long)a*b)>>30 */ long inv_q30_mult(long a, long b) { long long temp; long result; temp = (long long)a *b; result = (long)(temp >> 30); return result; } void inv_q_mult(const long *q1, const long *q2, long *qProd) { INVENSENSE_FUNC_START; qProd[0] = (long)(((long long)q1[0] * q2[0] - (long long)q1[1] * q2[1] - (long long)q1[2] * q2[2] - (long long)q1[3] * q2[3]) >> 30); qProd[1] = (int)(((long long)q1[0] * q2[1] + (long long)q1[1] * q2[0] + (long long)q1[2] * q2[3] - (long long)q1[3] * q2[2]) >> 30); qProd[2] = (long)(((long long)q1[0] * q2[2] - (long long)q1[1] * q2[3] + (long long)q1[2] * q2[0] + (long long)q1[3] * q2[1]) >> 30); qProd[3] = (long)(((long long)q1[0] * q2[3] + (long long)q1[1] * q2[2] - (long long)q1[2] * q2[1] + (long long)q1[3] * q2[0]) >> 30); } void inv_q_invert(const long *q, long *qInverted) { INVENSENSE_FUNC_START; qInverted[0] = q[0]; qInverted[1] = -q[1]; qInverted[2] = -q[2]; qInverted[3] = -q[3]; } /** * Converts a quaternion to a rotation matrix. * @param[in] quat 4-element quaternion in fixed point. One is 2^30. * @param[out] rot Rotation matrix in fixed point. One is 2^30. The * First 3 elements of the rotation matrix, represent * the first row of the matrix. Rotation matrix multiplied * by a 3 element column vector transform a vector from Body * to World. */ void inv_quaternion_to_rotation(const long *quat, long *rot) { rot[0] = inv_q29_mult(quat[1], quat[1]) + inv_q29_mult(quat[0], quat[0]) - 1073741824L; rot[1] = inv_q29_mult(quat[1], quat[2]) - inv_q29_mult(quat[3], quat[0]); rot[2] = inv_q29_mult(quat[1], quat[3]) + inv_q29_mult(quat[2], quat[0]); rot[3] = inv_q29_mult(quat[1], quat[2]) + inv_q29_mult(quat[3], quat[0]); rot[4] = inv_q29_mult(quat[2], quat[2]) + inv_q29_mult(quat[0], quat[0]) - 1073741824L; rot[5] = inv_q29_mult(quat[2], quat[3]) - inv_q29_mult(quat[1], quat[0]); rot[6] = inv_q29_mult(quat[1], quat[3]) - inv_q29_mult(quat[2], quat[0]); rot[7] = inv_q29_mult(quat[2], quat[3]) + inv_q29_mult(quat[1], quat[0]); rot[8] = inv_q29_mult(quat[3], quat[3]) + inv_q29_mult(quat[0], quat[0]) - 1073741824L; } /** Converts a 32-bit long to a big endian byte stream */ unsigned char *inv_int32_to_big8(long x, unsigned char *big8) { big8[0] = (unsigned char)((x >> 24) & 0xff); big8[1] = (unsigned char)((x >> 16) & 0xff); big8[2] = (unsigned char)((x >> 8) & 0xff); big8[3] = (unsigned char)(x & 0xff); return big8; } /** Converts a big endian byte stream into a 32-bit long */ long inv_big8_to_int32(const unsigned char *big8) { long x; x = ((long)big8[0] << 24) | ((long)big8[1] << 16) | ((long)big8[2] << 8) | ((long)big8[3]); return x; } /** Converts a 16-bit short to a big endian byte stream */ unsigned char *inv_int16_to_big8(short x, unsigned char *big8) { big8[0] = (unsigned char)((x >> 8) & 0xff); big8[1] = (unsigned char)(x & 0xff); return big8; } void inv_matrix_det_inc(float *a, float *b, int *n, int x, int y) { int k, l, i, j; for (i = 0, k = 0; i < *n; i++, k++) { for (j = 0, l = 0; j < *n; j++, l++) { if (i == x) i++; if (j == y) j++; *(b + 10 * k + l) = *(a + 10 * i + j); } } *n = *n - 1; } float inv_matrix_det(float *p, int *n) { float d[10][10], sum = 0; int i, j, m; m = *n; if (*n == 2) return (*p ** (p + 11) - *(p + 1) ** (p + 10)); for (i = 0, j = 0; j < m; j++) { *n = m; inv_matrix_det_inc(p, &d[0][0], n, i, j); sum = sum + *(p + 10 * i + j) * SIGNM(i + j) * inv_matrix_det(&d[0][0], n); } return (sum); } /** Wraps angle from (-M_PI,M_PI] * @param[in] ang Angle in radians to wrap * @return Wrapped angle from (-M_PI,M_PI] */ float inv_wrap_angle(float ang) { if (ang > M_PI) return ang - 2 * (float)M_PI; else if (ang <= -(float)M_PI) return ang + 2 * (float)M_PI; else return ang; } /** Finds the minimum angle difference ang1-ang2 such that difference * is between [-M_PI,M_PI] * @param[in] ang1 * @param[in] ang2 * @return angle difference ang1-ang2 */ float inv_angle_diff(float ang1, float ang2) { float d; ang1 = inv_wrap_angle(ang1); ang2 = inv_wrap_angle(ang2); d = ang1 - ang2; if (d > M_PI) d -= 2 * (float)M_PI; else if (d < -(float)M_PI) d += 2 * (float)M_PI; return d; }