View Full Version : Discussion GPS Data Accuracy
AdamKt1
Aug 20, 2007, 11:09 AM
I am developing a program to receive GPRMC strings from gps receiver and am trying to use it for guidance.
I am concerned with the accuracy of data received. I shall explain my problem by an example:
For LAT , I recieve a string value of 4916.5892. This value actually is extracted from a long sentence. This value represents actual Latitude coordinate multiplied by 100. In actual the coordinates are 49 deg, 16 Min and about 35Sec.
I convert the string to double using atof and then divide the value by 100 to get the coordinate.
One second movement corresponds to about 31 meters and 1 sec= 1/3600=0.0002degrees.
Has anybody worked on this type of problem.
I shall appreciate any suggestions on how to increase the accuracy without using the DGPS and etc.
One logical answer is, it depends upon the GPS being used, any other answers...
Thanks.
You can't just convert to float and divide by 100. There are 60 minutes per degree, not 100. You have to separate the degrees and the minutes. So to get a floating point value in degrees, you have to take off the 49, then fractional part in degrees is 16.5892 / 60. So the float value should end up as 49.276486666, not 49.165892.
MX
dmgoedde
Aug 20, 2007, 12:29 PM
Yep - 60 minutes to one degree. I have dealt with this problem on 2 different microcontrol architectures. Before I go on, the good news is that your least significant digit, the 0.0001 of minutes, is about 6" of resolution, which is far better than any GPS by a factor of about 10, meaning that mathematically you can extract full resolution information from your gps unit (maybe about 3 meters at 50% Circular Error of Probability).
I personally do this: wait for "$", then capture next 5 characters and if they are "GPGGA" (or whatever you want) then go through an algorithm that waits for the appropriate number of commas to pass, then captures the ddmm.mmmm latitude string. I take the first d character, subtract 48 from the ascii decimal version to get numeric version, then multiply that number by 6,000,000, next d character subtract 48, multiply by 600,000 and add to the first, next charact is a m minus 48, multiply by 100,000 and add to the running sum, next character m minus 48 x 10,000, etc... to the end. What you end up with is an integer version of latitude in minutes of angle that is a 10,000 x version.
This is a quick description of my approach, not exactly thorough. I have another approach that takes ddmm.mmmm or dddmm.mmmm longitude and converts it to a 100,000x version of dd.ddddd for doing integer math on simple microcontrollers. I can post the actual code if you are interested.
AdamKt1
Aug 21, 2007, 06:41 AM
It would sure help.
Pls. send me your code.
jparisse
Aug 21, 2007, 02:48 PM
Same here.... I'm using the BasicStamp and thinking that the Propeller chip might a good move for UAV research (hobby for me - I don't have the time to learn C+). Thanks...
Jeff
phubner
Aug 22, 2007, 10:41 AM
I'm working on a Parallax.com Propeller version now. See their website for posts and details, but there are a few of us who are sharing oour GPS code for this chipset.
Unfortunately the Propeller does not support floating point math directly, but it can do it through user added code. I am still working through that part... Seems like thats ll ive been doing!
Paul
AdamKt1
Aug 23, 2007, 10:01 AM
I am developing a code to calculate distance between two points.
The coordinates being used are LAT/LON.
My assumed figures for the two points are:
Point1: LAT1=31.444 deg, LON1=76.244 deg.
Point2=LAT2=31.434 deg, LON2=76.234 deg.
AS per my calculations the two points are 1462 meters apart.
But my code for the distance calculations (initially) show 0.004.
I need guidance from the learned ones to please pull me out of situation.
Below is the chunk of the code doing the calculations.
#define EarthRad 6371
float rLat,rLon,cLat,cLon;
float DTR(float Ang1)
/*
Converts degrees into radians
*/
{
float Val;
Val = Ang1 * (Pi / 180.0);
return(val);
}
float GetDist()
{
/*
Calculates distance between two points in meters.
Returns the value in meters
*/
float lat1, lon1, lat2, lon2;
double d,d2;
//Assumed values
cLat=31.444;
cLon=76.244;
rLat=31.434;
rLon=76.234;
lat1=dtr(rLat);
lon1=dtr(rLon);
lat2=dtr(cLat);
lon2=dtr(cLon);
d=Sin(Lat1)*Sin(Lat2);
d2=cos(lon2-lon1);
d2=d2*cos(Lat1)*cos(Lat2);
d=acos(d+d2);
d=d*1000;
d=d*EarthRad;
printf("\n\r * d= %f4", d);
return(d);
}
clolson
Aug 23, 2007, 10:25 AM
Here is some code to do spherical heading/distance computations that I just yanked from the FlightGear project [GPL License if you decide to use it ...]
It's probably overly complicated which seems to happen to code as it is modified and improved (?) over the years, but the original pseudocode algorithm is preserved in comments in case that helps.
The answer from your code might be coming out in radians and it might just need a radians to meters conversion?
Regards,
Curt.
/**
* Calculate new lon/lat given starting lon/lat, and offset radial, and
* distance. NOTE: starting point is specifed in radians, distance is
* specified in meters (and converted internally to radians)
* ... assumes a spherical world.
* @param orig specified in polar coordinates
* @param course offset radial
* @param dist offset distance
* @return destination point in polar coordinates
*/
Point3D calc_gc_lon_lat( const Point3D& orig, double course,
double dist ) {
Point3D result;
// lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc) )
// IF (cos(lat)=0)
// lon=lon1 // endpoint a pole
// ELSE
// lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
// ENDIF
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
// offset.theta, offset.dist);
dist *= SG_METER_TO_NM * SG_NM_TO_RAD;
result.sety( asin( sin(orig.y()) * cos(dist) +
cos(orig.y()) * sin(dist) * cos(course) ) );
if ( cos(result.y()) < SG_EPSILON ) {
result.setx( orig.x() ); // endpoint a pole
} else {
result.setx(
fmod(orig.x() - asin( sin(course) * sin(dist) /
cos(result.y()) )
+ SGD_PI, SGD_2PI) - SGD_PI );
}
return result;
}
/**
* Calculate course/dist given two spherical points.
* @param start starting point
* @param dest ending point
* @param course resulting course
* @param dist resulting distance
*/
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist )
{
if ( start == dest) {
*dist=0;
*course=0;
return;
}
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
double cos_start_y = cos( start.y() );
double tmp1 = sin( (start.y() - dest.y()) * 0.5 );
double tmp2 = sin( (start.x() - dest.x()) * 0.5 );
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
cos_start_y * cos(dest.y()) * tmp2 * tmp2));
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
#if 1
double c1 = atan2(
cos(dest.y())*sin(dest.x()-start.x()),
cos(start.y())*sin(dest.y())-
sin(start.y())*cos(dest.y())*cos(dest.x()-start.x()));
if (c1 >= 0)
*course = SGD_2PI-c1;
else
*course = -c1;
#else
// We obtain the initial course, tc1, (at point 1) from point 1 to
// point 2 by the following. The formula fails if the initial
// point is a pole. We can special case this with:
//
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
// IF (lat1 > 0)
// tc1= pi // starting from N pole
// ELSE
// tc1= 0 // starting from S pole
// ENDIF
// ENDIF
//
// For starting points other than the poles:
//
// IF sin(lon2-lon1)<0
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ELSE
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ENDIF
// if ( cos(start.y()) < SG_EPSILON ) {
// doing it this way saves a transcendental call
double sin_start_y = sin( start.y() );
if ( fabs(1.0-sin_start_y) < SG_EPSILON ) {
// EPS a small number ~ machine precision
if ( start.y() > 0 ) {
*course = SGD_PI; // starting from N pole
} else {
*course = 0; // starting from S pole
}
} else {
// For starting points other than the poles:
// double tmp3 = sin(d)*cos_start_y);
// double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
// double tmp5 = acos(tmp4/tmp3);
// Doing this way gaurentees that the temps are
// not stored into memory
double tmp5 = acos( (sin(dest.y()) - sin_start_y * cos(d)) /
(sin(d) * cos_start_y) );
// if ( sin( dest.x() - start.x() ) < 0 ) {
// the sin of the negative angle is just the opposite sign
// of the sin of the angle so tmp2 will have the opposite
// sign of sin( dest.x() - start.x() )
if ( tmp2 >= 0 ) {
*course = tmp5;
} else {
*course = SGD_2PI - tmp5;
}
}
#endif
}
clolson
Aug 23, 2007, 10:26 AM
For what it's worth, the previously posted code yanked out of FlightGear has been flown on a real UAV waypoint routing system and has proved to be robust and successful.
Curt.
John O'Sullivan
Aug 23, 2007, 10:26 PM
As a field geologist, I deal with GPS coordinates daily. I find Lat/Long a pain to deal with and use UPS Grid coordinates as a base, which gives readings in metres which are at least understandable distances. All GPS units have the capability of using this base.
John
AdamKt1
Aug 24, 2007, 11:01 AM
I converted my code to Haversine formula but the value is 400m off the actual value.
Any way to decrease this error...
clolson
Aug 24, 2007, 11:19 AM
I converted my code to Haversine formula but the value is 400m off the actual value.
Any way to decrease this error...
Are you using doubles or floats for your math? If you are using 4 bytes floats, you are probably losing some precision and that precision loss could be accumulating/multiplying as the individual values propogate through your formula.
Let's say the radius of the earth is 6,371,000 meters and a floating point number (float in C) can represent 6-7 significant digits ... now you are looking at that last digit of the earth's radius in meters being just about anything. Let's pretend that ends up being an average placement error of 10 meters. I'm taking a big logical leap here, but I'll assert (based on some past experience) that if you use float's to represent your lon/lat values, you are going to see errors of about the same magnitude. Now if you start computing sin() & cos() from this imprecise value, and get a similarly imprecise answer back, and then start multiplying those together, your errors can add up quite quickly.
If you aren't using the "double" data type, I'd suggest converting your code to use those instead of "float" and see if that improves your accuracy at all.
Curt.
XJet
Aug 24, 2007, 04:29 PM
Another thing you can do (if the distance between your waypoints isn't too great) is just use simple geometry/pythagoras to calculate the distance. It'll be accurate enough to work just fine if you're working between waypoints that are just a mile or two apart and can save plenty of CPU cycles.
AdamKt1
Aug 24, 2007, 11:29 PM
Yes, I am using floats (4 Bytes). Actually its CCS constraint due to which I am loosing the accuracy.
I have been searching the net for cordic algo could not find some good link so far. Any info about cordic for sine and cosines.
Secondly, I need to find out the spped of a common model plane like SkyRaiderII on a normal day (normal wind). This would help me find what must be the frequency of GPS data getting function..
clolson
Aug 24, 2007, 11:55 PM
Yes, I am using floats (4 Bytes). Actually its CCS constraint due to which I am loosing the accuracy.
I have been searching the net for cordic algo could not find some good link so far. Any info about cordic for sine and cosines.
Secondly, I need to find out the spped of a common model plane like SkyRaiderII on a normal day (normal wind). This would help me find what must be the frequency of GPS data getting function..
For what it's worth, I've got a telemaster here that cruises at about 35-40 kts. Now that I have my waypoint following working, I've gone up on a couple days that were pretty windy. Upwind headway can be excruciatingly slow ... 10-15 mph winds on the ground can be 20-25 at altitude.
The problem with flying into the wind and having a slow ground speed is that small heading changes for the airplane equate to large course changes in terms of your ground track.
So now if you are navigating by ground track, very small bank angles can result in large course changes and the routing algorithm begins to oscillate.
This is a common problem with uav autopilots ... no matter how you figure it, even with low speed aircraft, your ground speed can from very low to pretty high depending on which direction you are flying and what the winds are doing at the moment.
I do have magnetometers and a heading estimate which isn't universally trustworthy, but perhaps I could figure out some sort of offset between ground track and current heading estimate, along with an estimate of wind direction and speed (?) and combine all that to build a more stable "flying into the wind" navigation algorithm ... (???)
But then you find that the wind changes around on you rapidly, so even if you hold a constant real world heading, your ground track can wander around ...
I guess the solution is to just fly on days when the air is calm ... :-)
Curt.
AdamKt1
Sep 05, 2007, 10:07 AM
Although, I got trignometric values, of more than 3 digits accuracy, using cordic but still I have not been able to resolve the problem of calculating the distance between two points on the globe.
The problem now is that no matter if I use Haversine formula or other I cross the limits of int32.
Can any body suggest any solution.
or Should I switch to 32bit microcontrollers.
Another question:
What may be the best choice for 32 bit microcontrollers which are cheap requiring the least like the compiler, the development and simulation boards and are easy to master.
Request suggestions in this regards too...
Adam
_helitron_
Sep 05, 2007, 12:47 PM
Hi Adam,
for me, there was only one choice: ARM7 :D ! I just switched over from the AVR family to the ARM7 (exactly LPC2138/LPC2148 from NXP) for an OSD project with the BOB-4-H board and I'm totally satisfied. I'm working with the free GCC toolchain WinARM (I knew WinAVR already before) and the free programming tool FLASH MAGIC from Philips/NXP. Absolutely cool stuff :D !
Btw. the comming WPS-2 from MX is based on a LPC2138 for example !
Edit: have attached photos of my DevBoard with the BOB-4-H OSD on the breadboard and the little ARM stamp alone, 512 kB (!) FLASH, 32 kB SRAM, 32 Bit, 60 MHz. Btw. I got the DevBoard incl. ARM7 stamp (without BOB-4-H and LCD of course :) ) for EUR 55,- and an ARM7 stamp alone for EUR 29,90 in Bangkok/Thailand.
//Erwin
I am using ARM7 also (LPC2138). I have access to the Keil tools from work and those work very well also.
MX
Wulffy
Sep 06, 2007, 01:01 AM
The great circle formula reference that I have made extensive use of is detailed herein (http://williams.best.vwh.net/avform.htm).
These files (http://tech.groups.yahoo.com/group/ARMexpress/files/UAV_Project_Files/Airframe/) are an early version of my source. Rape it how ever you want.
I was trying to do integer math with fixed point notation, and was not having any success. As such, I migrated over the MicroMegaCorp's uM-FPU (http://www.micromegacorp.com/). I strongly recommend it.
At any rate, using the code/algorithms linked to should serve to get most anyone pointed in the right direction, including a darn well documented set of parsing utilities.
As info, the code is written for Coridium Corp's ARMbasic (http://www.coridiumcorp.com/) based microcontrollers.
Good luck, happy coding!
-t
_helitron_
Sep 06, 2007, 01:55 AM
The great circle formula reference that I have made extensive use of is detailed herein (http://williams.best.vwh.net/avform.htm).
These files (http://f1.grp.yahoofs.com/v1/QHvfRr_4CwS0AcxTOpdN409lbDp3QDA5an4GXHuF4PiulC-oYnQ6ffmKfPFrjb1v5JrYdPTlUyYhKdw19CGyl_X8Iv2-GeQ/UAV_Project_Files/Airframe/UAV_Airframe_Files_10May07AM.zip) are an early version of my source. Rape it how ever you want.
I was trying to do integer math with fixed point notation, and was not having any success. As such, I migrated over the MicroMegaCorp's uM-FPU (http://www.micromegacorp.com/). I strongly recommend it.
At any rate, using the code/algorithms linked to should serve to get most anyone pointed in the right direction, including a darn well documented set of parsing utilities.
As info, the code is written for Coridium Corp's ARMbasic (http://www.coridiumcorp.com/) based microcontrollers.
Good luck, happy coding!
-t
Thanks for the link to this paper Wulffy, very interesting. Btw. the link to your files doesn't work for me unfortunately.
Interesting device also this uM-FPU, how much is it ?
//Erwin
XJet
Sep 06, 2007, 02:27 AM
Although, I got trignometric values, of more than 3 digits accuracy, using cordic but still I have not been able to resolve the problem of calculating the distance between two points on the globe.
The problem now is that no matter if I use Haversine formula or other I cross the limits of int32.
Adam
You could always use a separate math co-processor.
Wulffy
Sep 06, 2007, 10:29 AM
Thanks for the link to this paper Wulffy, very interesting. Btw. the link to your files doesn't work for me unfortunately.
Interesting device also this uM-FPU, how much is it ?
//ErwinYou are welcome. Sorry 'bout the broken link - go here: http://tech.groups.yahoo.com/group/ARMexpress/files/UAV_Project_Files/Airframe/
The price of the uM-FPU is ~$20.00 US. Take care.
-t
_helitron_
Sep 06, 2007, 01:12 PM
You are welcome. Sorry 'bout the broken link - go here: http://tech.groups.yahoo.com/group/ARMexpress/files/UAV_Project_Files/Airframe/
The price of the uM-FPU is ~$20.00 US. Take care.
-t
Thanks a lot Wulffy !
//Erwin
Wulffy
Sep 06, 2007, 06:29 PM
Thanks a lot Wulffy !
//Erwin
You're more than welcome. PM me with any questions that you may have. I made quite an effort to over comment the code when I was writing it, but enevitably, what ever shorthand made sense to me could cause other's eyes to roll back in their head and instill an uncontrollable twitch... :D
OH, and also, I recently set up a GPS 'library' file, based on the code there in for the folks at Coridium Corp.
The code is available on this page (http://www.coridiumcorp.com/ProgrammingGPS.php) (ignore the pic, it is a place holder until Bruce get's his GPS Receiver hooked up and running). This graphic (http://www.coridiumcorp.com/images/GPS_Support03.gif) illustrates an example application that is making use of the 'library'.
I say 'library' as, IMHO, it falls short of what I would expect from a proper library file. But hey, that is what the future is for - revisions... :p
Wulffy
Sep 06, 2007, 06:47 PM
Yes, I am using floats (4 Bytes). Actually its CCS constraint due to which I am loosing the accuracy.
I have been searching the net for cordic algo could not find some good link so far. Any info about cordic for sine and cosines....
I too was trying, for many weeks, to implement a set of CORDIC routines for the language that I was using (ARMbasic). I eventually threw in the towel and caved to using the uM-FPU. The benefits to my use of the FPU are:
The trig functions use power series calculations. The dominant factor to consider for precision in calculations is the limit imposed by the 32-bit floating point representation itself - err, damn accurate alogorithms...
The number crunching is off-loaded to another processor, to facilitate a bit of load shedding off of the host MCU.
I can work in fixed point notation on the host MCU and still realize floating point accuracy in the alogorithims (that are programmed into the FPU's Flash).
The FPU has a dedicated IDE with in-circuit debugger capabilities - it is MEGA-Nice (punn intended ;)) to be able to actively monitor what the heck is going on in real-time, especially during code dev evolutions.
The FPU has firmware routine to handle the more common applications that we may choose to make use of the FPU for.
The FPU has many features that I haven't yet begun to explore, with regards to Matrix Math (Kalman Filter Applications), etc.
OK, I'll stop. No, I don't work for Cam, but have a tremendous amount of respect for him and appreciation for the product that he makes. 'Nuf said. Out.
-t
AdamKt1
Sep 09, 2007, 11:06 AM
I have decided to modify the navigation / guidance algo.
I need suggestions on using the GPS receiver capable of:
1) Waypoint storing.
2)RS232 interface capable.
3)APB sentence capable.
Whaen I am done, I hope to share the code...
vBulletin® Copyright ©2000-2009, Jelsoft Enterprises Ltd.