电子海图(ENC)中规定的坐标系为WGS-84,该坐标系就是GPS所采用的坐标系,因此电子海图系统必须要接入GPS数据。其实,卫星定位系统中,除了GPS,还有中国的北斗、俄罗斯的GLONASS和欧盟的Galileo,这些定位接收器的数据都可以通过NMEA0813传输。
设备类型 | 描述 | 设备类型 | 描述 | 设备类型 | 描述 |
---|---|---|---|---|---|
BD | 北斗 | GP | GPS | GN | 多卫星组合导航 |
GL | GLONASS | GA | Galileo | EC | ECDIS |
GPS报文格式有很多种,具体可参见https://gpsd.gitlab.io/gpsd/NMEA.html,但常见的有:
- RMC 推荐最小定位信息
1 2 3 4 5 6 7 8 9 10 1112 13
| | | | | | | | | | | | |
$--RMC,hhmmss.ss,A,llll.llll,a,yyyyy.yyyy,a,x.x,x.x,xxxx,x.x,a,m,*hh<CR><LF>
$GPRMC,075629.80,V,3759.2680,N,02334.6295,E,0.46,171.32,211206,2.6,W,N*34
字段1:定位时的世界时UTC;如:075629.80=07:56:29.80Z
字段2:状态:A=有效;V=警告
字段3:纬度:如:3759.2680=37°59.2680'
字段4:纬度的方向 N 或 S
字段5:经度;如:02334.6295=23°34.6295'
字段6:经度的方向 E 或 W
字段7:对地航速;如:0.46kn
字段8:对地航向;如:171.32°
字段9:日期,形式ddMMyy,起点为2000年;如:211206=2006-12-21
字段10:磁差;如:2.6°
字段11:磁差的方向 E 或 W
字段12:FAA模式指示符(A=自主定位,D=差分,E=估算,N=数据无效)
字段13:校验和;如:34
- GGA 定位数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| | | | | | | | | | | | | | |
$--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh<CR><LF>
$GNGGA,001043.00,4404.14036,N,12118.85961,W,1,12,0.98,1113.0,M,-21.3,M,,*47
字段1:定位时的世界时UTC;如:001043.00=00:10:43.00Z
字段2:纬度:如:4404.14036=44°04.14036'
字段3:纬度的方向 N 或 S
字段4:经度;如:12118.85961=121°18.85961'
字段5:经度的方向 E 或 W
字段6:GPS定位质量指示符;如:1=GPS定位
字段7:卫星的使用量;如:12
字段8:水平精度因子;如:0.98米
字段9:天线高度(相对于平均海面);如:1113.0
字段10:天线高度单位;如:米
字段11:坐标系与平均海面的差值;如:-21.3
字段12:差值的单位;如:米
字段13:差分GPS数据期限
字段14:差分参考基站ID,取值0000-1023
字段15:校验和;如:47
- GSA GPS精度因子与当前卫星
1 2 3 4 5 6 7 8 91011121314 15 16 17 18
| | | | | | | | | | | | | | | | | |
$--GSA,a,a,x,x,x,x,x,x,x,x,x,x,x,x,x.x,x.x,x.x*hh<CR><LF>
$GNGSA,A,3,80,71,73,79,69,,,,,,,,1.83,1.09,1.47*17
字段1:定位模式 M=手动;A=自动
字段2:定位类型 1=无定位;2=2D定位;3=3D定位
字段3:第1信道使用中的PRN码编号
字段4:第2信道使用中的PRN码编号
字段5:第3信道使用中的PRN码编号
字段6:第4信道使用中的PRN码编号
字段7:第5信道使用中的PRN码编号
字段8:第6信道使用中的PRN码编号
字段9:第7信道使用中的PRN码编号
字段10:第8信道使用中的PRN码编号
字段11:第9信道使用中的PRN码编号
字段12:第10信道使用中的PRN码编号
字段13:第11信道使用中的PRN码编号
字段14:第12信道使用中的PRN码编号
字段15:PDOP位置精度因子
字段16:HDOP水平精度因子
字段17:VDOP垂直精度因子
字段18:校验和
- GLL 地理位置:经/纬度
1 2 3 4 5 6 7 8
| | | | | | | |
$--GLL,llll.ll,a,yyyyy.yy,a,hhmmss.ss,a,m,*hh<CR><LF>
$GNGLL,4404.14012,N,12118.85993,W,001037.00,A,A*67
字段1:纬度
字段2:纬度的方向 N 或 S
字段3:经度
字段4:经度的方向 E 或 W
字段5:定位时的世界时UTC
字段6:状态:A=有效;V=无效
字段7:FAA模式指示符
字段8:校验和
- GST 伪距噪声统计
1 2 3 4 5 6 7 8 9
| | | | | | | | |
$ --GST,hhmmss.ss,x,x,x,x,x,x,x,*hh<CR><LF>
$GPGST,182141.000,15.5,15.3,7.2,21.8,0.9,0.5,0.8*54
字段1:时间
字段2:RMS的标准差
字段3:误差椭圆长半轴的标准差(米)
字段4:误差椭圆短半轴的标准差(米)
字段5:误差椭圆长半轴的方向(度)
字段6:纬度误差的标准差(米)
字段7:经度误差的标准差(米)
字段8:高度误差的标准差(米)
字段9:校验和
- GSV 可见卫星的信息
1 2 3 4 5 6 7 n
| | | | | | | |
$--GSV,x,x,x,x,x,x,x,...*hh<CR><LF>
$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74
$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D
字段1:GSV报文总数
字段2:当前组内报文编号
字段3:可见卫星的总数
字段4:卫星编号
字段5:仰角
字段6:方位角
字段7:信噪比 (有多少卫星,字段4-7会重复多少次)
- VTG 对地航向和航速
1 2 3 4 5 6 7 8 9 10
| | | | | | | | | |
$--VTG,x.x,T,x.x,M,x.x,N,x.x,K,m,*hh<CR><LF>
$GPVTG,220.86,T,,M,2.550,N,4.724,K,A*34
字段1:对地航向
字段2:T=真航向
字段3:对地航向
字段4:M=磁航向
字段5:对地航速
字段6:N=kn
字段7:对地航速
字段8:K=千米/时
字段9:FAA模式指示符
字段10:校验和
- ZDA 日期时间
1 2 3 4 5 6 7
| | | | | | |
$--ZDA,hhmmss.ss,xx,xx,xxxx,xx,xx*hh<CR><LF>
$GPZDA,160012.71,11,03,2004,-1,00*7D
字段1:UTC时间
字段2:天;范围:01~31
字段3:月;范围:01~12
字段4:年
字段5:当地时时差;范围:-13~+13
字段6:本地时分钟差;范围:00~59
字段7:校验和
新建静态类GPSParser
,对GPS报文进行','拆分,根据不同的报文进行解码,解码结果以键值对的形式封装进哈希表中:
public static class GPSParser
{
public static Hashtable ParseSentence(string sentence)
{
var ss = sentence.Split(',');
switch (ss[0])
{
case "$GPRMC":
return GpsMessage_RMC(ss);
... 其他报文
default:
throw new Exception($"暂不支持解析GPS报文[{ss[0]}]");
}
}
private static Hashtable GpsMessage_RMC(string[] ss)
{
//时间格式解析
var utc = new DateTime(
2000+int.Parse(ss[9].Substring(4,2)),
int.Parse(ss[9].Substring(2,2)),
int.Parse(ss[9].Substring(0,2)),
int.Parse(ss[1].Substring(0,2)),
int.Parse(ss[1].Substring(2,2)),
int.Parse(ss[1].Substring(4,2)),
DateTimeKind.Utc);
//纬度
var lat = int.Parse(ss[3].Substring(0, 2)) + double.Parse(ss[3].Substring(2)) / 60;
if (ss[4] == "S") lat *= -1;
//经度
var lon = int.Parse(ss[5].Substring(0, 3)) + double.Parse(ss[5].Substring(3)) / 60;
if (ss[6] == "W") lon *= -1;
var res = new Hashtable
{
{"UTCTime", utc},
{"Status", ss[2]},
{"Latitude", lat},
{"Longitude", lon},
{"SpeedOverGround", double.Parse(ss[7])},
{"TrackMadeGood", double.Parse(ss[8])},
{"MagneticVariation", ss[10]+ss[11]},
{"FAAModeIndicator", ss[12]},
};
return res;
}
}