AIS Channels Streaming
It is possible to stream the 4 filtered baseband AIS channels over the Ethernet interface, while the Polaris AIS receiver do the normal demodulation.
Data Format
Each stream is 16 bit complex signed integer with a sample rate of 96 Ksps. The data from the 4 AIS channels is interleaved and placed in a UDP packet with as size of 1448 and sent to port 53032. The first 8 bytes of each UDP packet is a sequence counter sent in little endian, this can be used to detect packet loss between the Polaris AIS receiver and the destination. The UDP packet format is show in UDP Packet Data Format.
Byte |
0-7 |
8-11 |
12-15 |
16-19 |
20-23 |
… |
1444-1447 |
Field content |
Sequence cnt. |
I0,Q0 |
I1,Q1 |
I2,Q2 |
I3,Q3 |
… |
I3,Q3 |
Example Setup
In the following example the Polaris AIS is setup to stream samples to a PC with a fixed IP address set to 192.168.100.22 and on the same network as the Polaris AIS. The Polaris AIS will be configured to have IP address 192.168.100.20.
Example network setup
In the debug shell on the Polaris AIS:
Follow Getting Started to setup communication with the receiver.
Connect a cable to the Ethernet connector
prop set sys.net.ip 192.168.100.20
prop set sys.net.prefix 24
prop set sys.net.gw 192.168.100.1
prop set sys.net.enable
prop set demod.iq.dest.ip 192.168.100.22
prop set demod.iq.enable 1
Now the Polaris AIS will start sending UDP packets to 192.168.100.22. The code example below, written in Python, show how to receive the data from a PC.
#!/usr/bin/env python
import struct
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 53032 # Port that the Polaris AIS is sending data to
POLARIS_AIS_UDP_SIZE = 1448
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.bind((HOST, PORT))
while True:
data = s.recv(POLARIS_AIS_UDP_SIZE)
seq_nr = struct.unpack("<Q", data[:8]) # Unpack sequence number
iq_samples = struct.unpack("<" + "h" * 720, data[8:]) # Unpack signed shorts
i0 = iq_samples[0::8] # Starting from 0 every 8 sample is from channel I0
q0 = iq_samples[1::8] # Starting from 1 every 8 sample is from channel Q0
i1 = iq_samples[2::8] # Starting from 2 every 8 sample is from channel I1
q1 = iq_samples[3::8] # Starting from 3 every 8 sample is from channel Q1
i2 = iq_samples[4::8] # Starting from 4 every 8 sample is from channel I2
q2 = iq_samples[5::8] # Starting from 5 every 8 sample is from channel Q2
i3 = iq_samples[6::8] # Starting from 6 every 8 sample is from channel I3
q3 = iq_samples[7::8] # Starting from 7 every 8 sample is from channel Q3
print(f"Seq. nr. {seq_nr[0]}, {i0[0]:+06d}, {q0[0]:+06d}, {i1[0]:+06d}, {q1[0]:+06d}, {i2[0]:+06d}, {q2[0]:+06d}, {i3[0]:+06d}, {q3[0]:+06d}")
For each UDP packet the script extracts the sequence number and I/Q from the 4 sample streams. The channel mapping are as follows:
CH0: 156.825 MHz
CH1: 156.775 MHz
CH2: 161.975 MHz
CH3: 162.025 MHz