Haversine 公式 - 数学略有偏差,不确定原因

Posted

技术标签:

【中文标题】Haversine 公式 - 数学略有偏差,不确定原因【英文标题】:Haversine formula - Math is slightly off, unsure why 【发布时间】:2019-12-12 23:07:44 【问题描述】:

我今天早些时候发布了这个问题并解决了这个问题。关于使用半正弦公式,我遇到了不同的问题。 我正在尝试计算两个经纬度点之间的距离。我有公式,我的计算非常接近我需要的输出,但有点偏离。我只需要正确的数字,而不是小数位。但有些计算距离太远,以至于它们不是同一只脚。

我已经完成并尝试从浮点数更改为双精度数,使用调试器比较我的 lat 和 long 以确保我正确地进行了从 DMS 到 Decimal 的计算。

我不知道发生了什么。我必须留下的所有 CONST,它们无法改变。

仅供参考,我没有对最后两列做任何事情。

我们将不胜感激任何有助于引导正确方向的帮助!谢谢!

代码:

//---------------------------------------------------------------------
//
// Input:   $GPRMC sentence for add (A). Distance traveled (D).
//          Average speed (S). Table of records (T).
//
// Output:  Record added. Table of records. Distance traveled.
//          Average speed.
//          
//---------------------------------------------------------------------

#include<iostream>
#include<string>
#include<iomanip>

using namespace std;

const int MAX_RECS = 5;
const float EARTH_RADIUIS_MILES = 3959;
const int FEET_IN_MILE = 5280;
const float HALF_CIRCLE = 180;
const float PI = 3.14159f;
const int SECS_IN_HR = 3600;
const int SECS_IN_MIN = 60;
const float FPS_PER_KNOT = 1.68781f;
const int ID1 = 2234;
const int ID2 = 5327;
const int ID3 = 7741;

const int TABLEFIRSTSPACE = 51;
const int TABLESECONDSPACE = 6;
const int TABLE8 = 8;
const int TABLE10 = 10;
const int TABLE11 = 11;
const int TABLE13 = 13;

enum FitBitID_Type 
 
   ID_FITBIT1 = ID1, ID_FITBIT2 = ID2, ID_FITBIT3 = ID3
;

enum CommandType 

   ADD_CMD = 'A', DISTANCE_TRAVELED_CMD = 'D',
   AVG_SPEED_CMD = 'S', TABLE_PRINT_CMD = 'T'
;

void ReadIn(string &time, string &latNum, string &longNum, 
   float &speedFloat);
//void timeBreakdown(int time, int &hours, int &minutes, int &seconds);
//void latLongCalc(float latNum, float longNum, float &latD, float &longD);
//float DegreesToRadians(float degrees);

class FitBit

private:
   string strTime[MAX_RECS];
   int totalSecs[MAX_RECS];
   float latitude[MAX_RECS];
   float longitude[MAX_RECS];
   float speed[MAX_RECS];
   int numRecs;//num of records currently stored in the parallel arrays

   void timeBreakdown(string time, int &hours, int &minutes, int &seconds)
   
      hours = stoi(time.substr(0, 2));
      minutes = stoi(time.substr(2, 2));
      seconds = stoi(time.substr(4, 2));
   

   void latLongCalc(string latNum, string longNum, float &latD, float &longD)
   
      float degreeLa = stof(latNum.substr(0, 2));
      float minuteLa = stof(latNum.substr(2, 2));
      float secondLa = stof(latNum.substr(5, 3));
      latD = degreeLa + (minuteLa / SECS_IN_MIN) +
         (((secondLa / 1000) * SECS_IN_MIN) / SECS_IN_HR);
      float degreeLo = stof(longNum.substr(0, 3));
      float minuteLo = stof(longNum.substr(3, 2));
      float secondLo = stof(longNum.substr(6, 3));
      longD = degreeLo + (minuteLo / SECS_IN_MIN) +
         (((secondLo / 1000) * SECS_IN_MIN) / SECS_IN_HR); longD = -longD;
   

   float DegreesToRadians(float degrees) const
   
      return degrees * PI / HALF_CIRCLE;
   

