ADS-B Reference

From regional-training


This discussion is about the universal ADS-B mode ES which stands for Extended Squit on 1090MHz originated from aircraft, and not the USA UAT mode requiring collaboration with ground stations.

Message structure

An ADS-B message is 112 bits long, and consists of 5 parts.

+--------+--------+-----------+--------------------------+---------+
|  DF 5  |  ** 3  |  ICAO 24  |          DATA 56         |  PI 24  |
+--------+--------+-----------+--------------------------+---------+

Any ADS-B must start with the Downlink Format 17, or 18 in case of TIS-B message. They correspond to 10001 or 10010 in binary for the first 5 bits. Bits 6-8 are used as an additional identifier, which has different meanings within each ADS-B subtype.

The key information of a ADS-B message is listed in the following table.

Number bits used Bits Bit Abbr. Name
5 1 - 5 DF Downlink Format
3 6 - 8 CA Capability (additional identifier)
24 9 - 32 ICAO ICAO aircraft address
56 33 - 88 DATA Data
[33 - 37] [TC] Type code
24 89 - 112 PI Parity/Interrogator ID

It is worth noting that the ADS-B Extended Squitter sent from a Mode S transponder uses Downlink Format 17 (DF=17).

Non-Transponder-Based ADS-B Transmitting Subsystems and TIS-B Transmitting equipment use Downlink Format 18 (DF=18). By using DF=18 instead of DF=17, an ADS-B/TIS-B Receiving Subsystem will know that the message comes from equipment that cannot be interrogated.

ICAO address

In each ADS-B message, the sender (originating aircraft) can be identified using the ICAO address. It is located from 9 to 32 bits in binary (or 3 to 8 in hexadecimal).

An unique ICAO address is assigned to each Mode-S transponder of an aircraft. Thus this is a unique identifier for each aircraft. You can use the query tool (World Aircraft Database) from mode-s.org to find out more about the aircraft with a given ICAO address. For instance, using ICAO 4840D6 example, it will return the result of a Fokker 70 with registration of PH-KZD.

In addition, you can download the database from the aforementioned https://junzis.com/adb/ in CSV format.

ADS-B message types

Data carried is determined by the Type Code of the message, indicated at bits 33 - 37 of the ADS-B message

ADS-B Type Code Content
1 - 4 Aircraft identification
5 - 8 Surface position
9 - 18 Airborne position (w/ Baro Altitude)
19 Airborne velocities
20 - 22 Airborne position (w/ GNSS Height)
23 - 27 Reserved
28 Aircraft status
29 Target state and status information
31 Aircraft operation status

ADS-B Checksum

ADS-B uses a cyclic redundancy check to validate the correctness of the received message, where the last 24 bits are the parity bits. The following pseudo-code describes the CRC process:

GENERATOR = 1111111111111010000001001

MSG = binary("8D4840D6202CC371C32CE0576098")  # total 112 bits

FOR i FROM 0 TO 88:                           # 112 - 24 parity bits
  if MSG[i] is 1:
    MSG[i:i+24] = MSG[i:i+24] ^ GENERATOR

CRC = MSG[-24:]                               # last 24 bits

IF CRC not 0:
  MSG is corrupted

For the implementation of CRC encoder in Python, refer to the pyModeS library function: pyModeS.crc()

A comprehensive documentation on Mode-S parity coding can be found:

Gertz, Jeffrey L. Fundamentals of mode s parity coding. No. ATC-117. MASSACHUSETTS INST OF TECH LEXINGTON LINCOLN LAB, 1984. APA

Compact Position Reporting

The position information in ADS-B messages is encoded in a compact position reporting (CPR) format. The general idea behind CPR is to be able to encode more coordinate decimals using less bits. It is achieved by trading global position ambiguity and time with local position accuracy.

An easy example to understand the principle behind CPR:

CPR

Imaging the world is constructed by 16 grid, which we have divided into two levels, each level is encoded with two bits. Higher levels in color are 00 (yellow), 01 (blue), 10 (red), 11 (green). And within each color grid, the lower levels are also encoded similarly.

