Building an AIS Message Decoder

I used https://github.com/schwehr/noaadata/tree/master/ais to decode AIS messages with this package (Python) until I started to get a new message format. As you may know, AIS messages are mainly of two types. one part (one message) or two parts (many messages). Message No. 5 always consists of two parts. Example:

!AIVDM,2,1,1,A,55?MbV02;H;s<HtKR20EHE: address@hidden @Dn2222222216L961O5Gf0NSQEp6ClRp8,0*1C !AIVDM,2,2,1,A,88888888880,2*25 

I used to decode this just fine using the following code snippet:

  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 

Now I get a new message format:

 !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 

Note. the number in the last index is the time in epoch format

I tried setting my code to decode the new format. I managed to decode messages in one piece. My problem is with several types of messages.

  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]) 

The decoder cannot output two lines as one. Thus, decoding is not performed because message # 5 must contain two lines, not one. The error I am getting is in these lines:

 if nmeastring.count('!SAVDM')==2 and len(nmeamsg)==13: aismsg = nmeamsg[5]+nmeamsg[11] 

Where len(nmeamsg) always 8 (second line), and nmeastring.count('!SAVDM') always 1

Hopefully I explained this clearly, so someone can tell me what I am missing here.

UPDATE

Ok, I think I found the reason. I pass the messages from the file to the script line by line:

 for line in file: i=i+1 try: doais(line) 

If message No. 5 should be transmitted as two lines. Any idea on how I can do this?

UPDATE

I did this by slightly modifying the code:

 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) 
+5
source share
2 answers

Keep in mind that noaadata is my old research code. libais is my production library which is used for NOAA ERMA and WhaleAlert.

I usually do decoding with a two-pass process. Attach multiline messages first. I see this as normalization (ais_normalize.py). At this point you have a few problems. First, the two component lines have different time stamps to the right of the second line. The old USCG metadata standard is the latter. Therefore, my code will assume that these two lines are not connected. Secondly, you do not have the required station identifier field.

Where do you get SA from SAVDM? What device ("speaker" in the NMEA dictionary) receives these messages?

+2
source

If you are in Ruby, I can recommend the NMEA and the ruby ​​gem AIS decoder I wrote is available on github . It is based on the unofficial AIS specification at catb.org , which is supported by one of Kurt’s colleagues.

It handles combining multi-page messages, reading from streams, and supports a large number of NMEA and AIS messages. Decoding of 50 binary subtypes of AIS 6 and 8 messages is currently under development.

To handle the custom lines you posted:

 !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 

You must add a new parsing rule that accepts the fields after the checksum, but otherwise it should go smoothly. In other words, you copied the line of the analyzer :

  | BANG DATA CSUM { result = NMEAPlus::AISMessageFactory.create(val[0], val[1], val[2]) } 

and have something like

  | BANG DATA CSUM COMMA DATA { result = NMEAPlus::AISMessageFactory.create(val[0], val[1], val[2], val[4]) } 

What do you do with these extra timestamps? It looks like they were added by any registration software, and not part of the actual message.

0
source

Source: https://habr.com/ru/post/1209598/


All Articles