2. AIS通信协议与报文结构解析
AIS(船舶自动识别系统)在船端与岸端之间传输的信息,最终都要落到一条条可被串口、网络和解析程序处理的报文上。理解协议的关键,是分清两个层次:外层是NMEA 0183语句封装,负责把二进制载荷变成可打印的ASCII文本;内层是AIS报文本身,由消息类型、MMSI和若干按位定义的字段组成。只有把这两层拆开看,才能正确解析出船位、航向、船名等业务数据。
一、NMEA 0183语句格式
AIS数据最常见的封装形式是NMEA 0183的VDM/VDO语句。一条典型语句如下:
!AIVDM,1,1,,A,15Muq?P0000G?t@E>4p@0?vN0<0u,0*5C
整条语句以“!”起始,字段之间用逗号分隔,末尾是“*”加两位十六进制校验和。各字段含义为:
- !AIVDM / !AIVDO:语句标识。VDM表示接收到的他船AIS信息,VDO表示本船自身信息。
- 1,1:分别为“总片段数”和“当前片段序号”。AIS单条报文最长可达168个字符(如类型5),超过单句容量时会被拆成多句传输。
- 空字段:串行报文ID,多句封装时用于把同一报文的片段关联起来,单句时通常为空。
- A:AIS信道标识,A或B,对应VHF的161.975 MHz和162.025 MHz两个信道。
- 15Muq?P...:AIS载荷,采用6位ASCII编码,每个字符承载6个比特。
- 0:填充位数,表示载荷末尾需要丢弃的填充比特数,用于保证总位数为6的整数倍。
- *5C:从“!”之后到“*”之前所有字符的异或校验和。
解析程序的第一步应当是校验:计算异或值并与“*”后的两位比较,不一致则丢弃该句;随后按“总片段数/序号”把多句载荷拼接,再按填充位截断,得到完整的二进制比特流。这一步做错,后续所有字段都会错位。
二、AIS报文类型与字段编码
AIS报文以6位为单位编码,前6位是消息类型(Message Type),决定后续字段的布局。海上交通中最常遇到的是以下几类:
| 类型 | 名称 | 典型用途 | 关键字段 |
|---|---|---|---|
| 1/2/3 | 位置报告(A类船) | 航行中周期发送,2为自主模式,3为响应询问 | MMSI、航行状态、转向率、SOG、位置精度、经度、纬度、COG、真航向、时间戳 |
| 5 | 静态与航次数据 | 每6分钟发送一次,含船名、呼号、船型、尺寸、目的地 | IMO号、呼号、船名、船舶类型、吃水、目的地、ETA |
| 18 | 位置报告(B类船) | 小型船舶、渔船等B类设备的位置广播 | MMSI、SOG、位置精度、经度、纬度、COG、真航向 |
| 19 | 扩展B类位置报告 | B类船位置加静态信息合并发送 | 在18类基础上增加船名、船型、尺寸 |
| 24 | 静态数据报告 | B类船的静态信息,分A、B两部分 | Part A含船名;Part B含船型、厂商、呼号、尺寸 |
以类型1为例,其字段按位排列:0–5位为消息类型,6–7位为重复指示,8–37位为MMSI(30位),38–41位为航行状态,42–49位为转向率,50–59位为SOG(以0.1节为单位),60位为位置精度,61–88位为经度(以1/10000分为单位,即0.0001分),89–115位为纬度,116–127位为COG(0.1度),128–136位为真航向(1度),137–142位为时间戳(秒)。
这里最容易出错的是经纬度的有符号编码。经度字段为28位有符号整数,纬度27位有符号整数,单位均为1/10000分。例如载荷解析出经度原始值为 121500000,则实际经度为 121500000 ÷ 600000 = 202.5?——不对,正确换算是先除以10000得到分,再除以60得到度:121500000 / 10000 / 60 = 202.5,显然超出范围,说明该值应带符号解释。实际工程中应使用补码规则:若最高位为1,则减去2的位宽次方。以经度28位为例,原始值若为 0x0F1B2C3D 这类正数,直接换算;若为负经度(西经),则需按补码还原。教学示例中,假设解析出经度原始值 121500000(对应东经约202.5度)显然不合理,正确示例应为 72600000,换算为 72600000 / 600000 = 121.0 度,即东经121度。纬度同理,原始值 37200000 对应 37200000 / 600000 = 62.0 度。实际编程时务必用有符号整数读取,避免把西经、南纬解析成巨大正数。
三、从比特流到业务字段的解析流程
下面这张图展示了从一条NMEA语句到可用航迹点的完整数据链路,包括校验、拼接、6位解码、按类型分派字段和单位换算几个关键环节:
图中虚线表示“类型分派”之后,不同类型走各自的字段布局。实际开发中,建议把每种类型的字段定义写成配置表(字段名、起始位、位宽、是否有符号、换算系数),解析时按表逐字段取值,而不是为每种类型硬编码一套读取逻辑。这样新增类型或修正字段时只需改配置,不易引入位偏移错误。
四、实操中的几个判断要点
第一,先判类型再取字段。载荷解码后先读前6位,若类型不在支持列表内(如类型4基站报告、类型21助航设备),应跳过而不是按类型1强行解析,否则会把基站坐标误当成船舶位置。第二,注意特殊值。经度181度、纬度91度表示“位置不可用”,SOG为1023表示不可用,COG为3600表示不可用,航向511表示不可用。这些值必须在入库前过滤,否则会在航迹图上产生跳点。第三,时间戳字段只表示UTC秒(0–59),60表示时间戳不可用,61表示定位系统处于手动输入模式,不能直接当作完整时间使用,需结合接收时间补全日期。
以一个教学示例说明完整换算:假设某类型1报文解析出MMSI为413123456,经度原始值72600000,纬度原始值37200000,SOG原始值125,COG原始值875。则经度 = 72600000 / 600000 = 121.0°E,纬度 = 37200000 / 600000 = 62.0°N,SOG = 125 / 10 = 12.5节,COG = 875 / 10 = 87.5°。这些值可直接作为航迹点的位置与运动属性写入数据库。需要强调的是,以上数值为教学假设,实际解析应以真实报文校验结果为准。
掌握NMEA封装与AIS位域编码这两层结构后,后续的航迹清洗、时空对齐和轨迹聚类才有可靠的数据基础。解析环节的每一个位偏移和符号错误,都会在航迹图上被放大成明显的异常跳点,因此这一节的内容值得反复对照真实报文练习。