Then each grid can be represented as 4 digits from 0000 to 1111. Now, we want to describe the movement indicated as the arrows in the green grids 1100 -> 1101, but we only have 3 bits to encode each position.

It is easy to see that the high 2 bits appeared in all positions, so we can define a structure to do the following:

   The last two bits shall represent the local position
   The combination of first digit from two messages defines the higher grid

Then the two messages can be sent as 1 00 -> 1 01.

From lower bits 00 -> 01, we have four different possibility of movement as shown in dashed arrows, and from the two first bits combination 11, we know that the arrow shall represent the movement in the green grids:

CPR 2

The CPR and functions

The actual CPR algorithm of course is more complicated, but the principle is very similar to the previous example. If only one message is given, it is possible to find multiple solutions that are spaced around the world. The combination of two (different types of) messages will yield the final result.

In CPR encoding, the Earth is divided in many zones (similar to the grid in the previous example). And the encoding algorithm is also more complicated (described in a later section). First, we will list some of the parameters and common functions used in the decoding process here.

NZ

Number of geographic latitude zones between equator and a pole. It is set to NZ = 15 for Mode-S CPR encoding.

floor(x)

the floor function floor(x) defines as the greatest integer value k, such that k<=x, for example:

floor(5.6) = 5 floor(-5.6) = -6

mod(x, y)

the modulus function mod(x, y) returns:

where y can not be zero

NL(lat)

Denotes the “number of longitude zones” function, given the latitude angle lat. The returned integer value is constrained within [1, 59], calculated as:


For latitudes that are close to the equator or the poles, one of following values is returned:

lat = 0     ->    NL = 59
lat = +87   ->    NL = 2
lat = -87   ->    NL = 2
lat > +87   ->    NL = 1
lat < -87   ->    NL = 1

Position Reports

Airborne Reports

Airborne Positions

An aircraft airborne position message has downlink format 17 (or 18) with type code from 9 to 18

Messages are composed as follows:

Data Bits MSG Bits N-bit Abbr Content
33 - 37 1 - 5 5 TC Type code
38 - 39 6 - 7 2 SS Surveillance status
40 8 1 NICsb NIC supplement-B
41 - 52 9 - 20 12 ALT Altitude
53 21 1 T Time
54 22 1 F CPR odd/even frame flag
55 - 71 23 - 39 17 LAT-CPR Latitude in CPR format
72 - 88 40 - 56 17 LON-CPR Longitude in CPR format

Two types of the position messages (odd and even frames) are broadcast alternately. There are two different ways to decode an airborne position based on these messages:

  • Unknown position, using both types of messages (aka globally unambiguous position)
  • Knowing previous position, using only one message (aka locally unambiguous position)

Note: The definition of functions NL(lat), floor(x), and mod(x,y) are described above.

Globally unambiguous position (decoding with two messages)

odd or even message?

For each frame, bit 54 determines whether it is an odd or even frame:

0 -> Even frame
1 -> Odd frame

For example, the two following messages are received:

8D40621D58C382D690C8AC2863A7
8D40621D58C386435CC412692AD6


|----|--------|----------------|--------|
|    | ICAO24 |      DATA      |  CRC   |
|----|--------|----------------|--------|
| 8D | 40621D | 58C382D690C8AC | 2863A7 |
| 8D | 40621D | 58C386435CC412 | 692AD6 |
|----|--------|----------------|--------|

The payload data in binary format:

|============================================================================|
| DATA                                                                       |
|============================================================================|
| TC    | ... | ALT          | T | F | CPR-LAT           | CPR-LON           |
|-------|-----|--------------|---|---|-------------------|-------------------|
| 01011 | 000 | 110000111000 | 0 | 0 | 10110101101001000 | 01100100010101100 |
| 01011 | 000 | 110000111000 | 0 | 1 | 10010000110101110 | 01100010000010010 |
|============================================================================|

In both messages we can find DF=17 and TC=11, with the same ICAO24 address 40621D. So, those two frames are valid for decoding the positions of this aircraft. Assume the first message is the newest message received.


