views:

752

answers:

8

Does anyone know the most efficient representation for lat/long coordinates? Accuracy level should be enough for consumer GPS devices.

Most implementations seem to use double for each unit, but I'm suspicious that a float or fixed point format should be sufficient. I'd be curious to hear from anyone who has tried to compress and or store large arrays of these values.

EDIT:

In other words, whats the minimum accuracy required to represent lat/long for a consumer level device?

+4  A: 

EDIT: added some points from comments, 32-bit values should be capable of offering enough precision.

I would use a 32-bit fixed point representation. If the values are:

42.915512,-99.521654 I would store the values * 100000 in int32_t's (they can be negative).

int32_t lat = 42915512;
int32_t lon = -99521654;

This is a good compromise between simple and accurate (5 decimal points is usually good enough, you could always bump it up to 1000000 to get 6 if needed).

To display to the user, do what caf suggests:

... to display to the user - use integer divide and modulo, eg printf("Lat = %d.%06d\n", lat / 1000000, abs(lat) % 1000000)

These will also be comparable/sortable in an efficient way since the relative ordering will be preserved.

EDIT: an additional benefit is that it can sent over a network or stored to disk in a binary format in a portable way.

Evan Teran
Maybe be a bit more careful to not obliterate the meaning of the difference between -77.521654 and 77.521654
Kieveli
I would suggest using a power-of-two multiplier rather than 10,000. Using 10,000 might be human-readable if you find that you have to hard-code numbers, but is fairly useless otherwise. Also, if you do use this method, ALWAYS use macros/inline functions to convert to/from double to ints.
Tal Pressman
unsigned isn't much chop since they can be negative. Also, .0001 degrees can be as much as 22 metres, and consumer GPS can be more accurate than that. So use signed ints, and multiply by at least 1000000 (the maximum value will still easily fit into signed 32 bits).
caf
Thanks, good points, I forgot to account for negative values, I've adjusted my answer.
Evan Teran
Oh, and don't cast to double and divide to display to the user - use integer divide and modulo, eg printf("Lat = %d.%06d\n", lat / 1000000, lat % 1000000)
caf
another good catch, answer adjusted to include that as well.
Evan Teran
Good god, just use a float. It's more readable, for one thing, if you're storing the values in a database.
MusiGenesis
In another post's comment, he indicated that it may be sent over the network. In which case, a fixed point representation may be simpler in the long run.
Evan Teran
Don't use that printf statement! The C modulus operator isn't really a modulus, it's a remainder operator, and gives negative results for negative inputs. For example, if lat=-1234567, then the code will print "-1.-234567".
Dietrich Epp
Ahh, very good point. Throw an abs() around that, or labs() if you need to use longs (and adjust the format specifiers appropriately).
caf
+3  A: 

Floats would be way more than sufficient for storing GPS coordinates, even if consumer-level GPS devices had anywhere near the accuracy claimed for them. If you don't believe this is true, try these two simple experiments:

  1. Take two or more GPS devices out into one spot on a field somewhere, and jot down the coordinates measured by each device. Go back inside and plot the points from each device on a map (I think Google has something that does this for you). You'll be suprised at how far apart the points are (even though they're all supposed to be measuring the exact same spot).
  2. Take your (allegedly) most accurate device, and place it somewhere where it can get a satellite fix but won't get rained on, and record a series of measurements taken over a couple of days. Plot all of the readings (as in #1). Again, you'll be surprised by how the points (which should all be the same or nearly the same) wander all over the map, sometimes by as much as a couple hundred feet.

