我正在计算3轴加速度计的角度,但我的编译器没有atan或atan2功能。它有一个保留的内存插槽,但它调用了我在任何文件中都找不到的功能。
我的编译器是运行ARMCC编译器的KeilμVision4。 编译有文件math.h,但函数是extern并且不存在:
extern _ARMABI double atan2(double /*y*/, double /*x*/);
我是否可以包含具有arctan功能的lib或函数? 或者是否有另一种从加速度计计算角度的功能?我需要完整的3轴角度校准。
编辑:我希望避免使用充满预先计算值的表格。
答案 0 :(得分:7)
实现自己的arctan2
并不是很困难。使用this公式将arctan2
转换为arctan
。然后,您可以使用此infinite series计算arctan
。如果你总结这个无限系列的足够数量的术语,你将非常接近库函数arctan2
的作用。
以下是一个类似的implementation for exp()
,您可以将其作为参考。
答案 1 :(得分:5)
以下代码使用rational approximation来将反正则归一化到[0 1]区间(您可以将结果乘以Pi / 2以获得真正的反正切)
normalized_atan(x)〜(b x + x ^ 2)/(1 + 2 b x + 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)〜(c x + x ^ 2 + x ^ 3)/(1 +(c + 1)x +(c + 1)x ^ 2 + x ^ 3)
其中c =(1 + sqrt(17))/ 8
最大近似误差为0.00811º
答案 2 :(得分:4)
有一个开源实现here。
答案 3 :(得分:0)
数学函数的实际实现(或HWFPU的存根(如果存在)应该在libm中。使用GCC通过将-lm
传递给编译器来表示,但我不知道如何使用您的特定工具。