Sky Sleuth

Curious about the planes that fly over your home? With some simple and affordable equipment, you can receive their ADS-B signals and uncover detailed flight information.

If a plane is flying above your house, do you ever wonder about its origin and destination? While there are many websites that provide this information (see Figure 1 for an example), you don’t actually need them. In many countries around the world, various aircraft types (primarily commercial passenger carriers) are required to be equipped with an Automatic Dependent Surveillance-Broadcast (ADS-B) transmitter. ADS-B provides air traffic controllers with more information about the aircraft than what radar can offer. With a simple antenna and an RTL-SDR USB dongle, anyone can capture these signals and process them on a computer.

F1_airplanes_live.tif
Figure 1: Planes are tracked on various websites, such as airplanes.live.

ADS-B works automatically, broadcasting the flight state periodically without input from the pilot or air traffic controller. Typically, the aircraft transmits its position, altitude, and speed, along with its call sign for identification. This is how those websites are able to show you planes on a map: They use data from a network of computers equipped with an ADS-B receiver, which is then visualized and supplemented with external data. For more in-depth details about ADS-B and decoding signals, consider reading The 1090 Megahertz Riddle, which you can download for free.

Hardware Requirements

ADS-B equipment on planes emits radio waves on a frequency of 1,090MHz, using a sample rate of 2 million samples per second (MS/s) to transmit data bits. To receive this, you need a software-defined radio (SDR) that works within this frequency range and can handle the sample rate. Some companies offer SDR sticks specifically optimized for ADS-B signals, but any SDR stick meeting these specifications will suffice. You can find receive-only SDR sticks for EUR30-50 (roughly $35-60 or £26-45): You don’t need to transmit. The well-known RTL-SDR dongle, with a frequency range of 24 to 1,766MHz and a maximum sample rate of 2.8MS/s, is a good option. Choosing a device with a higher sampling rate immediately increases the cost to a few hundred euros.

You also need an antenna that’s tuned to the 1,090MHz frequency. Again, some companies offer antennas specifically designed for ADS-B, costing around EUR50-70 ($60-80 or £45-60). These are typically outdoor antennas, which come with weather protection. However, for indoor use, you can easily create your own antenna. Given that the carrier frequency of ADS-B is 1,090MHz, its wavelength is 27.5cm (300/1,090). A popular antenna design is a half-wavelength (13.75cm) dipole.

For instance, the RTL-SDR dongle is available in a kit featuring a telescopic dipole antenna on a tripod. Simply extend two parts of the dipole to 6.9cm and position it vertically (because ADS-B transmissions are vertically polarized) to tune it to the 1,090MHz signals (see Figure 2). If you don’t have this kit, just build your own antenna using two wires of this length and a BNC adapter with two banana jacks. Unscrew the jacks, insert the stripped wire end into the hole, and tighten it to secure the wire (see Figure 3).

F2_rtl-sdr_antenna.tif
Figure 2: The RTL-SDR telescopic dipole extended for the half-wavelength of 1,090MHz radio waves and aligned vertically, next to the Raspberry Pi with an RTL-SDR dongle.
F3_diy_antenna.tif
Figure 3: I made my own 1,090MHz antenna with some 22 AWG solid-core wire and a BNC adapter with banana jacks.

Whichever antenna you choose, you need to connect it to your SDR dongle via a coaxial cable with the appropriate connector. The RTL-SDR dipole kit comes with a coaxial cable with an SMA male connector, which fits on the SMA female connector of the RTL-SDR dongle. If you make your own antenna, you’ll need a coaxial cable with a BNC connector on one end to connect to the adapter with banana jacks and an SMA male connector on the other end to connect to the dongle. Connector adapters, for instance from BNC to SMA, are also available.

There are still a lot of optimizations possible on the hardware side, and I haven’t even discussed optimal antenna placement yet. However, this basic setup will be good enough, even with an indoor antenna, for identifying which planes are flying over your house. Later, I’ll provide some tips to achieve optimal reception, especially if you plan to feed ADS-B data to a website.

