2012-12-06 126 views
2

我想優化我的MCU的sin/cos以計算地理距離。公式的這一部分尤其是使用三角:如何改善正弦/餘弦函數?

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

所以我試圖建立自己的sin/cos查找表-PIPI如下:

#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個不同結果的圖表。藍色系列具有理想的正弦/餘弦,紅色來自LUT。

enter image description here

+0

你可以嘗試使用導數sin(x + h)〜sin x + h * cos x'來近似,這應該給出更好的結果。 –

+0

@Daniel Fischer:你的意思是填充查找表嗎?你能否用一些小的僞代碼來回答,這會給我提示如何實現它? – Pablo

回答

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點之間更好的近似值。

+0

不錯,讓我試試這個! – Pablo

+0

這使得LUT的結果與理想的結果相差甚遠!我真的很感謝你的幫助! – Pablo

+0

實際上,當結果是切換標誌時會有一些小問題...我會盡量簡短地描述它。如果您能跟進並幫助我解決問題,我將不勝感激。 – Pablo

1

贖罪舊的,但良好的遞推關係/ COS插補描述here

+0

這是我應該在LUT上應用的東西,當從表中加載值或者這可以完全替代LUT?我認爲插值可以使用表格中的相鄰值完成。 – Pablo