2016-03-30 9 views
0

私は書いている小さなGPSプログラムでHaversineフォーミュラを実装しようとしています。距離の計算は、スポット・オンであるように見えます。しかし、私はベアリングがラジアンで計算されていると信じていますし、結果をコンパス方向(北は0、東は90など)に正しく変換する方法がわかりません。Haversineのベアリング計算による不正確な結果

何か助けていただければ幸いです。コサインとアークタンジェントのこのすべての話は、私に大きな頭痛を与えています!私はコーダーであり、数学者ではありません!

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

void FindDistance (double latHome, double lonHome, double latDest, double lonDest) 
{ 
    double pi=3.141592653589793; 
    int R=6371; //Radius of the Earth in kilometers 
    //Keep the parameters passed to the function immutable 
    double latHomeTmp=(pi/180)*(latHome); 
    double latDestTmp=(pi/180)*(latDest); 
    double differenceLon= (pi/180)*(lonDest- lonHome); 
    double differenceLat=(pi/180)*(latDest- latHome); 
    double a= sin (differenceLat/2.)*sin (differenceLat/2.)+cos (latHomeTmp)*cos (latDestTmp)*sin (differenceLon/2.)*sin (differenceLon/2.); 
    double c=2*atan2 (sqrt (a), sqrt (1-a)); 
    double Distance=R*c; 
    printf ("Distance is %f\n", Distance); 

    double RadBearing=atan2 (sin (differenceLon)*cos (latDestTmp), cos (latHomeTmp)*sin (latDestTmp)-sin (latHomeTmp)*cos (latDestTmp)*cos  (differenceLon)); 
    double DegBearing=RadBearing*57.2958; 
    if (DegBearing<0) DegBearing=360+DegBearing; 
    printf ("Bearing is %f\n", DegBearing); 
} //Function FindDistance 

int main (void) { 
    puts ("LA to NY"); 
    FindDistance (34.052235, -118.243683, 40.748817, -73.985428); 
    puts ("NY to LA"); 
    FindDistance (40.748817, -73.985428, 34.052235, -118.243683); 
} //Function main 

gcc -o gps -lm gps.c 

LAからNYへ65、NYからLAに273のベアリングを返します。

ベアリングを一緒に追加すると、正しいとは言えない338が得られます。
または私は完全に昼食ですか?

とにかく、わかるように、私は常に距離と方位の両方を同時に計算します。コードをクリーンアップして不要な計算を実行しないようにする方法を提案できれば、それは非常に優れています!私はこれを小さなマイクロプロセッサー上で実行しています。ここでは、すべてのサイクル数をカウントしたいのです!

+2

あなたは外出しています。反対方向のベアリングを仮定すると、より大きなベアリングから小さい方のベアリングを引くと180が得られます。ベアリングを追加すると、180と540の間の数値が得られます。たとえば、45と225は反対で、合計は270です。また、大きな円に沿って移動する場合、ベアリングは一定ではありません。だから、LAから出発して、あなたは北東の方向から始まり、ほぼ東に向かい終わります。 NYで始まると、ほぼ西から始まりますが、南西の道で終わります。 – user3386109

+1

湾曲した地面では、私はベアリングが180度補完する必要はないと思います。 – chux

+1

反対方向に180度異なる方向に加えて、大きな円に沿って移動するにつれて、子午線に対する角度としてのベアリングが変化するため、入ってくるベアリングは出てくるベアリングの反対ではありません[http: /www.movable-type.co.uk/scripts/latlong.html)。反対の角度の概念は、最短距離を地図上の直線として精神的に想像することから来ているが、最短経路はほとんどの投影において直線ではない。 –

答えて

3

問題ありません。

同じ緯度で2つの場所を考慮しますが、経度は異なります。短絡大サーキットのルートに行くとき、一方はもう一方の東側にはない(90)。最初の支払い期限もありません(西270)。ベアリングは必ずしも補完的ではありません。

FindDistance(34.0, -118.0, 34.0, -73.0); 
FindDistance(34.0, -73.0, 34.0, -118.0); 

Distance is 4113.598081 
Bearing is 76.958824 
Distance is 4113.598081 
Bearing is 283.041176 

@user3386109さらに詳しい情報が追加されました。

siteによると、@M Oehmのコードは正しいです。


OPリクエストごとに、速度の向上がわずかなモッズがいくつかあります。

void FindDistance(double latHome, double lonHome, double latDest, 
    double lonDest) { 
    // A few extra digits sometimes is worth it - rare is adding more digits a problem 
    // double pi=3.141592653589793; 
    static const double pi_d180 = 3.1415926535897932384626433832795/180; 
    static const double d180_pi = 180/3.1415926535897932384626433832795; 

    // int R=6371; //Radius of the Earth in kilometers 
    // (Compiler may do this all ready) 
    static const double R = 6371.0; // better to make FP to avoid the need to convert 

    //Keep the parameters passed to the function immutable 
    double latHomeTmp = pi_d180 * (latHome); 
    double latDestTmp = pi_d180 * (latDest); 
    double differenceLon = pi_d180 * (lonDest - lonHome); 
    double differenceLat = pi_d180 * (latDest - latHome); 

    double a = sin(differenceLat/2.) * sin(differenceLat/2.) 
     + cos(latHomeTmp) * cos(latDestTmp) * sin(differenceLon/2.) 
      * sin(differenceLon/2.); 

    double c = 2 * atan2(sqrt(a), sqrt(1 - a)); 
    double Distance = R * c; 
    printf("Distance is %f\n", Distance); 

    double RadBearing = atan2(sin(differenceLon) * cos(latDestTmp), 
     cos(latHomeTmp) * sin(latDestTmp) 
      - sin(latHomeTmp) * cos(latDestTmp) * cos(differenceLon)); 

    // double DegBearing = RadBearing * 57.2958; 
    double DegBearing = RadBearing * d180_pi; 

    // Why is this even needed? 
    if (DegBearing < 0) DegBearing = 360 + DegBearing; 

    printf("Bearing is %f\n", DegBearing); 
} //Function FindDistance 
+0

すべての入力をお友達に感謝します。 私は自分の実装を正しいものとして数えます。少なくとも、今は十分に修正されています。コードの最適化方法についていくつかの素晴らしい考えがありましたが、私のプログラムに変更を組み込む方法はわかりません。トリッジを大変うまく使ったことはありませんでした。 Happy Thursday everyone! – programer8472

+0

@ programer8472いくつかのマイナーな改善点が掲載されています。 2つ以上のアイデア: 'use float'と' float'関数 'sinf()'など。[Code Review](http://codereview.stackexchange.com/questions/ask)の_working_ codeを投稿し、_performance_考察について質問してください。それが真のコードの一部である場合にのみ 'printf()'に残してください。 – chux

関連する問題