如何改善sin / cos lut功能?

时间:2012-12-06 18:54:28

标签: c trigonometry

我正在尝试为我的MCU优化sin / cos以计算地理距离。这部分公式特别使用三角法:

double e = (MyTan( lat2 / 2 + quarter_pi ) / MyTan( lat1 / 2 + quarter_pi ));

所以我尝试为sin/cos-PI构建我自己的PI查找表,如下所示:

#define PARTPERDEGREE 10
double mysinlut[PARTPERDEGREE * 90 + 1];
double mycoslut[PARTPERDEGREE * 90 + 1];
void MySinCosCreate()
{
    int i;
    double angle, angleinc;

    // Each degree also divided into 10 parts
    angleinc = (M_PI / 180) / PARTPERDEGREE;
    for (i = 0, angle = 0.0; i <= (PARTPERDEGREE * 90 + 1); ++i, angle += angleinc)
    {
        mysinlut[i] = sin(angle);
    }

    angleinc = (M_PI / 180) / PARTPERDEGREE;
    for (i = 0, angle = 0.0; i <= (PARTPERDEGREE * 90 + 1); ++i, angle += angleinc)
    {
        mycoslut[i] = cos(angle);
    }
}



double MySin(double rad)
{
   int ix;
   int sign = 1;


   if(rad > (M_PI / 2))
        rad = M_PI / 2 - (rad - M_PI / 2);

   if(rad < -(M_PI / 2))
       rad = -M_PI / 2 - (rad + M_PI / 2);

   if(rad < 0)
   {
        sign = -1;
        rad *= -1;
   }

   ix = (rad * 180) / M_PI * PARTPERDEGREE;

   return sign * mysinlut[ix];
}

double MyCos(double rad)
{
   int ix;
   int sign = 1;


    if(rad > M_PI / 2)
    {
        rad = M_PI / 2 - (rad - M_PI / 2);
        sign = -1;
    }
    else if(rad < -(M_PI / 2))
    {
        rad = M_PI / 2 + (rad + M_PI / 2);
        sign = -1;
    }
    else if(rad > -M_PI / 2 && rad < M_PI / 2)
    {   
        rad = abs(rad);
        sign = 1;
    }

    ix = (rad * 180) / M_PI * PARTPERDEGREE;

    return sign * mycoslut[ix];
}

double MyTan(double rad)
{
    return MySin(rad) / MyCos(rad);
}

你可以看到表的分辨率是每度10个部分。我可以增加一点,但它没有多大帮助,看起来我需要一些插值。任何人都可以建议我的功能有一些实际改进,以获得更好的结果下面是e的234个不同结果的图表。蓝色系列具有理想的sin / cos,红色来自LUT。

enter image description here

2 个答案:

答案 0 :(得分:4)

您的查找表似乎太粗糙了。如果你不能使你的表更精细,使用导数近似值可以得到更好的结果。我们有

sin (x+h) ≈ sin x + h*cos x
cos (x+h) ≈ cos x - h*sin x

代表小h。 (您可以使用更高的导数或使用表中您的(计算的)角度所在的值来获得更好的近似值,但这需要更长的时间,而我收集速度是LUT首先出现的原因。)

因此,在您使用

对角度进行标准化后
ix = (rad * 180) / M_PI * PARTPERDEGREE;

使用

double h = rad - ix*angleinc;
return sign*(mysinlut[ix] + h*mycoslut[ix]);

RESP。

return sign*(mycoslut[ix] - h*mysinlut[ix]);

这不应该太慢,并且应该在LUT点之间给出明显更好的近似值。

答案 1 :(得分:1)

描述here的sin / cos插值的旧但好的递归关系。