mmoller2k / Float64

Double precision 64-bit floating point library for Arduino
GNU General Public License v3.0
20 stars 8 forks source link

Best way to create f64 from raw GPS data #2

Open vtomanov opened 8 years ago

vtomanov commented 8 years ago

Hi,

The raw GPS data is in the following format :

int16_t deg; // the integer part of the number uint32_t minSec; // exact 9 digits after the decimal point - e.g. 3.123456789, 4.123000000

Do you have any suggestion for the best way to create f64 type from this structure ? atoi seems slow to me ? Also vise-verse from f64 extract the data in the original structure ?

FYI: I'm planing to use your library for some GPS calculations and currently experimenting with it....

Kind Regards Vasko Tomanov

mmoller2k commented 8 years ago

Interesting. I would try to convert the two integer parts to f64 each and add them together afterwards. Are you sure that you absolutely need 64-bit floats? I've done some pretty impressively accurate polar coordinate stuff for astronomy using just 32 bits. See my godob project. mic

On 20 Aug 2016 15:59, "vtomanov" notifications@github.com wrote:

Hi,

The raw GPS data is in the following format :

int16_t deg; // the integer part of the number uint32_t minSec; // exact 9 digits after the decimal point - e.g. 3.123456789, 4.123000000

Do you have any suggestion for the best way to create f64 type from this structure ? atoi seems slow to me ? Also vise-verse from f64 extract the data in the original structure ?

FYI: I'm planing to use your library for some GPS calculations and currently experimenting with it....

Kind Regards Vasko Tomanov

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mmoller2k/Float64/issues/2, or mute the thread https://github.com/notifications/unsubscribe-auth/ADIetN-fBl2Tb-Qs3FTPA0Zh5Rz2zoqvks5qhwhYgaJpZM4JpFLo .

vtomanov commented 8 years ago

OK that can do the job - 1.get the fractional integer 2. divide by 1000000000 3. add the integer part...

re: f32 - I need 6 decimal places after the decimal point and in degrees I need max 3 decimals in the integer part - e.g in total 9 decimal places... I miss about 2-3 in f32

vtomanov commented 8 years ago

hmmm performance wise not good so far ... a distance calculation takes 5 second... result is correct ( 687513.69 meters) but really slow...

point 1 lat : 40.748600000 lng : -73, 986400000

point 2 lat: 45, 748600000 lng: -78, 986400000 // Return distance between two coordinates in meters inline void dist64(f64 & latStart, f64 & lngStart,

               f64 & latEnd,
               f64 & lngEnd,

               f64 & dist)

{

f64 _latStart; dtor64(latStart, _latStart); f64 _lngStart; dtor64(lngStart, _lngStart);

f64 _latEnd; dtor64(latEnd, _latEnd); f64 _lngEnd; dtor64(lngEnd, _lngEnd);

//=ACOS( SIN(lat1)_SIN(lat2) + COS(lat1)_COS(lat2)COS(lon2-lon1) ) * 6371000 dist = acos64( sin64(_latStart) * sin64(_latEnd) + cos64(_latStart) * cos64(_latEnd) * cos64(_lngEnd - _lngStart) ) \ GPS_DATA_6371000;

}

vtomanov commented 8 years ago

// Convert degree to radians inline void dtor64(const f64 & d, f64 & r) { r = d; r *= GPS_DATA_PI_180; }

vtomanov commented 8 years ago

define GPS_DATA_90 f64(90L)

define GPS_DATA_PIO2 f64(0x3FF921FB, 0x54442D18)

define GPS_DATA_6371000 f64(6371000L)

mmoller2k commented 8 years ago

Impressive. What cpu are you running it on?

On 21 Aug 2016 3:35 p.m., "vtomanov" notifications@github.com wrote:

define GPS_DATA_90 f64(90L)

define GPS_DATA_PIO2 f64(0x3FF921FB, 0x54442D18)

define GPS_DATA_6371000 f64(6371000L)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mmoller2k/Float64/issues/2#issuecomment-241257631, or mute the thread https://github.com/notifications/unsubscribe-auth/ADIetAflRB1dl8mRlWnEbtW9EUNUzxq8ks5qiFQHgaJpZM4JpFLo .

vtomanov commented 8 years ago

https://www.arduino.cc/en/Main/ArduinoBoardMega2560

but the result is not good .... I will measure the functions one by one to find the bottleneck.. - should be about 1/10 sec max...

vtomanov commented 8 years ago