The CPR representation of coordinates


|---|-------------------|-------------------|
| F | CPR Latitude      | CPR Longitude     |
|---|-------------------|-------------------|
| 0 | 10110101101001000 | 01100100010101100 |  -> newest
| 1 | 10010000110101110 | 01100010000010010 |
|---|-------------------|-------------------|

In decimal:

|---|-------------------|-------------------|
| 0 | 93000             | 51372             |
| 1 | 74158             | 50194             |
|---|-------------------|-------------------|

CPR_LAT_EVEN: 93000 / 131072 -> 0.7095
CPR_LON_EVEN: 51372 / 131072 -> 0.3919
CPR_LAT_ODD:  74158 / 131072 -> 0.5658
CPR_LON_ODD:  50194 / 131072 -> 0.3829

Since CPR latitude and longitude are encoded in 17 bits, 13107 2^17 is the maximum value.

Lattitude

In the example:

Lat_EVEN = 52.25720214843750
Lat_ODD  = 52.26578017412606
Lat = Lat_EVEN = 52.25720

Longitude

In the example:

Lon: 3.91937

Here is a Python implementation: https://github.com/junzis/pyModeS/blob/faf4313/pyModeS/adsb.py#L166

Calculate altitude

The altitude of the aircraft is much easier to compute from the data frame. The bits in the altitude field (either odd or even frame) are as follows:

1100001 1 1000
        ^
       Q-bit

This Q-bit (bit 48) indicates whether the altitude is encoded in multiples of 25 or 100 ft (0: 100 ft, 1: 25 ft).

For Q = 1, we can calculate the altitude as follows:

First, remove the Q-bit :

N = 1100001 1000 => 1560 (in decimal)

The final altitude value will be:

Alt=N⋅25−1000(ft.)

In this example, the altitude at which the aircraft is flying is:

1560 * 25 - 1000 = 38000 ft.

Note that the altitude has the accuracy of +/- 25 ft when the Q-bit is 1, and the value can represent altitudes from -1000 to +50175 ft.


The final position

Finally, we have all three components (latitude/longitude/altitude) of the aircraft position:

LAT: 52.25720 (degrees N)
LON:  3.91937 (degrees E)
ALT:    38000 ft

Locally unambiguous position (decoding with one message)

This method gives the possibility of decoding aircraft using only one message knowing a reference position. This method computes the latitude index (j) and the longitude index (m) based on such reference, and can be used with either type of the messages.

The reference position

The reference position should be close to the actual position (eg. position of aircraft previously decoded, or the location of ADS-B antenna), and must be within a 180 NM range.

calculate local latitude

calculate local longitude

example

For the same example message:

8D40621D58C382D690C8AC2863A7
Reference position:
 LAT: 52.258
 LON:  3.918

The structure of the message is:

8D40621D58C382D690C8AC2863A7
|----|--------|----------------|--------|
|    | ICAO24 |      DATA      |  CRC   |
|----|--------|----------------|--------|
| 8D | 40621D | 58C382D690C8AC | 2863A7 |


Data in binary:

| DATA                                                                       |
|============================================================================|
| TC    | ... | ALT          | T | F | CPR-LAT           | CPR-LON           |
|-------|-----|--------------|---|---|-------------------|-------------------|
| 01011 | 000 | 110000111000 | 0 | 0 | 10110101101001000 | 01100100010101100 |

CPR representation:

| F | CPR Latitude      | CPR Longitude     |
|---|-------------------|-------------------|
| 0 | 10110101101001000 | 01100100010101100 |
|---|-------------------|-------------------|
|   | 93000 / 131072    | 51372 / 131072    |
|   | 0.7095            | 0.3919            |
|---|-------------------|-------------------|
d_lat:  6
j:      8
lat:    52.25720
m:      0
d_lon:  10
lon:    3.91937

references

picap

I wrote a small utility called piCap to capture piaware data running on any raspberry pi.

The latest variant, under utils, also formats and send data as ir-xml to activemq topics TRACKS and ATC.

categories