|
|
View previous topic :: View next topic |
Author |
Message |
minoan_war Guest
|
Compute distance using Lat & long data |
Posted: Wed Aug 09, 2006 2:33 pm |
|
|
HI All!
I work in a small program to get the distance between 2 points using latitud and longitud data,
this is the program:
#define EARTH 6371
#define PI 3.141592654
float d_lat1=19.508016;
float d_lat2=19.674716;
float d_lon1=99.234144;
float d_lon2=99.234000;
float distance;
main()
{
clrscr(); // turbo c
// degrees to radians!
d_lat1=d_lat1*PI/180;
d_lat2=d_lat2*PI/180;
d_lon1=d_lon1*PI/180;
d_lon2=d_lon2*PI/180;
distance=acos( (sin(d_lat1)*sin(d_lat2)) + (cos(d_lat1)*cos(d_lat2)*cos(d_lon2-d_lon1)))*EARTH ;
printf("\n\nDistance is %f",distance);
getch();
}
Where EARTH is the Curvature of the EARTH
using Turbo c the result is OK! 18.5 km
using Hi tech compiler the result is 17.8 Km
using CCS compiler the result is 15.2 Km
I can live with the result of CCS compiler, but... when the distance between points is more small the error math is bigger
Anyone has idea Why this discrepances?
Thanks |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Wed Aug 09, 2006 3:39 pm |
|
|
This is probably a precision issue with a 23 bit mantissa in floating point binary with CCS. Take a look at the CORDIC algorithm it can get you as much precision as you want. The CORDIC got the Lunar lander down and it wasn't out 2 or 3 kilometers.
Below is a 13bit example using degrees
you can get the sine cosine arctan and sqrt(x^2+y^2) with nothing more than addition. Watch out for crossing quadrants.
Code: |
#include <18F452.h>
#DEVICE *=16 ICD=TRUE
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#use delay(clock=40 000 000)
//#use rs232(baud=57600, bits=8, parity = N, xmit=PIN_C6, rcv=PIN_C7)
#use rs232(DEBUGGER)
//////////// cordic ///////////////////////////////////
////////////////////////////////////////////////////////////////
/// theory /////
/// /////
/// coords (x,y) are rotated thru angle a to (x',y') /////
/// /////
/// x'=x.cos(a)-y.sin(a) /////
/// y'=y.cos(a)+x.sin(a) /////
/// /////
/// x'/cos(a)=x-y.tan(a) /////
/// y'/cos(a)=y+x.tan(a) /////
/// /////
/// now if we choose tan(a) to be /////
/// 1/2,1/4,1/8......1/2*n /////
/// /////
/// we can rotate thru sucessive values /////
/// ex 30.00 degs = 45-26.57+14.03-7.13+3.58 ////
/// +17.9,.90,.45 ////
/// where a minus angle is a counter rotation ////
/// after a rotation of 30 degs ////
/// x' is x.cos(30) if we start with y=0 ////
/// y' is x.sin(30) ////
/// ////
/// angle is in 1/100th units 4500 is 45 degrees ////
/// lengths are in aggregate constant units ////
/// ////
/// aggregate const cos(atan(1)*cos(atan(1/2)*cos(atan(1/4).....)))))
/// or .607252935 ////
/// so 10000 is 6073
long int const atan[13]={4500,2656,1404,712,358,179,90,45,
22,12,6,3,1};/// atan(1/2n)
////
////
//// to clac sin(A) cos(A) set y=0 a=angle and drive a to zero
//// via iterations
//// x value is the cos(a) providing x=6073
//// y value is the sign(a) providing x=6073
////
//// to calc atan(a) set a=0 and drive y to zero
//// a value is atan(y/x)
//// x value is sqrt(x^2+y^2) providing x=6073
signed long int cos(signed long a)
{
int i;
signed long x,y,dx,dy,da;;
x=6073;
y=0;
for (i=0;i<13>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (a>=0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (x);
}
signed long int sin(signed long a)
{
int i;
signed long x,y,dx,dy,da;;
x=6073;
y=0;
for (i=0;i<13>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (a>=0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (y);
}
signed long int arctan(signed long x,signed long y)
{
int i;
signed long a,dx,dy,da;;
a=0;
for (i=0;i<13>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (y<0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (a);
}
signed long int sqrt_x2_y2(signed long x,signed long y)
{
int i;
signed long a,dx,dy,da;;
a=0;
for (i=0;i<13>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (y<0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (x);
}
main()
{
signed int16 result;
result= cos(6000);
printf("cosine of 60 is %ld \n\r",result);
result= sin(6000);
printf("sine of 60 is %ld \n\r",result);
result= arctan(10000,6000);
printf("arctan of 0.60 is %ld \n\r",result);
result=sqrt_x2_y2(10000,6000);
printf("sqrt of (6^2+10^2)/0.6073 is %ld \n\r",result);
while(true);
}
|
Last edited by Douglas Kennedy on Wed Aug 09, 2006 3:46 pm; edited 1 time in total |
|
|
Ttelmah Guest
|
|
Posted: Wed Aug 09, 2006 3:42 pm |
|
|
The big problem is rounding errors. For instance, your 'sin' value, is being held as 3.1415927, and this is one of the least 'rounded' of the values involved... Turbo C, will probably be using a 'double', internally for the sin calculations.
Your 'Earth' diameter is slightly below the normally accepted average value (6372.795), but the effect of this is small.
Generally, you might be better off using the haversine formula, which shows less rounding errors for small angles. You would need to add testing for the denominator being zero in the final atan function for this.
Best Wishes |
|
|
minoan_war Guest
|
Haversine implementation |
Posted: Wed Aug 09, 2006 3:59 pm |
|
|
Thanks Douglas, Ttelmah!
I have done the Haversine implementation, ands look a little better
this is!
tmp1=d_lat2-d_lat1;
tmp2=d_lon2-d_lon1;
tmp3=(sin(tmp1/2) * sin(tmp1/2)) + cos(d_lat1) * cos(d_lat2) * (sin(tmp2/2) * sin(tmp2/2));
tmp4=2 * atan2(sqrt(tmp3),sqrt(1-tmp3));
tmp5=EARTH * tmp4;
printf("\nHaversine %f Km",tmp5);
prints "Haversine 18.8 Km"
it have also a error of .4 km, I will test it, extensively
I think that for a $3USD chip is ok! |
|
|
ryan.reeve
Joined: 23 Jul 2006 Posts: 20
|
whats wrong in haversine formula ? |
Posted: Thu Sep 28, 2006 4:30 am |
|
|
Hi
I am using the Haversine formula, but value is too much erronious.Not even near the expected value.
float lat1,lat2,dlat,long1,long2,dlong,tmp1,tmp2,d;
lat1=31.000100;
lat2=31.000000;
long1=74.260000;
long2=74.260000;
dlat=lat1-lat2;
dlong=long1-long2;
tmp1=(sin(dlat/2)*sin(dlat/2))+cos(lat1)*cos(lat2)*(sin(dlong/2*sin(dlong/2)));
tmp2=2*atan2(sqrt(tmp1),sqrt(1-tmp1));
d=EARTH*tmp2; |
|
|
Ttelmah Guest
|
|
Posted: Sun Oct 01, 2006 5:04 am |
|
|
Remember that in C, sin, cos etc., work in _radians_, not degrees....
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|