Test shows that acos64 need SERIOUS improvement about 20x - 4.65 sec cos64 and sin64 are slow but not so tragic....

results :

dtor64 (latStart): 0 dtor64 (lngStart): 0 dtor64 (lngEnd): 0 dtor64 (lngEnd): 1 sin64 (sin64_latStart): 74 sin64 (sin64_latEnd): 76 mul64 (sin_mul): 0 cos64 (cos64_latStart): 77 cos64 (cos64_latEnd): 77 cos64 (cos64_lngEnd_lngStart): 86 mul64 (cos_mul): 0 acos64 (acos64_sin_mul_cos_mul): 4650

-- test code ---- // Return distance between two coordinates in meters inline void dist64(f64 & latStart, f64 & lngStart,

               f64 & latEnd,
               f64 & lngEnd,

               f64 & dist)

{ uint32_t s = millis();

f64 _latStart; dtor64(latStart, _latStart); uint32_t sLatStart = millis(); f64 _lngStart; dtor64(lngStart, _lngStart); uint32_t sLngStart = millis();

f64 _latEnd; dtor64(latEnd, _latEnd); uint32_t sLatEnd = millis(); f64 _lngEnd; dtor64(lngEnd, _lngEnd); uint32_t sLngEnd = millis();

//=ACOS( SIN(lat1)_SIN(lat2) + COS(lat1)_COS(lat2)COS(lon2-lon1) ) \ 6371000

f64 sin64_latStart = sin64(_latStart); uint32_t sSin64_latStart = millis(); f64 sin64_latEnd = sin64(_latEnd); uint32_t sSin64_latEnd = millis(); f64 sin_mul = sin64_latStart * sin64_latEnd; uint32_t sSin_mul = millis();

f64 cos64_latStart = cos64(_latStart); uint32_t sCos64_latStart = millis(); f64 cos64_latEnd = cos64(_latEnd); uint32_t sCos64_latEnd = millis(); f64 cos64_lngEnd_lngStart = cos64(_lngEnd - _lngStart); uint32_t sCos64_lngEnd_lngStart = millis(); f64 cos_mul = cos64_latStart * cos64_latEnd * cos64_lngEnd_lngStart; uint32_t sCos_mul = millis();

f64 acos64_sin_mul_cos_mul = acos64( sin_mul + cos_mul ); uint32_t sAcos64_sin_mul_cos_mul = millis(); dist = acos64_sin_mul_cos_mul * GPS_DATA_6371000;

uint32_t e = millis();

Serial.println("dtor64 (latStart): " + String(sLatStart - s)); Serial.println("dtor64 (lngStart): " + String(sLngStart - sLatStart)); Serial.println("dtor64 (lngEnd): " + String(sLatEnd - sLngStart)); Serial.println("dtor64 (lngEnd): " + String(sLngEnd - sLatEnd));

Serial.println("sin64 (sin64_latStart): " + String(sSin64_latStart - sLngEnd)); Serial.println("sin64 (sin64_latEnd): " + String(sSin64_latEnd - sSin64_latStart)); Serial.println("mul64 (sin_mul): " + String(sSin_mul - sSin64_latEnd));

Serial.println("cos64 (cos64_latStart): " + String(sCos64_latStart - sSin_mul)); Serial.println("cos64 (cos64_latEnd): " + String(sCos64_latEnd - sCos64_latStart)); Serial.println("cos64 (cos64_lngEnd_lngStart): " + String(sCos64_lngEnd_lngStart - sCos64_latEnd)); Serial.println("mul64 (cos_mul): " + String(sCos_mul - sCos64_lngEnd_lngStart));

Serial.println("acos64 (acos64_sin_mul_cos_mul): " + String(sAcos64_sin_mul_cos_mul - sCos_mul));

Serial.println("dist64: " + String(e - s)); }

vtomanov commented 8 years ago

will be very useful if you can add to your Math64 lib fast trigonometric functions based on the code from here : http://http.developer.nvidia.com/Cg/index_stdlib.html

you can name them little bit different to acknowledge that they actually have some tradeoff in the precision ... but will be still good for most cases

vtomanov commented 8 years ago

after more tests the things looks actually worse - in case of small distances the acos64 may go more then 10sec ... definitely it needs a faster algorithm implementation


acos64 (acos64_sin_mul_cos_mul): 10224

mmoller2k commented 8 years ago

Wow! Thanks for all the effort. I'll have a look and see what I can do. When I first wrote the math lib, memory was the problem, not speed. But faster trig functions are definitely possible. I'm away most of next week but will look into it when I'm back. If you think the trig functions are slow you should try the logs and exponent functions... mic

