diff --git a/images/error_analysis.ods b/images/error_analysis.ods new file mode 100644 index 0000000..e410dd3 Binary files /dev/null and b/images/error_analysis.ods differ diff --git a/libfixmath/fix16.h b/libfixmath/fix16.h index dfb8cb7..7763389 100644 --- a/libfixmath/fix16.h +++ b/libfixmath/fix16.h @@ -10,6 +10,10 @@ extern "C" typedef int32_t fix16_t; +static const fix16_t FOUR_DIV_PI = 0x145F3; /*!< Fix16 value of 4/PI */ +static const fix16_t _FOUR_DIV_PI2 = 0xFFFF9840; /*!< Fix16 value of -4/PI² */ +static const fix16_t X4_CORRECTION_COMPONENT = 0x399A; /*!< Fix16 value of 0.225 */ + static const fix16_t fix16_max = 0x7FFFFFFF; /*!< the maximum value of fix16_t */ static const fix16_t fix16_min = 0x80000000; /*!< the minimum value of fix16_t */ @@ -80,7 +84,9 @@ extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract); extern fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract); #endif - +/*! Returns the sine of the given fix16_t. +*/ +extern fix16_t fix16_sin_parabola(fix16_t inAngle); /*! Returns the sine of the given fix16_t. */ diff --git a/libfixmath/fix16_trig.c b/libfixmath/fix16_trig.c index a198b3d..2f92d31 100644 --- a/libfixmath/fix16_trig.c +++ b/libfixmath/fix16_trig.c @@ -1,3 +1,4 @@ +#include #include "fix16.h" #if defined(FIXMATH_SIN_LUT) @@ -13,6 +14,35 @@ static fix16_t _fix16_atan_cache_value[4096] = { 0 }; #endif +fix16_t fix16_sin_parabola(fix16_t inAngle) +{ + fix16_t abs_inAngle, abs_retval, retval; + fix16_t mask; + + /* Absolute function */ + mask = (inAngle >> (sizeof(fix16_t)*CHAR_BIT-1)); + abs_inAngle = (inAngle + mask) ^ mask; + + /* On 0->PI, sin looks like x² that is : + - centered on PI/2, + - equals 1 on PI/2, + - equals 0 on 0 and PI + that means : 4/PI * x - 4/PI² * x² + Use abs(x) to handle (-PI) -> 0 zone. + */ + retval = fix16_mul(FOUR_DIV_PI, inAngle) + fix16_mul( fix16_mul(_FOUR_DIV_PI2, inAngle), abs_inAngle ); + /* At this point, retval equals sin(inAngle) on important points ( -PI, -PI/2, 0, PI/2, PI), + but is not very precise between these points + */ + #ifndef FIXMATH_FAST_SIN + /* Absolute value of retval */ + mask = (retval >> (sizeof(fix16_t)*CHAR_BIT-1)); + abs_retval = (retval + mask) ^ mask; + /* So improve its precision by adding some x^4 component to retval */ + retval += fix16_mul(X4_CORRECTION_COMPONENT, fix16_mul(retval, abs_retval) - retval ); + #endif + return retval; +} fix16_t fix16_sin(fix16_t inAngle) { fix16_t tempAngle = inAngle % (fix16_pi << 1);