我正在尝试为我的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。
答案 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插值的旧但好的递归关系。