On 21 Aug 2016 7:15 p.m., "vtomanov" notifications@github.com wrote:

after mote test the things are actually worse in small distances the

acos64 may go more then 10sec ... definitely in need of a faster algo

acos64 (acos64_sin_mul_cos_mul): 10224

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mmoller2k/Float64/issues/2#issuecomment-241269584, or mute the thread https://github.com/notifications/unsubscribe-auth/ADIetJeH89cG06ie-KjTI_MMDyglQEgDks5qiIeggaJpZM4JpFLo .

vtomanov commented 8 years ago

The thing definitely need a huge improvement ( btw: sqrt64 seems very slow also)

this is with normal floats on arduino e.g. 32bit floating point: e.g. about 10 millis result compared to 10 seconds with f64 ... e.g. 1000x slower with f64

dtor (latStart): 1 dtor (lngStart): 2 dtor (lngEnd): 1 dtor (lngEnd): 0 sin (sin_latStart): 5 sin (sin_latEnd): 0 mul (sin_mul): 0 cos (cos_latStart): 0 cos (cos_latEnd): 0 cos(cos_lngEnd_lngStart): 0 mul(cos_mul): 0 acos (acos_sin_mul_cos_mul): 1

total dist: 10

this is with f64 :

dtor64 (latStart): 0 dtor64 (lngStart): 1 dtor64 (lngEnd): 1 dtor64 (lngEnd): 0 sin64 (sin64_latStart): 74 sin64 (sin64_latEnd): 75 mul64 (sin_mul): 0 cos64 (cos64_latStart): 77 cos64 (cos64_latEnd): 77 cos64 (cos64_lngEnd_lngStart): 87 mul64 (cos_mul): 0 acos64 (acos64_sin_mul_cos_mul): 10226

total dist64: 10618

mmoller2k commented 8 years ago

Yeah I know. I actually removed the square root function to save memory. It should still be commented out in the code somewhere. The sqrt function in the math library actually used logs - which is nice and memory efficient of you don't mind the wait. I'll try and look into some speed improvements sometime soon. mic

On 23 Aug 2016 11:05, "vtomanov" notifications@github.com wrote:

The thing definitely need a huge improvement ( btw: sqrt64 seems very slow also)

this is with normal floats on arduino e.g. 32bit floating point: e.g. about 10 millis result compared to 10 seconds with f64 ... e.g. 1000x slower with f64

dtor (latStart): 1 dtor (lngStart): 2 dtor (lngEnd): 1 dtor (lngEnd): 0 sin (sin_latStart): 5 sin (sin_latEnd): 0 mul (sin_mul): 0 cos (cos_latStart): 0 cos (cos_latEnd): 0 cos(cos_lngEnd_lngStart): 0 mul(cos_mul): 0 acos (acos_sin_mul_cos_mul): 1

total dist: 10

this is with f64 :

dtor64 (latStart): 0 dtor64 (lngStart): 1 dtor64 (lngEnd): 1 dtor64 (lngEnd): 0 sin64 (sin64_latStart): 74 sin64 (sin64_latEnd): 75 mul64 (sin_mul): 0 cos64 (cos64_latStart): 77 cos64 (cos64_latEnd): 77 cos64 (cos64_lngEnd_lngStart): 87 mul64 (cos_mul): 0 acos64 (acos64_sin_mul_cos_mul): 10226

total dist64: 10618

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mmoller2k/Float64/issues/2#issuecomment-241671267, or mute the thread https://github.com/notifications/unsubscribe-auth/ADIetM4vjff4liqSgyLiCMAhrG5z_gdUks5qirfagaJpZM4JpFLo .

vtomanov commented 8 years ago

I've try this implementation of acos (..) and the sqrt inside still takes 10sec


inline void acos64o(const f64 & rhs, f64 & ret) { f64 negate = f64(rhs < 0); f64 x(rhs.fabs()); ret = f64(f64(-187293L) / f64(10000000L)); ret = x; ret += f64(f64(742610L) / f64(10000000L)); ret = x; ret -= f64(f64(2121144L) / f64(10000000L)); ret = x; ret += f64(f64(15707288L) / f64(10000000L)); ret = sqrt64(f64(1L) - x); ///// THIS LINE TAKES 10sec ret -= f64(2L) * negate * ret; ret += negate * GPS_DATA_PI; }

vtomanov commented 8 years ago

you can test the performance using the following lib that I just commited :

https://github.com/vtomanov/Gps64