ADS-B guide

Date: 24/02/2025

Wherever you are, aircraft frequently pass overhead; sometimes several ones in a few minutes. Services like Flightradar24 provide precise real-time information about these flights using data received over the ADS-B protocol. You can also receive and decode such data; just follow instructions provided in this guide!

I assume that you have either traveled by airplane or at least saw one in operation. Modern aircraft operate globally transporting vast numbers of passengers across various regions. But it wasn’t always this way: just a century ago, people could travel only on the ground; reliable aircraft become available fairly recently.

After the invention of airplanes and start of commercial flights, it became clear that all vehicles in the air must be tracked somehow; otherwise, accidents are inevitable. Radars, not to mention visual observations, were not good enough for this task; so, radio communication came into play. Currently, every airplane is equipped with an aviation transponder. This greatly eases the work of dispatchers and pilots making it possible to transmit data from onboard sensors during the flight and receive instructions from the ground.

In simple terms, an aviation transponder is a two-way radio communication device that performs two functions:

  1. Respond to requests from ground stations: when a dispatcher requests data, the transponder automatically responds. Such requests for data are also called “interrogation”; and 
  2. Act as an aircraft’s radio beacon: in this mode, the transponder periodically sends information about itself (e.g. its location or speed).

There are different generations, or modes, of transponders. All of them were created for different purposes and feature distinctive signal structures, although later modes support all functions performed by earlier ones (even though their signals are incompatible). There are five main modes:

  • Mode A only transmits the aircraft identification number. This number can be hardcoded into the transponder or assigned by a dispatcher prior to takeoff. In practice, it was used only to determine the airport currently accommodating a specific airplane.
  • Mode C was created later; it tracks not only the aircraft ID but also its flight altitude. Its main advantage is the possibility to get the plane’s altitude automatically, without asking the pilot;
  • Mode S is a modern mode currently used by 99% of airplanes. It allows not only to receive data from onboard sensors, but also send data back to the airplane. This mode ensures full two-way communication between the aircraft and ground stations. The ADS-B protocol discussed below is a part of this mode; and 
  • Mode 4 and Mode 5 are more advanced and used exclusively by military forces. Unlike the above-listed modes, both of them are protected much better, and it’s not possible to tamper with them.

Modes B and D were not included in this list since their existence was brief, and they are irrelevant to the subject of this article.

info

You can buy your own transponder-they are available on eBay at a cost of up to five thousand dollars.

ADS-B

According to the Mode S description, messages transmitted over this protocol are sent by the transponder in response to requests from a ground dispatcher, except for ADS-B (Automatic Dependent Surveillance – Broadcast). The word “Broadcast” means that such messages are sent to everyone (i.e. not just one specific recipient), which enables you to receive them.

Some researchers consider ADS-B a separate transponder operation mode, similar to Modes A, C, or S. However, it’s actually just a part of the larger Mode S. An ADS-B message is simply a Mode S message of type 17.

Types of Mode S messages

This article discusses only ADS-B (type 17), but it might be useful to know other types of Mode S messages as well:

  • All-call reply (type 11) – this message transmits the unique 24-bit identifier of the transponder in response to an operator’s request. This number is usually hardcoded at the factory and cannot be changed (although for military purposes, it actually can);
  • ACAS short and long replies (type 0/16) – these messages are used to prevent collisions between aircraft. If a transponder detects another aircraft nearby, it sends an alert to other systems whose purpose is to prevent mid-air collisions;
  • Altitude and identity replies (type 4/5) – this message contains data about the altitude and callsign (often referred to as squawk code, which is manually entered by the pilot prior to takeoff); and 
  • Comm-B (type 20/21) – these messages include readings from onboard sensors, planned routes, and other data that can be useful for aircraft handling.

ACAS operates in a particularly cunning way, but this is beyond the scope of this article.

All Mode S messages are transmitted to the aircraft at 1030 MHz and to the ground at 1090 MHz.

The radio transmission isn’t encrypted and contains plenty of interesting information about the aircraft’s location, altitude, speed, and other parameters. This resulted in the creation of such services as Flightradar24 that make flight information publicly available for free. These services gather data from numerous sensors installed worldwide by volunteers. You can also become a volunteer; all you have to do is state your willingness and obtain a sensor from the service providers for subsequent installation.

