计算没有std函数或C99的atan2

我正在计算3轴加速度计的角度,但我的编译器没有atan或atan2function。 它有一个保留的内存插槽,但它调用了一个我在任何文件中都找不到的function。

我的编译器是运行ARMCC编译器的KeilμVision4。 编译有文件math.h,但函数是extern并且不存在:

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

是否有我可以包含的lib或函数,它具有arctan函数的实现? 或者是否有另一种function来计算加速度计的角度? 我需要完整的3轴角度校准。

编辑:我希望避免一个充满预先计算值的表格。

实现自己的arctan2并不是很困难。 使用此公式将arctan2转换为arctan 。 然后你可以使用这个无限系列来计算arctan 。 如果你总结这个无限系列的足够数量的项,你将非常接近库函数arctan2作用。

这是exp()一个类似实现 ,您可以将其用作参考。

下面的代码使用有理逼近来使反正切归一化到[0 1]区间(你可以将结果乘以Pi / 2得到真正的反正切)

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

其中b = 0.596227

最大误差为0.1620º

 #include  #include  // 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; } 

如果您需要更高的精度,有一个三阶有理函数:

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

其中c =(1 + sqrt(17))/ 8

其最大近似误差为0.00811º

这里有一个开源实现。

数学函数的实际实现(或HWFPU的存根(如果存在)应该在libm中。 使用GCC通过将-lm传递给编译器来表示,但我不知道如何使用您的特定工具。