public:
   FitBit()
   
      numRecs = 0;
   
   void addRecord(string time, string latNum, string longNum, 
      float speedFloat)
   
      int hours, minutes, seconds;
      timeBreakdown(time, hours, minutes, seconds);
      float latD, longD;
      latLongCalc(latNum, longNum, latD, longD);
      hours *= SECS_IN_MIN; minutes += hours; minutes *= SECS_IN_MIN;
      seconds += minutes; speedFloat *= FPS_PER_KNOT;
      if (numRecs < MAX_RECS)
      
         strTime[numRecs] = time; totalSecs[numRecs] = seconds;
         latitude[numRecs] = latD; longitude[numRecs] = longD;
         speed[numRecs] = speedFloat;
         numRecs++;
      
      else
      
         for (int i = 1; i < numRecs; i++)
         
            strTime[i - 1] = strTime[i]; totalSecs[i - 1] = totalSecs[i];
            latitude[i - 1] = latitude[i];
            longitude[i - 1] = longitude[i]; speed[i - 1] = speed[i];
         
         strTime[numRecs] = time; totalSecs[numRecs] = seconds;
         latitude[numRecs] = latD; longitude[numRecs] = longD;
         speed[numRecs] = speedFloat;
      
   
   float distanceBetweenEarthCoordinates(float lat1, float lon1, 
                                       float lat2, float lon2) const
   
      float dLat, dLon, a, c;
      lat1 = DegreesToRadians(lat1);
      lon1 = DegreesToRadians(lon1);
      lat2 = DegreesToRadians(lat2);
      lon2 = DegreesToRadians(lon2);
      lon1 = -lon1;
      lon2 = -lon2;
      dLat = (lat2 - lat1);
      dLon = (lon2 - lon1);

      a = (sin(dLat / 2) * sin(dLat / 2)) + cos(lat1) * cos(lat2) 
         * (sin(dLon / 2) * sin(dLon / 2));
      c = 2 * atan2(sqrt(a), sqrt(1 - a));

      //return ((EARTH_RADIUIS_MILES * c) * FEET_IN_MILE);
      return EARTH_RADIUIS_MILES * c * FEET_IN_MILE;
   
   float Distance()
   
      if (!(numRecs <= 1))
      
         float total = 0;
         for (int i = 1; i < numRecs; i++)
         
            float x = distanceBetweenEarthCoordinates(latitude[i-1],
               longitude[i-1], latitude[i], longitude[i]);
            total += x;
         
         return total;
      
      return 0;
   
   float DistanceForTable(int i) const
   
      if (!(i < 1))
      
         return distanceBetweenEarthCoordinates(latitude[i - 1],
            longitude[i - 1], latitude[i], longitude[i]);
      
      return 0;
   
   void PrintTable()
   
      cout << left << setw(TABLE8) << "Time" << setw(TABLE10)
         << "Latitude" << setw(TABLE10) << "Longitude" << setw(TABLE11)
         << "Speed" << setw(TABLE13) << "Distance" << setw(TABLE10)
         << "Average" << setw(TABLE13) << "Acceleration" << endl << right
         << setw(TABLEFIRSTSPACE) << "Traveled(ft)" 
         << setw(TABLESECONDSPACE) << "Speed" << endl;
      if (numRecs > 0)
      
         for (int i = 0; i < numRecs; i++)
         
            cout << left << setw(TABLE8) << strTime[i];
            cout << left << setw(TABLE10) << latitude[i];
            cout << left << setw(TABLE10) << longitude[i];
            cout << left << setw(TABLE11) << speed[i];
            if (i < 1)
               cout << left << setw(TABLE13) << " ";
            else
               cout << left << setw(TABLE13) << DistanceForTable(i);
            cout << left << setw(TABLE10) << 200.0;
            cout << left << setw(TABLE13) << 1.0101 << endl;
         
      
   
;

void ProcessCommandForFitBit(FitBit & bit, CommandType command,
   FitBitID_Type FitBitID);