Physical structure of the signal

Similar to other Mode S signals, ADS-B signals are transmitted by the aircraft at 1090 MHz. The second frequency, 1030 MHz (uplink), isn’t required because ADS-B signals are sent without requests.

Pulse-Position Modulation (PPM) is used for encoding. Essentially, bits are transmitted into the air, and to read them, you have to take a sample every N microseconds. The image below clearly illustrates this process.

PPM (source: Wikipedia)
PPM (source: Wikipedia)

In ADS-B, each bit lasts 0.5 microseconds; accordingly, samples should be taken every 0.5 microseconds to determine whether each bit has a high or low level. These levels are then recorded and converted into bytes to reconstruct the original message. However, this is theory; in practice, various issues arise (see below).

Packet structure

If you receive the data ‘as is’, you’ll get just a mess of bits; useful information still has to be extracted from them. The transmitted data have a very clear structure: if you notice its constant parts in the data stream, you can get the entire packet.

The packet consists of a preamble and actual data. As can be seen above, the preamble lasts for 8 microseconds and is followed by data lasting for 56 or 112 microseconds.

Taking that all aircraft broadcast at the same frequency and signals from them can arrive simultaneously, the preamble is of particular importance. The issue related to lost overlapping signals is resolved quite simply: if something wasn’t picked by one receiver, another receiver will pick it up. Numerous receivers cover all inhabited areas on Earth; therefore, if a specific signal is too weak for one receiver, it will be strong enough to be picked up by another one and won’t be lost. Of course, this approach does not guarantee that all signals are received, but this isn’t necessary since the signals are repeated on a regular basis, and losing some of them won’t cause significant problems.

I’ve already mentioned that each bit is encoded to last for 0.5 microseconds, and this is true. However, to simplify reception, a conventionality was introduced: one actual bit is encoded as two bits 0.5 microseconds each. A one is coded as 1 and 0, while a zero is coded as 0 and 1 (i.e. 1011 appears as 10011010). This doesn’t complicate the receiver but protects against interference and allows reliable signal capture. Without this modification, transmitting several zeros would look like silence on the air, and this method ensures that the receiver always clearly sees the signal, even when zeros are transmitted.

Data structure

Imagine that you have decoded a signal and found a message within it. Now you have to decode the useful data block and filter out unnecessary messages (i.e. all Mode S messages except ADS-B).

ADS-B fields
ADS-B fields

The length of the message you are interested in is 112 microseconds, which equals exactly 112 bits (thanks to two-bit encoding!), and it’s divided into five main blocks:

  1. DF (Downlink Format) – transmission format code, 5 bits. For ADS-B, its value is always 17;
  2. CA (Transponder capability) – transponder type and its capability level, 3 bits. This field tells the dispatcher what data can be requested from this transponder. The field can have values 0, 4, 5, or 6; values 1-3 and 7 are reserved for future use. Value 0 indicates a first-level transponder that typically doesn’t have ACAS (collision avoidance system). Value 4 indicates a second-level or more advanced transponder that doesn’t have ACAS, but can transmit altitude (i.e. supports Mode C and Mode S). Values 5 and 6 are similar to 4 but indicate that the transponder supports ACAS that can be either enabled (6) or disabled (5);
  3. ICAO – unique aircraft identifier, 24 bits. This number identifies the signal sender. It’s embedded at the factory once and forever and doesn’t change during operation (although some individuals can alter it). In addition, military transponders don’t obey civil rules; so, anything could be there;
  4. ME (Message) – actual payload containing data about altitude, speed, or other factors, 56 bits in length (to be examined in more detail below); and 
  5. PI (Parity/Interrogator ID) – checksum, 24 bits.

ME field

The ME field is of special interest because it contains coordinates, flight speed, altitude, and other data from onboard sensors. 56 bits aren’t sufficient to transmit all this information at once; so, each message has its own type indicated by the first five bits in this field. It’s like a nesting doll: there is a specific format for Mode S messages indicating ADS-B, and another format within ADS-B specifying what data are contained inside.

In total, ADS-B supports 31 types of data, but let’s focus on the most important ones.