I've been writing applications for GPS-enabled PDAs for years, and I've verified this for dubious customers over and over again (I've even won bets this way). There are higher-quality GPS devices out there that do achieve better accuracy than this, but the better accuracy is achieved with more expensive chipsets, and the devices are left in one spot for days or even weeks, with the readings averaged over time.

A four-byte float is far more accurate than the devices themselves. It would of course not hurt you at all to use a double instead, as long as the 2X factor isn't a problem for you.

MusiGenesis
Good point - I guess the question could be rephrased as "Whats the minimum accuracy required for consumer gps devices?"
Justicle
the the heck downvoted all the answers?! Personally I think both yours and mine were valid answers.
Evan Teran
I've had people in the real world get particularly angry with me for puncturing the GPS accuracy myth (and then I take their money). And I've encountered people on StackOverflow who feel that 32-bit floats belong in the same category as vacuum tubes. So this question is the perfect storm, in a sense. :)
MusiGenesis
+5  A: 

The circumference of the Earth is approx. 40.000 km or 24900 miles.

You need one-meter accuracy (3ft) to be able to out-resolve gps precision by an order of magnitude.

Therefore you need precisiton to store 40.000.000 different values. That's at minimum 26 bits of information. A 32 bit float or int will do well.

Kristoffon
Thanks for breaking it down.
Justicle
No, you need to store 40,075,020 different values to have one metre resolution, which requires 26 bits.
caf
Actually, a 32-bit IEEE float has 23 explicit bits of fraction (and an assumed 1) for 24 effective bits of significand. That is only capable of distinguishing 16 million unique values, of the 40 million required. Looked at another way, it can represent position to within 2.4 meter at the equator, which may still be close enough.
RBerteig
I'd lean towards a fixed point representation since floats don't have advantages for this kind of application, and a signed 32-bit value has plenty of bits available to pick a convenient scale.
RBerteig
@RBerteig Don't forget the sign, that gives you another bit, since the default representation is ±180° for latitude and longitude. Since the accuracy is better if you are close to zero 32 bit floats gives you 1m accuracy except for ca 1/5 of the globe near the date line.
starblue
Depends on the application. WP suggests that "civilian GPS fixes under a clear view of the sky are on average accurate to about 5 meters", but with "specially equipped receivers" (e.g., in surveying) the "error might be as low as 2 millimeters". So pick your precision, and realize that next year a $5 cell phone will probably be able to beat it. :-)
Ken
@Ken: no way in hell are civilian GPS devices accurate on average to 5 meters (in any event, accuracies are usually measured in a statistical sense with variances and standard deviations and so forth - a single number can't possibly reflect the accuracy). What they mean is: once in a while the device measures a position within 5 meters of the true position - kind of like how a broken clock is right twice a day.
MusiGenesis
+2  A: 

Personally I would use a 32 bit decimal fixed point representation, dividing by 1,000,000 as per Evan's answer and my comments.

However, if space is truly at a premium, here are some additional ideas:

  • You could use a 26 bit fixed point representation on the wire. This will require marshalling and unmarshalling the latitude and longitude into a large array of bytes, but will save you 12 bits for each location over the 32 bit value representation - almost a 19% saving, so it might well be worthwhile.

  • You could take advantage of the fact that longitude values need less precision as you get closer to the poles - they only need 26 bits worth at the equator. So you could write a scheme where the number of bits used to encode the longitude depends on the value of the latitude.

  • If your data has other compressible attributes - say, all the points are usually quite close together - you could take specific advantage of those, like using a delta coding scheme (where each point other than the first can be encoded as a delta from the last point).

caf
A: 

I am suprised that no one has posted the fact that long/lat is a terrible way to store data on a sphere (someone did mention that longitude requires less precision near the poles).

Basically you can store data position as X and Y co-ords in meters. Imagine a cube around the earth that exactally fits (haha ok almost fits it). You only need store X and Y position, not all 3 co-ords, because the 3-rd co-ord can come from the redius of the earth, r = square root[x^2 + y^2 + z^2].

So convert your lat/long to x/y in meters. You will only need a total of 12756200m per co-ord (thats the diameters of the earth). So your total value will only have to span 0 to 25,512,400 (someone else claimed 40,000,000 because they were using long/lat) to be accurate to +/- 0.5m.

That will result in just 25 bits per position. If I were you I would just do accuracy to within 2m and use 24 bits per position, as that is a tidy 3 bytes.

Also if you are storing way-point information on a path, you can store each way-point as an offset from the last waypoint. Like start with a 24bit x/y co-ord. And then have a 16bit 'update' that adjusts the position by adding/subtracting x/y meters. 16bit would allow a waypoint update to be over 400m away. So if you know the device is not meant for planes and updates every so often, this might be acceptable too.

myforwik
Storing X/Y coordinates for a sphere just doesn't work. At all. You lose a lot of precision near the sphere's intersection with the XY plane, and you can't reconstruct the Z coordinate -- you only get a half of a sphere. If you're looking for uniformity, use three dimensional cartesian coordinates. Otherwise, lat/long is a good way of storing it.
Dietrich Epp
Wow, you should give Garmin a call and explain to them how "terrible" latitude and longitude are for positional information. What were they thinking all these years?
MusiGenesis
UTM uses a similar approach with its Easting and Northing coordinate pairs, so X/Y "coordinates" do work for spheres. It's all a matter of projection.
Erich Mirabal
myforwik: your approach still has problems, though. As Dietrich mentions, your version of X/Y is not a good projection. You need flatten to a 2D plane, not to a 3D cube.
Erich Mirabal
Programming Pearls (2nd Edition) (ACM Press) (Paperback)is an excellent book which discusses conversion to x,y,z to reduce the number of expensive trig operations which occurred for one particular application of map data.
Juan
Earth is not a sphere it is a geoid. Its radius is different in different locations. You need x,y,z to know the r at that point. Therefore it is not possible to deduce z by knowing only x and y.
Szere Dyeri
@Szere: I think most of us know the Earth is not a perfect sphere. I was just using Dietrich's wording. Besides, just because the Earth is not a sphere does not mean that it cannot be approximated by a sphere.
Erich Mirabal
Actually I didn't just 'make this up'. My gps stores data this way. It has a look up table for radius in its rom. Any error in radius is only going to be a tiny factor anyway. It works out where you are in the hemispheres by simply asking the user what countery/region they are in, or where the sun is in the sky.
Myforwik
A: 

23 bits of precision at 179 degrees of longitude gives under 10-meter accuracy, which is the best that ordinary GPS devices give. At the equator:

% gps distance "0.0, 179.0" "0.0, $((179 * (1 + 2**-23)))"
From 0.0, 179.0 to 0.0, 179.00002133846283 is 7.79 feet E
From 0.0, 179.0 to 0.0, 179.00002133846283 is 2.38 meters E

So an IEEE 754 single-precision floating-point number, known to your C compiler as float, wil be just adequate for representation. Beware of using floats for extended computations! Rounding error may eat your lunch. Consult a numerical analyst.

Norman Ramsey
+1  A: 

You can pack both the latitude and longitude values in a single 32-bit integer with a resolution of at worst ~2.4 meters/pixel (at the equator) if you use a recursive tiling system. Using two bits per level, you can store 16 levels in 32 bits. You can get an idea of how that would work looking at this article about Virtual Earth's tiling system. This uses Mercator, so it would give you problems for the poles. You could instead use a different projection and still get very similar results.

This can also be used for a rough filter to find any points within a given parent tile since the first N bits will be the same (and so search becomes bit masking).

Erich Mirabal
A: 

In Garmin's IMG map format they store coordinates inside bounding boxes using floats to set the edges of the boxes. Coords within the boxes are defined using a variable number of bits that are are just linear between min and max values depending on the precision needed.

For example: minlat=49.0, maxlat=50.0, minlon=122.0, maxlon=123.0, number of bits=16

So a value of:
32768,32768 would be converted to 49.5, 122.5
16384,0 would be 49.25, 122.0

If you need less precision, the same output could be generated with a number of bits=4
8,8 would be converted to 49.5, 122.5
4,0 would be 49.25, 122.0

KPexEA