[Ovmsdev] SIM808/SIM908 GPS accuracy
cheesemanedward at gmail.com
Thu Feb 2 04:38:02 HKT 2017
> On 23/01/2017, at 8:12 PM, Edward Cheeseman wrote:
> I’ve started rewriting gps2latlon() to use a long long (64bit) integer multiply and divide.
> I see reference to SIM808 and 908 on an arduino shield, so I might have a look to see what they have done.
I totally overestimated the pic18F capability.
So it turns out the C18, and for that matter, the XC8 compilers treat long long the same as long - 32bit.
This of course isn’t news to anyone who has been working with this processor.
So, given the floating point library has been pulled in anyway, I think the current implementation isn’t too bad.
Floating point accuracy:
- The equatorial circumference of the Earth is 40,075,017 meters.
- Divided by 23bit, resolution is 4.8meters
The math is probably unrounded, so probably the best you could hope for is within 10 meters.
I think the following is an improvement in speed (no divides), variables used and accuracy (should be as good as received from the GPS), but these claims are yet to be proved. Readability has taken a hit.
I’ve tried to set up the ide on a mac. I’ve got it to compile with the following code but haven’t tested it yet (can’t figure out how to simulate or view assembler output, don’t have a programmer)
If you think this is worth adding in please point me in a direction that I can test it. At some point I will get a programmer, but I only have the one unit for my car so bench testing is a bit hard.
// Convert GPS coordinate form to internal latlon value
// SIM908: DDDMM.MMMMMM (separate South/West handling, see net.c)
// SIM808: +-ddd.dddddd
long gps2latlon(char *gpscoord)
signed int degrees;
unsigned int rem;
degrees = atoi(gpscoord); //use built-in to read integer value
#ifdef OVMS_SIMCOM_SIM908 // SIM908: DDDMM.MMMM
frac = degrees % 100; // extract minutes
degrees /= 100; // fix degrees
rem = 4;
#define GPS_DIVIDER ((unsigned long) 3221225) //(3600 * 2048 / 600000) * 2**18
#else //SIM808: (-)DDD.DDDDDD
frac = 0;
rem = 6;
#define GPS_DIVIDER ((unsigned long) 1932735) //(3600 * 2048 / 1000000) * 2**18
if ( (s = strchr(gpscoord, '.')) )
while (*++s) //read and scale fractional part
if( (unsigned char)(*s - '0') > (unsigned char) 9 )
break; //check for non-decimal
frac = frac * 10 + (*s - '0');
if(--rem==0) //check for too many decimal places
while (rem--!=0) //make up missing digits with zeros
frac = frac * 10;
//fractional part is at most 20bits (999999 < 2^20)
//multiply 10bits at a time with 22bit constant to keep within 32bits
//then bit shift into place and accumulate
//(reuse rem here to reduce memory requirement)
rem = (unsigned long)(((int)frac & 0x03FF) * GPS_DIVIDER) >> 18 ;
frac = (((frac & 0x000FFC00)>>10) * GPS_DIVIDER) >> 8 ;
frac += rem;
frac = -frac;
return degrees * 2048 * 3600 + frac;
--------------utils.c snip end--------------------
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the OvmsDev