Hello, I am new to OVMS. I have a Gen2 Leaf on Dexters server. Tom has helped me set it up. I found my GPS data was off up to two degrees. I’ve traced it to myatof() in utils.c. It adds the fractional part with both positive and negative numbers, where it should subtract for negative numbers. myatof() is used in SIM808 lat and long conversions, and somewhere in Twizy which I didn’t look into. I suppose there isn’t that many SIM808 based OVMSs in the Southern or Western hemispheres? It is easy to fix, but maybe going through float in the first place isn’t necessary? Looks like there is 31bits of information coming out of the GPS where float will drop this to 23bits. 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. Edward
Hi Edward, welcome :) I do notice some offset from road maps once in a while. So go ahead optimizing gps2latlon(), maybe that's the offset source. The atof() function should be fixed regardless of the GPS conversion, I'll take care of that. Regards, Michael Am 23.01.2017 um 08:12 schrieb Edward Cheeseman:
Hello,
I am new to OVMS. I have a Gen2 Leaf on Dexters server. Tom has helped me set it up.
I found my GPS data was off up to two degrees. I’ve traced it to myatof() in utils.c. It adds the fractional part with both positive and negative numbers, where it should subtract for negative numbers.
myatof() is used in SIM808 lat and long conversions, and somewhere in Twizy which I didn’t look into. I suppose there isn’t that many SIM808 based OVMSs in the Southern or Western hemispheres?
It is easy to fix, but maybe going through float in the first place isn’t necessary? Looks like there is 31bits of information coming out of the GPS where float will drop this to 23bits. 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.
Edward
_______________________________________________ OvmsDev mailing list OvmsDev@lists.teslaclub.hk http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
-- Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
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. Edward --------------utils.c snip-------------------- // 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; long frac; char *s; 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 #endif //OVMS_SIMCOM_SIM908 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 break; } 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; } if(degrees <0) frac = -frac; return degrees * 2048 * 3600 + frac; } --------------utils.c snip end--------------------
Edwards. First I’ve heard of this, but it doesn’t surprise me. Testing this sort of stuff is not particularly easy. What we have done in the past is put in a DIAG mode command to allow this function to be called with a given string parameter, and then to print the result. Then, we can script up something to feed in a bunch of input and see what the output is like. But, that does require physical hardware. Perhaps also the function could just be run in a standalone C program on the mac? So long as the type sizes are the same, the results should be equivalent (perhaps with some float rounding differences in the original version). Regards, Mark.
On 2 Feb 2017, at 4:38 AM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
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.
Edward
--------------utils.c snip-------------------- // 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; long frac; char *s;
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 #endif //OVMS_SIMCOM_SIM908
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 break; } 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; }
if(degrees <0) frac = -frac; return degrees * 2048 * 3600 + frac; } --------------utils.c snip end-------------------- _______________________________________________ OvmsDev mailing list OvmsDev@lists.teslaclub.hk http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
Hi Mark, I only found this out because I read the C18 user manual. Something it has that I haven't seen before is a “long short” - a 24bit signed integer type! (also an unsigned long short too) I’ve made a spreadsheet which was the basis for the math. I will try with Mac gcc. Part of the fun is gcc (64bit) will have a vastly different idea of what an int is compared to C18 (8bit)! I’ll have to change data types between the two compilers. The “uint8_t” style declarations don’t seem to work - I haven’t found a C18 stdint.h header. I prefer these to remove this sort of ambiguity! I’ll let you know how that step goes. Edward
On 2/02/2017, at 7:23 PM, Mark Webb-Johnson <mark@webb-johnson.net> wrote:
Edwards.
First I’ve heard of this, but it doesn’t surprise me.
Testing this sort of stuff is not particularly easy. What we have done in the past is put in a DIAG mode command to allow this function to be called with a given string parameter, and then to print the result. Then, we can script up something to feed in a bunch of input and see what the output is like. But, that does require physical hardware.
Perhaps also the function could just be run in a standalone C program on the mac? So long as the type sizes are the same, the results should be equivalent (perhaps with some float rounding differences in the original version).
Regards, Mark.
On 2 Feb 2017, at 4:38 AM, Edward Cheeseman <cheesemanedward@gmail.com <mailto:cheesemanedward@gmail.com>> wrote:
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.
Oh, can someone send me a DIAG capture (or confirm) that the SIM908 lat/long outputs are (D)DDMM.MMMM format, rather than (D)DDMM.MMMMMM? I’m error checking so either will work, just don’t want to leave data behind :) Edward
On 2/02/2017, at 7:59 PM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
Hi Mark,
I only found this out because I read the C18 user manual. Something it has that I haven't seen before is a “long short” - a 24bit signed integer type! (also an unsigned long short too)
I’ve made a spreadsheet which was the basis for the math. I will try with Mac gcc. Part of the fun is gcc (64bit) will have a vastly different idea of what an int is compared to C18 (8bit)! I’ll have to change data types between the two compilers. The “uint8_t” style declarations don’t seem to work - I haven’t found a C18 stdint.h header. I prefer these to remove this sort of ambiguity!
I’ll let you know how that step goes.
Edward
On 2/02/2017, at 7:23 PM, Mark Webb-Johnson <mark@webb-johnson.net <mailto:mark@webb-johnson.net>> wrote:
Edwards.
First I’ve heard of this, but it doesn’t surprise me.
Testing this sort of stuff is not particularly easy. What we have done in the past is put in a DIAG mode command to allow this function to be called with a given string parameter, and then to print the result. Then, we can script up something to feed in a bunch of input and see what the output is like. But, that does require physical hardware.
Perhaps also the function could just be run in a standalone C program on the mac? So long as the type sizes are the same, the results should be equivalent (perhaps with some float rounding differences in the original version).
Regards, Mark.
On 2 Feb 2017, at 4:38 AM, Edward Cheeseman <cheesemanedward@gmail.com <mailto:cheesemanedward@gmail.com>> wrote:
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.
Edward Cheeseman Electrical Engineer cheesemanedward@gmail.com
Example GPS log excerpt from the SIM908: 2,142452,5118.427633,N,723.060952,E,1,4,2.862085,41.881016,M,47.558514,M,,0000 64,79.84,T,,M,0.00,N,0.00,K,A 2,142454,5118.427617,N,723.060236,E,1,4,2.863321,41.924519,M,47.558521,M,,0000 64,28.72,T,,M,2.84,N,5.25,K,A 2,142456,5118.428416,N,723.057457,E,1,4,2.864882,43.029949,M,47.558483,M,,0000 64,289.11,T,,M,3.24,N,6.01,K,A 2,142458,5118.423982,N,723.060985,E,1,5,1.995852,50.477901,M,47.558537,M,,0000 64,289.11,T,,M,0.00,N,0.00,K,A 2,142500,5118.421071,N,723.063434,E,1,5,1.996306,54.801235,M,47.558567,M,,0000 64,289.11,T,,M,0.00,N,0.00,K,A 2,142502,5118.421071,N,723.063434,E,1,5,1.995406,54.801235,M,47.558567,M,,0000 64,289.11,T,,M,0.00,N,0.00,K,A Regarding testing without hardware, there is a PIC simulator built into the MPLAB X IDE, that also emulates some PIC18 CPUs. Haven't used it though, and I doubt it will be able to run the complete OVMS firmware, but it should be usable to test single functions. Regards, Michael Am 02.02.2017 um 08:52 schrieb Edward Cheeseman:
Oh, can someone send me a DIAG capture (or confirm) that the SIM908 lat/long outputs are (D)DDMM.MMMM format, rather than (D)DDMM.MMMMMM? I’m error checking so either will work, just don’t want to leave data behind :)
Edward
On 2/02/2017, at 7:59 PM, Edward Cheeseman <cheesemanedward@gmail.com <mailto:cheesemanedward@gmail.com>> wrote:
Hi Mark,
I only found this out because I read the C18 user manual. Something it has that I haven't seen before is a “long short” - a 24bit signed integer type! (also an unsigned long short too)
I’ve made a spreadsheet which was the basis for the math. I will try with Mac gcc. Part of the fun is gcc (64bit) will have a vastly different idea of what an int is compared to C18 (8bit)! I’ll have to change data types between the two compilers. The “uint8_t” style declarations don’t seem to work - I haven’t found a C18 stdint.h header. I prefer these to remove this sort of ambiguity!
I’ll let you know how that step goes.
Edward
On 2/02/2017, at 7:23 PM, Mark Webb-Johnson <mark@webb-johnson.net <mailto:mark@webb-johnson.net>> wrote:
Edwards.
First I’ve heard of this, but it doesn’t surprise me.
Testing this sort of stuff is not particularly easy. What we have done in the past is put in a DIAG mode command to allow this function to be called with a given string parameter, and then to print the result. Then, we can script up something to feed in a bunch of input and see what the output is like. But, that does require physical hardware.
Perhaps also the function could just be run in a standalone C program on the mac? So long as the type sizes are the same, the results should be equivalent (perhaps with some float rounding differences in the original version).
Regards, Mark.
On 2 Feb 2017, at 4:38 AM, Edward Cheeseman <cheesemanedward@gmail.com <mailto:cheesemanedward@gmail.com>> wrote:
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.
Edward Cheeseman Electrical Engineer cheesemanedward@gmail.com <mailto:cheesemanedward@gmail.com>
_______________________________________________ OvmsDev mailing list OvmsDev@lists.teslaclub.hk http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
-- Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
Thanks. The 908 reports a bit more resolution than the 808. I think the extra info is well in the position margin of error, but I modified the SIM908 implementation slightly to include it. Latest is on Github: https://github.com/evbuilder/Open-Vehicle-Monitoring-System I have tested both variants using gcc and everything looks ok. I’ll try looking at the MPLab simulator, but I’ll also get it into the vehicle and try the complete system. Edward
On 3/02/2017, at 7:40 AM, Michael Balzer <dexter@expeedo.de> wrote:
Example GPS log excerpt from the SIM908:
2,142452,5118.427633,N,723.060952,E,1,4,2.862085,41.881016,M,47.558514,M,,0000 64,79.84,T,,M,0.00,N,0.00,K,A ...
Hello again, I have tried out the integer math approach for converting Lat and Long GPS values on my SIM808 unit. It seems to be reasonable for the short drive I had today. Going by the iOS app (which I think uses Apple maps?) I was on the road, although maybe on the wrong side of it! So, maybe within 5 meters? I haven’t compared this to the floating point implementation since the negative fix, so can’t say whether it is an improvement in accuracy. I’m reasonably certain it takes less cycles. It may take more program space with the constants used. The SIM908 code hasn’t been tested on a live unit, but worked ok on mac gcc. I’ve transferred the changes I needed to make that ensure the C18 data types behave correctly. Integer Promotion and char unsigned by default were interesting quirks. So was the “don’t make a line too complicated” piece of advice. (1<<8) just disappeared, where 256 worked?! Anyway, this minor change is on Github: https://github.com/evbuilder/Open-Vehicle-Monitoring-System/tree/lat-long-pr... Let me know if you want this as a pull request. Edward
Hi Edward, I'll try to test your new code on a SIM908 module this weekend. Regards, Michael Am 06.02.2017 um 10:50 schrieb Edward Cheeseman:
Hello again,
I have tried out the integer math approach for converting Lat and Long GPS values on my SIM808 unit. It seems to be reasonable for the short drive I had today. Going by the iOS app (which I think uses Apple maps?) I was on the road, although maybe on the wrong side of it! So, maybe within 5 meters?
I haven’t compared this to the floating point implementation since the negative fix, so can’t say whether it is an improvement in accuracy. I’m reasonably certain it takes less cycles. It may take more program space with the constants used.
The SIM908 code hasn’t been tested on a live unit, but worked ok on mac gcc. I’ve transferred the changes I needed to make that ensure the C18 data types behave correctly. Integer Promotion and char unsigned by default were interesting quirks. So was the “don’t make a line too complicated” piece of advice. (1<<8) just disappeared, where 256 worked?!
Anyway, this minor change is on Github:
https://github.com/evbuilder/Open-Vehicle-Monitoring-System/tree/lat-long-pr...
Let me know if you want this as a pull request.
Edward _______________________________________________ OvmsDev mailing list OvmsDev@lists.teslaclub.hk http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
-- Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
Hi Edward, 32-bit float does indeed store 23 bits of significand, but there is an additional implicit bit, making the total 24 bits. When you also consider the separate sign bit, 32-bit float has as much precision as a 25-bit signed fixed-point integer. Adjusting your math without any other adjustments, that would imply a resolution of 1.2 meters and perhaps 2.5 meters unrounded. However, I don't quite follow your calculations since floating point always carries a certain number of significant digits, regardless of the exponent. Can you show why the circumference divided by a fixed precision would reflect the ability and precision of a floating point calculation? It's a snowy day here, and I don't have my floating point thinking cap... Brian On Feb 1, 2017, at 12:38 PM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
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.
So, while I’ve dabbled in this stuff I didn’t get a PhD in its analysis! Lets give it a go: (please point out any errors found) --------- OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon(). Circumference at Equator is worst case. So a native unit represents a maximum of 40,075,017m / ( 360d * 60m * 60s *2048) = 15mm. Certainly enough, and just fits into 32bit at 31.3bits. Looks like someone designed it that way. Floating point number accuracy: Worst case accuracy is at 180degrees. IEEE754 binary32 is: 0x43340000 -> +(s) 0x86(e) 0x340000(f). One less is 0x4333FFFF -> 179.999985 degrees. Worst case resolution is 0.000015 degrees or 40,075,017(m) / 360(d) * 0.000015(d) = 1.670m By implied bit, I gather this relates to the fact that at close to 0degrees, the precision would be much greater. I live near 180degrees so this has less relevance to me than say someone in the UK. SIM908 reports DDDMM.MMMMMM, a resolution of 0.0000000167 degrees or 1.9mm SIM808 reports DDD.DDDDDD, a resolution of 0.000001 degrees or 111mm Clearly going through floating point is throwing away some information, but there is no way we can use all the resolution reported by the SIM908. Is this worth the reduction in code readability (and maintainability)? is the integer math any better? On the SIM908 version, the worst I’ve seen is 0.00000025deg error -> 28mm. That’s not to say I’ve done much testing by any means. Adopting the change probably comes down to other considerations than resolution. Edward
On 7/02/2017, at 10:53 AM, HONDA S-2000 wrote:
Hi Edward,
32-bit float does indeed store 23 bits of significand, but there is an additional implicit bit, making the total 24 bits. When you also consider the separate sign bit, 32-bit float has as much precision as a 25-bit signed fixed-point integer.
Adjusting your math without any other adjustments, that would imply a resolution of 1.2 meters and perhaps 2.5 meters unrounded.
However, I don't quite follow your calculations since floating point always carries a certain number of significant digits, regardless of the exponent. Can you show why the circumference divided by a fixed precision would reflect the ability and precision of a floating point calculation? It's a snowy day here, and I don't have my floating point thinking cap...
Brian
Float gets slightly worse when it gets multiplied by 3600*2048. 180*3600*2048 = 1327104000, represented in IEEE754 as 0x4E9E3400. 0x4E9E33FF is 1327103872, 128 less, giving a resolution of 1.9meters Every calculation with float can cause 1m order errors. Having resolution in the centimetre range puts calculation error well under the inaccuracy of the GPS. This is still only critical if you need to know which lane you are in :) Oh, good time to point out that C18 actually doesn’t follow IEEE754 exactly: rather than the usual [sign, exponent, fraction] notation, it swaps the bit order to [exponent, sign, fraction]. I can kind of see why - with the 8bit processor, having the 8 bit exponent aligned with the MSbyte could save a number of bit shift operations among many other byte aligned actions. Sign becomes the MSB of the three remaining bytes. I wonder if this is the source of error in the original atof()?
On 7/02/2017, at 12:47 PM, Edward Cheeseman wrote:
So, while I’ve dabbled in this stuff I didn’t get a PhD in its analysis! Lets give it a go: (please point out any errors found)
--------- OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon(). Circumference at Equator is worst case. So a native unit represents a maximum of 40,075,017m / ( 360d * 60m * 60s *2048) = 15mm. Certainly enough, and just fits into 32bit at 31.3bits. Looks like someone designed it that way.
Floating point number accuracy: Worst case accuracy is at 180degrees. IEEE754 binary32 is: 0x43340000 -> +(s) 0x86(e) 0x340000(f). One less is 0x4333FFFF -> 179.999985 degrees. Worst case resolution is 0.000015 degrees or 40,075,017(m) / 360(d) * 0.000015(d) = 1.670m By implied bit, I gather this relates to the fact that at close to 0degrees, the precision would be much greater. I live near 180degrees so this has less relevance to me than say someone in the UK.
SIM908 reports DDDMM.MMMMMM, a resolution of 0.0000000167 degrees or 1.9mm SIM808 reports DDD.DDDDDD, a resolution of 0.000001 degrees or 111mm
Clearly going through floating point is throwing away some information, but there is no way we can use all the resolution reported by the SIM908.
Is this worth the reduction in code readability (and maintainability)? is the integer math any better? On the SIM908 version, the worst I’ve seen is 0.00000025deg error -> 28mm. That’s not to say I’ve done much testing by any means.
Adopting the change probably comes down to other considerations than resolution.
Edward
On 7/02/2017, at 10:53 AM, HONDA S-2000 wrote:
Hi Edward,
32-bit float does indeed store 23 bits of significand, but there is an additional implicit bit, making the total 24 bits. When you also consider the separate sign bit, 32-bit float has as much precision as a 25-bit signed fixed-point integer.
Adjusting your math without any other adjustments, that would imply a resolution of 1.2 meters and perhaps 2.5 meters unrounded.
However, I don't quite follow your calculations since floating point always carries a certain number of significant digits, regardless of the exponent. Can you show why the circumference divided by a fixed precision would reflect the ability and precision of a floating point calculation? It's a snowy day here, and I don't have my floating point thinking cap...
Brian
I don't have a PhD on this topic, either, so here's my best shot. Please note that floating point numbers only represent a potential for loss of precision when adding very large numbers to very small numbers. In those cases, the very small numbers can completely disappear from the total. Multiplication doesn't affect the precision at all - nothing is usually lost because there are rarely that many significant digits to start with. I briefly got distracted by the calculations done within the GPS unit itself, even though they're not the same calculations that are done of the latitude+longitude results. If you'll indulge the distraction, it might illuminate the subject. Navigation equations involve calculating the square root of a sum of several squares and a product involving the speed of light. The speed of light is defined as 299,792,458 meters per second. That number cannot be represented in 32-bit - it becomes 299,792,448 meters per second, for a loss of 10 meters per second. That might seem rather large, but many scientific calculations approximate the speed of light as 300,000,000 meters per second, which is off by 207,542 meters. Note that the common approximation is four orders of magnitude larger than the loss of precision due to 32-bit float. So, basically, if you're starting with fewer digits of precision in the first place, then floating point is not going to cause any additional loss of precision. However, if you need the full precision of the speed of light, as an example, then 32-bit floating point starts out with a loss of precision (but at least it doesn't get any worse after that). Getting back to the positioning, it looks to me like the resolution would be in millimeters, even with 32-bit float. The SIM908 format of DDDMM.MMMMMM would seem to allow for the smallest angle (of 0 degrees, 0.000001 minutes) to be precise to 0.00185531 meters, or 1.85531 millimeters. That number can be obtained with 32-bit float as precisely as with 64-bit float. The largest angle of 180 degrees corresponds to 20037392.103861 meters as a double, or 20037392.0 meters as a float. Thus, using 32-bit float seems to mean that the worst case latitude error would be 0.1 meters or a centimeter. Sounds like you may have come to the same conclusion, unless I misread your message. I assume that for longitude it could be twice as bad (2 centimeters!) in parts of the world. I do not follow your comments about the scaling factor of 3600*2048. Floating point does not lose accuracy when scaled - at least not unless small, unscaled values are added to large (scaled) values with the expectation that those small values will be retained. I haven't looked at all of the code, but where does the 3600*2048 scaling factor come into play? Maybe I just misunderstand what you're referring to. I disagree that every floating point calculation causes additional errors. Can you explain how you came to that conclusion? It's standard scientific and engineering practice to assume that the precision of any final product is no greater than the precision of any input factor. Apart from the example of the speed of light, which is more precise than 32-bit float can represent, I can't see any numbers in the realm of GPS calculations that would lose precision. And, even with the speed of light, once the precision is reduced to fit within 32-bit float at the beginning of the calculations, there would be no further loss of precision - at least not in terms of standard, accepted scientific and engineering precision. Floating point is actually great for just this sort of thing. Brian Willoughby Sound Consulting On Feb 6, 2017, at 6:00 PM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
Float gets slightly worse when it gets multiplied by 3600*2048.
180*3600*2048 = 1327104000, represented in IEEE754 as 0x4E9E3400. 0x4E9E33FF is 1327103872, 128 less, giving a resolution of 1.9meters Every calculation with float can cause 1m order errors. Having resolution in the centimetre range puts calculation error well under the inaccuracy of the GPS.
This is still only critical if you need to know which lane you are in :)
Oh, good time to point out that C18 actually doesn’t follow IEEE754 exactly: rather than the usual [sign, exponent, fraction] notation, it swaps the bit order to [exponent, sign, fraction]. I can kind of see why - with the 8bit processor, having the 8 bit exponent aligned with the MSbyte could save a number of bit shift operations among many other byte aligned actions. Sign becomes the MSB of the three remaining bytes. I wonder if this is the source of error in the original atof()?
On 7/02/2017, at 12:47 PM, Edward Cheeseman wrote:
So, while I’ve dabbled in this stuff I didn’t get a PhD in its analysis! Lets give it a go: (please point out any errors found)
--------- OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon(). Circumference at Equator is worst case. So a native unit represents a maximum of 40,075,017m / ( 360d * 60m * 60s *2048) = 15mm. Certainly enough, and just fits into 32bit at 31.3bits. Looks like someone designed it that way.
Floating point number accuracy: Worst case accuracy is at 180degrees. IEEE754 binary32 is: 0x43340000 -> +(s) 0x86(e) 0x340000(f). One less is 0x4333FFFF -> 179.999985 degrees. Worst case resolution is 0.000015 degrees or 40,075,017(m) / 360(d) * 0.000015(d) = 1.670m By implied bit, I gather this relates to the fact that at close to 0degrees, the precision would be much greater. I live near 180degrees so this has less relevance to me than say someone in the UK.
SIM908 reports DDDMM.MMMMMM, a resolution of 0.0000000167 degrees or 1.9mm SIM808 reports DDD.DDDDDD, a resolution of 0.000001 degrees or 111mm
Clearly going through floating point is throwing away some information, but there is no way we can use all the resolution reported by the SIM908.
Is this worth the reduction in code readability (and maintainability)? is the integer math any better? On the SIM908 version, the worst I’ve seen is 0.00000025deg error -> 28mm. That’s not to say I’ve done much testing by any means.
Adopting the change probably comes down to other considerations than resolution.
Edward
On 7/02/2017, at 10:53 AM, Brian wrote:
32-bit float does indeed store 23 bits of significand, but there is an additional implicit bit, making the total 24 bits. When you also consider the separate sign bit, 32-bit float has as much precision as a 25-bit signed fixed-point integer.
Adjusting your math without any other adjustments, that would imply a resolution of 1.2 meters and perhaps 2.5 meters unrounded.
However, I don't quite follow your calculations since floating point always carries a certain number of significant digits, regardless of the exponent. Can you show why the circumference divided by a fixed precision would reflect the ability and precision of a floating point calculation? It's a snowy day here, and I don't have my floating point thinking cap...
Sorry to reply to my own (long) message, but I overlooked a few things in my writeup. I already realized that 32-bit float is limited to between 6 and 9 decimal digits of precision. The reason it varies across such a wide range (6 to 9) is that decimal fractions and binary fractions do not always convert precisely. So, that range really represents worst case and best case limits. This is important because latitude and longitude are reported in decimal degrees and minutes, not binary. Anyway, there's no way that the SIM908 format of DDDMM.MMMMMM can be represented in 32-bit float without loss of precision. Not even the SIM808 format of DDD.DDDDDD can be represented in 32-bit float, because 9 digits is the best case and isn't always guaranteed. 32-bit float can handle about DDD.DDD, and I haven't taken the time to see how many digits of DDDMM.M… can be handled. You are correct that 64-bit double would handle this easily, except for the fact that the PIC doesn't easily support 64-bit double. So, while 32-bit float can accurately convert a 0.000001 minute arc to meters as a relative distance, it cannot maintain that precision with larger degrees. Without getting further distracted, there are math libraries which work on strings of decimal digits, rather than binary words. With such a library, it is probably possible to handle DDDMM.MMMMMM without any loss (but, as you say, is it really necessary to calculate to centimeter accuracy when the open GPS technology is not that precise?). Finally, to satisfy my curiosity, what are the latitude and longitude angles being converted to? I can see how they can be converted to distance in meters on the surface of the Earth, but those distances would have to be relative to a known position like the North Pole or the Greenwich longitude line. Are maps really using those references? … or does each map have a local reference position where all other positions are relative in degrees and minutes? If the latter case, then some of the burden of resolution is relaxed, since any given map would not cover more than a small number of degrees. Brian Willoughby Sound Consulting On Feb 6, 2017, at 9:33 PM, HONDA S-2000 <s2000@audiobanshee.com> wrote:
I don't have a PhD on this topic, either, so here's my best shot.
Please note that floating point numbers only represent a potential for loss of precision when adding very large numbers to very small numbers. In those cases, the very small numbers can completely disappear from the total. Multiplication doesn't affect the precision at all - nothing is usually lost because there are rarely that many significant digits to start with.
I briefly got distracted by the calculations done within the GPS unit itself, even though they're not the same calculations that are done of the latitude+longitude results. If you'll indulge the distraction, it might illuminate the subject. Navigation equations involve calculating the square root of a sum of several squares and a product involving the speed of light. The speed of light is defined as 299,792,458 meters per second. That number cannot be represented in 32-bit - it becomes 299,792,448 meters per second, for a loss of 10 meters per second. That might seem rather large, but many scientific calculations approximate the speed of light as 300,000,000 meters per second, which is off by 207,542 meters. Note that the common approximation is four orders of magnitude larger than the loss of precision due to 32-bit float. So, basically, if you're starting with fewer digits of precision in the first place, then floating point is not going to cause any additional loss of precision. However, if you need the full precision of the speed of light, as an example, then 32-bit floating point starts out with a loss of precision (but at least it doesn't get any worse after that).
Getting back to the positioning, it looks to me like the resolution would be in millimeters, even with 32-bit float. The SIM908 format of DDDMM.MMMMMM would seem to allow for the smallest angle (of 0 degrees, 0.000001 minutes) to be precise to 0.00185531 meters, or 1.85531 millimeters. That number can be obtained with 32-bit float as precisely as with 64-bit float. The largest angle of 180 degrees corresponds to 20037392.103861 meters as a double, or 20037392.0 meters as a float. Thus, using 32-bit float seems to mean that the worst case latitude error would be 0.1 meters or a centimeter. Sounds like you may have come to the same conclusion, unless I misread your message. I assume that for longitude it could be twice as bad (2 centimeters!) in parts of the world.
I do not follow your comments about the scaling factor of 3600*2048. Floating point does not lose accuracy when scaled - at least not unless small, unscaled values are added to large (scaled) values with the expectation that those small values will be retained. I haven't looked at all of the code, but where does the 3600*2048 scaling factor come into play? Maybe I just misunderstand what you're referring to. I disagree that every floating point calculation causes additional errors. Can you explain how you came to that conclusion?
It's standard scientific and engineering practice to assume that the precision of any final product is no greater than the precision of any input factor. Apart from the example of the speed of light, which is more precise than 32-bit float can represent, I can't see any numbers in the realm of GPS calculations that would lose precision. And, even with the speed of light, once the precision is reduced to fit within 32-bit float at the beginning of the calculations, there would be no further loss of precision - at least not in terms of standard, accepted scientific and engineering precision. Floating point is actually great for just this sort of thing.
Brian Willoughby Sound Consulting
On Feb 6, 2017, at 6:00 PM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
Float gets slightly worse when it gets multiplied by 3600*2048.
180*3600*2048 = 1327104000, represented in IEEE754 as 0x4E9E3400. 0x4E9E33FF is 1327103872, 128 less, giving a resolution of 1.9meters Every calculation with float can cause 1m order errors. Having resolution in the centimetre range puts calculation error well under the inaccuracy of the GPS.
This is still only critical if you need to know which lane you are in :)
Oh, good time to point out that C18 actually doesn’t follow IEEE754 exactly: rather than the usual [sign, exponent, fraction] notation, it swaps the bit order to [exponent, sign, fraction]. I can kind of see why - with the 8bit processor, having the 8 bit exponent aligned with the MSbyte could save a number of bit shift operations among many other byte aligned actions. Sign becomes the MSB of the three remaining bytes. I wonder if this is the source of error in the original atof()?
On 7/02/2017, at 12:47 PM, Edward Cheeseman wrote:
So, while I’ve dabbled in this stuff I didn’t get a PhD in its analysis! Lets give it a go: (please point out any errors found)
--------- OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon(). Circumference at Equator is worst case. So a native unit represents a maximum of 40,075,017m / ( 360d * 60m * 60s *2048) = 15mm. Certainly enough, and just fits into 32bit at 31.3bits. Looks like someone designed it that way.
Floating point number accuracy: Worst case accuracy is at 180degrees. IEEE754 binary32 is: 0x43340000 -> +(s) 0x86(e) 0x340000(f). One less is 0x4333FFFF -> 179.999985 degrees. Worst case resolution is 0.000015 degrees or 40,075,017(m) / 360(d) * 0.000015(d) = 1.670m By implied bit, I gather this relates to the fact that at close to 0degrees, the precision would be much greater. I live near 180degrees so this has less relevance to me than say someone in the UK.
SIM908 reports DDDMM.MMMMMM, a resolution of 0.0000000167 degrees or 1.9mm SIM808 reports DDD.DDDDDD, a resolution of 0.000001 degrees or 111mm
Clearly going through floating point is throwing away some information, but there is no way we can use all the resolution reported by the SIM908.
Is this worth the reduction in code readability (and maintainability)? is the integer math any better? On the SIM908 version, the worst I’ve seen is 0.00000025deg error -> 28mm. That’s not to say I’ve done much testing by any means.
Adopting the change probably comes down to other considerations than resolution.
Edward
On 7/02/2017, at 10:53 AM, Brian wrote:
32-bit float does indeed store 23 bits of significand, but there is an additional implicit bit, making the total 24 bits. When you also consider the separate sign bit, 32-bit float has as much precision as a 25-bit signed fixed-point integer.
Adjusting your math without any other adjustments, that would imply a resolution of 1.2 meters and perhaps 2.5 meters unrounded.
However, I don't quite follow your calculations since floating point always carries a certain number of significant digits, regardless of the exponent. Can you show why the circumference divided by a fixed precision would reflect the ability and precision of a floating point calculation? It's a snowy day here, and I don't have my floating point thinking cap…
On 7/02/2017, at 6:59 PM, HONDA S-2000 wrote: Finally, to satisfy my curiosity, what are the latitude and longitude angles being converted to?
On 7/02/2017, at 12:47 PM, Edward Cheeseman wrote: OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon().
Seconds * 3600 = degrees. So native units would be degrees * 3600 * 2048. I think we all agree - if land or road surveying was the application better precision would be necessary. When all we want is to know where our car is, within 30 meters is probably fine. Cars don’t hide that easy :) I only delved down this rabbit hole because the position was 200kms off! That cause has been separately solved. The main advantage is, given the poor little 8bit PIC doesn’t need to deal with a floating point at all, there could be a speed improvement. A huge disadvantage is the code is not easily read. Edward
On Feb 6, 2017, at 10:43 PM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
On 7/02/2017, at 6:59 PM, HONDA S-2000 wrote: Finally, to satisfy my curiosity, what are the latitude and longitude angles being converted to?
On 7/02/2017, at 12:47 PM, Edward Cheeseman wrote: OVMS native format: Appears to be signed seconds * 2048. I haven’t delved into documentation here, just what I saw in the gps2latlon().
Seconds * 3600 = degrees. So native units would be degrees * 3600 * 2048.
I see. While intermediate values are calculated in float, the return value is a fixed-point, signed 32-bit long value (a.k.a. Q19.11). That allows for a maximum of ±145 degrees (?).
I think we all agree - if land or road surveying was the application better precision would be necessary.
When all we want is to know where our car is, within 30 meters is probably fine. Cars don’t hide that easy :) I only delved down this rabbit hole because the position was 200kms off! That cause has been separately solved.
The main advantage is, given the poor little 8bit PIC doesn’t need to deal with a floating point at all, there could be a speed improvement. A huge disadvantage is the code is not easily read.
Is there a way to separate the math into a generic function, and then rewrite the main function to use more readable function-based code? Again, I suggest that a decimal math library might be able to directly handle the DDDMM.MMMMMM format without using float as an intermediate. If the decimal math library can convert directly to Q19.11 then it would be a sure win. Only problem is that I've never used a multi-digit decimal math library, so I wouldn't know where to point you for starters. I agree that readability is important, but fixed-point math is never very readable, but it's indispensable in low-level firmware. At the very least, multiplication of fixed-point numbers like the Q19.11 format is not very readable, and that's already part of the design even before considering your optimizations. In other words, I think it's worth investigating integer and fixed-point optimizations. Brian
On 7/02/2017, at 8:21 PM, HONDA S-2000 wrote: On Feb 6, 2017, at 10:43 PM, Edward Cheeseman wrote:
Seconds * 3600 = degrees. So native units would be degrees * 3600 * 2048.
I see. While intermediate values are calculated in float, the return value is a fixed-point, signed 32-bit long value (a.k.a. Q19.11). That allows for a maximum of ±145 degrees (?). I think its more like Q20.11? One bit sign, 11 bits of fractions of a second, 20bits of seconds/3600 = +/-291 degrees
Is there a way to separate the math into a generic function, and then rewrite the main function to use more readable function-based code? Yes, but I’ve been told that the stack is very limited and that everything should be inlined where possible. I’ve also been hitting the (very mediocre) limits of the C preprocessor. Where normally I’d #define a constant with all its glorious minutes and seconds spelled out, C18 can silently just ignore half of it. I wanted to use +(1<<7) to make clear I was rounding for the >>8 divide. It totally ignored that. +128 however did work. I only found that running the MPLAB simulator feeding in values and comparing to a spreadsheet. Oh, Libre Office appears to use double precision floats. My guess is Excel would be the same.
I came to the conclusion the only thing we get for free in the compiler is comments so I wrote a bit of a novel explaining what I was up to. I boiled it down to the simplest C and that seems to work. I was pretty close to breaking out assembly but when I found out the pain required in multiplying anything that wasn’t 8x8bit I decided it was better to stick with what help C18 can give.
Again, I suggest that a decimal math library might be able to directly handle the DDDMM.MMMMMM format without using float as an intermediate. If the decimal math library can convert directly to Q19.11 then it would be a sure win. Only problem is that I've never used a multi-digit decimal math library, so I wouldn't know where to point you for starters. In anything more capable I would agree. I’ve used TI’s IQ math library and it is reasonable to read.
For the C18 compiler, an int is 8 bits. In C, all math is done in ints unless forced to a larger type by operands or casting. When you do (1<<7) in an 8-bit int, you shift the bit off the end of the int and get zero. The compiler didn't ignore your constant, it did exactly what it's supposed to do. You can fix it with a cast, like: ((long)1 << 7) or (1L << 7) Tom On 2/7/17, 4:30 AM, "Edward Cheeseman" <ovmsdev-bounces@lists.teslaclub.hk on behalf of cheesemanedward@gmail.com> wrote: Where normally I’d #define a constant with all its glorious minutes and seconds spelled out, C18 can silently just ignore half of it. I wanted to use +(1<<7) to make clear I was rounding for the >>8 divide. It totally ignored that. +128 however did work. I only found that running the MPLAB simulator feeding in values and comparing to a spreadsheet.
I was about to complain that 128 fits into 8bits - but of course it doesn’t fit into a signed 8bit int. My bad.
On 8/02/2017, at 10:14 AM, Tom Saxton <tom@idleloop.com> wrote:
For the C18 compiler, an int is 8 bits. In C, all math is done in ints unless forced to a larger type by operands or casting. When you do (1<<7) in an 8-bit int, you shift the bit off the end of the int and get zero. The compiler didn't ignore your constant, it did exactly what it's supposed to do.
You can fix it with a cast, like:
((long)1 << 7) or (1L << 7)
Tom
You're right, 1 << 7 doesn't send it off the end. That's my mistake. 00000001 << 7 is 10000000, which is -128 when treated as a signed byte and +128 when treated as unsigned. In this case, the operation should be treated as a signed int, so it should have been adding -128 (subtracting 128) instead of adding the 128 you intended. What actually happened would depend on the rest of the expression. See for example, the casts I had to do in the function vehicle_teslaroadster_minutestocharge() to get the math to work correctly (note that bIntercept, wAvail and mx100 are all ints): // calculate temperature to charge rate equation bIntercept = (wAvail >= 2300) ? 288 : (signed long)745 - (signed long)199 * wAvail / 1000; mx1000 = (signed long)3588 - (signed long)250 * wAvail / 1000; For example, without the cast, "199 * wAvail / 1000" would get done as an int, the numerator overflows and who knows how it handles the 1000 constant. By casting 199 to a signed long, the multiply and divide both get done in longs. As I recall, the cast on 745 was required to get the subtract done as a long. It was fun getting all that code working as fast and small as possible, with no floating point and minimizing use of longs. See also KmFromMi(), MiFromKm(), and JdToYMD() in utils.c. My favorite is JdFromYMD() which took just one cast, the "L" on 1461, to get that whole giant magic expression to evaluate correctly. Tom On 2/7/17, 1:22 PM, "Edward Cheeseman" <ovmsdev-bounces@lists.teslaclub.hk on behalf of cheesemanedward@gmail.com> wrote: I was about to complain that 128 fits into 8bits - but of course it doesn’t fit into a signed 8bit int. My bad. > On 8/02/2017, at 10:14 AM, Tom Saxton <tom@idleloop.com> wrote: > > For the C18 compiler, an int is 8 bits. In C, all math is done in ints unless forced to a larger type by operands or casting. When you do (1<<7) in an 8-bit int, you shift the bit off the end of the int and get zero. The compiler didn't ignore your constant, it did exactly what it's supposed to do. > > You can fix it with a cast, like: > > ((long)1 << 7) or (1L << 7) > > Tom _______________________________________________ OvmsDev mailing list OvmsDev@lists.teslaclub.hk http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
On 8/02/2017, at 11:50 AM, Tom Saxton <tom@idleloop.com> wrote:
You're right, 1 << 7 doesn't send it off the end. That's my mistake.
00000001 << 7 is 10000000, which is -128 when treated as a signed byte and +128 when treated as unsigned. In this case, the operation should be treated as a signed int, so it should have been adding -128 (subtracting 128) instead of adding the 128 you intended. What actually happened would depend on the rest of the expression.
Given it was a rounding value only, subtraction instead of addition would have a result of one less which is what I saw. The other rounding I used (1<<17) was sure to overflow 8bit!
My favorite is JdFromYMD() which took just one cast, the "L" on 1461, to get that whole giant magic expression to evaluate correctly.
Yeah I’ve skimmed past the Date stuff and thought I’m glad I’m not having to work out how that works. Now that I am becoming aware of the extent of casting required, this function seems all the more magical.
Sadly, there's no ROM space left for adding fancy libraries... Am 07.02.2017 um 13:30 schrieb Edward Cheeseman:
Again, I suggest that a decimal math library might be able to directly handle the DDDMM.MMMMMM format without using float as an intermediate. If the decimal math library can convert directly to Q19.11 then it would be a sure win. Only problem is that I've never used a multi-digit decimal math library, so I wouldn't know where to point you for starters. In anything more capable I would agree. I’ve used TI’s IQ math library and it is reasonable to read.
-- Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
On Feb 7, 2017, at 4:30 AM, Edward Cheeseman <cheesemanedward@gmail.com> wrote:
On 7/02/2017, at 8:21 PM, HONDA S-2000 wrote: On Feb 6, 2017, at 10:43 PM, Edward Cheeseman wrote:
Seconds * 3600 = degrees. So native units would be degrees * 3600 * 2048.
I see. While intermediate values are calculated in float, the return value is a fixed-point, signed 32-bit long value (a.k.a. Q19.11). That allows for a maximum of ±145 degrees (?). I think its more like Q20.11? One bit sign, 11 bits of fractions of a second, 20bits of seconds/3600 = +/-291 degrees
Oops. I somehow subtracted the sign bit twice. Something about the number 11 must have freaked me out ;-) That's good news, because Q20.11 can handle longitude better than the mythical Q19.11, i.e., ±291 degrees, as you point out. That's enough for up to 180°E and 180°W. Brian p.s. The rest of your comments are also correct. It seems that we don't have a lot of Flash space left for readable code solutions. Your idea to use comments to explain the source is a good one. That's assuming that any rewrite turns out to be an improvement, otherwise the code could stay as it was. Let us know what you find out.
On 8/02/2017, at 7:25 PM, HONDA S-2000 wrote: That's assuming that any rewrite turns out to be an improvement, otherwise the code could stay as it was. Let us know what you find out.
So, I got curious as to what happens to the lat and long coordinates after they got converted to the Q20.11 seconds notation. The result of calls to gps2latlon() only end up in globals car_latitude and car_longitude. Those variables get used directly in acc.c and log.c, which I gather is for logs, and calculating if an advanced charger is close? As far as I can tell, everywhere else they are used only via stp_latlon(). Here I found a comment that pointed to the origin of the fixed point Q20.11 seconds format: it is native to the Tesla Roadster. So what happens in stp_latlon() is another conversion via float to go from Q20.11seconds to 32bit degrees*1000000. Degrees*1000000 is chosen for conversion to a human readable ascii string “(-)(D)(D)D.DDDDDD” … ... which just happens to be what the SIM808 puts out natively! Rather than refactor all the location code I’m going to suggest changing that one remaining floating point conversion out with another fixed point integer multiply, and leaving it at that. Edward
On 8/02/2017, at 11:45 PM, Edward Cheeseman wrote:
On 8/02/2017, at 7:25 PM, HONDA S-2000 wrote: That's assuming that any rewrite turns out to be an improvement, otherwise the code could stay as it was. Let us know what you find out.
I’m going to suggest changing that one remaining floating point conversion out with another fixed point integer multiply, and leaving it at that.
My fork has both float operations replaced with integer multiplies. Ran the car around the block and positions were definitely good enough for what road I was on, usually within the lane, but sometimes the lane over from where I should be. The two multiply operations look to be as accurate as the SIM808 +/- 0.000001 or about 0.1m. I’m reasonably confident in these changes giving accurate results. https://github.com/evbuilder/Open-Vehicle-Monitoring-System/tree/lat-long-pr... Edward
participants (5)
-
Edward Cheeseman -
HONDA S-2000 -
Mark Webb-Johnson -
Michael Balzer -
Tom Saxton