Compute atan2 without std functions or C99

I calculate angles from a 3-axis accelerometer, but my compiler does not have atan or atan2 functions. It has a reserved memory slot, but it calls a function that I cannot find in any files.

My Keil μVision 4 compiler works with the ARMCC compiler. Compilations have the math.h file, but the extern function does not exist:

extern _ARMABI double atan2(double /*y*/, double /*x*/); 

Is there a lib or function that I can enable that executes the arctan function? Or is there an alternative function for calculating angles from an accelerometer? I need a full 3-axis angle calibration.

Edit: I was hoping to avoid a table full of pre-calculated values.

+3
source share
4 answers

It is not very difficult to implement your own arctan2 . Convert arctan2 to arctan using this formula. And you can calculate arctan using this endless series . If you summarize enough members of this infinite series, you will get very close to what the arctan2 library function arctan2 .

Here is one of the implementations for exp() that you can use as a reference.

+6
source

The following code uses a rational approximation to get the arc tangent normalized to the interval [0 1) (you can multiply the result by Pi / 2 to get the real arc tangent)

normalized_atan (x) ~ (bx + x ^ 2) / (1 + 2 bx + x ^ 2)

where b = 0.596227

Maximum accuracy 0.1620º

 #include <stdint.h> #include <math.h> // Approximates atan(x) normalized to the [-1,1] range // with a maximum error of 0.1620 degrees. float normalized_atan( float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bit uint32_t ux_s = sign_mask & (uint32_t &)x; // Calculate the arctangent in the first quadrant float bx_a = ::fabs( b * x ); float num = bx_a + x * x; float atan_1q = num / ( 1.f + bx_a + num ); // Restore the sign bit uint32_t atan_2q = ux_s | (uint32_t &)atan_1q; return (float &)atan_2q; } // Approximates atan2(y, x) normalized to the [0,4) range // with a maximum error of 0.1620 degrees float normalized_atan2( float y, float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bits uint32_t ux_s = sign_mask & (uint32_t &)x; uint32_t uy_s = sign_mask & (uint32_t &)y; // Determine the quadrant offset float q = (float)( ( ~ux_s & uy_s ) >> 29 | ux_s >> 30 ); // Calculate the arctangent in the first quadrant float bxy_a = ::fabs( b * x * y ); float num = bxy_a + y * y; float atan_1q = num / ( x * x + bxy_a + num ); // Translate it to the proper quadrant uint32_t uatan_2q = (ux_s ^ uy_s) | (uint32_t &)atan_1q; return q + (float &)uatan_2q; } 

If you need higher accuracy, there is a 3rd order rational function:

normalized_atan (x) ~ (cx + x ^ 2 + x ^ 3) / (1 + (c + 1) x + (c + 1) x ^ 2 + x ^ 3)

where c = (1 + sqrt (17)) / 8

which has a maximum approximation error of 0.00811º

+5
source

There is open source code for implementation here .

+4
source

Actual implementations of math functions (or stubs for HWFPU, if any) should be in libm. With GCC, this is indicated by passing -lm compiler, but I don't know how to do this with your specific tools.

0
source

Source: https://habr.com/ru/post/1496584/


All Articles