我曾经使用theis包(Python)https://github.com/schwehr/noaadata/tree/master/ais解码AIS消息,直到我开始获取新的消息格式。 您可能知道,AIS消息主要有两种类型。一部分(一条消息)或两部分(多消息)。消息#5总是分为两部分。例如:
!AIVDM,2,1,1,A,55?MbV02;H;s<HtKR20EHE:address@hidden@Dn2222222216L961O5Gf0NSQEp6ClRp8,0*1C
!AIVDM,2,2,1,A,88888888880,2*25
我曾经使用以下代码对此进行解码:
nmeamsg = fields.split(',')
if nmeamsg[0] != '!AIVDM':
return
total = eval(nmeamsg[1])
part = eval(nmeamsg[2])
aismsg = nmeamsg[5]
nmeastring = string.join(nmeamsg[0:-1],',')
bv = binary.ais6tobitvec(aismsg)
msgnum = int(bv[0:6])
-
elif (total>1):
# Multi Slot Messages: 5,6,8,12,14,17,19,20?,21,24,26
global multimsg
if total==2:
if msgnum==5:
if nmeastring.count('!AIVDM')==2 and len(nmeamsg)==13: # make sure there are two parts concatenated together
aismsg = nmeamsg[5]+nmeamsg[11]
bv = binary.ais6tobitvec(aismsg)
msg5 = ais_msg_5.decode(bv)
print "message5 :",msg5
return msg5
现在我收到了一种新格式的消息:
!SAVDM,2,1,7,A,55@0hd01sq`pQ3W?O81L5@E:1=0U8U@000000016000006H0004m8523k@Dp,0*2A,1410825672
!SAVDM,2,2,7,A,4hC`2U@C`40,2*76,1410825672,1410825673
请注意。最后一个索引的数字是以纪元格式的时间
我尝试调整代码来解码这种新格式。我成功地用一部分解码消息。我的问题是多消息类型。
nmeamsg = fields.split(',')
if nmeamsg[0] != '!AIVDM' and nmeamsg[0] != '!SAVDM':
return
total = eval(nmeamsg[1])
part = eval(nmeamsg[2])
aismsg = nmeamsg[5]
nmeastring = string.join(nmeamsg[0:-1],',')
dbtimestring = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(nmeamsg[7])))
bv = binary.ais6tobitvec(aismsg)
msgnum = int(bv[0:6])
解码器无法将两条线作为一条线。因此解码失败,因为消息#5应该包含两个字符串而不是一个。我得到的错误在以下几行:
if nmeastring.count('!SAVDM')==2 and len(nmeamsg)==13:
aismsg = nmeamsg[5]+nmeamsg[11]
len(nmeamsg)
始终为8(第二行)且nmeastring.count('!SAVDM')
始终为1
我希望我能清楚地解释清楚,所以有人可以让我知道我在这里缺少的东西。
更新
好吧,我想我找到了原因。我将消息从文件传递到脚本:
for line in file:
i=i+1
try:
doais(line)
消息#5应该作为两行传递。关于如何实现这一点的任何想法?
更新
我是通过稍微修改代码来实现的:
for line in file:
i=i+1
try:
nmeamsg = line.split(',')
aismsg = nmeamsg[5]
bv = binary.ais6tobitvec(aismsg)
msgnum = int(bv[0:6])
print msgnum
if nmeamsg[0] != '!AIVDM' and nmeamsg[0] != '!SAVDM':
print "wrong format"
total = eval(nmeamsg[1])
if total == 1:
dbtimestring = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(nmeamsg[8])))
doais(line,msgnum,dbtimestring,aismsg)
if total == 2: #Multi-line messages
lines= line+file.next()
nmeamsg = lines.split(',')
dbtimestring = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(nmeamsg[15])))
aismsg = nmeamsg[5]+nmeamsg[12]
doais(lines,msgnum,dbtimestring,aismsg)
答案 0 :(得分:3)
请注意,noaadata是我的旧研究代码。 libais是我的制作库,用于NOAA的ERMA和WhaleAlert。
我通常会解码两次传递过程。首先加入多行消息。我称之为规范化(ais_normalize.py)。您在此步骤中遇到了几个问题。首先,两个组件行在第二个字符串的右侧具有不同的时间戳。根据USCG旧元数据标准,最后一个重要。所以我的代码将假设这两行不相关。其次,您没有所需的电台ID字段。
你在哪里从SAVDM获得SA?什么设备(&#34;讲话者&#34;在NMEA词汇表中)正在接收这些消息?
答案 1 :(得分:0)
如果你是Ruby,我可以推荐我写的NMEA and AIS decoder ruby gem,available on github。它基于the unofficial AIS spec at catb.org,由Kurt的一位同事维护。
它处理多部分消息的组合,从流中读取,并支持大量NMEA和AIS消息。目前正在开发解码AIS消息6和8的50个二进制子类型。
要处理您发布的非标准行:
!SAVDM,2,1,7,A,55@0hd01sq`pQ3W?O81L5@E:1=0U8U@000000016000006H0004m8523k@Dp,0*2A,1410825672
!SAVDM,2,2,7,A,4hC`2U@C`40,2*76,1410825672,1410825673
有必要添加一个新的解析规则,在校验和之后接受字段,但除此之外它应该顺利进行。换句话说,您要复制the parser line here:
| BANG DATA CSUM { result = NMEAPlus::AISMessageFactory.create(val[0], val[1], val[2]) }
并且有类似
的内容 | BANG DATA CSUM COMMA DATA { result = NMEAPlus::AISMessageFactory.create(val[0], val[1], val[2], val[4]) }
你如何处理这些额外的时间戳?几乎看起来他们已被任何正在进行日志记录的软件追加,而不是成为实际消息的一部分。