How to convert latitude and longitude of NMEA format data to decimal?
Asked Answered
D

7

12

I have latitude and longitude of NMEA format, and I want to convert it into decimal value. Is there any formula? For example, NMEA format Latitude = 35.15 N and Longitude = 12849.52 E

Dearr answered 28/3, 2016 at 0:44 Comment(0)
G
23

The format for NMEA coordinates is (d)ddmm.mmmm
d=degrees and m=minutes
There are 60 minutes in a degree so divide the minutes by 60 and add that to the degrees.

For the Latitude=35.15 N
35.15/60 = .5858 N

For the Longitude= 12849.52 E,
128+ 49.52/60 = 128.825333 E

In php, you could do this:

<?php
$lng = "12849.52 W";

$brk = strpos($lng,".") - 2;
if($brk < 0){ $brk = 0; }

$minutes = substr($lng, $brk);
$degrees = substr($lng, 0,$brk);

$newLng = $degrees + $minutes/60;

if(stristr($lng,"W")){
    $newLng = -1 * $newLng;
}

?>
Gambol answered 28/3, 2016 at 2:9 Comment(1)
Should it be if(stristr($lng,"W") || stristr($lng,"S")){ ?Thisbee
T
13

Yes, NMEA format is ddmm.mmmm, n/s (d)ddmm.mmmm, e/w

To get to decimal degrees from degrees ad minutes, you use the following formula:

(d)dd + (mm.mmmm/60) (* -1 for W and S)

There is a nice little calculator here: http://www.hiddenvision.co.uk/ez/

Tarsuss answered 28/3, 2016 at 1:15 Comment(3)
Thank you Ros Hartigan. I have converted the above mentioned latitude and longitude of NMEA format like this, latitude=35.15 and longitude=128.825333; Is it correct?Dearr
Not quite NajLinus, you have the longitude correct, but have not the latitude. The conversion for latitude yields 0.5858 - see @johnDoe's most excellent answer above.Tarsuss
Thank you , appreciate you help.Dearr
C
5

Here is a minimalist C function to do it.

It returns decimal coordinates and shall be fed with the NMEA coordinate and respective quadrant or "indicator" character (N,S,E,W). E.g:

float latitude= GpsToDecimalDegrees("4349.7294",'N');
// latitude == 43.82882

float longitude= GpsToDecimalDegrees("10036.1057",'W');
// latitude == 43.82882

It is not optimized but should be readable, should be safe and does the job:

/**
 * Convert NMEA absolute position to decimal degrees
 * "ddmm.mmmm" or "dddmm.mmmm" really is D+M/60,
 * then negated if quadrant is 'W' or 'S'
 */
float GpsToDecimalDegrees(const char* nmeaPos, char quadrant)
{
  float v= 0;
  if(strlen(nmeaPos)>5)
  {
    char integerPart[3+1];
    int digitCount= (nmeaPos[4]=='.' ? 2 : 3);
    memcpy(integerPart, nmeaPos, digitCount);
    integerPart[digitCount]= 0;
    nmeaPos+= digitCount;
    v= atoi(integerPart) + atof(nmeaPos)/60.;
    if(quadrant=='W' || quadrant=='S')
      v= -v;
  }
  return v;
}
Carduaceous answered 11/8, 2020 at 17:54 Comment(0)
S
1

The C# version would be:

public double NmeaToDecimal(double ll, int hemisph)
{
    return Math.Round((Convert.ToInt32(ll / 100) + (ll - Convert.ToInt32(ll / 100) * 100) / 60) * hemisph,5);
}
Shoop answered 2/12, 2021 at 20:17 Comment(0)
B
0

This is for small devices where double values are a problem. It is done in c code but can be changed to another language easily:

void GetGPSPos(char *str,char *NMEAgpspos,uint8_t sign)
{
  unsigned short int u=0,d=0;
  unsigned int minutes;
  unsigned char pos,i,j;

  for(pos=0;pos<strlen(NMEAgpspos) && NMEAgpspos[pos]!='.';pos++);

  for(i=0;i<pos-2;i++)
    {
     u*=10;
     u+=NMEAgpspos[i]-'0';
    }
  d=(NMEAgpspos[pos-2]-'0')*10;
  d+=(NMEAgpspos[pos-1]-'0');
  for(i=pos+1,j=0;i<strlen(NMEAgpspos) && j<4;i++,j++) //Only 4 chars
    {
     d*=10;
     d+=NMEAgpspos[i]-'0';
    }


  minutes=d/60;
  sprintf(str,"%d.%04d",(sign?-1:1)*u,minutes);
}

if you dont have sprintf or it doesn't allow "%04" (like it is my case), just change the sprintf line for:

  pos=0;
  if(sign)
    str[pos++]='-';
  if(u>100)
    str[pos++]=u/100+'0';
  if(u>10)
    str[pos++]=u/10%10+'0';
  str[pos++]=u%10+'0';
  str[pos++]='.';
  str[pos++]=minutes/1000+'0';
  str[pos++]=minutes/100%10+'0';
  str[pos++]=minutes/10%10+'0';
  str[pos++]=minutes%10+'0';
  str[pos++]=0;
Boyett answered 3/2, 2020 at 14:29 Comment(0)
D
0

Another C function.
This one allows for variable number of decimal places in the nmea string.
Give it the latidude or longitude string in (d)ddmm.mmmm format,
and the N,S,E,W direction (also as a null terminated string).
It will return a double representing the decimal equivalent.


Tested on ESP32 (which allows longer float precision than conventional arduino)

double convertToDecimalDegrees(const char *latLon, const char *direction)
{
  char deg[4] = {0};
  char *dot, *min;
  int len;
  double dec = 0;

  if ((dot = strchr(latLon, '.')))
  {                                         // decimal point was found
    min = dot - 2;                          // mark the start of minutes 2 chars back
    len = min - latLon;                     // find the length of degrees
    strncpy(deg, latLon, len);              // copy the degree string to allow conversion to float
    dec = atof(deg) + atof(min) / 60;       // convert to float
    if (strcmp(direction, "S") == 0 || strcmp(direction, "W") == 0)
      dec *= -1;
  }
  return dec;
}
Dwightdwindle answered 9/12, 2020 at 16:28 Comment(0)
C
0

Decided to pitch in with my C++ version:

#include <sstream>
#include <iomanip>

std::string nmea_to_deg(std::string& lat_lon, std::string& orientation)
{
  size_t dot = lat_lon.find(".");
  if (dot != std::string::npos)
  {
    int deg = std::stoi(lat_lon.substr(0, dot-2));
    double min = std::stod(lat_lon.substr(dot-2, std::string::npos));

    double pos = (double)deg + min / 60.0;
    pos *= ((orientation == "W" || orientation == "S")? -1 : 1 );

    std::stringstream output;
    output << std::fixed << std::setprecision(7) << pos;

    return output.str();
  }
  return "";
}

What is worth noting, the precision of output is determined by

std::setprecision(7)

and can be increased if needed.

Conceptualize answered 7/11, 2022 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.