Microcontroller selection for floating point math calcs?

I want to manipulate GPS data using the TinygpsPlus library. Specifically, the conversion of 'string' gps coords to a floating point number results in a 5 decimal point accuracy when using the 8bit ATmega328P microcontroller on the UNO. To get 6 decimal place accuracy, would I have to go to a more powerful microcontroller such as the 32bit one found on the DUE or, is this just a 'programming' issue? My knowledge in this area is limited, so any practical assistance offered will be gratefully received.
Regards
Geoff

Have you tried 32bit fixed-point?

You may want to look into /dev's NeoGPS library, I think it uses integers for coordinates.
("/dev" is this forum user name of the author, Devin)

I haven't tested it, he also says the NeoGPS is quite compact and fast.

geoffvr:
<...>
To get 6 decimal place accuracy, would I have to go to a more powerful microcontroller such as the 32bit one found on the DUE or, is this just a 'programming' issue? My knowledge in this area is limited, so any practical assistance offered will be gratefully received.
Regards
Geoff

There are a number or 32-bit device modules, Arduino compatible, that will offer significant benefits beyond just the math libs.

For any software algorithm, the end-results of uC (duration) work is directly related to the uC clock. Go from 16 MHz to 72 MHz and you will see 72::16 reduction in time for the software math library. The ESP8266 can do 160::16 for 10x improvement.

The Maple Mini clone is $4.

The ESP8266 NodeMCU is under $4

At the above (AliExpress) prices, there is no excuse for not jumping into the 32-bit devices.

Now, the 8-bitters are still a great engineering choice when lower clock and wide-library support are required as well as for low-power uses.

Ray

So where is the problem?

@jurs, likely you were addressing the inquiry to geoffvr, but I thought I would just make a general statement that while an 8-bitter can do 32-bit math, it obviously cannot do it natively - that is, it can not do the math without some grunt work.

My personal take is if there are extra cycles constantly at the start of every loop() and the user is happy with the performance, then the choice of uC is acceptable.

If however, the user is not pleased because the loop() performance is stressed, then the absolute easiest way to correct the issue is to go to 32-bit core processing and a faster core clock.

There are consequences with the 32-bit decision in that the choice for true compatibility with all existing libs is not guaranteed, but the Due has been out for a few years as has the 32-bit Teensy. Most important libs have been updated.

The Ops I have personally worked with on 32-bit migration would not go back to 8-bit except maybe for low-power needs. Yea, there are lots of wasted processor cycles in the loop(), but at $4 per board, no one seems to complain.

Ray

Thanks for your replies. The knowledge shared here in the forum is brilliant.

AWOL:
Have you tried 32bit fixed-point?

AWOL, I am having trouble finding any reference to this datatype. Would you mind expanding on your suggestion? Thanks Geoff.

Using the following example of GPS data, you can see that Lat & Long are received in 'decimal minute' format.
Example:
$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M, , , ,0000*18

GGA Data Format

Name ......... Example .......... Units ................ Description
Message ID .. $GPGGA .................................... GGA protocol header
UTC Time ... 161229.487 ...... hhmmss.sss
Latitude ...... 3723.2475 ........ ddmm.mmmm
N/S Indicator N .................. N=north or S=south
Longitude .... 12158.3416 ...... dddmm.mmmm

As far as I can see, the TinyGPS Plus library functions parse the Lat & Long coords into 'decimal degree' format, which converts the above example to coords 37.387458, 121.972360 (dec degs – to 6 decimal places). My own amateur observations seem to show that a 5 decimal place coordinate can be as much as 2 metres different to a 6 decimal place coord.
Also, here in the ‘land-down-under’, lat values are negative, which would seem to exclude some datatypes.

If you look at this post…
Title: Serial Input Basics updated
Post by: Robin2 on Apr 25, 2016, 05:12 pm

… and run ‘Example 5’ but send a 6 decimal place number instead, the resultant ‘string_to_float’ conversion returns, using the UNO, a float number only accurate to 5 decimal places. The 6th decimal place digit looks to be random. The number sent and the number received back do not match.

CONCLUSION.
When I run my own GPS sketch using TinyGPSPlus, it all looks to be working perfectly, but is it? I suspect the coords are only accurate to 5 decimal places even though they look correct when serially printed to the monitor. So, with my limited knowledge of these things, I decided to seek help from the forum… Many thanks for your contributions.
Cheers
Geoff

geoffvr:
Thanks for your replies. The knowledge shared here in the forum is brilliant.
AWOL, I am having trouble finding any reference to this datatype. Would you mind expanding on your suggestion? Thanks Geoff.

Using the following example of GPS data, you can see that Lat & Long are received in 'decimal minute' format.
Example:
$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M, , , ,0000*18

It's not a data type :wink:

Take e.g. 161229.487; you basically multiply the number by 1000 to get rid of the decimal dot. Same for 3723.2475, but you multiply by 10000; for consistency, use 10000 for both numbers.

You know that the last four digits of the number represent the decimal part because you multiplied by 10000.

Now you can't do this directly, so you need to split the text (number) on the decimal dot, convert both parts to long, multiply the first part by 10000 and sum both parts.

This could be a function to do that work

/*
  convert text number to fixed point number with 4 decimal places
  in:
    text representation of a number with up to 4 decimal places
  returns:
    0x80000000 on error, else converted result.
*/
long convertToFixedPoint(char *number)
{
  long result;

  // find the dot
  char *ptr = strchr(number, '.');
  // if dot not found
  if (ptr == NULL)
  {
    // simply convert
    result = atol(number) * 10000L;
  }
  else
  {
    // replace dot by string terminator
    *ptr = '\0';
    // increment pointer to point to first character after the dot
    ptr++;

    // check
    if(strlen(ptr)>4)
    {
      Serial.println("Multiplying by 10000 will not do the job");
      return 0x80000000;
    }
    
    // convert first part
    result = atol(number) * 10000L;
    // convert the second part
    long dec = atol(ptr);
    while (dec < 1000 && dec != 0)
    {
      dec *= 10;
    }
    // sum
    result += dec;
  }

  // if a decimal dot was found (and hence the original input was corrupted), restore
  if(ptr!=NULL)
  {
    ptr--;
    *ptr = '.';
  }
  
  return result;
}

You can use it as shown below

void setup()
{
  Serial.begin(115200);


  char txt[20] = "161229.487";
  Serial.println(convertToFixedPoint(txt));

  strcpy(txt, "161229");
  Serial.println(convertToFixedPoint(txt));

  strcpy(txt, "161229.0");
  Serial.println(convertToFixedPoint(txt));

  strcpy(txt, "161229.12345678");
  Serial.println(convertToFixedPoint(txt));

}

void loop()
{
}

And the output is

1612294870
1612290000
1612290000
Multiplying by 10000 will not do the job
-2147483648

sterretje:
<...>
Now you can't do this directly, so you need to split the text (number) on the decimal dot, convert both parts to long, multiply the first part by 10000 and sum both parts.
<...>

Respectfully, while the math is reasonably easy, IMO this kind of integer arithmetic need should have gone out with the BASIC STAMP and PICAXE.

We senior members understand all of this stuff, but for discussions with newbies, it just all seems unnecessary and convoluted. If the Op is set on an 8-bit uC, then redirecting their attention to Nick's Big Numbers / Arbitrary precision Big Number library is likely to add significant value for the long-term.

I suspect the coords are only accurate to 5 decimal places even though they look correct when serially printed to the monitor. So, with my limited knowledge of these things, I decided to seek help from the forum… Many thanks for your contributions.

Unfortunately you cannot manufacture resolution: that must come from the GPS receiver.

* The first decimal place is worth up to 11.1 km: it can distinguish the position of one large city from a neighboring large city.
* The second decimal place is worth up to 1.1 km: it can separate one village from the next.
* The third decimal place is worth up to 110 m: it can identify a large agricultural field or institutional campus.
* The fourth decimal place is worth up to 11 m: it can identify a parcel of land. It is comparable to the typical accuracy of an uncorrected GPS unit with no interference.
* The fifth decimal place is worth up to 1.1 m: it distinguish trees from each other. Accuracy to this level with commercial GPS units can only be achieved with differential correction.
* The sixth decimal place is worth up to 0.11 m: you can use this for laying out structures in detail, for designing landscapes, building roads. It should be more than good enough for tracking movements of glaciers and rivers. This can be achieved by taking painstaking measures with GPS, such as differentially corrected GPS.
* The seventh decimal place is worth up to 11 mm: this is good for much surveying and is near the limit of what GPS-based techniques can achieve.
* The eighth decimal place is worth up to 1.1 mm: this is good for charting motions of tectonic plates and movements of volcanoes. Permanent, corrected, constantly-running GPS base stations might be able to achieve this level of accuracy.
* The ninth decimal place is worth up to 110 microns: we are getting into the range of microscopy. For almost any conceivable application with earth positions, this is overkill and will be more precise than the accuracy of any surveying device.
* Ten or more decimal places indicates a computer or calculator was used and that no attention was paid to the fact that the extra decimals are useless. Be careful, because unless you are the one reading these numbers off the device, this can indicate low quality processing!

Reference

  • The fifth decimal place is worth up to 1.1 m: it distinguish trees from each other. Accuracy to this level with commercial GPS units can only be achieved with differential correction.

Doesn't this means there is no point in more precise coordinates?

Thanks again for the inputs.

Keeping in mind that the GPS coords are converted to decimal format (to 6 decimal places) by the TinyGPSPlus functions as called by the user, I have no control over the math used, the result is just received back into my variable which has a defined datatype. My conclusion for now, is that the Atmega328 is not up to the task and that I will have to try a more powerful processor and then make a direct comparison of the results.

Cheers
Geoff

the Atmega328 is not up to the task

Just what is the task? I read thru this all, you never say what you're going to do with the GPS coordinates you receive.

I did a design where I picked off lat & long, cleaned up their format to be a little more human readable, and sent them out via text message.
Plugging the data I got out into maps.google.com I could place myself in my living room or my dining room, as long as the GPS module could get data.

GPS data is only good to a couple of meters unless you have a local station that is sending out corrected data to end up with a more precise location.

A little late to this party, I see. The short answer is that the NeoGPS library retains the full accuracy of your GPS device, unlike all other libraries. NeoGPS is also smaller and faster than other libraries, and maintains that accuracy in distance and bearing calculations, so there's that... :slight_smile:

NeoGPS also works on the 32-bit processors, including the ESP8266. If you're trying to choose, I can definitively say that parsing GPS data and calculating distance and bearing works quite well on an 8-bit processor. On a 16MHz 8-bit processor, NeoGPS uses less than 0.1% of the MCU's time.

You don't need any particular processor for the tasks you have described. If you are using 99.9% of the 8-bit Arduino's time for "other things", then the 0.1% used for GPS processing isn't the problem. Right now, the library is the problem. :wink:

Cheers,
/dev

/dev:
You don't need any particular processor for the tasks you have described. If you are using 99.9% of the 8-bit Arduino's time for "other things", then the 0.1% used for GPS processing isn't the problem. Right now, the library is the problem. :wink:

Thanks for that Dev. I checked out the github repository and looked through some of the NeoGPS examples and I am starting to see how the data is handled. Your post has been a real help. I've got NeoGPS loaded so will be interested to see what results I get.

Cheers
Geoff
from across the ditch...

will be interested to see what results I get.

Just remember that if you use the float value (e.g., fix.latitude()), it will lose some significant digits, just as you originally described. NMEAloc shows one way to display the 32-bit integer lat/lon values as if they were high-precision floating-point numbers (see printL).

This float/integer difference isn't even visible in NMEAdistance.

Cheers,
/dev