NMEA格式数据的经纬度如何转换为十进制?

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

我有NMEA格式的经纬度,我想把它转换成十进制值。有什么公式吗?例如,NMEA 格式 Latitude = 35.15 N 和 Longitude = 12849.52 E

是的,NMEA 格式为 ddmm.mmmm、n/s (d)ddmm.mmmm、e/w

要将度数转换为十进制度数,请使用以下公式:

(d)dd + (mm.mmmm/60) (* -1 对于 W 和 S)

这里有一个不错的小计算器:http://www.hiddenvision.co.uk/ez/

NMEA 坐标的格式为 (d)ddmm.mmmm
d=度和 m=分钟
一个学位有 60 分钟,所以将分钟除以 60,然后加上度数。

对于纬度=35.15 N
35.15/60 = .5858 N

对于经度= 12849.52 E,
128+ 49.52/60 = 128.825333 E

在 php 中,您可以这样做:

<?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;
}

?>

这适用于双精度值存在问题的小型设备。它是用 C 代码完成的,但可以轻松更改为另一种语言:

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);
}

如果您没有 sprintf 或者它不允许“%04”(就像我的情况一样),只需将 sprintf 行更改为:

  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;

这是一个极简的 C 函数。

它 returns 十进制坐标,应与 NMEA 坐标和相应的象限或“指示器”字符(N、S、E、W)一起馈送。例如:

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

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

它没有优化,但应该是可读的,应该是安全的并且可以完成工作:

/**
 * 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;
}

另一个C函数。
这允许 nmea 字符串中的小数位数可变。
以 (d)ddmm.mmmm 格式给它纬度或经度字符串,
和 N、S、E、W 方向(也作为空终止字符串)。
它将 return 表示十进制等效值的双精度值。


在 ESP32 上测试(允许比传统 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;
}

C# 版本为:

public double NmeaToDecimal(double ll, int hemisph)
{
    return Math.Round((Convert.ToInt32(ll / 100) + (ll - Convert.ToInt32(ll / 100) * 100) / 60) * hemisph,5);
}