Code 1-4: a message containing identification data. It includes the callsign and other registration-related properties (e.g. light or heavy aircraft). These callsigns are displayed by airport terminals and represent flight numbers. A decoded message looks like this:

ME : ADSB Msg Type : (4) Aircraft Identification and Category
CAT: Aircraft Cat : (0:0) No ADS-B Emitter Category Information
flight Number : SIA224
Wake Type : (TC:4 CAT:0) - No Information Provided

Code 5-8: ground position. These data are normally used to find out the aircraft location and runway used by it. The message can include latitude, longitude, speed, and movement direction. An example of a decoded message:

ME : ADSB Msg Type : (7) Surface Position
Super Sonic? : No
velocity : 0.00
EW/NS VEL : (East/west: 0) (North/South: 0)
heading : 253.12
Before Decoding : Half of vehicle location
UTC Sync? : false
CPR Frame : Odd
CPR latitude : 8675
CPR longitude : 17674

Code 9-19: position in the air (usually transmitted together with altitude). Important: you won’t be able to find a familiar latitude and longitude in the example below because it uses a short notation of coordinates instead of the normal one. I will explain how to decode with such coordinates a bit later.

ME : ADSB Msg Type : (14) Airborne Position (with Barometric altitude)
Containment Radius: 1852.00 metres
Surveillance : (status:0) No condition information
NIC Supplement B : 0
Nav Integrity : 5
AC: altitude : 3100 feet (q bit: false, m bit: false)
Before Decoding : Half of vehicle location
UTC Sync? : true
CPR Frame : Odd
CPR latitude : 101906
CPR longitude : 103292

Code 19: aircraft speed.

ME : ADSB Msg Type : (19) Airborne velocity
SUB: Sub Type : 3
Intent Change : false
IFR Capable : true
Nav Accuracy Cat : 0
heading : 8.44
Super Sonic? : No
velocity : 136.00
EW/NS VEL : (East/west: 0) (North/South: 0)
Vertical Rate : -768
HAE Delta : Unavailable

Decoding each message bit by bit can take a while; if you are really interested in their structure, I suggest to look for ready-made ADS-B parsers on GitHub. At this point, I won’t delve into the structure of such messages because I am not going to transmit anything yet. Let’s put the protocol details aside for now and move on.

CPR: how to complicate a simple thing

To accurately determine coordinates, two values are typically used: latitude and longitude. A 32-bit float ensures precision up to seven decimal places, which translates into coordinates with an accuracy of a few centimeters. If you slightly reduce the accuracy (to tens of centimeters), then two such values can fit into the 56 bits of a message without the need to employ complex compact coordinate systems. For an aircraft flying faster than 100 m/s, accuracy in the range of tens of centimeters is enormous, and it’s hard to understand the reasons guiding protocol developers.

Nevertheless, coordinates are recorded using the CPR (Compact Position Reporting) format. As its name suggests, the protocol was designed for compact transmission of coordinates. You’ve seen some of such data in the sample coordinate signal provided above. Since compressing a large amount of data into a small space is impossible, these data are split into parts and sent in two batches: the packets are called “even” and “odd.” How can one get ‘normal’ coordinates from them? Let me show you!

Imagine that all aircraft fly in 2D space. This space is divided into two grids with different parameters – an even grid and an odd one. The even grid is 4×4; while the odd grid, 5×5.

Let’s say you want to transmit the location of an aircraft whose coordinates in a 16×16 grid are (9,7). If there were just one grid, you could simply send 9 and 7, and operators would find the location on their map. However, CPR actually uses two grids.

Grids
Grids

In such grids, your position (9,7) is indicated as (1,3) in the even grid (left) and (4,2) in the odd grid (right). When operators receive both messages, they have to superimpose them on both grids.

Grids 2
Grids 2

If you superimpose these two grids with the received coordinates, you’ll find the object at the point of intersection.

Grids 3
Grids 3

I have described this algorithm without complex mathematical calculations so that you can understand how actual coordinates are restored from the two components. The real grid is different from this example and looks as shown below.

Real grid
Real grid

A simple way to receive ADS-B

