# Haversine Formula converting to meters

So I set up the Haversine formula for my GPS device but I have no idea how to convert the output into meters.

Here's my code:
float dlon = 1;
float dlat = 1;
float a = 1;
float c = 1;
float d = 1;
float long1 = -77.037852;
float long2 = -77.043934;
float lat1 = 38.898556;
float lat2 = 38.897147;

void setup() {

}

void loop() {
Serial.begin(9600);
dlon = long2 - long1;
dlat = lat2 - lat1 ;
a = sq(sin(dlat/2))+cos(lat1)*cos(lat2) * sq(sin(dlon/2));
c = 2 * atan2( sqrt(a), sqrt(1-a) );
d = 6378137.0 * c;
Serial.print(d ,7);

}

The output would not make sense in any case, because the trigonometric functions require radians as input, not degrees.

Unfortunately, the standard Arduino does not support the "double" data type, which is generally required for accuracy in GPS position calculations such as you are attempting. Float data types can represent at most 7 decimal digits, and you need 8 to 9.

See Calculate distance and bearing between two Latitude/Longitude points using haversine formula in JavaScript for general approaches to navigation with GPS coordinates.

Edit: I fixed the code and it works much better than I expected for this particular case, within about 1 meter of the "correct" distance (549.2 m). I did not test it with other cases. Perhaps it will work well enough for you, but it should not be trusted when using single precision arithmetic.

``````float dlon = 1;
float dlat = 1;
float a = 1;
float c = 1;
float d = 1;
float long1 = -77.037852;
float long2 = -77.043934;
float lat1 = 38.898556;
float lat2 = 38.897147;
float d2r = PI / 180.0;
void setup() {
Serial.begin(9600);
dlon = long2 - long1;
dlat = lat2 - lat1 ;
a = sq(sin(d2r * dlat / 2)) + cos(d2r * lat1) * cos(d2r * lat2) * sq(sin(d2r * dlon / 2));
c = 2 * atan2( sqrt(a), sqrt(1 - a) );
d = 6378137.0 * c;
Serial.print(d);
}

void loop() {}
``````

I was interested to know how large the error in positional and distance accuracy might be using single precision float variables, so did a couple of tests.

First, the circumference of the Earth is about 40,075,000 meters, so you clearly need 8 decimal digits to know where you are on that circle to within 1 meter. So, what is the consequence of storing that value in a single precision float?

The results from this modified version of the program demonstrates that the values of the stored coordinates are not the same as the entered values and suggest worst case about 4 meters distance error using the Haversine formula, based on single precision float positional accuracy (+/- 3 m) alone. GPS errors can be MUCH larger. Ignoring the latter source of error the distance will usually be correct to within +/- 2 m; not as bad as I thought!

``````float dlon = 1;
float dlat = 1;
float a = 1;
float c = 40074997.0;  //estimate of the Earth's circumference in meters
float d = 1;
float long1 = -77.037852;
float long2 = -77.043934;
float lat1 = 38.898556;
float lat2 = 38.897147;
float d2r = PI / 180.0;
void setup() {
Serial.begin(9600);
for (int i = 0; i < 9; i++) Serial.println(c + i);  //circumference as stored, in steps of 1 m
Serial.println("Coordinates as actually stored");
Serial.print(long1, 6);
Serial.print(", ");
Serial.println(lat1, 6);
Serial.print(long2, 6);
Serial.print(", ");
Serial.println(lat2, 6);
dlon = long2 - long1;
dlat = lat2 - lat1 ;
a = sq(sin(d2r * dlat / 2)) + cos(d2r * lat1) * cos(d2r * lat2) * sq(sin(d2r * dlon / 2));
c = 2 * atan2( sqrt(a), sqrt(1 - a) );
d = 6378137.0 * c;
Serial.println(d);
}

void loop() {}
``````

For actual values 40074997, 40074998, 40074999, … prints instead:

``````40074996.00
40074996.00
40075000.00
40075000.00
40075000.00
40075000.00
40075000.00
40075004.00
40075004.00
Coordinates as actually stored
-77.037849, 38.898555
-77.043937, 38.897148
550.25
``````

Interesting, it seems that float can be used because GPS can be much larger.

Anyway, I used your sketch on a Maple Mini, an STM32 board who has real double but not an FPU.

``````40074997.00
40074998.00
40074999.00
40075000.00
40075001.00
40075002.00
40075003.00
40075004.00
40075005.00
Coordinates as actually stored
-77.037852, 38.898556
-77.043934, 38.897147
549.77
``````

Using float I got your same result.