int main()

   cout << fixed << showpoint << setprecision(4);
   char cmd; int id;

   FitBit bit1, bit2, bit3;

   while (cin)
   
      cin >> cmd >> id;
      FitBitID_Type FitBitID = FitBitID_Type(id);
      CommandType command = CommandType(cmd); 
      if (FitBitID == ID_FITBIT1)
         ProcessCommandForFitBit(bit1, command, FitBitID);
      else if (FitBitID == ID_FITBIT2)
         ProcessCommandForFitBit(bit2, command, FitBitID);
      else if (FitBitID == ID_FITBIT3)
         ProcessCommandForFitBit(bit3, command, FitBitID);
   

   cout << "Normal Termination of Program 5.";
   return 0;


void ProcessCommandForFitBit(FitBit & bit, CommandType command,
                             FitBitID_Type FitBitID)

   int returnedDistance = 0;  float returnedAvgSpeed = 0;
   string time, latNum, longNum; float speedFloat = 0;

   switch (command)
   
   case ADD_CMD:
      ReadIn(time, latNum, longNum, speedFloat);
      bit.addRecord(time, latNum, longNum, speedFloat);
      cout << "Record added for FitBit with ID " << FitBitID << endl;
      break;
   case DISTANCE_TRAVELED_CMD:
      returnedDistance = bit.Distance();
      cout << "Distance Traveled in feet for FitBit with ID "
           << FitBitID << " is " << returnedDistance << endl;
      break;
   case AVG_SPEED_CMD:

      cout << "Average Speed for FitBit with ID " << FitBitID
           << " is " << returnedAvgSpeed << endl;
      break;
   case TABLE_PRINT_CMD:
      cout << "Records for FitBit with ID " << FitBitID << endl;
      bit.PrintTable();
      break;
   


void ReadIn(string &time, string &latNum, string &longNum, float &speedFloat)

   string trash;
   cin >> trash >> time >> trash >> latNum >> trash >> longNum
      >> trash >> speedFloat >> trash >> trash >> trash >> trash;

输入文件:

A 2234 $GPRMC 204849 A 4243.636 N 09028.597 W 000.0 065.5 091297 000.2 W*7F
A 2234 $GPRMC 204851 A 4243.636 N 09028.594 W 006.4 074.4 091297 000.2 W*76
A 2234 $GPRMC 204853 A 4243.638 N 09028.586 W 011.7 067.9 091297 000.2 W*73
A 2234 $GPRMC 204855 A 4243.641 N 09028.574 W 014.2 067.5 091297 000.2 W*7A
T 2234
D 2234
S 2234
A 2234 $GPRMC 204903 A 4243.662 N 09028.593 W 018.7 066.2 090108 000.2 W*7A
T 2234
D 2234
S 2234
T 5327
D 5327
S 5327
A 5327 $GPRMC 204905 A 4273.667 N 09047.499 W 021.6 064.5 090108 000.2 W*78
T 5327
D 5327
S 5327
A 5327 $GPRMC 204907 A 4273.671 N 09047.480 W 027.3 065.4 090108 000.2 W*73
T 5327
D 5327
S 5327
A 7741 $GPRMC 204909 A 4273.679 N 09047.459 W 026.5 066.8 090108 000.2 W*77
A 7741 $GPRMC 204913 A 4273.689 N 09047.418 W 031.7 068.6 090108 000.2 W*7F
T 7741
D 7741
S 7741

