AIS decoder

This object processes 48 kHz wide IQ blocks and extracts then processes AIS messages.

Note

This feature is available only with a License - Contact us for more details

class AIS {
    constructor();

    bool process( IQData iq );
    bool hasData();
    Object getData();
} ;

.process

Inject IQ data for processing. Returns true if messages have been processed.

.hasData

Returns true if AIS messages have been decoded and are available

.getData

Returns a decoded object. Available fields are :

  • mmsi : The Maritime Mobile Service Identity (MMSI)identifier received
  • ais_msg_type last AIS message received, for a detail of each message type, check this page
  • timestamp : date of update, number of millisecs since 01/01/1970

  • ship_type: Type of Ship and Cargo

  • 0 = not available or no ship = default
  • 1-99 = as defined below
  • 100-199 = reserved, for regional use
  • 200-255 = reserved, for future use
  • nav_status: Navigational status
  • 0 = under way using engine,
  • 1 = at anchor,
  • 2 = not under command,
  • 3 = restricted maneuverability,
  • 4 = constrained by her draught,
  • 5 = moored, 6 = aground,
  • 7 = engaged in fishing,
  • 8 = under way sailing,
  • 9 = reserved for future amendment of navigational status for ships carrying DG, HS, or MP, or IMO hazard or pollutant category C, high speed craft (HSC),
  • 10 = reserved for future amendment of navigational status for ships carrying dangerous goods (DG), harmful substances (HS) or marine pollutants (MP), or IMO hazard or pollutant category A, wing in ground (WIG);
  • 11 = power-driven vessel towing astern (regional use);
  • 12 = power-driven vessel pushing ahead or towing alongside (regional use);
  • 13 = reserved for future use,
  • 14 = AIS-SART (active), MOB-AIS, EPIRB-AIS
  • 15 = undefined = default (also used by AIS-SART, MOB-AIS and EPIRB-AIS under test)
  • call :Callsign if available
  • name: The Name should be as shown on the station radio license, if available
  • dest : Maximum 20 characters using 6-bit ASCII
  • sog_kn: speed over ground, in knots
  • cog : Course over ground, 0 is North
  • pos_valid: true if the position fields (lat,lon) are valid or not
  • offset_hz: offset of the AIS message relative to the center of the IQ channel, in Hz

Type of Ship and Cargo, as defined here:

  • 50 : Pilot vessel
  • 51 : Search and rescue vessels
  • 52 : Tugs
  • 53 : Port tenders
  • 54 : Vessels with anti-pollution facilities or equipment
  • 55 : Law enforcement vessels
  • 56 : Spare - for assignments to local vessels
  • 57 : Spare - for assignments to local vessels
  • 58 : Medical transports (as defined in the 1949 Geneva Conventions and Additional Protocols)
  • 59 : Ships and aircraft of States not parties to an armed conflict

Example:

    {
        "valid":true,
        "timestamp":105813,
        "mmsi":"230984000",
        "ship_type":0,
        "nav_status":15,
        "call":"",
        "name":"",
        "dest":"",
        "sog_kn":15.4,
        "cog":250,
        "rot":0,
        "heading":249,
        "pos_valid":true,
        "lat":51.408658333333335,
        "lon":3.0341216666666666,
        "ais_msg_type":1,
        "offset_hz":-103.2
    }

Use case example

In this example a 192 kHz IQ file is processed. Note that an additionnal bandpass filter is added, it is not mandatory but significantly improves the detection rate in noisy conditions.

var fname = 'ais_192k_162000.cf32';

var f = new IQFile();
if( f.open( fname) == false ) {
    print('cannot open file');
    exit();
}
f.setCenterFreq( 162);
f.setSampleRate( 192e3 );

var channelA = 162 - 161.975 ;
var channelB = 162 - 162.025 ;

print('Channel A:' + channelA );
print('Channel B:' + channelB );

// ddc for 192 => 48 KHz
var ddc = new DDC();
ddc.setOutBandwidth( 48e3 );
ddc.setCenter( -1e6 * channelA );

var fir = new JFir('filter');
fir.configure({ 'fft_size': 2048, 'max_insize': 10240, 'max_outsize': 10240 });
fir.setCutoff( 9600/48000 * 1.2 );

var ais = new AIS();
var msg = 0 ;
for( ; ; ) {
    var IQ = f.getSamples(16384); 
    if( IQ.getLength() == 0 ) {
        break ;
    }
    ddc.write( IQ );
    var ifdata = ddc.read();
    while( ifdata.getLength() > 0 ) { 
        fir.write(ifdata);
        while (fir.getAvailable() > 0) {
        out = fir.read();
        var hasMsg = ais.process(out) ;
        while( hasMsg ) {
            var positionMsg = ais.getData();
            print( JSON.stringify( positionMsg ));
            hasMsg = ais.hasData();
            msg++ ;
        }
        }
        ifdata = ddc.read(); 
    }
}
print( msg + ' ais msg processed');
Last update: August 20, 2023