Monday, May 17, 2010

GPS Degrees, Minutes, Seconds to Decimals C#

I have been trying to connect to a device and get the GPS Data, I was using the library provided by Microsoft's Coding4Fun.
http://blogs.msdn.com/coding4fun/archive/2006/10/31/912287.aspx and written by Scott Hanselman... how can he be wrong!?

The issue I came across was the precision was out by quite a bit, so the parsing was incorrect, for my device. I'm not sure if NMEA standard is 100% standard, so I'm just posting this code here in case other people have issues.

ProcessGPRMC and ProcessGPGGA both need to be updated, I have created a method to do this.


private static double DDMMSSToDecimalDegrees(string data)
{
var ddmmss = (Convert.ToDouble(data) / 100);

var degrees = (int)ddmmss;

var minutesseconds = ( (ddmmss - degrees) * 100 ) / 60.0;

return degrees + minutesseconds;

}



There is also the issue to do with North, Southern, Western and Eastern Hemisphere where the value has go to be negated. :)


So the update methods needs to look like this


public void ProcessGPGGA(string data)
{
try
{


string[] fields = Regex.Split(data, ",");

//Time: Hour, Minute, Second
//Time is Zulu
GPGGA.Hour = Convert.ToInt32(fields[0].Substring(0, 2));
GPGGA.Minute = Convert.ToInt32(fields[0].Substring(2, 2));
GPGGA.Second = Convert.ToInt32(fields[0].Substring(4, 2));

//Latitude

GPGGA.Latitude = DDMMSSToDecimalDegrees(fields[1]);


if (fields[2] == "S")
GPGGA.LatitudeHemisphere = Cardinal.South;
else
GPGGA.LatitudeHemisphere = Cardinal.North;


if (GPGGA.LatitudeHemisphere == Cardinal.South)
GPGGA.Latitude = GPGGA.Latitude * -1;



//Longitude

GPGGA.Longitude = DDMMSSToDecimalDegrees(fields[3]);


if (fields[4] == "W")
GPGGA.LongitudeHemisphere = Cardinal.West;
else
GPGGA.LongitudeHemisphere = Cardinal.East;



if (GPGGA.LongitudeHemisphere == Cardinal.West)
GPGGA.Longitude = GPGGA.Longitude * -1;



//GPS Signal Quality
GPGGA.GPSQuality = (GPSQuality)Convert.ToUInt32( fields[5] );

//Satellites
GPGGA.NumberOfSatellitesInUse = Convert.ToInt32(fields[6]);

//HDOP
GPGGA.HDOP = Convert.ToDouble( fields[7] );

//Altitude
GPGGA.Altitude = Convert.ToDouble(fields[8]);

//increase message count
GPGGA.Count ++;
}
catch(Exception e)
{
System.Diagnostics.Trace.WriteLine("Chaos in ProcessGPGGA! " + e.ToString());
}
}




public void ProcessGPRMC(string data)
{
string[] fields = Regex.Split(data, ",");


//Time: Hour, Minute, Second
//Time is Zulu
GPRMC.Hour = Convert.ToInt32(fields[0].Substring(0, 2));
GPRMC.Minute = Convert.ToInt32(fields[0].Substring(2, 2));
GPRMC.Second = Convert.ToInt32(fields[0].Substring(4, 2));

GPRMC.Day = Convert.ToInt32(fields[8].Substring(0, 2));
GPRMC.Month = Convert.ToInt32(fields[8].Substring(2, 2));
GPRMC.Year = Convert.ToInt32(fields[8].Substring(4, 2));

GPRMC.DataValid = Convert.ToChar(fields[1]);

//Latitude

GPRMC.Latitude = DDMMSSToDecimalDegrees(fields[2]);


if (fields[3] == "S")
GPRMC.LatitudeHemisphere = Cardinal.South;
else
GPRMC.LatitudeHemisphere = Cardinal.North;


if (GPRMC.LatitudeHemisphere == Cardinal.South)
GPRMC.Latitude = GPRMC.Latitude * -1;



//Longitude

GPRMC.Longitude = DDMMSSToDecimalDegrees(fields[4]);


if (fields[5] == "W")
GPRMC.LongitudeHemisphere = Cardinal.West;
else
GPRMC.LongitudeHemisphere = Cardinal.East;



if (GPRMC.LongitudeHemisphere == Cardinal.West)
GPRMC.Longitude = GPRMC.Longitude * -1;



GPRMC.GroundSpeed = Convert.ToDouble(fields[6]);

//TODO: MagVar and Course
GPRMC.Count++;
}



That's it for now, I haven't implemented the rest of the project. I'll post all the updated code when I get somewhere, github maybe?

1 comment: