# Need 7 digits of accuracy on an UNO

Hi,

I'm trying to process a GPS NMEA sentence.
For example latitude and longitude are in the format:
DDDMM.MMMMM
where DDD is the integer degrees
MM.MMMMM is floating point minutes (5 digits after the decimal point)

After heroic efforts to read/process the string I have separated the DDD and the MM.MMMMM.
I'm converting minutes to degrees by deg = MM.MMMMM/60.

Example:
latitude in NMEA sentence is 3713.91378. So this maps to:
37 degrees + 13.91378/60 = 37.2318963

However on Arduino UNO, using double I get the following result:
37.2318954

Difference doesn't seem like a lot, but I really need the 7 digits of accuracy as I'm using Differential GPS RTK with a local BASE station providing the corrections. The last digit represents approx +/-1.5cm error for the distance calculations.

Any ideas how to fix this ?

In Arduino UNO, the data types float and double are the same and they refer to the 32-bit binray32 (IEEE-754 Standard) formatted data where you can get at best 6-digit accuracy after the decimal point.

If you want more accurate digits, you must switch over to Arduino DUE which supports true double data type (64-bit) and will offer about 15-digit accuracy.

if your project deals on lon/lat of less than 10min (=always within the same area) you have some constant digits in front so can have the wanted accuracy. in other words your DDDMM.MMMMM becomes CCCCM.MMMMM which is feasible on uno.

You may get somewhere with the arbitrary precision library:

Or maybe always work in units of 0.00001 minutes so you are effectively handling integers.

Hi,

Really appreciate the replies. Just ordered a due (64 bit) and, as suggested, am looking into shifting the data using long to store the results.

Regards,
Brian (AI6MK)

btw, is your receiver's acuracy that good?
recently we were playing with 2 receivers (same manufactor, same seller, same order, same parameter programming). They were put at a specific distance - 5meters, east - west. After some days logging, we realised that

• there were no valuable data we could use and "find" the between distance accurately.
• all data were drifting but not by same amount - same direction
• during some period of time (hours) , every day, the data showed that the more east receiver was more west than the "really west" .

so, is the (~6 decimal) accuracy of an uno really an obstacle?

Good luck

am looking into shifting the data using long to store the results.

Save yourself the trouble and use one of the libraries, like NeoGPS or TinyGPS++, where this is already done.

For short distance calculations between lat/lon pairs, the equirectangular approximation is easy to use and overcomes the single precision float limitation of AVR-based Arduinos. See Calculate distance and bearing between two Latitude/Longitude points using haversine formula in JavaScript

Thanks for the 2 additional replies.

FYI, I'm using C94-M8P modules (BASE and ROVER) in differential GPS mode from U-BLOX. \$500 for the pair, which sounds expensive until you check other solutions. The ROVER can be easily configured for both COORS operation or using a fixed BASE station using U-CENTER software. The BASE, which is in a fixed location, sends correction data to the ROVER to provide an accuracy of cm's.

The NMEA sentence provided by the ROVER is in he normal odd format, DDDMM.MMMMM, and I need to convert to decimal minutes with high accuracy.

I did start using TinyGPS, but it has not kept up to date with the GNSS (GPS + GLONASS) used for differential GPS and after fixing it, was not accurate enough.

I do have a solution using DUE, but iI would prefer to go back to UNO and will try the 2 libraries you suggested.

Thanks again for all the comments.
Brian (AI6MK)

AI6MK:
I did start using TinyGPS, but it has not kept up to date with the GNSS (GPS + GLONASS) used for differential GPS and after fixing it, was not accurate enough.

TinyGPSplus has been reading the GNSS sentences for some time, so worth updating your library, although I have not noticed any imnprovement in accuracy over GPS mode.

if use of NMEA output, accuracy does not depend on library.
NMEA sentense has specific format and "library" just extracts from the sentense the asked data in a variable.
for example, if output is :
\$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh

lat (llll.ll) is extracted with the same accuracy (plus : and about the same way as anybody can do with String.substring(from, to) and convert to float) nomatter the library used

demkat1:
if use of NMEA output, accuracy does not depend on library.
NMEA sentense has specific format and "library" just extracts from the sentense the asked data in a variable.
for example, if output is :
\$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh

lat (llll.ll) is extracted with the same accuracy (plus : and about the same way as anybody can do with String.substring(from, to) and convert to float) nomatter the library used

I recall that NeoGPS uses integers to convert the NMEA data into numbers, specifically to avoid the loss of resolution that can occur when using floats.

In fact, I dont use any libraries with NMEA, so can;t tell about differences.
For processing I take the integer parts separately from the demimal

That is :

``````String RmcOut="\$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh"

StartLat=RmcOut.indexOf(","17)+1 // In fact get the 3rd comma position+1
StopLat=RmcOut.indexOf(","20)
DotLat=RmcOut.indexOf(","20)
IntPart=RmcOut.substring(StartLat, DotLat).toInt();
DecPart=RmcOut.substring(DotLat+1, StopLat).toInt();
``````
``````StartLat=RmcOut.indexOf(","17)+1 // In fact get the 3rd comma position+1
StopLat=RmcOut.indexOf(","20)
DotLat=RmcOut.indexOf(","20)
``````

WTF?

PaulS:

``````StartLat=RmcOut.indexOf(","17)+1 // In fact get the 3rd comma position+1
``````

StopLat=RmcOut.indexOf(","20)
DotLat=RmcOut.indexOf(","20)

``````

WTF?
``````

despite some missing commas {indexOf(val, from)} I think it is simple.
And of course its an idea, a discussion. If someone wants an exact advise, he can ask for it.

With all respect to you, can't understand the WTF

With all respect to you, can't understand the WTF

Did you google WTF?

while I look arouns for WTF explanation

Can you be so kind to explain what YOUR above WTF means :

For example , you think what I say is junk, clever, wrong, stupidly easy, anybody can think about it, or completely nonsense ?
thank you

@demkat1: Why post code that so obviously violates language standards, and won't compile? The occasional typo can be overlooked, but so many in a row?

Avoid use of Strings on Arduino. They cause memory problems and program crashes.

jremington:
@demkat1: Why post code that so obviously violates language standards, and won't compile? The occasional typo can be overlooked, but so many in a row?

Avoid use of Strings on Arduino. They cause memory problems and program crashes.

Here we go again...again...

I was not asked to give code - advise so to become responsible for. I was in the middle of a discussion and just said the way I solve a problem. If someone sees errors "so obviously", he can throw away the code and keep the idea or throw the idea too. Or can look - test the code and check for correct syntax or dig in the referense.

Avoid Strings on Arduino? ok. who says it is obligatory, mandatory? If the Forum has problems with the use of Strings a team can act and "remove" them or fix the issues, or dont act or ...do ..whatever. But can't pinpoint a member who uses Strings. (If I ask for help on Strings, you have the right to remain silent).

Above I use one String and my experiense says "1 String is ok, even if it is 150 chars long" .
Pls, i dont want to discuss it any further, i wont reply to anybody in this thread

demkat1:
Above I use one String and my experiense says “1 String is ok, even if it is 150 chars long” .
Pls, i dont want to discuss it any further, i wont reply to anybody in this thread

To be pedantic, you actually created 3 strings in your code. The following two lines create one string each:

``````IntPart=RmcOut.substring(StartLat, DotLat).toInt();
DecPart=RmcOut.substring(DotLat+1, StopLat).toInt();
``````

i wont reply to anybody in this thread

Excellent idea!