计算没有std函数或C99的atan2

Jef*_*ffa 4 c embedded math arm atan2

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

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

  extern _ARMABI double atan2(double /*y*/, double /*x*/);
Run Code Online (Sandbox Code Playgroud)

是否有我可以包含的lib或函数,它具有arctan函数的实现?或者是否有另一种从加速度计计算角度的功能?我需要对角度进行完整的3轴校准.

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

Pav*_*ath 7

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

以下是您可以用作参考的一个类似实现exp().

  • 这些无限级数对于探索函数的数学性质很有用,但它们不适合计算.它们收敛速度慢,需要很多项才能得到准确的结果,并且很难在没有累积错误的情况下以浮点计算.通常,数学库通过使用minimax多项式来计算这些函数,这些多项式旨在使用几个项最小化最大误差. (5认同)
  • 另外,由于各种原因,功能被划分为间隔.arctan应划分为| x | <1和| x | > 1(| x | = 1可以在任一分区中).对于| x | <1,arctan(x)用minimax多项式近似.对于| x | > 1,arctan(x)可以用1/x作为输入的极小极大多项式近似. (2认同)

小智 5

下面的代码使用有理逼近来将反正则归一化到[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;
} 
Run Code Online (Sandbox Code Playgroud)

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

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º