Now that you are familiar with the main components of the protocol, let’s try to receive a real signal. To capture any such signal, you’ll need three basic items: an antenna, a receiver, and a PC.

Antenna

Let’s start with the most important item essential for any radio communication: antenna. Its selection depends on many factors, including frequency, signal directionality, and environment it’s transmitted through. The signal you are looking for is transmitted at 1090 MHz and will be received outdoors.

The simplest (although less efficient) option is a whip antenna that can be assembled using a piece of metal wire. Its length must be calculated accurately to match the signal frequency. The antenna length depends on the wavelength you want to receive. Wavelength is the distance between two adjacent signal ‘peaks’ (see the image below).

Wavelength
Wavelength

Lambda (λ) is the wavelength; it can be computed based on the frequency using the formula λ = C/f where C is the speed of light and f is the signal frequency. For 1090 MHz, it’s approximately 27.5 cm.

If you use a metal rod of this length, you’ll get what is called a full-wave antenna. To get a half-wave or quarter-wave antenna, you can reduce it by half or to one-fourth of its original size, respectively. Such antennas differ in sensitivity; so, I recommend using a half-wave antenna approximately 13.75 cm long.

www

If you want to fully DIY a project, check the guide explaining how to make a dipole antenna for ADS-B using a wine cork and wire.

Assembling an antenna from scratch can be a complicated matter; therefore, I will use a ready-made antenna in this demonstration. Walkie-talkie antennas can be suitable if you receive signals in open areas with minimum interference. I’m going to use a standard coil-loaded whip antenna, which essentially functions like a whip antenna but is shorter due to the coil.

My antenna
My antenna

You can measure the main parameters of an antenna using a special vector analyzer that generates different frequencies and checks how your antenna reacts to them.

NanoVNA
NanoVNA

At first glance, the analyzer output seems complicated, but it’s actually quite simple. To check if your antenna is suitable for a specific frequency, look at the yellow SWR (Standing Wave Ratio) line. This coefficient shows how much of the signal the antenna has transmitted into the air and how much has returned. The less signal returns, the better the antenna performs at a specific frequency.

The device shows that at marker 1 (I set it to 1090 MHz), SWR is 1.73, which is not bad at all. Typically, a decent antenna has an SWR of some 1 (no more than 2).

Receiver

As a receiver, I will use an SDR (Software Defined Radio) dongle. This is a regular radio controlled by special software instead of knobs used in old-fashioned receivers. Any SDR adapter can be used for ADS-B: from the cheapest RTL-SDR to more expensive ones like BladeRF and similar models. Cheaper options cost some $30.

I will use a BladeRF micro: it supports a wide frequency range and features a high sampling rate (to be discussed later).

BladeRF
BladeRF

info

If you don’t have an SDR yet, don’t worry: RTL-SDR costs some $30 and is available in many online stores. Important: this device can receive signals but cannot transmit them.

Putting it all together

Now that you have an antenna and SDR, you have to find a place free from interference and obstacles (I just drove some 10 km from the city). Signals around 1 GHz (which includes ADS-B) barely propagate beyond the horizon. So, if you are far from an airport and are surrounded by obstacles, you might not receive any signals at all.

Enhancing reception

You can add a filter between the antenna and the SDR to reduce noise. Special filters designed for ADS-B can be ordered in China for some $10-15.

To analyze the radio spectrum, you’ll need a special tool: either GQRX for Linux and macOS or SDR# for Windows. On Ubuntu, GQRX can be installed from the official repository:

apt update
apt install -y gqrx

Turn up volume, select your SDR as the input source, and press the large Start button. If everything has been set up correctly, you should hear a loud hissing noise. If so, mute the sound using the Mute button in the bottom right corner.

To set frequency, enter 1.090.000 (which equals 1090 MHz) at the top of the screen. Once you do this, you should see something similar to the screenshot below.

GQRX
GQRX

The short bars in the center are ADS-B signals that clearly stand out against the background noise. If no signals can be seen, adjust the signal gain settings in the Input Controls tab. Alternatively, modify the Plot and WF parameters in the FFT Settings tab or reposition the antenna for better reception.

Dump1090

When you achieve stable signal reception in GQRX, you can move on to the next step.