Preparations

With planes constantly flying around, you’ll need a computer that can stay powered on 24/7 to continuously receive ADS-B data. A Raspberry Pi is ideal for this purpose. For this article, I’ve used a Raspberry Pi 3B+ with 1GB RAM, running Raspberry Pi OS 12 (“Bookworm”). I’ll run the Docker container distributed by the SDR Enthusiasts project, which provides a docker-install script that helps you install Docker and prepare your system. However, at the time of writing, it wasn’t yet adapted to Raspberry Pi OS 13 (“Trixie”).

If you don’t want to use this script, you can instead manually install Docker and Docker Compose, but there’s one critical step you need to take. If the RTL-SDR kernel module is loaded by the host kernel, it takes ownership of the device and prevents access in the container because the device is “busy.” You need to prevent this by following the steps for blacklisting kernel modules on the SDR Enthusiast’s website (the docker-install script already takes care of this). Afterwards, reboot your Raspberry Pi.

Now create a directory for the Docker Compose file and the data files and navigate to it:

sudo mkdir -p -m 777 /opt/adsb
cd /opt/adsb

Create and then edit a file named .env within this directory, which will hold some environment variables for configuring the ADS-B container. Start by specifying the serial number of your SDR dongle. To find this, connect the dongle to a USB port and check the dmesg command’s output for new USB devices. For the RTL-SDR v3 dongle I used, this shows a product RTL2838UHIDIR, a manufacturer Realtek, and a serial number 00000001. This means I can specify the serial number as follows in the .env file:

ADSB_SDR_SERIAL=1 

Adapt this to your own situation. Specifying the serial number is particularly important if you have multiple SDR dongles connected, since many dongles of the same type ship with the same serial number. The SDR Enthusiasts project provides a web page on how to change the serial number of your devices, which lets you distinguish them and point the container to the correct one.

Next, generate a Universally Unique Identifier (UUID), which is a random value used to identify yourself to the feeding servers you’ll send your ADS-B data to (feeding is optional). You’ll get a UUID by typing:

cat /proc/sys/kernel/random/uuid

Then add this value to the .env file:

ULTRAFEEDER_UUID=53756995-d216-4b11-b025-e7fd127f3cf9

(Don’t copy the example value shown above. Use your own generated UUID, as this should be unique for each feeder station.) 

Adding Your Location

Next, the container needs your location: not only your latitude and longitude, but also your (or, more correctly, your antenna’s) altitude, which is an important parameter that influences your range. You can find this information on the Free Map Tools Elevation Finder. Pick your location on the map, and you’ll get your elevation in meters and feet, along with your latitude and longitude. Then put these values in the .env file:

FEEDER_ALT_M=58
FEEDER_LAT=50.87867
FEEDER_LONG=4.92690

Instead of FEEDER_ALT_M, you can use FEEDER_ALT_FT to set the height in feet. Either way, altitude is measured above mean sea level. If your antenna is on the second floor, in your attic, or mounted on a pole (which will all improve reception), add its height above the ground to the number from the Elevation Finder page, as you’re specifying the antenna’s height.

Next, configure the software to use the correct time zone and include a name for your location:

FEEDER_TZ=Europe/Brussels
FEEDER_NAME=Attenrode 

The latter is solely used for the title of the map’s web page; it isn’t shared in any way with external servers.

Showing Your Range

There’s only one thing left to add to the .env file, which you need to show the theoretical range of your location based on obstacles and Earth’s curvature. As the 1,090MHz radio waves transmitted by planes only reach you with a direct line of sight, this means there’s a maximum range. The website HeyWhatsThat can create an overlay on your map that shows this range.

