2

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

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

因此,我尝试为 to 构建自己的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 份。我可以稍微增加它,但它没有多大帮助,看起来我需要一些插值。任何人都可以建议对我的功能进行一些实际的改进以获得更好的结果吗?下面是 234 个不同结果的图表e。蓝色系列具有理想的 sin/cos,红色系列来自 LUT。

在此处输入图像描述

4

2 回答 2

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]);

分别

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

这不应该太慢,并且应该在 LUT 点之间提供更好的近似值。

于 2012-12-06T19:19:42.710 回答
1

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

于 2012-12-06T18:59:21.850 回答