To receive and decode Mode S signals, I recommend dump1090. This open-source tool demodulates and decodes almost all Mode S signals and even displays them in the form of a neat table.

To install it, you have to clone the project repository from GitHub and build the binary:

git clone https://github.com/antirez/dump1090
cd dump1090
make

The dump1090 binary should appear. If you use an RTL-SDR, you can start dump1090 without any preparations, but I am using a BladeRF, which requires some additional setup.

First, find and install a suitable driver for your SDR (they are available in repositories of most distributions).

Second, you have to flash special firmware to your SDR. For BladeRF, such firmware images are available on the Nuand website: choose a file suitable for your version of BladeRF.

Next, download the program that decodes ADS-B messages and build it:

git clone https://github.com/Nuand/bladeRF-adsb
cd bladeRF-adsb/bladeRF_adsb
make

Flash the firmware to your BladeRF using the bladerf-cli package:

bladeRF-cli -l ~/Downloads/adsbxA4.rbf

After that, run dump1090 in one window and your newly-built bladeRF-adsb in another window:

~/Soft/dump1090/dump1090 --raw --device-type bladerf --bladerf-fpga ''
~/Soft/Blade/bladeRF-adsb

If everything has been set up correctly, you should see multiple hexadecimal lines in the dump1090 window. These are Mode S messages that should be decoded and filtered.

dump1090 output
dump1090 output

If you remove --raw from the dump1090 startup arguments, the signals will be automatically decoded and displayed in a table as shown in the screenshot below.

Mode S signals dump1090
Mode S signals dump1090

The table contains data automatically decoded from CPR: latitude and longitude, aircraft callsign, its speed, altitude, and other information. But for better understanding, let’s decode the received data manually.

A more complicated way to receive ADS-B

To receive the signal manually, you have to demodulate it and then decode the result.

info

Demodulation (signal detection) is a process opposite to signal modulation: the information (modulating) signal is extracted from a high-frequency modulated wave. In simpler terms, demodulation means extracting the signal from high-frequency oscillations.

ADS-B uses PPM (Pulse Position Modulation). To extract the target signal, you have to determine its state (0 or 1) every 0.5 microseconds. Here’s the plan:

  1. Record the signal;
  2. Take samples every 0.5 microseconds;
  3. Convert them into bytes; and 
  4. Decode ADS-B messages.

For convenience, let’s use either Python or a premade set of tools called GNU Radio. On Ubuntu, GNU Radio can be installed as follows:

sudo add-apt-repository ppa:gnuradio/gnuradio-releases -y
sudo apt update
sudo apt install gnuradio -y

Of course, to use GNU Radio, you’ll need drivers for your SDR. Important: SDR won’t be used as the primary signal source; instead, let’s apply different algorithms to the same data and compare results.

Recording signal

After starting GNU Radio, you have to build a basic pipeline. It’s shown in the screenshot below.

Basic pipeline
Basic pipeline

The pipeline consists of five blocks; two of them are Options and Variable. At the very beginning is osmocom Source: it’s responsible for the reception of raw data from SDR. There are plenty of settings, but only five of them are required for your purposes (the example below applies to BladeRF):

  1. Device Argument – arguments passed to SDR. Enter bladerf=0 there;
  2. Ch0 Freq – channel 0 frequency. BladeRF has two channels, but you’ll need only one. Enter the ADS-B frequency, which is 1090 MHz or 1.09 GHz;
  3. RF Gain – sets the receiver sensitivity. I set it to 15 dB. Do not set sensitivity too high: strong signals can damage the radio chain;
  4. Bandwidth – reception channel bandwidth; for ADS-B, it’s 2 MHz; and 
  5. Sample Rate. In simple terms, this is the number of samples per second that SDR takes to digitize the signal. What is it and why is it required? SDR receives an analog signal as input, and it must be digitized for processing. To digitize a signal, samples are taken at regular intervals. The more samples per second, the better, but this requires a more powerful device. The digitization process is shown in the image below.
ADC example
ADC example

The number of bars represents the number of samples; while SPS stands for Samples per Second (i.e. number of samples taken per second). In the samp_rate parameter at the top, I set the sampling rate to 4 MS/s (MegaSamples per Second). This value isn’t random; it’s four times higher than the input signal frequency. According to the Nyquist theorem, sampling rate must be at least twice as high as signal frequency. For ADS-B, you can use sampling rates of 2 and 2.5 MS/s, but higher sampling rates result in better digitization quality.

