5

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

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

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

是否有一个我可以包含的库或函数已经实现了函数 arctan?或者是否有替代功能来计算加速度计的角度?我需要对角度进行完整的 3 轴校准。

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

4

4 回答 4

10

以下代码使用有理近似值将反正切归一化为 [0 1) 区间(您可以将结果乘以 Pi/2 以获得真正的反正切)

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

其中 b = 0.596227

最大误差为 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;
} 

如果您需要更高的精度,可以使用三阶有理函数:

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º

于 2012-12-31T11:29:18.540 回答
8

自己实现也不是很困难arctan2。转换arctan2arctan使用公式。然后您可以arctan使用这个无限级数进行计算。如果你对这个无限级数的足够数量的项求和,你将非常接近库函数的arctan2作用。

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

于 2012-08-13T08:51:03.590 回答
4

这里有一个开源的 atan 实现。

于 2012-08-13T11:25:43.140 回答
0

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

于 2012-08-13T08:33:52.620 回答