作者:devstone(微信公众号devstone)
时间:2017年8月23日17:50:49
版本:V 0.0.0
邮箱:kevinlq@yeah.net
AIS学习
AIS定义
船舶自动识别系统(Automatic Indentification System)简称AIS系统。由基站设施和船载设备共同组成,是一种新型的集网络技术、现代通讯技术 、计算机技术、电子信息显示技术为一体的数字助航系统和设备。
目的
- 识别船舶;
- 帮助跟踪目标;
- 简化和促进信息交换;
- 减少口头的强制船舶报告;
学习手册
AIS学习参考官方发布的标准协议手册;
ITU-R M1371-4建议书
http://www.itu.int/rec/R-REC-M.1371/en
报文介绍
根据标准,AIS只能传输可打印的ASCII字符,字符有效范围为0x30到0x77之间的字符;
AIS报文分为2中,VDM和VMO。VDM是指本船接收到其他船只发送的信息,VDO是指船舶自身广播的信息,解析报文主要是指计解析VDM报文。 对于VMD消息中的压缩码,编码格式根据下面的对照表来进行的。
数据解压处理是将VDM消息字符串中的每一位ASCII字符转换成对应6bit二进制码,根据上述转换表进行转换,在将这些6bit码按顺序组成6bit二进制数据串,并经过移位处理后最终保存到8bit字符串中
单个字符转化
信息提取
解压后的数据保存在8bit位宽的字符串中,信息获取是按照VDM协议定义,从指定位置开始,提取指定位宽的数据。信息提取分为提取整数和字符串两种类型进行处理,提取整数的有效位宽为1到32位,处理过程是按照给定的起始位寻找对应的其实字节和字节内的起始位,从此开始,连续获取指定位宽的数据,在经过移位合并成需要的信息
常见报文类型表
每位表示的意思
!ABVDM,1,1,3,A,169DvlgP1R8KPtvFBfOCt3?h0@RT,0*03 AB指的是SAAB的AIS数据,VDM表示本台站收到的船舶的信息, SAAB公司以!ABVDM开头的数据报文和以!AIVDM开头的国际标准的报文编码是完全一致的。 1,1,3,第一位表示传递本消息需要的报文总条数,第二位数字表示该报文是整个消息的第几条,最后一位是报文的序列标识,当同时存在多条需要分段的消息时,该字段用来区分隶属于不同消息的报文。其下的A表示该报文是通过A信道接收的。
数据区段共168bit,具体含义如下:
消息分类
- 消息1、2、3:位置报告
- 消息4:基站报告
- 消息5:船舶静态和航行相关数据
- 消息6:寻址二进制消息
- 消息7:二进制确认
- 消息8:二进制广播消息
- 消息9:标准的SAR航空器位置报告
- 消息10:UTC/日期询问
- 消息11:UTC/日期响应
- 消息12:寻址安全相关信息
- 消息13:安全相关确认
- 消息14:安全相关广播消息
- 消息15:询问
- 消息16:指配模式命令
- 消息17:GNSS广播二进制消息
- 消息18:标准的B类设备位置报告
- 消息19:扩展的B类设备位置报告
- 消息20:数据链路管理消息
- 消息21:助航设备报告
- 消息22:信道管理
- 消息23:群组指配命令
- 消息24:静态数据报告
- 消息25:单时隙二进制消息
- 消息26:带有通信状态的多时隙二进制消息
- 消息27:大量程AIS广播消
报文解析
- 将ASCII码转化成6位二进制值
bool eightByteToSixByte(char inEight,char outSix)
{
//以下只检测所输入的ASCII码是否有效
if (inEight < 0x30 || inEight > 0x77)
return false;
if (inEight > 0x57 && inEight < 0x60)
return false;
//加上101000
outSix = inEight + 0x28;
if (outSix > 0x80)
outSix += 0x20;
else
outSix += 0x28;
//左移2位获取LSB(最低位)
outSix = outSix<<2;
return true;
}
- 将ASCII码字符串转化成二进制值表示的字符数组
将每个ASCII码转换成6bits码后,因为数据是以字节为单位保存的,因此需要将这些6bits码放置到字节中去。比如ASCII码串”A2L9”,转换成6bits二进制是这样的:010001 000010 011100 001001。用字节表示就是 01000100 00100111 00001001即0x44,0x27,0x09这三个ASCII码。
数据校验
AIS数据校验采用的是异或校验,才校验中,校验的是!和*之间的数据,例如
!AIVDM,1,1,,A,H52IRsP518Tj0l59D0000000000,2*45
则校验的数据应该是:
AIVDM,1,1,,A,H52IRsP518Tj0l59D0000000000,2
校验算法的实现
找到开始校验的位置:
int Nmea::find_start()
{
QByteArray arry = m_msg.toLatin1();
int i = 0;
int index = 0;
foreach (char var, arry) {
if ( (var == '!') || (var == '$')){
index = i;
break;
}else{
index = NMEA_NOT_FINE;
}
i++;
}
return index;
}
校验检验
int Nmea::calculateChecksum()
{
int ptr;
int result;
/* Find start of sentence, after a '!' or '$' */
ptr = this->find_start() + 1;
QByteArray msgArray = m_msg.mid(ptr).toLatin1();
this->m_checkSum = 0;
foreach (char var, msgArray) {
if ( (var == '!') || (var == '$')){
qDebug()<<"Start Character Found before Checksum\r\n";
result = NMEA_ERROR;
return result;
}
if ( var == '*'){
result = NMEA_MATCH;
return result;
}
this->m_checkSum ^= var;
}
return result;
}
校验
int Nmea::checkChecksum()
{
QString msgChecksum;
int ptr;
bool ok;
int checkSum;
ptr = calculateChecksum();
if (ptr == NMEA_ERROR)
{
return 2;
}
ptr = m_msg.indexOf('*');
if (ptr < 0)
return 2;
/*
*下面取出校验位,即从*开始往后,比如 ....2*45,将会取出45
*/
msgChecksum = m_msg.mid(ptr + 1,ptr + 3);
if (msgChecksum.isEmpty())
return 2;
checkSum = msgChecksum.toInt(&ok,16);
if (checkSum != this->m_checkSum){
qDebug()<<"check sum faild\r\n";
return 1;
}
return 0;
}
学习网站
- 航运海务和商务大数据支持平台
http://www.hifleet.com/shipdetail.jsp?keyword=412522554
- AIS信息服务平台
http://www.ais.msa.gov.cn/hsj/portal/ais_cbxx.page
- 在线解析
http://www.aggsoft.com/ais-decoder.htm
如果您对本文有任何问题,可以在下方留言,或者Email我
微信公众号:devstone,扫描二维码直接关注