info

The Nyquist theorem (also known as the Sampling theorem or Kotelnikov’s theorem) is a fundamental principle for digital signal processing that connects continuous and discrete signals. It states that “any function F(t), consisting of frequencies from 0 to f1, can be continuously transmitted with any accuracy using numbers following each other at intervals less than 1 / (2 * f1) seconds.”

Finally, everything has been set up, and you can press the Start button on the top panel in GNU Radio. If everything has been configured correctly, you should see a spectrum similar to the one shown below.

GNU Radio specter
GNU Radio specter

ADS-B signals are shown as stripes at the top of the screenshot. Even though my BladeRF wasn’t calibrated, distortions don’t significantly impact the experiment.

Demodulation

For demodulation, I had to assemble a more sophisticated and exciting scheme in GNU Radio.

Demodulation in GNU Radio
Demodulation in GNU Radio

Let’s go through each block of the scheme so that you understand what’s going on. On the diagram, some inputs and outputs have different colors; these colors indicate different data types:

  • Blue – complex numbers;
  • Orange – floating-point numbers; and 
  • Purple – bytes.

Now let’s examine the blocks.

  1. File Source – a signal source in the form of a file. In this block, you have to select the file recorded during signal reception. For the purposes of my experiment, this block replaces the real SDR;
  2. Throttle – an element that slows down the inflow of signals into the scheme. Without this block, the processing would be performed too quickly, and won’t see nothing;
  3. Waterfall – signal visualization. It’s represented by the yellow-blue pixel mush in the above screenshot;
  4. QT GUI Time Sink plots the time-signal dependency graph;
  5. Complex To Mag – a block that converts complex numbers into floating-point numbers. It has blue input values and orange output values;
  6. Threshold – the most important block in the demodulation scheme that separates signals from noise. I set its values to low 13m and high 13m: these are signal amplitudes that must be separated;

    How to determine sensitivity threshold

    To find out the threshold of your SDR, you have to assemble an additional scheme. On the right side, search for blocks Peak Detector and Time Sink. In the Time Sink block, set three inputs; if Peak Detector lacks a Debug port, then only two. After assembling this scheme, you’ll see the amplitude corresponding to useful signal peaks.

  7. Symbol Sync – another important synchronization block for symbols. As mentioned earlier, I chose a sampling rate of 4 MSPS because of this sync block whose minimum value for the Samples per Symbol parameter is 2; accordingly, the input signal’s sampling rate must be at least 4 MSPS. If you use a less powerful receiver (e.g. RTL-SDR), you can disable Symbol Sync and use the Keep 1 in N block (highlighted in gray in the diagram above). Using the synchronization block, I extracted from a raw recordings 18 good packets out of 31; while without it, only 11 out of 29. In other words, proper synchronization provides you with significantly more valid data;

  8. Float to Char – this block converts floating-point numbers to characters and sends them to the File Sink; and

  9. File Sink saves bytes to a file for subsequent analysis.

Now that you are familiar with the scheme, you can activate it. Once it’s activated, you should see something like the screenshot below.

Demodulation scheme in action
Demodulation scheme in action

On top is Waterfall; you can use it to visually search for signals. Below it is Time Sink after synchronization, and you can see two different signals: red (error signal) and blue (time-corrected signal) ones. These signals look somewhat digital, but the true digital signal appears on the third graph (processed by the Threshold block). The lowest graph shows the same original signal as in the first graph, but processed by the Threshold block.

File analysis

After demodulation, the file looks like this.

000717e0: 0000 0100 0100 0000 0000 0001 0000 0000 ................
000717f0: 0101 0000 0100 0000 0000 0101 0000 0100 ................
00071800: 0101 0001 0000 0100 0101 0000 0101 0001 ................
00071810: 0000 0101 0001 0001 0100 0101 0000 0100 ................
00071820: 0100 0100 0100 0101 0001 0001 0001 0000 ................
00071830: 0100 0100 0100 0100 0101 0000 0100 0100 ................
00071840: 0100 0001 0101 0000 0100 0100 0100 0100 ................
00071850: 0100 0100 0100 0100 0100 0100 0100 0100 ................
00071860: 0100 0100 0100 0100 0100 0100 0100 0100 ................
00071870: 0100 0100 0100 0100 0100 0100 0100 0101 ................