我的输出:

Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204849  42.7273   -90.4766  0.0000                  200.0000  1.0101       
204851  42.7273   -90.4766  10.8020    12.8137      200.0000  1.0101       
204853  42.7273   -90.4764  19.7474    37.9431      200.0000  1.0101       
204855  42.7274   -90.4762  23.9669    54.9950      200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 2234 is 105
Average Speed for FitBit with ID 2234 is 0.0000
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204849  42.7273   -90.4766  0.0000                  200.0000  1.0101       
204851  42.7273   -90.4766  10.8020    12.8137      200.0000  1.0101       
204853  42.7273   -90.4764  19.7474    37.9431      200.0000  1.0101       
204855  42.7274   -90.4762  23.9669    54.9950      200.0000  1.0101       
204903  42.7277   -90.4765  31.5620    151.4476     200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 2234 is 257
Average Speed for FitBit with ID 2234 is 0.0000
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204905  43.2278   -90.7916  36.4567                 200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204905  43.2278   -90.7916  36.4567                 200.0000  1.0101       
204907  43.2279   -90.7913  46.0772    87.9045      200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 5327 is 87
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 7741
Record added for FitBit with ID 7741
Records for FitBit with ID 7741
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204909  43.2280   -90.7910  44.7270                 200.0000  1.0101       
204913  43.2281   -90.7903  53.5036    193.2789     200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 7741 is 193
Average Speed for FitBit with ID 7741 is 0.0000
Average Speed for FitBit with ID 7741 is 0.0000
Normal Termination of Program 5.

我需要匹配的输出:

Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204849  42.7273   -90.4766  0.0000     
204851  42.7273   -90.4766  10.8020    12           5.4010    5.4010       
204853  42.7273   -90.4764  19.7474    36           10.1831   4.4727       
204855  42.7274   -90.4762  23.9669    56           13.6291   2.1098       
Distance Traveled in feet for FitBit with ID 2234 is 104
Average Speed for FitBit with ID 2234 is 13.6291
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204849  42.7273   -90.4766  0.0000     
204851  42.7273   -90.4766  10.8020    12           5.4010    5.4010       
204853  42.7273   -90.4764  19.7474    36           10.1831   4.4727       
204855  42.7274   -90.4762  23.9669    56           13.6291   2.1098       
204903  42.7277   -90.4765  31.5620    153          17.2157   0.9494       
Distance Traveled in feet for FitBit with ID 2234 is 257
Average Speed for FitBit with ID 2234 is 17.2157
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204905  43.2278   -90.7916  36.4567    
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 36.4567
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204905  43.2278   -90.7916  36.4567    
204907  43.2278   -90.7913  46.0772    84           41.2670   4.8103       
Distance Traveled in feet for FitBit with ID 5327 is 84
Average Speed for FitBit with ID 5327 is 41.2670
Record added for FitBit with ID 7741
Record added for FitBit with ID 7741
Records for FitBit with ID 7741
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204909  43.2280   -90.7910  44.7270    
204913  43.2281   -90.7903  53.5036    192          49.1153   2.1942       
Distance Traveled in feet for FitBit with ID 7741 is 192
Average Speed for FitBit with ID 7741 is 49.1153
Normal Termination of Program 5.

【问题讨论】:

嗨。您是否尝试过为 PI 使用更精确的常数?我没有检查你所有的代码,但 5 位数对我来说似乎真的很低。 @AlexG,我做到了,但这让这些数字甚至变得很糟糕。我得到的 PI 必须使用,所以我不能再精确了。 看起来您的输入程序可能有点不对劲。查看您的输入很难看出您如何将 ID 223442.7273-90.4766 的纬度/经度联系起来。根据您的输入,看起来那些经纬度与 ID 5327?? @DavidC.Rankin 我刚刚经历并从我的输入文件中删除了另一个 id。输出是相同的,数学只是略有偏差。这是一个学校项目,所以他们严格要求不传递身份。 可以在this question 中找到另一种选择。 【参考方案1】:

解决了

我不得不重用一段我们的教授从未告诉我们需要复制的旧代码。这是度分秒转换器的不同实现,与半正弦公式无关。

感谢大家的帮助!

【讨论】:

以上是关于Haversine 公式 - 数学略有偏差,不确定原因的主要内容,如果未能解决你的问题,请参考以下文章

Haversine 函数的 Python 数学库中的错误

用mysqli从haversine公式绑定距离参数

Java中的Haversine公式产生不正确的结果

Sql:Haversine 公式错误列不存在

Haversine 公式错误 - 距离不正确 - Arduino

球形余弦Haversine公式