1c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/* 2c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro $License: 3c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro Copyright (C) 2011-2012 InvenSense Corporation, All Rights Reserved. 4c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro See included License.txt for License information. 5c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro $ 6c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 7c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 8c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/******************************************************************************* 9c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * 10c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * $Id:$ 11c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * 12c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro ******************************************************************************/ 13c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 14c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** 15c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @defgroup ML_MATH_FUNC ml_math_func 16c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @brief Motion Library - Math Functions 17c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * Common math functions the Motion Library 18c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * 19c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @{ 20c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @file ml_math_func.c 21c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @brief Math Functions. 22c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 23c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 24c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#include "mlmath.h" 25c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#include "ml_math_func.h" 26c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#include "mlinclude.h" 27c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#include <string.h> 28c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 29c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** @internal 30c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * Does the cross product of compass by gravity, then converts that 31c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * to the world frame using the quaternion, then computes the angle that 32c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * is made. 33c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * 34c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] compass Compass Vector (Body Frame), length 3 35c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] grav Gravity Vector (Body Frame), length 3 36c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] quat Quaternion, Length 4 37c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return Angle Cross Product makes after quaternion rotation. 38c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 39c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarofloat inv_compass_angle(const long *compass, const long *grav, const float *quat) 40c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 41c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float cgcross[4], q1[4], q2[4], qi[4]; 42c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float angW; 43c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 44c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Compass cross Gravity 45c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[0] = 0.f; 46c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[1] = (float)compass[1] * grav[2] - (float)compass[2] * grav[1]; 47c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[2] = (float)compass[2] * grav[0] - (float)compass[0] * grav[2]; 48c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[3] = (float)compass[0] * grav[1] - (float)compass[1] * grav[0]; 49c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 50c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Now convert cross product into world frame 51c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_multf(quat, cgcross, q1); 52c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_invertf(quat, qi); 53c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_multf(q1, qi, q2); 54c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 55c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Protect against atan2 of 0,0 56c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((q2[2] == 0.f) && (q2[1] == 0.f)) 57c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 0.f; 58c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 59c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // This is the unfiltered heading correction 60c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro angW = -atan2f(q2[2], q2[1]); 61c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return angW; 62c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 63c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 64c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** 65c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @brief The gyro data magnitude squared : 66c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * (1 degree per second)^2 = 2^6 = 2^GYRO_MAG_SQR_SHIFT. 67c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] gyro Gyro data scaled with 1 dps = 2^16 68c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return the computed magnitude squared output of the gyroscope. 69c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 70c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarounsigned long inv_get_gyro_sum_of_sqr(const long *gyro) 71c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 72c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro unsigned long gmag = 0; 73c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long temp; 74c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int kk; 75c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 76c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (kk = 0; kk < 3; ++kk) { 77c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp = gyro[kk] >> (16 - (GYRO_MAG_SQR_SHIFT / 2)); 78c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro gmag += temp * temp; 79c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 80c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 81c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return gmag; 82c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 83c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 84c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a multiply and shift by 29. These are good functions to write in assembly on 85c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * with devices with small memory where you want to get rid of the long long which some 86c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * assemblers don't handle well 87c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] a 88c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] b 89c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return ((long long)a*b)>>29 90c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 91c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_q29_mult(long a, long b) 92c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 93c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#ifdef UMPL_ELIMINATE_64BIT 94c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 95c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)((float)a * b / (1L << 29)); 96c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 97c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#else 98c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long long temp; 99c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 100c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp = (long long)a * b; 101c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)(temp >> 29); 102c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 103c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#endif 104c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 105c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 106c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a multiply and shift by 30. These are good functions to write in assembly on 107c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * with devices with small memory where you want to get rid of the long long which some 108c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * assemblers don't handle well 109c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] a 110c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] b 111c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return ((long long)a*b)>>30 112c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 113c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_q30_mult(long a, long b) 114c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 115c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#ifdef UMPL_ELIMINATE_64BIT 116c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 117c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)((float)a * b / (1L << 30)); 118c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 119c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#else 120c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long long temp; 121c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 122c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp = (long long)a * b; 123c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)(temp >> 30); 124c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 125c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#endif 126c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 127c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 128c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#ifndef UMPL_ELIMINATE_64BIT 129c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_q30_div(long a, long b) 130c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 131c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long long temp; 132c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 133c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp = (((long long)a) << 30) / b; 134c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)temp; 135c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 136c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 137c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#endif 138c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 139c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a multiply and shift by shift. These are good functions to write 140c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * in assembly on with devices with small memory where you want to get rid of 141c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * the long long which some assemblers don't handle well 142c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] a First multicand 143c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] b Second multicand 144c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] shift Shift amount after multiplying 145c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return ((long long)a*b)<<shift 146c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 147c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#ifndef UMPL_ELIMINATE_64BIT 148c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_q_shift_mult(long a, long b, int shift) 149c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 150c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long result; 151c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro result = (long)(((long long)a * b) >> shift); 152c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return result; 153c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 154c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro#endif 155c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 156c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a fixed point quaternion multiply. 157c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] q1 First Quaternion Multicand, length 4. 1.0 scaled 158c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* to 2^30 159c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] q2 Second Quaternion Multicand, length 4. 1.0 scaled 160c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* to 2^30 161c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] qProd Product after quaternion multiply. Length 4. 162c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* 1.0 scaled to 2^30. 163c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 164c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_mult(const long *q1, const long *q2, long *qProd) 165c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 166c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 167c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[0] = inv_q30_mult(q1[0], q2[0]) - inv_q30_mult(q1[1], q2[1]) - 168c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q30_mult(q1[2], q2[2]) - inv_q30_mult(q1[3], q2[3]); 169c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 170c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[1] = inv_q30_mult(q1[0], q2[1]) + inv_q30_mult(q1[1], q2[0]) + 171c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q30_mult(q1[2], q2[3]) - inv_q30_mult(q1[3], q2[2]); 172c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 173c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[2] = inv_q30_mult(q1[0], q2[2]) - inv_q30_mult(q1[1], q2[3]) + 174c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q30_mult(q1[2], q2[0]) + inv_q30_mult(q1[3], q2[1]); 175c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 176c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[3] = inv_q30_mult(q1[0], q2[3]) + inv_q30_mult(q1[1], q2[2]) - 177c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q30_mult(q1[2], q2[1]) + inv_q30_mult(q1[3], q2[0]); 178c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 179c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 180c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a fixed point quaternion addition. 181c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] q1 First Quaternion term, length 4. 1.0 scaled 182c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* to 2^30 183c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] q2 Second Quaternion term, length 4. 1.0 scaled 184c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* to 2^30 185c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] qSum Sum after quaternion summation. Length 4. 186c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* 1.0 scaled to 2^30. 187c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 188c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_add(long *q1, long *q2, long *qSum) 189c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 190c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 191c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[0] = q1[0] + q2[0]; 192c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[1] = q1[1] + q2[1]; 193c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[2] = q1[2] + q2[2]; 194c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[3] = q1[3] + q2[3]; 195c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 196c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 197c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_vector_normalize(long *vec, int length) 198c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 199c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 200c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro double normSF = 0; 201c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int ii; 202c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (ii = 0; ii < length; ii++) { 203c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF += 204c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q30_to_double(vec[ii]) * inv_q30_to_double(vec[ii]); 205c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 206c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (normSF > 0) { 207c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = 1 / sqrt(normSF); 208c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (ii = 0; ii < length; ii++) { 209c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro vec[ii] = (int)((double)vec[ii] * normSF); 210c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 211c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else { 212c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro vec[0] = 1073741824L; 213c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (ii = 1; ii < length; ii++) { 214c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro vec[ii] = 0; 215c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 216c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 217c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 218c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 219c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_normalize(long *q) 220c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 221c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 222c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_vector_normalize(q, 4); 223c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 224c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 225c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_invert(const long *q, long *qInverted) 226c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 227c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 228c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[0] = q[0]; 229c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[1] = -q[1]; 230c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[2] = -q[2]; 231c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[3] = -q[3]; 232c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 233c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 234c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarodouble quaternion_to_rotation_angle(const long *quat) { 235c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro double quat0 = (double )quat[0] / 1073741824; 236c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (quat0 > 1.0f) { 237c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro quat0 = 1.0; 238c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else if (quat0 < -1.0f) { 239c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro quat0 = -1.0; 240c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 241c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 242c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return acos(quat0)*2*180/M_PI; 243c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 244c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 245c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Rotates a 3-element vector by Rotation defined by Q 246c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 247c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_rotate(const long *q, const long *in, long *out) 248c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 249c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long q_temp1[4], q_temp2[4]; 250c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long in4[4], out4[4]; 251c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 252c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Fixme optimize 253c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro in4[0] = 0; 254c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro memcpy(&in4[1], in, 3 * sizeof(long)); 255c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_mult(q, in4, q_temp1); 256c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_invert(q, q_temp2); 257c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q_mult(q_temp1, q_temp2, out4); 258c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro memcpy(out, &out4[1], 3 * sizeof(long)); 259c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 260c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 261c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_multf(const float *q1, const float *q2, float *qProd) 262c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 263c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 264c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[0] = 265c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro (q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3]); 266c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[1] = 267c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro (q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2]); 268c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[2] = 269c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro (q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1]); 270c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qProd[3] = 271c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro (q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0]); 272c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 273c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 274c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_addf(const float *q1, const float *q2, float *qSum) 275c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 276c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 277c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[0] = q1[0] + q2[0]; 278c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[1] = q1[1] + q2[1]; 279c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[2] = q1[2] + q2[2]; 280c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qSum[3] = q1[3] + q2[3]; 281c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 282c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 283c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_normalizef(float *q) 284c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 285c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 286c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float normSF = 0; 287c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float xHalf = 0; 288c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); 289c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (normSF < 2) { 290c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xHalf = 0.5f * normSF; 291c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = normSF * (1.5f - xHalf * normSF * normSF); 292c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = normSF * (1.5f - xHalf * normSF * normSF); 293c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = normSF * (1.5f - xHalf * normSF * normSF); 294c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = normSF * (1.5f - xHalf * normSF * normSF); 295c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[0] *= normSF; 296c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[1] *= normSF; 297c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[2] *= normSF; 298c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[3] *= normSF; 299c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else { 300c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[0] = 1.0; 301c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[1] = 0.0; 302c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[2] = 0.0; 303c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[3] = 0.0; 304c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 305c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro normSF = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); 306c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 307c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 308c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Performs a length 4 vector normalization with a square root. 309c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in,out] q vector to normalize. Returns [1,0,0,0] is magnitude is zero. 310c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 311c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_norm4(float *q) 312c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 313c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float mag; 314c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro mag = sqrtf(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); 315c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (mag) { 316c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[0] /= mag; 317c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[1] /= mag; 318c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[2] /= mag; 319c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[3] /= mag; 320c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else { 321c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[0] = 1.f; 322c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[1] = 0.f; 323c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[2] = 0.f; 324c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro q[3] = 0.f; 325c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 326c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 327c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 328c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_q_invertf(const float *q, float *qInverted) 329c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 330c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro INVENSENSE_FUNC_START; 331c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[0] = q[0]; 332c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[1] = -q[1]; 333c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[2] = -q[2]; 334c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro qInverted[3] = -q[3]; 335c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 336c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 337c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** 338c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * Converts a quaternion to a rotation matrix. 339c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] quat 4-element quaternion in fixed point. One is 2^30. 340c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[out] rot Rotation matrix in fixed point. One is 2^30. The 341c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * First 3 elements of the rotation matrix, represent 342c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * the first row of the matrix. Rotation matrix multiplied 343c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * by a 3 element column vector transform a vector from Body 344c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * to World. 345c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 346c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_quaternion_to_rotation(const long *quat, long *rot) 347c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 348c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[0] = 349c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[1], quat[1]) + inv_q29_mult(quat[0], 350c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro quat[0]) - 351c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1073741824L; 352c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[1] = 353c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[1], quat[2]) - inv_q29_mult(quat[3], quat[0]); 354c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[2] = 355c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[1], quat[3]) + inv_q29_mult(quat[2], quat[0]); 356c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[3] = 357c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[1], quat[2]) + inv_q29_mult(quat[3], quat[0]); 358c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[4] = 359c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[2], quat[2]) + inv_q29_mult(quat[0], 360c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro quat[0]) - 361c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1073741824L; 362c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[5] = 363c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[2], quat[3]) - inv_q29_mult(quat[1], quat[0]); 364c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[6] = 365c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[1], quat[3]) - inv_q29_mult(quat[2], quat[0]); 366c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[7] = 367c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[2], quat[3]) + inv_q29_mult(quat[1], quat[0]); 368c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[8] = 369c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_q29_mult(quat[3], quat[3]) + inv_q29_mult(quat[0], 370c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro quat[0]) - 371c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1073741824L; 372c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 373c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 374c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** 375c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * Converts a quaternion to a rotation vector. A rotation vector is 376c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * a method to represent a 4-element quaternion vector in 3-elements. 377c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * To get the quaternion from the 3-elements, The last 3-elements of 378c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * the quaternion will be the given rotation vector. The first element 379c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * of the quaternion will be the positive value that will be required 380c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * to make the magnitude of the quaternion 1.0 or 2^30 in fixed point units. 381c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] quat 4-element quaternion in fixed point. One is 2^30. 382c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[out] rot Rotation vector in fixed point. One is 2^30. 383c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 384c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_quaternion_to_rotation_vector(const long *quat, long *rot) 385c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 386c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[0] = quat[1]; 387c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[1] = quat[2]; 388c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[2] = quat[3]; 389c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 390c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (quat[0] < 0.0) { 391c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[0] = -rot[0]; 392c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[1] = -rot[1]; 393c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro rot[2] = -rot[2]; 394c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 395c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 396c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 397c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts a 32-bit long to a big endian byte stream */ 398c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarounsigned char *inv_int32_to_big8(long x, unsigned char *big8) 399c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 400c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[0] = (unsigned char)((x >> 24) & 0xff); 401c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[1] = (unsigned char)((x >> 16) & 0xff); 402c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[2] = (unsigned char)((x >> 8) & 0xff); 403c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[3] = (unsigned char)(x & 0xff); 404c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return big8; 405c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 406c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 407c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts a big endian byte stream into a 32-bit long */ 408c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_big8_to_int32(const unsigned char *big8) 409c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 410c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long x; 411c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x = ((long)big8[0] << 24) | ((long)big8[1] << 16) | ((long)big8[2] << 8) 412c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro | ((long)big8[3]); 413c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return x; 414c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 415c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 416c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts a big endian byte stream into a 16-bit integer (short) */ 417c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaroshort inv_big8_to_int16(const unsigned char *big8) 418c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 419c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro short x; 420c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x = ((short)big8[0] << 8) | ((short)big8[1]); 421c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return x; 422c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 423c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 424c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts a little endian byte stream into a 16-bit integer (short) */ 425c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaroshort inv_little8_to_int16(const unsigned char *little8) 426c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 427c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro short x; 428c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x = ((short)little8[1] << 8) | ((short)little8[0]); 429c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return x; 430c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 431c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 432c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts a 16-bit short to a big endian byte stream */ 433c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarounsigned char *inv_int16_to_big8(short x, unsigned char *big8) 434c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 435c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[0] = (unsigned char)((x >> 8) & 0xff); 436c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro big8[1] = (unsigned char)(x & 0xff); 437c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return big8; 438c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 439c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 440c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_matrix_det_inc(float *a, float *b, int *n, int x, int y) 441c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 442c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int k, l, i, j; 443c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i = 0, k = 0; i < *n; i++, k++) { 444c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (j = 0, l = 0; j < *n; j++, l++) { 445c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (i == x) 446c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro i++; 447c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (j == y) 448c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro j++; 449c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *(b + 6 * k + l) = *(a + 6 * i + j); 450c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 451c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 452c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *n = *n - 1; 453c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 454c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 455c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_matrix_det_incd(double *a, double *b, int *n, int x, int y) 456c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 457c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int k, l, i, j; 458c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i = 0, k = 0; i < *n; i++, k++) { 459c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (j = 0, l = 0; j < *n; j++, l++) { 460c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (i == x) 461c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro i++; 462c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (j == y) 463c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro j++; 464c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *(b + 6 * k + l) = *(a + 6 * i + j); 465c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 466c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 467c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *n = *n - 1; 468c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 469c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 470c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarofloat inv_matrix_det(float *p, int *n) 471c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 472c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float d[6][6], sum = 0; 473c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int i, j, m; 474c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro m = *n; 475c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (*n == 2) 476c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return (*p ** (p + 7) - *(p + 1) ** (p + 6)); 477c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i = 0, j = 0; j < m; j++) { 478c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *n = m; 479c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_matrix_det_inc(p, &d[0][0], n, i, j); 480c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sum = 481c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sum + *(p + 6 * i + j) * SIGNM(i + 482c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro j) * 483c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_matrix_det(&d[0][0], n); 484c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 485c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 486c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return (sum); 487c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 488c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 489c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarodouble inv_matrix_detd(double *p, int *n) 490c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 491c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro double d[6][6], sum = 0; 492c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int i, j, m; 493c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro m = *n; 494c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (*n == 2) 495c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return (*p ** (p + 7) - *(p + 1) ** (p + 6)); 496c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i = 0, j = 0; j < m; j++) { 497c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *n = m; 498c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_matrix_det_incd(p, &d[0][0], n, i, j); 499c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sum = 500c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sum + *(p + 6 * i + j) * SIGNM(i + 501c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro j) * 502c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro inv_matrix_detd(&d[0][0], n); 503c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 504c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 505c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return (sum); 506c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 507c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 508c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Wraps angle from (-M_PI,M_PI] 509c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] ang Angle in radians to wrap 510c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return Wrapped angle from (-M_PI,M_PI] 511c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 512c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarofloat inv_wrap_angle(float ang) 513c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 514c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (ang > M_PI) 515c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return ang - 2 * (float)M_PI; 516c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (ang <= -(float)M_PI) 517c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return ang + 2 * (float)M_PI; 518c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else 519c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return ang; 520c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 521c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 522c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Finds the minimum angle difference ang1-ang2 such that difference 523c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * is between [-M_PI,M_PI] 524c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] ang1 525c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @param[in] ang2 526c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @return angle difference ang1-ang2 527c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 528c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarofloat inv_angle_diff(float ang1, float ang2) 529c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 530c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float d; 531c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro ang1 = inv_wrap_angle(ang1); 532c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro ang2 = inv_wrap_angle(ang2); 533c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro d = ang1 - ang2; 534c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (d > M_PI) 535c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro d -= 2 * (float)M_PI; 536c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (d < -(float)M_PI) 537c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro d += 2 * (float)M_PI; 538c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return d; 539c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 540c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 541c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** bernstein hash, derived from public domain source */ 542c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarouint32_t inv_checksum(const unsigned char *str, int len) 543c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 544c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro uint32_t hash = 5381; 545c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int i, c; 546c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 547c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i = 0; i < len; i++) { 548c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro c = *(str + i); 549c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 550c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 551c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 552c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return hash; 553c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 554c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 555c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarostatic unsigned short inv_row_2_scale(const signed char *row) 556c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 557c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro unsigned short b; 558c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 559c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (row[0] > 0) 560c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 0; 561c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (row[0] < 0) 562c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 4; 563c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (row[1] > 0) 564c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 1; 565c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (row[1] < 0) 566c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 5; 567c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (row[2] > 0) 568c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 2; 569c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (row[2] < 0) 570c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 6; 571c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else 572c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro b = 7; // error 573c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return b; 574c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 575c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 576c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 577c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Converts an orientation matrix made up of 0,+1,and -1 to a scalar representation. 578c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] mtx Orientation matrix to convert to a scalar. 579c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return Description of orientation matrix. The lowest 2 bits (0 and 1) represent the column the one is on for the 580c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* first row, with the bit number 2 being the sign. The next 2 bits (3 and 4) represent 581c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* the column the one is on for the second row with bit number 5 being the sign. 582c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* The next 2 bits (6 and 7) represent the column the one is on for the third row with 583c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* bit number 8 being the sign. In binary the identity matrix would therefor be: 584c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* 010_001_000 or 0x88 in hex. 585c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 586c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarounsigned short inv_orientation_matrix_to_scalar(const signed char *mtx) 587c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 588c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 589c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro unsigned short scalar; 590c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 591c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro /* 592c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro XYZ 010_001_000 Identity Matrix 593c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro XZY 001_010_000 594c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro YXZ 010_000_001 595c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro YZX 000_010_001 596c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro ZXY 001_000_010 597c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro ZYX 000_001_010 598c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 599c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 600c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro scalar = inv_row_2_scale(mtx); 601c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro scalar |= inv_row_2_scale(mtx + 3) << 3; 602c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro scalar |= inv_row_2_scale(mtx + 6) << 6; 603c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 604c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return scalar; 605c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 606c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 607c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Uses the scalar orientation value to convert from chip frame to body frame 608c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] orientation A scalar that represent how to go from chip to body frame 609c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] input Input vector, length 3 610c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] output Output vector, length 3 611c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 612c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_convert_to_body(unsigned short orientation, const long *input, long *output) 613c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 614c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[0] = input[orientation & 0x03] * SIGNSET(orientation & 0x004); 615c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[1] = input[(orientation>>3) & 0x03] * SIGNSET(orientation & 0x020); 616c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[2] = input[(orientation>>6) & 0x03] * SIGNSET(orientation & 0x100); 617c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 618c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 619c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Uses the scalar orientation value to convert from body frame to chip frame 620c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] orientation A scalar that represent how to go from chip to body frame 621c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] input Input vector, length 3 622c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] output Output vector, length 3 623c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 624c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_convert_to_chip(unsigned short orientation, const long *input, long *output) 625c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 626c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[orientation & 0x03] = input[0] * SIGNSET(orientation & 0x004); 627c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[(orientation>>3) & 0x03] = input[1] * SIGNSET(orientation & 0x020); 628c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[(orientation>>6) & 0x03] = input[2] * SIGNSET(orientation & 0x100); 629c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 630c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 631c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 632c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Uses the scalar orientation value to convert from chip frame to body frame and 633c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* apply appropriate scaling. 634c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] orientation A scalar that represent how to go from chip to body frame 635c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] sensitivity Sensitivity scale 636c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] input Input vector, length 3 637c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] output Output vector, length 3 638c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 639c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_convert_to_body_with_scale(unsigned short orientation, 640c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long sensitivity, 641c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro const long *input, long *output) 642c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 643c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[0] = inv_q30_mult(input[orientation & 0x03] * 644c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro SIGNSET(orientation & 0x004), sensitivity); 645c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[1] = inv_q30_mult(input[(orientation>>3) & 0x03] * 646c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro SIGNSET(orientation & 0x020), sensitivity); 647c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro output[2] = inv_q30_mult(input[(orientation>>6) & 0x03] * 648c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro SIGNSET(orientation & 0x100), sensitivity); 649c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 650c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 651c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** find a norm for a vector 652c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] a vector [3x1] 653c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] output the norm of the input vector 654c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 655c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarodouble inv_vector_norm(const float *x) 656c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 657c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]); 658c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 659c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 660c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_init_biquad_filter(inv_biquad_filter_t *pFilter, float *pBiquadCoeff) { 661c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int i; 662c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // initial state to zero 663c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[0] = 0; 664c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[1] = 0; 665c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 666c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // set up coefficients 667c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i=0; i<5; i++) { 668c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->c[i] = pBiquadCoeff[i]; 669c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 670c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 671c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 672c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_calc_state_to_match_output(inv_biquad_filter_t *pFilter, float input) 673c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 674c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->input = input; 675c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->output = input; 676c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[0] = input / (1 + pFilter->c[2] + pFilter->c[3]); 677c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[1] = pFilter->state[0]; 678c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 679c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 680c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarofloat inv_biquad_filter_process(inv_biquad_filter_t *pFilter, float input) { 681c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro float stateZero; 682c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 683c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->input = input; 684c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // calculate the new state; 685c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro stateZero = pFilter->input - pFilter->c[2]*pFilter->state[0] 686c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro - pFilter->c[3]*pFilter->state[1]; 687c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 688c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->output = stateZero + pFilter->c[0]*pFilter->state[0] 689c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro + pFilter->c[1]*pFilter->state[1]; 690c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 691c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // update the output and state 692c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->output = pFilter->output * pFilter->c[4]; 693c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[1] = pFilter->state[0]; 694c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pFilter->state[0] = stateZero; 695c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return pFilter->output; 696c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 697c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 698c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid inv_get_cross_product_vec(float *cgcross, float compass[3], float grav[3]) { 699c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 700c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[0] = (float)compass[1] * grav[2] - (float)compass[2] * grav[1]; 701c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[1] = (float)compass[2] * grav[0] - (float)compass[0] * grav[2]; 702c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cgcross[2] = (float)compass[0] * grav[1] - (float)compass[1] * grav[0]; 703c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 704c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 705c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarovoid mlMatrixVectorMult(long matrix[9], const long vecIn[3], long *vecOut) { 706c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // matrix format 707c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // [ 0 3 6; 708c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // 1 4 7; 709c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // 2 5 8] 710c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 711c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // vector format: [0 1 2]^T; 712c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int i, j; 713c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long temp; 714c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 715c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (i=0; i<3; i++) { 716c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp = 0; 717c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro for (j=0; j<3; j++) { 718c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro temp += inv_q30_mult(matrix[i+j*3], vecIn[j]); 719c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 720c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro vecOut[i] = temp; 721c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 722c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 723c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 724c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro//============== 1/sqrt(x), 1/x, sqrt(x) Functions ================================ 725c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 726c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Calculates 1/square-root of a fixed-point number (30 bit mantissa, positive): Q1.30 727c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Input must be a positive scaled (2^30) integer 728c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* The number is scaled to lie between a range in which a Newton-Raphson 729c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* iteration works best. Corresponding square root of the power of two is returned. 730c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Caller must scale final result by 2^rempow (while avoiding overflow). 731c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] x0, length 1 732c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] rempow, length 1 733c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return scaledSquareRoot on success or zero. 734c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 735c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_inverse_sqrt(long x0, int*rempow) 736c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 737c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% Inverse sqrt NR in the neighborhood of 1.3>x>=0.65 738c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% x(k+1) = x(k)*(3 - x0*x(k)^2) 739c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 740c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% Seed equals 1. Works best in this region. 741c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //xx0 = int32(1*2^30); 742c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 743c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long oneoversqrt2, oneandhalf, x0_2; 744c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro unsigned long xx; 745c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int pow2, sq2scale, nr_iters; 746c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //long upscale, sqrt_upscale, upsclimit; 747c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //long downscale, sqrt_downscale, downsclimit; 748c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 749c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Precompute some constants for efficiency 750c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% int32(2^30*1/sqrt(2)) 751c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro oneoversqrt2=759250125L; 752c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% int32(1.5*2^30); 753c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro oneandhalf=1610612736L; 754c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 755c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //// Further scaling into optimal region saves one or more NR iterations. Maps into region (.9, 1.1) 756c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //// int32(0.9/log(2)*2^30) 757c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //upscale = 1394173804L; 758c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //// int32(sqrt(0.9/log(2))*2^30) 759c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //sqrt_upscale = 1223512453L; 760c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // // int32(1.1*log(2)/.9*2^30) 761c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //upsclimit = 909652478L; 762c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //// int32(1.1/log(4)*2^30) 763c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //downscale = 851995103L; 764c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //// int32(sqrt(1.1/log(4))*2^30) 765c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //sqrt_downscale = 956463682L; 766c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // // int32(0.9*log(4)/1.1*2^30) 767c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //downsclimit = 1217881829L; 768c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 769c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = test_limits_and_scale(&x0, &pow2); 770c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 771c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sq2scale=pow2%2; // Find remainder. Is it even or odd? 772c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 773c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 774c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Further scaling to decrease NR iterations 775c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // With the mapping below, 89% of calculations will require 2 NR iterations or less. 776c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // TBD 777c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 778c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 779c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x0_2 = x0 >>1; // This scaling incorporates factor of 2 in NR iteration below. 780c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Initial condition starts at 1: xx=(1L<<30); 781c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // First iteration is simple: Instead of initializing xx=1, assign to result of first iteration: 782c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // xx= (3/2-x0/2); 783c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% NR formula: xx=xx*(3/2-x0*xx*xx/2); = xx*(1.5 - (x0/2)*xx*xx) 784c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Initialize NR (first iteration). Note we are starting with xx=1, so the first iteration becomes an initialization. 785c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = oneandhalf - x0_2; 786c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters>=2 ) { 787c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Second NR iteration 788c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, ( oneandhalf - inv_q30_mult(x0_2, inv_q30_mult(xx,xx) ) ) ); 789c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters==3 ) { 790c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Third NR iteration. 791c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, ( oneandhalf - inv_q30_mult(x0_2, inv_q30_mult(xx,xx) ) ) ); 792c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Fourth NR iteration: Not needed due to single precision. 793c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 794c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 795c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (sq2scale) { 796c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *rempow = (pow2>>1) + 1; // Account for sqrt(2) in denominator, note we multiply if s2scale is true 797c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return (inv_q30_mult(xx,oneoversqrt2)); 798c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 799c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else { 800c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *rempow = pow2>>1; 801c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return xx; 802c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 803c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 804c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 805c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 806c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Calculates square-root of a fixed-point number (30 bit mantissa, positive) 807c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Input must be a positive scaled (2^30) integer 808c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* The number is scaled to lie between a range in which a Newton-Raphson 809c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* iteration works best. 810c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] x0, length 1 811c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return scaledSquareRoot on success or zero. **/ 812c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_fast_sqrt(long x0) 813c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 814c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 815c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% Square-Root with NR in the neighborhood of 1.3>x>=0.65 (log(2) <= x <= log(4) ) 816c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Two-variable NR iteration: 817c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Initialize: a=x; c=x-1; 818c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // 1st Newton Step: a=a-a*c/2; ( or: a = x - x*(x-1)/2 ) 819c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Iterate: c = c*c*(c-3)/4 820c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // a = a - a*c/2 --> reevaluating c at this step gives error of approximation 821c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 822c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% Seed equals 1. Works best in this region. 823c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //xx0 = int32(1*2^30); 824c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 825c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long sqrt2, oneoversqrt2, one_pt5; 826c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long xx, cc; 827c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int pow2, sq2scale, nr_iters; 828c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 829c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Return if input is zero. Negative should really error out. 830c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0 <= 0L) { 831c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 0L; 832c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 833c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 834c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sqrt2 =1518500250L; 835c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro oneoversqrt2=759250125L; 836c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro one_pt5=1610612736L; 837c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 838c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = test_limits_and_scale(&x0, &pow2); 839c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 840c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sq2scale = 0; 841c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (pow2 > 0) 842c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro sq2scale=pow2%2; // Find remainder. Is it even or odd? 843c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro pow2 = pow2-sq2scale; // Now pow2 is even. Note we are adding because result is scaled with sqrt(2) 844c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 845c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Sqrt 1st NR iteration 846c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cc = x0 - (1L<<30); 847c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = x0 - (inv_q30_mult(x0, cc)>>1); 848c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters>=2 ) { 849c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Sqrt second NR iteration 850c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // cc = cc*cc*(cc-3)/4; = cc*cc*(cc/2 - 3/2)/2; 851c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // cc = ( cc*cc*((cc>>1) - onePt5) ) >> 1 852c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cc = inv_q30_mult( cc, inv_q30_mult(cc, (cc>>1) - one_pt5) ) >> 1; 853c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = xx - (inv_q30_mult(xx, cc)>>1); 854c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters==3 ) { 855c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Sqrt third NR iteration 856c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro cc = inv_q30_mult( cc, inv_q30_mult(cc, (cc>>1) - one_pt5) ) >> 1; 857c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = xx - (inv_q30_mult(xx, cc)>>1); 858c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 859c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 860c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (sq2scale) 861c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult(xx,oneoversqrt2); 862c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Scale the number with the half of the power of 2 scaling 863c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (pow2>0) 864c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = (xx >> (pow2>>1)); 865c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (pow2 == -1) 866c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult(xx,sqrt2); 867c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return xx; 868c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 869c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 870c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Calculates 1/x of a fixed-point number (30 bit mantissa) 871c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Input must be a scaled (2^30) integer (+/-) 872c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* The number is scaled to lie between a range in which a Newton-Raphson 873c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* iteration works best. Corresponding multiplier power of two is returned. 874c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Caller must scale final result by 2^pow (while avoiding overflow). 875c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] x, length 1 876c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] pow, length 1 877c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return scaledOneOverX on success or zero. 878c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 879c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccarolong inv_one_over_x(long x0, int*pow) 880c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 881c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% NR for 1/x in the neighborhood of log(2) => x => log(4) 882c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% y(k+1)=y(k)*(2 \ 96 x0*y(k)) 883c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //% with y(0) = 1 as the starting value for NR 884c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 885c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long two, xx; 886c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int numberwasnegative, nr_iters, did_upscale, did_downscale; 887c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 888c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long upscale, downscale, upsclimit, downsclimit; 889c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 890c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow = 0; 891c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Return if input is zero. 892c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0 == 0L) { 893c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 0L; 894c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 895c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 896c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // This is really (2^31-1), i.e. 1.99999... . 897c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Approximation error is 1e-9. Note 2^31 will overflow to sign bit, so it can't be used here. 898c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro two = 2147483647L; 899c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 900c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(0.92/log(2)*2^30) 901c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro upscale = 1425155444L; 902c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(1.08/upscale*2^30) 903c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro upsclimit = 873697834L; 904c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 905c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(1.08/log(4)*2^30) 906c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro downscale = 836504283L; 907c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(0.92/downscale*2^30) 908c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro downsclimit = 1268000423L; 909c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 910c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Algorithm is intended to work with positive numbers only. Change sign: 911c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro numberwasnegative = 0; 912c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0 < 0L) { 913c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro numberwasnegative = 1; 914c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x0 = -x0; 915c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 916c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 917c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = test_limits_and_scale(&x0, pow); 918c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 919c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro did_upscale=0; 920c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro did_downscale=0; 921c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Pre-scaling to reduce NR iterations and improve accuracy: 922c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0<=upsclimit) { 923c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x0 = inv_q30_mult(x0, upscale); 924c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro did_upscale = 1; 925c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // The scaling ALWAYS leaves the number in the 2-NR iterations region: 926c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = 2; 927c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Is x0 in the single NR iteration region (0.994, 1.006) ? 928c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0 > 1067299373 && x0 < 1080184275) 929c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = 1; 930c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else if (x0>=downsclimit) { 931c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro x0 = inv_q30_mult(x0, downscale); 932c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro did_downscale = 1; 933c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // The scaling ALWAYS leaves the number in the 2-NR iterations region: 934c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = 2; 935c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Is x0 in the single NR iteration region (0.994, 1.006) ? 936c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (x0 > 1067299373 && x0 < 1080184275) 937c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro nr_iters = 1; 938c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 939c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 940c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = (two - x0) + 1; // Note 2 will overflow so the computation (2-x) is done with "two" == (2^30-1) 941c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // First NR iteration 942c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, (two - inv_q30_mult(x0, xx)) + 1 ); 943c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters>=2 ) { 944c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Second NR iteration 945c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, (two - inv_q30_mult(x0, xx)) + 1 ); 946c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( nr_iters==3 ) { 947c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // THird NR iteration. 948c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, (two - inv_q30_mult(x0, xx)) + 1 ); 949c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Fourth NR iteration: Not needed due to single precision. 950c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 951c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 952c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 953c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Post-scaling 954c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (did_upscale) 955c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, upscale); 956c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (did_downscale) 957c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = inv_q30_mult( xx, downscale); 958c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 959c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (numberwasnegative) 960c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro xx = -xx; 961c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return xx; 962c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 963c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 964c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Auxiliary function used by inv_OneOverX(), inv_fastSquareRoot(), inv_inverseSqrt(). 965c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Finds the range of the argument, determines the optimal number of Newton-Raphson 966c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* iterations and . Corresponding square root of the power of two is returned. 967c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Restrictions: Number is represented as Q1.30. 968c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Number is betweeen the range 2<x<=0 969c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] x, length 1 970c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[out] pow, length 1 971c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return # of NR iterations, x0 scaled between log(2) and log(4) and 2^N scaling (N=pow) 972c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 973c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaroint test_limits_and_scale(long *x0, int *pow) 974c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 975c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long lowerlimit, upperlimit, oneiterlothr, oneiterhithr, zeroiterlothr, zeroiterhithr; 976c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 977c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Lower Limit: ll = int32(log(2)*2^30); 978c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro lowerlimit = 744261118L; 979c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //Upper Limit ul = int32(log(4)*2^30); 980c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro upperlimit = 1488522236L; 981c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(0.9*2^30) 982c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro oneiterlothr = 966367642L; 983c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(1.1*2^30) 984c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro oneiterhithr = 1181116006L; 985c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // int32(0.99*2^30) 986c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro zeroiterlothr=1063004406L; 987c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro //int32(1.01*2^30) 988c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro zeroiterhithr=1084479242L; 989c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 990c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Scale number such that Newton Raphson iteration works best: 991c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Find the power of two scaling that leaves the number in the optimal range, 992c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // ll <= number <= ul. Note odd powers have special scaling further below 993c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (*x0 > upperlimit) { 994c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Halving the number will push it in the optimal range since largest value is 2 995c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *x0 = *x0>>1; 996c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow=-1; 997c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else if (*x0 < lowerlimit) { 998c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Find position of highest bit, counting from left, and scale number 999c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow=get_highest_bit_position((unsigned long*)x0); 1000c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (*x0 >= upperlimit) { 1001c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Halving the number will push it in the optimal range 1002c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *x0 = *x0>>1; 1003c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow=*pow-1; 1004c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1005c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro else if (*x0 < lowerlimit) { 1006c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // Doubling the number will push it in the optimal range 1007c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *x0 = *x0<<1; 1008c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow=*pow+1; 1009c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1010c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } else { 1011c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *pow = 0; 1012c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1013c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1014c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( *x0<oneiterlothr || *x0>oneiterhithr ) 1015c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 3; // 3 NR iterations 1016c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ( *x0<zeroiterlothr || *x0>zeroiterhithr ) 1017c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 2; // 2 NR iteration 1018c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1019c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 1; // 1 NR iteration 1020c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 1021c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1022c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** Auxiliary function used by testLimitsAndScale() 1023c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* Find the highest nonzero bit in an unsigned 32 bit integer: 1024c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @param[in] value, length 1. 1025c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro* @return highes bit position. 1026c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro**/int get_highest_bit_position(unsigned long *value) 1027c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 1028c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro int position; 1029c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position = 0; 1030c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if (*value == 0) return 0; 1031c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1032c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((*value & 0xFFFF0000) == 0) { 1033c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position += 16; 1034c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *value=*value<<16; 1035c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1036c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((*value & 0xFF000000) == 0) { 1037c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position += 8; 1038c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *value=*value<<8; 1039c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1040c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((*value & 0xF0000000) == 0) { 1041c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position += 4; 1042c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *value=*value<<4; 1043c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1044c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((*value & 0xC0000000) == 0) { 1045c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position += 2; 1046c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *value=*value<<2; 1047c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1048c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1049c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // If we got too far into sign bit, shift back. Note we are using an 1050c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro // unsigned long here, so right shift is going to shift all the bits. 1051c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro if ((*value & 0x80000000)) { 1052c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro position -= 1; 1053c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro *value=*value>>1; 1054c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro } 1055c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return position; 1056c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 1057c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1058c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/* compute real part of quaternion, element[0] 1059c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro@param[in] inQuat, 3 elements gyro quaternion 1060c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro@param[out] outquat, 4 elements gyro quaternion 1061c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro*/ 1062c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaroint inv_compute_scalar_part(const long * inQuat, long* outQuat) 1063c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro{ 1064c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro long scalarPart = 0; 1065c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1066c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro scalarPart = inv_fast_sqrt((1L<<30) - inv_q30_mult(inQuat[0], inQuat[0]) 1067c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro - inv_q30_mult(inQuat[1], inQuat[1]) 1068c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro - inv_q30_mult(inQuat[2], inQuat[2]) ); 1069c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro outQuat[0] = scalarPart; 1070c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro outQuat[1] = inQuat[0]; 1071c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro outQuat[2] = inQuat[1]; 1072c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro outQuat[3] = inQuat[2]; 1073c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro 1074c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro return 0; 1075c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro} 1076c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro/** 1077c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro * @} 1078c3d4ca9f2df5ddf9894b36d1554fdfc95d625d3fNick Vaccaro */ 1079