【问题标题】:Inaccurate Result from Haversine's Bearing CalculationHaversine 的方位角计算结果不准确
【发布时间】:2016-03-30 18:36:04
【问题描述】:

我正在尝试在我正在编写的一个小 GPS 程序中实现 Haversine 公式。距离计算似乎是准确的。但是,我相信方位是以弧度计算的,我不知道如何正确地将结果转换为指南针方向(0 表示北,90 表示东等)。

任何帮助都将不胜感激,所有这些关于余符号和反正切的讨论都让我头疼!我是程序员,不是数学家!

#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,这是不可能的 - 它不应该等于 360 吗?
还是我完全出去吃午饭了?

无论如何,如您所见,我总是同时计算距离和方位。如果您还可以建议一种清理代码的方法,使其不会执行不必​​要的计算,那将非常出色!我在一个小型微处理器上运行它,我喜欢计算每个周期!

【问题讨论】:

  • 你出去吃午饭了。假设轴承方向相反,从较大轴承中减去较小轴承应得到 180。将轴承相加得到 180 到 540 之间的数字。例如,45 和 225 是相反的,总和为 270,但差为180. 此外,当沿大圆移动时,方位角不是恒定的。所以从洛杉矶开始,你从东北方向开始,到几乎正东方向结束。从纽约开始,您几乎从正西开始,但在西南路径结束。
  • 在弯曲的地球表面上,我认为方位角不需要是 180 度互补。
  • 除了相反的方向相差 180° 外,当您沿着大圆移动时,方位角与经线的角度会发生变化,因此输入方位与输出方位不会相反,@ 987654322@。对角的概念来自于将最短距离想象为地图上的直线,但在大多数投影中最短路径不是直线。

标签: c linux gps haversine


【解决方案1】:

没问题。

考虑相同纬度但经度不同的 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 增加了更多好的信息。

根据@M Oehmsite 建议,您的代码基本正确。


根据 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

【讨论】:

  • 感谢朋友们的所有投入。我会认为我的实现是正确的,至少现在足够正确。听起来你们中的一些人对如何优化代码有一些很好的想法,但是,唉,我不知道如何将这些更改合并到我的程序中。从来没有非常擅长触发。祝大家星期四快乐!
  • @programer8472 发布了一些小的改进,但不太可能使事情变得更快。还有 2 个想法:use floatfloat 函数 sinf() 等。在 Code Review 上发布 working 代码并询问有关性能 的注意事项。如果这是真实代码的一部分,请仅保留 printf()
猜你喜欢
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
  • 2020-06-06
  • 1970-01-01
  • 2011-10-01
  • 2020-11-13
  • 2019-08-13
  • 1970-01-01
相关资源
最近更新 更多