Navigate to heywhatsthat.­com and click on New panorama. Choose your location by marking your position on the map, searching for your address, or entering your latitude and longitude. Then specify your elevation (in feet, but you can change this to meters below the map) above the ground or above sea level, or leave this blank for the default 6ft (or 2m) above ground level. Give your location a title and click on Submit request.

Wait for a few minutes until the request has been processed. Then you get a panorama view, with a map beneath it. Scroll down to the map and click Up in the Air at the top-right corner of the map. After zooming out, the map reveals a yellow line indicating how far you can receive planes flying 10,000ft above the ground and a blue line depicting the theoretical range of planes flying 30,000ft above the ground (Figure 4).

F4_heywhatsthat_range.tif
Figure 4: Discover how far you can receive planes’ ADS-B signals with HeyWhatsThat [6].

At the top of the page, HeyWhatsThat provides a URL with an ID after ?view=. Copy this ID and enter it in the .env file as follows, together with the altitudes in meters for which you want to see the theoretical range:

FEEDER_HEYWHATSTHAT_ID=MXMV5WE9
FEEDER_HEYWHATSTHAT_ALTS=3000,12000

Your application environment now has all the information it needs.

Starting the Container

While still in the /opt/adsb directory, create a docker-compose.yml file defining the ultrafeeder container to start. An example is available on the SDR Enthusiast’s GitBook site. Start from this example, but review it line by line to customize it to your needs. The file includes extensive documentation within comments (after the # characters).

You’ll find that the Docker Compose file uses the environment variables you’ve put in the .env file. The most important changes you probably want to make are in the ULTRAFEEDER_CONFIG variable. If you don’t want to share your received ADS-B data with any websites, you can remove or comment out all the indented lines below this variable.

Once you’ve saved the docker-compose.yml file, start the container with:

docker-compose up -d

After the command finishes, review the logs of the running container using: 

docker compose logs -f

Watching Planes

If you don’t see any errors in the logs, visit http://­IP:8080 (with your Raspberry Pi’s IP address) in your web browser. Some planes should appear on a map centered around your location, along with the theoretical range and concentric circles indicating 50km, 100km, 150km, and 200km distances. This is the tar1090 web interface visualizing data from the ADS-B decoder. You can zoom in and out on the map, and the planes are color-coded by altitude according to the scale at the bottom.

Clicking on a plane displays its flight path on the map, in a corresponding color based on its altitude, indicating whether it’s ascending or descending (Figure 5). This also opens a sidebar at the left with information about the selected plane. Some of this information comes from your SDR receiver, including its speed, altitude, and call sign. Other information is extracted from the FlightAware website, which adds the type and a picture of the plane, its country and registration, as well as its departure and destination. Clicking on the plane’s registration opens its FlightAware page with even more details, such as the full flight path and even past and upcoming flights.

F5_flight_paths.tif
Figure 5: You can follow the flight paths of any planes in your range.

Map Options

On the right, a table lists all planes from which ADS-B data is received, with some basic information such as the country, call sign, route, type, altitude, speed, and distance. You can customize which columns are displayed in the Columns tab. Clicking on a call sign opens the corresponding FlightAware page. If you receive a lot of planes, go to the Filters tab to filter by altitude, call sign, type, registration, route, category, and other criteria. After typing a filter text and clicking the Filter button, only matching planes appear in the table and on the map.

Along the top and right sides of the map, you’ll find several buttons. The > and < buttons expand the map or the table to cover the entire web page. Clicking on the map layers icon lets you choose map tiles and add or remove features like the theoretical range outline and range rings. You can even add overlays with rain clouds (RainViewer Radar) or with airports and restricted airspaces (OpenAIP TMS). The gear icon opens a dialog with some settings for units, labels, and more layout options. The Table 1 explains the remaining letter buttons and what you can do with them.

Table 1: Letter Buttons in tar1090

U

Shows only military planes

H

Resets the map to your home location

T

Toggles between showing all tracks and only the track of the selected plane

L

Shows a label with the call sign and route next to selected planes

O

Includes the speed and altitude in the labels

K

Provides a label on points of the selected plane’s track to view its speed and altitude at various times

V

Restricts the table to the planes currently visible on the map

M

Lets you select (and view the tracks of) multiple planes

P

Shows planes that have flown out of sight of your SDR receiver

I

Shows only the selected plane

F

Follows the currently selected plane (keeping the map centered on the plane)

R

Follows a random plane

Statistics and Other Useful Graphs

In the right sidebar with the table, clicking on the link next to Stats available presents various performance graphs that help you optimize your setup. For instance, when I moved the antenna from one side of the house on the ground floor to the other side of the house on the first floor, the range graph clearly depicted an improved maximum range (Figure 6). Similarly, you can analyze the effects of using a different antenna, adding a filter, and other optimizations.

F6_range_graph.tif
Figure 6: Use performance graphs to analyze the effects of changes to your ADS-B setup.

The tar1090 web interface has some useful graphs as well. For instance, adding
?pTracks after the URL shows all the plane tracks from the last 24 hours, adding all those planes to the table in the right sidebar. Adding ?heatmap&realheat instead reveals a heat map of all received signals over the past 24 hours (Figure 7). If you want to rewatch all planes in a specific period, add ?replay and set the date, time, and speed for a replay.

F7_heatmap.tif
Figure 7: tar1090 can generate a heat map of all received ADS-B signals over the past 24 hours.

Improving Reception

Once your basic ADS-B receiver setup is operational and you seek further improvements in reception, several optimizations are possible. The first, and probably cheapest, optimization is antenna placement. Elevating your antenna increases the area from which it can receive signals. If you want to stay indoors, move your antenna to a higher floor, preferably next to a window. Let your ADS-B receiver run for 24 hours with the new antenna position and then check tar1090’s performance graphs for the impact of this change.

For optimal reception, consider placing your antenna outdoors. This will eliminate walls, which attenuate the radio signals. Even then you need to choose the antenna location carefully to avoid signal-attenuating structures like trees and buildings. Higher outdoor installations provide greater range. Also, make sure that the antenna can withstand the weather; you probably need to buy one that’s specifically built for outdoor situations, such as a fiberglass antenna with an N connector.

Additionally, wherever you place the antenna, maintain a distance from any other antennas or metal objects. Ideally, ensure clear space of two times the frequency’s wavelength around the antenna. For 1,090MHz, this means you need to clear a space of at least 55cm. Another point of attention is the coaxial cable that connects the antenna to your SDR dongle. A long cable causes more signal degradation, so use the shortest possible, low-attenuation cable.

Using a better antenna could also improve range, but even if your antenna isn’t exactly the correct length, it can still perform quite well. You can find various DIY antenna designs for ADS-B on the Internet, and you can buy 1,090MHz antennas as well if you don’t trust your DIY skills or need a weatherproof antenna.

If your range still disappoints after all previous steps, there may be nearby powerful transmitters that generate noise near the 1,090MHz band. Introducing a bandpass filter to eliminate noise from neighboring frequencies can help, though this always attenuates the signal. Use such a filter only when it’s absolutely necessary.

Helping the OpenSky Network

It isn’t required, but you can also contribute by feeding your ADS-B receiver data to various websites that aggregate data from multiple feeders. This way you support a global network of plane enthusiasts. There are several networks you can contribute to, and the SDR Enthusiasts documentation covers how to configure many of them. You can even let the ultrafeeder feed multiple networks simultaneously.

As an example, you could feed your ADS-B data to the OpenSky Network , a Switzerland-based nonprofit association that’s dedicated to improving airspace security and efficiency through open data. Because it aggregates ADS-B data from around the world, you can see full trajectories of numerous planes (Figure 8) on its map. By the way, this and many similar websites also use tar1090 to visualize all flights.

F8_trajectory_opensky.tif
Figure 8: Follow the trajectory of any plane around the world on the OpenSky Network.

First, register for an account on the OpenSky Network website, which is free. Verify your email address through the link sent to it. Then obtain a serial number from the OpenSky Network by running a temporary container. Add an environment variable with your OpenSky username to your ultrafeeder’s .env file:

OPENSKY_USERNAME=YOUR_OPENSKY_USERNAME

(Replace YOUR_OPENSKY_USERNAME with the username registered on the OpenSky Network.) Next, source the environment file and run the temporary container, as shown in Listing 1. The container’s output includes a line like this:

[opensky-feeder] [INFO] [SERIAL] Got a new serial number: XXXX

Listing 1: Obtaining a Serial Number

01 source ./.env
02 timeout 60s docker run ‑‑rm ‑it \
03   ‑e LAT=${FEEDER_LAT}   ‑e LONG=${FEEDER_LONG} \
04   ‑e ALT=${FEEDER_ALT_M} ‑e BEASTHOST=ultrafeeder \
05   ‑e OPENSKY_USERNAME=${OPENSKY_USERNAME} \
06   ghcr.io/sdr‑enthusiasts/docker‑opensky‑network:latest

The number XXXX (which can be a negative number) is your serial number. Insert this into your .env file:

OPENSKY_SERIAL=XXXX

Then add the container definition at the end of your docker-compose.yml file, as shown in Listing 2, and start it alongside the ultrafeeder container with docker-compose up -d. After this, you should see in the logs (docker-compose logs -f) that the container sends your ADS-B data to the OpenSky Network.

Listing 2: OpenSky Network Container Definition

01   opensky:
02     image: ghcr.io/sdr‑enthusiasts/docker‑opensky‑network:latest
03     container_name: opensky
04     restart: unless‑stopped
05     environment:
06       ‑ TZ=${FEEDER_TZ}
07       ‑ BEASTHOST=ultrafeeder
08       ‑ LAT=${FEEDER_LAT}
09       ‑ LONG=${FEEDER_LONG}
10       ‑ ALT=${FEEDER_ALT_M}
11       ‑ OPENSKY_USERNAME=${OPENSKY_USERNAME}
12       ‑ OPENSKY_SERIAL=${OPENSKY_SERIAL}
13     tmpfs:
14       ‑ /run:exec,size=64M
15       ‑ /var/log

Conclusion

It’s oddly satisfying to observe planes flying above your home, especially knowing that you’re doing this without any expensive equipment. If you set up an ADS-B receiver out of sheer curiosity, consider feeding the data to a nonprofit network such as the OpenSky Network: This way you support air traffic researchers, NGOs, and journalists who use the flight data for various purposes. For example, they can research GPS jamming activities (see the “How to Detect Aircraft GPS Jamming” box).

How to Detect Aircraft GPS Jamming

One of the things that aircraft report in their ADS-B data is the accuracy of their navigation system. John Wiseman used this by extracting this data from ADS-B Exchange and showing it on a map on his website GPSJAM. Parts of the map where more than 98 percent of all aircraft reported good navigation accuracy are shown in green, parts of the map where between 2 percent and 10 percent of aircraft reported low navigation accuracy are shown in yellow, and parts where more than 10 percent of aircraft reported low navigation accuracy are shown in red. This doesn’t tell you what causes this low accuracy, but the red parts seem to be in regions where it’s known or suspected that GPS jamming is occurring, such as at the borders between Russia and Europe (see Figure 9).
F9_gps_jamming.tif
Figure 9: John Wiseman’s gpsjam.org website maintains a map of suspected GPS jamming activity.

If you want to know more about ADS-B or try out other projects, you should check out the Awesome ADS-B website. For example, ADSB Feeder Image is an alternative to SDR Enthusiasts’ ultrafeeder Docker container. ADSB Feeder Image runs the same tar1090 web interface and has the same performance graphs, but it adds a web-based configuration instead of configuration via environment variables, which some users may prefer.