Decode ADS-B and Mode S messages with rs1090

rs1090 is a Rust library designed to decode ADS-B and Mode S messages.

A proper introduction to aircraft surveillance, ADS-B and Mode S, is accessible here: https://mode-s.org/1090mhz/

The most basic usage of the library goes through the decode function. When passed a message as input, the decoded result will be the same with the three following tools, which are linking to the same code:

  • the decode1090 command-line interface program;
  • the rs1090 Python library;
  • the rs1090 Javascript/WASM library (in usage here)

You can reuse the library in another notebook:

import { rs1090 } from "@xoolive/rs1090"

Basic introduction

example_msg = "8c4841753a9a153237aef0f275be"

Object {df: "17", icao24: "484175", bds: "06", tc: 7, NUCp: 7, groundspeed: 17, track: 92.8125, parity: "odd", lat_cpr: 39195, lon_cpr: 110320}

The 5 first bits are mapped to a Downlink Format:

DF=17 corresponds to Extended Squitter messages, i.e. the ADS-B protocol.

df = 17

Since we have DF = 17, the 3 following bytes (blocks of 8 bits) are decoded into a 24-bit transponder address (field "icao24"); then the 5th block starts with a 5-bit typecode (field "tc") which further conditions how to decode the rest of the message (here, it says we must decode a surface position message according to standard BDS 0,6)

More details here: https://mode-s.org/1090mhz/content/ads-b/1-basics.html

icao24 = "484175"

tc = 7

The majority of messages can be decoded without any external information.

Moreover, DF=17 messages are CRC checked, which ensures that decoded data is not (too much) nonsense.

If one bit is corrupted, the CRC code helps to invalidate the message.

Error: Assertion error: Invalid CRC in ADS-B message: 1

The particular case of DF=20 and DF=21

Another category of messages is not received equally around the planet. In particular, messages with a downlink format value of 20 or 21 are not sent in broadcast mode (like ADS-B messages), but only in response to a query from a Secondary Surveillance Radar (SSR).

This means that aircraft will always emit ADS-B (DF=17) messages at the same pace and according to the same patterns wherever they are on the planet. Conversely, DF=20 or 21 messages are not sent if:

  • the aircraft fly a remote region without SSR (oceans, polar areas, etc.)
  • the SSR in the region do not query for those messages.

In most European and in some Asian countries, these messages are commonly queried, but it is not the case everywhere, even in Northern America.

df20_message = "a0001838e519f33160240142d7fa" df21_message = "a8001ebcfffb23286004a73f6a5b"

There are several challenges when decoding such messages: the first one is that the messages are not CRC-checked. Actually, the CRC value helps to decode the icao24 identifier, so if one bit is shifted, the icao24 value (i.e. the aircraft identifier) is different.

The main difference between DF20 and DF21 messages is that the first ones always contain an altitude value (like DF4 messages) and the second one an identity (squawk) value (like DF5 messages).

Object {df: "20", altitude: 38000, bds60: Object, icao24: "3c674d"}

Object {df: "4", altitude: 25, icao24: "484ee4"}

Object {df: "21", squawk: "7333", bds50: Object, bds60: Object, icao24: "48548e"}

Object {df: "5", squawk: "6276", icao24: "4ca293"}

All the BDS blocks that are valid for ADS-B messages start with a typecode field which is enough to discriminate among them.

DF20 and DF21 messages can contain much more BDS blocks, and it is not possible to discriminate them. In practice, the addressees of the messages know what the SSR queried, so there is no ambiguity to decode the messages.

However, when we get data from a crowdsourced platform, we do not have access to the messages sent by the SSR (the so-called uplink format, sent from the ground, on a different frequency) so we are left with assumptions to make.

Below is the result of a few attempts to decode some BDS blocks in the messages. There are several types of errors:

  • some messages are expected to have some bits positioned to 1 or 0;
  • the values of some fields result in irrealistic values.

Error: Assertion error: Invalid typecode 28 for BDS 0,5 (9 to 18 or 20 to 22)

Error: Assertion error: First bits must be 0x10 in BDS 1,0

Error: Assertion error: BDS 2,0 is always valid in BDS 1,7

Error: Assertion error: First bits must be 0x20 in BDS 2,0

Error: Assertion error: Invalid aircraft registration 2#O#X#A

Error: Assertion error: First bits must be 0x30 in BDS 3,0

Error: Assertion error: Value for selected_fms or selected_mcp: 51700 ft > 45000 ft

Error: Assertion error: Invalid wind speed value

Error: Assertion error: Invalid level value

Error: Assertion error: Roll angle -37.96875 and track rate 0.125 signs do not agree.

Object {bds: "60", heading: 284.23828125, IAS: 249, Mach: 0.788, vrate_barometric: 128, vrate_inertial: 32}

In this case, there is only one possibility which does not raise errors in the decoding: our message contains a BDS 6,0 field with Heading and speed report information.

Even though most messages can be decoded into a unique BDS block, this is not always the case. A lot of ambiguous messages can be decoded both as BDS 5,0 ( Track and turn report) and BDS 6,0 ( Heading and speed report).

In that case, one must use extra information known about the aircraft in order to invalidate one of the resulting blocks. The content encoded in one message is not enough to decode it.