Let’s analyze it to identify Mode S packet preambles within the data stream. For this purpose, I wrote several functions in Python.

import requests
def read_binary_file(filename):
with open(filename, 'rb') as file:
return [int(byte) for byte in file.read()]
def find_pattern(data, pattern):
pattern_length = len(pattern)
matches = []
for i in range(len(data) - pattern_length + 1):
if data[i:i+pattern_length] == pattern:
matches.append(i)
return matches

The first function simply reads the file; while the second one searches for a specified pattern (the preamble). However, prior to searches, you have to convert double bits (the above-mentioned repetitions that make each bit last 1 microsecond instead of 0.5 microseconds) into single ones. The next function performs this task:

def decode_adsb(bits):
decoded = []
for i in range(0, len(bits), 2):
if bits[i:i+2] == [1, 0]:
decoded.append(1)
elif bits[i:i+2] == [0, 1]:
decoded.append(0)
return decoded

Reading the file and finding all preambles:

data = read_binary_file("decoded2.bin")
pattern = [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
matches = find_pattern(data, pattern)
print("Total matches: ", len(matches))
good = 0
bad = 0

In this function, pattern is the desired preamble. If you want, you can scroll up to the beginning of the article and compare the figures. Since this preamble indicates any Mode S signal, not just ADS-B, there might be 56-bit signals as well. Support for them is implemented as follows:

for match_index in matches:
try:
start_index = match_index + len(pattern)
end_index = start_index + 224
end_index2 = start_index + 112
extracted_bits = data[start_index:end_index]
extracted_bits2 = data[start_index:end_index2]
decoded_bits = decode_adsb(extracted_bits)
decoded_bits2 = decode_adsb(extracted_bits2)
hex_value = hex(int(''.join(map(str, decoded_bits)), 2)).replace('0x','')
hex_value2 = hex(int(''.join(map(str, decoded_bits2)), 2)).replace('0x','')
if len(hex_value) == 28:
response = requests.get(f"http://jasonplayne.com:8080/decode?packet={hex_value}&refLat=&refLon=")
if "Failed to decode." in response.text:
bad += 1
else:
good += 1
print(response.text)
if len(hex_value2) == 14:
response = requests.get(f"http://jasonplayne.com:8080/decode?packet={hex_value}&refLat=&refLon=")
if "Failed to decode." in response.text:
bad += 1
else:
good += 1
print(response.text)
except:
pass
print("Total good/bad: ", good, "/", bad)

As you can see from the code, I extract ADS-B packets and pass them to an external service for decoding instead of creating a custom parser for all packet types. You can also open this site in your browser to see various sample packets and get more information on Mode S and ADS-B.

If everything goes well, you’ll see an output similar to the following:

8d89617999086e99b8480ab9e174
MODE S Packet:
Length : 56 bits
Frame : 8d89617999086e99b8480ab9e174
DF: Downlink Format : (17) ADS-B
CA: Plane Mode S Cap: (5) Level 2,3 or 4. can set code 7. is airborne
VS: Vertical status : Airborne
AA: ICAO : 896179
ME : ADSB Msg Type : (19) Airborne velocity
SUB: Sub Type : 1
Intent Change : false
IFR Capable : false
Nav Accuracy Cat : 1
heading : 151.88
Super Sonic? : No
velocity : 232.65
EW/NS VEL : (East/west: 109) (North/South: -204)
Vertical Rate : -1088
HAE Delta : 225 (Height Above Ellipsoid)

I received signals containing aircraft speed information, but you can get a lot more of them. In my case, DF is 17 (ADS-B); while the transponder’s ICAO code is 896179.

Now you are familiar with basic technical aspects of ADS-B and radio signal decoding. In the next article, I am going to create an imaginary airplane, generate its telemetry signals, transmit them, receive the transmitted data, and decode them.

See you soon and good luck in your experiments!


Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>