ChannelSPURIOUS EMISSIONS

Sheet 4 · The written guides

HFDL

At the end, your computer decodes the position reports and messages that aircraft send by shortwave from the middle of an ocean. You can read them on your own message screen, and you can share them with airframes.io if you want to.

Rev A · checked 2026-10-10

Download the Markdown

The Markdown file is the whole guide in plain text. You can give it to a coding agent.

Some links are affiliate links: if you buy through them, I may earn a commission at no extra cost to you. As an Amazon Associate I earn from qualifying purchases. How links work.

Contents

1. What this guide builds

A receiving station for HFDL. HFDL means High Frequency Data Link: aircraft over oceans send position reports and messages by shortwave to ground stations. A free program, dumphfdl, decodes them. This guide gives two complete paths.

  • Path A is the lowest-cost start. One tuned radio listens to one HFDL band at a time.
  • Path B is what I use. One wideband receiver listens to all 12 HFDL bands at the same time.
Path A: one band Path B: every band ◆
Signal HFDL, 2.9 to 21.9 MHz The same
Antenna Small active loop Small active loop
Radio One tuned SDR (Airspy HF+ Discovery, or an RTL-SDR Blog V4) RX-888 Mk II
Decoder One dumphfdl, in a Docker container 12 copies of dumphfdl, one for each band
Computer Raspberry Pi 5, or any 64-bit Linux computer x86 desktop PC, plus a small computer for the message screen
Gives up The other 11 bands. You change band by hand, or a script does it Nothing. It costs more and needs more work
Path A
 loop -- coax -- power injector -- tuned SDR -- USB -- pi (Docker)
                                                        |  dumphfdl container
                                                        |  acars_router    (optional)
                                                        |  ACARS Hub       (optional)
                                                        `-- airframes.io   (optional)

Path B
 loop -- coax -- power injector -- 30 MHz filter -- limiter -- RX-888 Mk II
                                                                   |  USB 3
                                                        hf (x86 PC, ka9q-radio)
                                                          12 band channels
                                                          12 x dumphfdl
                                                                   |  UDP, home network
                                                        pi (Docker)
                                                          acars_router -- ACARS Hub
                                                                `-- airframes.io (optional)

The two computers have these names in this guide: pi runs Docker, and hf runs the wideband receiver.

2. What you need

A part marked ◆ is what I use. Prices are US dollars from the named seller on 2026-10-07, as listed in my full station guide. I did not check them again for this guide. A blank box is for your pencil.

Path A: the lowest-cost path

☐ Part Job Connector Price Note
☐ ◆ MLA-30+ active loop with its power injector Antenna SMA See listing, Amazon The amplifier is in the loop head
☐ Airspy HF+ Discovery Radio, 768 kHz wide See listing See listing dumphfdl is tested on the Airspy HF+ (its README). I do not own one
☐ or: RTL-SDR Blog V4L Radio, the cheapest See listing $37.95, rtl-sdr.com Read the caution below
☐ Raspberry Pi 5, or any 64-bit Linux computer Computer pi USB $175 list for 8 GB (4 GB: $110) The container runs on amd64 and arm64
☐ Raspberry Pi 27 W USB-C power supply, and a microSD card of 32 GB or more Power and storage See seller
☐ RG-6 quad-shield coax, and two F to SMA adapters Loop to injector to radio F and SMA See seller On shortwave, 10 to 20 m of it loses under 1 dB
☐ Snap-on ferrites Both ends of the loop cable, and the USB cable See seller

Caution. A low-cost RTL-SDR radio is the weakest choice for shortwave. The dumphfdl README says normal RTL-SDR radios are not suitable. It calls the RTL-SDR Blog V4 “a decent low-budget option”. The container’s README says V4 radios “work but are not optimal for HF”. The V4 is no longer made. I did not try its replacement, the V4L, on shortwave. Buy the Airspy HF+ Discovery if you can.

Path B: what I use

☐ Part Job Price Note
☐ ◆ MLA-30+ active loop with its power injector Antenna See listing, Amazon The same loop as path A
☐ ◆ Turn Island Systems F3060 low-pass filter In front of the receiver $80, Turn Island Systems Required at 64.8 MS/s
☐ ◆ TAPR RF Limiter Last part before the receiver $20, TAPR Needed if you also transmit
☐ ◆ RX-888 Mk II, 16-bit, 10 kHz to 64 MHz direct All of shortwave at once $152.79, OpenSourceSDRLab, 2026-10-11 Copies exist. Mine is from OpenSourceSDRLab
☐ ◆ x86-64 desktop PC with a USB 3.0 socket on the main board Computer hf Used market Mine is a Core i5-4570 from 2013, bought used
☐ ◆ Raspberry Pi 5, 8 GB Computer pi: the message screen $175 list Optional. Section 9 says what you lose without it
☐ RG-6 quad-shield coax, two F to SMA adapters, short SMA jumpers, ferrites The chain in section 4 See seller

The receiver itself (the PC, ka9q-radio, the gain, the noise test) has its own guide: /guides/shortwave-receiver/. Build that first for path B. This guide then adds everything that is specific to HFDL.

3. Before you start

Skills. You type commands in a terminal on a Linux computer. You edit a text file. Each step gives the exact text.

Time. I did not time either path. In path B, my first message came 20 minutes after the first start.

Accounts. You need none to receive. To share, you need a free account at https://app.airframes.io.

Values to choose first. The steps use them as placeholders.

Placeholder Meaning Example form
<TZ> Time zone, TZ database name America/Los_Angeles
<STATION_ID> A station name with no personal detail. The airframes.io form is XX-YYYY: two letters, then the code of the nearest large airport XX-YYYY

dumphfdl does not need your position, and this guide never asks for it.

The law, for the United States. I am not a lawyer. You only receive: this guide has no step that transmits. US law (47 U.S.C. section 605) says that a person who receives a radio message not meant for the public must not tell others its contents, or use it for gain. So I show that a message arrived and what kind it was. I do not publish the text of real aircraft messages. Other countries differ.

4. The antenna and the radio-frequency chain

HFDL uses 12 bands from 2.9 to 21.9 MHz. One wideband receive antenna covers them all. The dumphfdl README recommends a magnetic loop or a mini whip. I use a small active loop.

Build the chain in this order, antenna first.

Path A   loop -- RG-6 -- power injector -- tuned SDR

Path B   loop -- RG-6 -- power injector -- F3060 (30 MHz low-pass in,
         shelf filter bypassed) -- RF limiter -- RX-888 Mk II, HF input

Caution. Direct current on the cable can damage a filter or a radio input. Put the power injector first on the loop cable. Keep the bias tee of the radio off.

  1. Put the loop outdoors if you can. Distance from the electronics in the house matters more than height.
  2. Run the coax from the loop to the power injector.
  3. Connect the radio side of the injector to the next part in the chain.
  4. Clip a ferrite on each end of the loop cable.
  5. Path B only: connect the F3060, then the limiter, then the receiver. Leave the F3060 shelf filter bypassed.

Why path B needs the 30 MHz filter: at 64.8 million samples each second, a signal from 32 to 65 MHz folds back onto shortwave. A tuned radio in path A has its own filters, so path A does not need it.

Warning. An outdoor antenna cable can carry a surge into the house. Fit a grounding block where the cable enters the building. Bond it to the building’s own grounding electrode system (in the US: National Electrical Code Article 810). Use a licensed electrician if you are not sure.

My own loop is still indoors, near the computer. That is the worst place for it, and it still decodes several thousand messages a day.

5. How HFDL uses its bands

Read this section before you set a frequency. It tells you where to listen.

The ground stations

The public list of ground stations is the HFDL system table. Version 52 has 16 stations. Each station has 6 to 19 frequencies. Each station sends a short beacon, called a squitter, on each frequency it uses at that time. The squitter names the station and the frequencies in use. An aircraft logs on to a station it can hear.

A reader in North America is most likely to hear the stations below. The frequencies are from system table version 52, in kHz. A frequency marked * is also used by another station.

Station Frequencies in kHz
San Francisco, California 5508, 6559, 8927*, 10081*, 11327, 13276*, 17919*, 21934
Molokai, Hawaii 5514, 6565, 8912*, 8936*, 10027*, 11312, 11348*, 13276*, 13312*, 13324, 17919*, 21937*
Riverhead, New York 5652, 6661, 8912*, 11387, 13276*, 17919*, 21931*
Barrow, Alaska 2944, 2992, 3007, 3497, 4654, 4687, 5529*, 5538, 5544*, 6646*, 8927*, 8936*, 10027*, 10093, 11354, 17919*, 17934, 21928*, 21937*
Albrook, Panama 5589, 6589, 8894, 10063, 13264, 17901
Reykjavik, Iceland 3900, 5720, 6712, 8977, 11184, 15025, 17985

What I measured in the Puget Sound, with an indoor loop: 61 % of my messages were on frequencies that only Molokai uses. 7 % were on Riverhead’s own frequencies. Reykjavik, Auckland, Hat Yai, Muan and Agana had about 1 % or less each. The nearest station is not always the one you hear best. A message on a station’s frequency can come from an aircraft that talks to that station. It does not prove that I heard the station itself.

The 12 bands

The channel lists are the ones that ka9q-radio gives to dumphfdl. Use them for both paths.

Band Channels in kHz Width
21 MHz 21928 21931 21934 21937 21949 21955 21982 21990 21997 69 kHz
17 MHz 17901 17912 17916 17919 17922 17928 17934 17958 17967 17985 84 kHz
15 MHz 15025 one channel
13 MHz 13264 13270 13276 13303 13312 13315 13321 13324 13342 13351 13354 90 kHz
11 MHz 11184 11306 11312 11318 11321 11327 11348 11354 11384 11387 203 kHz
10 MHz 10027 10030 10060 10063 10066 10075 10081 10084 10087 10093 66 kHz
8 MHz 8825 8834 8843 8885 8886 8894 8912 8921 8927 8936 8939 8942 8948 8957 8977 152 kHz
6 MHz 6529 6532 6535 6559 6565 6589 6596 6619 6628 6646 6652 6661 6712 183 kHz
5 MHz 5451 5502 5508 5514 5529 5538 5544 5547 5583 5589 5622 5652 5655 5720 269 kHz
4 MHz 4654 4660 4681 4687 33 kHz
3 MHz 3455 3497 42 kHz
2 MHz 2941 2944 2992 2998 3007 3016 75 kHz

Choose a band by time of day

The best frequency depends on the sun. As a general rule, the higher bands travel far in daylight, and the lower bands travel far at night. The real split changes with the season, the sun and the path.

When, at your station Try first Then
Daylight 13 MHz 17 MHz, 11 MHz, 21 MHz
Around sunrise and sunset 8 MHz 10 MHz, 11 MHz
Night 6 MHz 8 MHz, 5 MHz

The table is a starting point from the general rule and from my own counts. In about ten days, 47 % of my messages came in the 13 MHz band, 25 % in the 6 MHz band, and 9 % in the 8 MHz band. The 2, 3 and 4 MHz bands gave me no message at all in that time. The scanner of the container in section 7 also leaves out the bands below 5 MHz, “due to very low activity”.

The airframes.io documents name https://hfdl.observer as a place to see the frequencies in use now. I did not read that site for this guide.

6. Path A: prepare the computer

A Docker container is a packaged program with everything it needs. You do not build dumphfdl or install radio drivers by hand. These steps are for a Raspberry Pi 5. On another Linux computer, start at step 3.

  1. Write Raspberry Pi OS Lite (64-bit) to the card with Raspberry Pi Imager. In the Imager settings, set the host name to pi and turn SSH on.

  2. Start the Pi on wired Ethernet. Log in with SSH.

  3. Update the system.

    sudo apt update && sudo apt full-upgrade -y && sudo reboot
    
  4. Install Docker with the sdr-enthusiasts script. It also stops the kernel’s TV drivers from taking an RTL radio.

    bash <(curl -s https://raw.githubusercontent.com/sdr-enthusiasts/docker-install/main/docker-install.sh)
    sudo reboot
    
  5. Check Docker.

    docker compose version
    

    Result: one line with a version number.

  6. Make the project folder.

    sudo mkdir -p -m 777 /opt/station && cd /opt/station
    
  7. Create /opt/station/.env with your values.

    FEEDER_TZ=<TZ>
    STATION_ID=<STATION_ID>
    
  8. Connect the radio to a USB socket of the computer.

7. Path A: the decoder

Program: docker-dumphfdl, which runs dumphfdl.

  1. Create /opt/station/docker-compose.yml. This one is for the Airspy HF+ Discovery.

    services:
      dumphfdl:
        image: ghcr.io/sdr-enthusiasts/docker-dumphfdl:latest
        container_name: dumphfdl
        restart: always
        device_cgroup_rules:
          - "c 189:* rwm"
        environment:
          - TZ=${FEEDER_TZ}
          - SOAPYSDRDRIVER=driver=airspyhf
          - GAIN_TYPE=--gain
          - SOAPYSAMPLERATE=768000
          - FEED_ID=${STATION_ID}-HFDL
          - ZMQ_MODE=server
          - ZMQ_ENDPOINT=tcp://0.0.0.0:45555
          - DUMP_HFDL_COMMAND_EXTRA=--output decoded:text:file:path=-
        tmpfs:
          - /run:exec,size=64M
          - /var/log
          - /tmp
        volumes:
          - /dev:/dev:ro
          - /opt/station/dumphfdl-data:/opt/dumphfdl-data
          - /opt/station/dumphfdl-scanner:/opt/scanner
    

    What the lines do:

    • SOAPYSDRDRIVER names the radio driver. With no serial number, the first radio of that type is used.
    • GAIN_TYPE=--gain with no GAIN line leaves the gain to the radio’s automatic control.
    • SOAPYSAMPLERATE is the width that the radio hears, in samples each second. 768000 is the highest rate of the Airspy HF+.
    • FEED_ID is your station name in every message.
    • DUMP_HFDL_COMMAND_EXTRA adds one more output: readable text in the container log.
    • The first volume keeps the system table. The second keeps the band that the scanner chose.
  2. For an RTL-SDR Blog V4 or V4L, change two lines. The rate 250000 is the one in the dumphfdl README example. I did not confirm it for an RTL radio.

          - SOAPYSDRDRIVER=driver=rtlsdr
          - SOAPYSAMPLERATE=250000
    
  3. Start the container.

    cd /opt/station && docker compose up -d
    docker logs -f dumphfdl
    

    Result: the log says “Running through test to determine best frequencies.” Press Ctrl and C to leave the log. The container keeps running.

What the container does by itself

With no frequency list, the container runs a scanner. The scanner listens to 8 groups of channels, 90 seconds each. It scores each group by the messages it heard. Then it stays on the best group. A full scan takes about 13 minutes.

After 30 minutes the container counts messages over the last 30 minutes. Below an average of 5, it scans again. So the container follows the bands from day to night with no help.

To scan again now:

docker exec -it dumphfdl /reset-dumphfdl.sh

Set a band by hand

  1. Choose a band from section 5.

  2. Add one line to the environment list. The channels are in kHz, with spaces between them. This example is the 13 MHz band.

          - FREQUENCIES=13264 13270 13276 13303 13312 13315 13321 13324 13342 13351 13354
    
  3. Apply the change.

    docker compose up -d
    docker logs dumphfdl 2>&1 | grep "Frequencies were supplied"
    

    Result: one line, “Frequencies were supplied, skipping test.”

Rule for the channel list: every channel must fit inside about 80 % of the sample rate. At 768000 that is 614 kHz, so every band in section 5 fits. At 250000 it is 200 kHz. The 5 MHz and 11 MHz bands are wider than that. Leave out the channels at the edges (5451 and 5720, or 11184).

8. Path A: the first signal

  1. Wait for the scanner to finish, or set a band by hand.

  2. Watch the log.

    docker logs -f dumphfdl
    
  3. Wait up to 30 minutes on a band that fits the time of day.

Result: blocks of text appear, one for each message. Each block starts with a line in square brackets: the time, the frequency in kHz, and the speed in bps. Section 10 explains one block.

If the scan ends with “No messages, repeating scan.”, go to section 15.

9. Path B: every band at once

Build the receiver first: /guides/shortwave-receiver/. At the end of that guide, radiod@hf is active on the computer hf, and the gain is set. The steps below are the ones on my station. They build dumphfdl 1.7.0 and use ka9q-radio at commit b5bbb9aa.

The hfdl service of ka9q-radio starts one copy of dumphfdl for each of the 12 bands. radiod gives each copy its own band as a stream of samples.

Your station name becomes public in step 6. As installed, the ka9q-radio helper sends every message straight to airframes.io. Steps 3 and 4 change that: the messages then go to your own router, and section 11 decides what leaves the house. Do steps 3 and 4 before step 6 if you do not want to share.

  1. Build dumphfdl on hf. Ubuntu 24.04 has no package for it.

    sudo apt install -y cmake pkg-config libglib2.0-dev libconfig++-dev libacars2-dev
    cd ~ && git clone https://github.com/szpajder/dumphfdl.git && cd dumphfdl
    git checkout v1.7.0
    mkdir build && cd build && cmake ../ && make && sudo make install
    dumphfdl --version                   # expect 1.7.0
    
  2. Give radiod the 12 HFDL channels. In /etc/radio/radiod@hf.conf, add the line disable = yes to the section [HFDL]. Then add the project’s HFDL file at the end.

    cat ~/ka9q-radio/config/examples/fragments/hfdl.conf | sudo tee -a /etc/radio/radiod@hf.conf >/dev/null
    sudo systemctl restart radiod@hf
    

    Result: 12 new sections, [HFDL21] to [HFDL2]. Each one is a band, with its center frequency and its width. All 12 send to one group on the computer’s internal network, hfdl.local.

  3. Make the helper send each message to the router on pi, not straight to airframes.io. Work on a copy, so a later install does not undo it.

    sudo cp /usr/local/sbin/start-hfdl /usr/local/sbin/start-hfdl-local
    sudo sed -i 's/decoded:json:tcp:address=feed.airframes.io,port=5556/decoded:json:udp:address=pi.local,port=5556/' \
      /usr/local/sbin/start-hfdl-local
    grep -c "udp:address=pi.local" /usr/local/sbin/start-hfdl-local     # expect 1
    

    If hf cannot find the name pi.local, use the fixed address of pi.

  4. Point the service at the copy. Run sudo systemctl edit hfdl and enter these three lines.

    [Service]
    ExecStart=
    ExecStart=/usr/local/bin/pcmrecord --raw -v --exec "/usr/local/sbin/start-hfdl-local \"$k\" \"$d\" \"$r\"" ${MCAST}
    
  5. Set your station name. It is the description line in the [rx888] section of /etc/radio/radiod@hf.conf. The helper gives that text to dumphfdl as the station name.

    description = "<STATION_ID>-HFDL"
    

    Then start the receiver again, so it reads the new line.

    sudo systemctl restart radiod@hf
    
  6. Set the decoder’s location and give it the ground-station table. In /etc/radio/hfdl.conf, change the DUMPHFDL line to DUMPHFDL=/usr/local/bin/dumphfdl. Then run:

    sudo install -D -o radio -g radio -m 664 ~/dumphfdl/etc/systable.conf /var/lib/hfdl/systable.conf
    sudo systemctl enable --now hfdl
    tail -f /var/log/hfdl.log
    

    Result: 12 lines that start with the helper’s name. Each one gives a center frequency, a sample rate and a list of channels. After that, one long line of JSON arrives for each message. JSON is a text format for programs.

  7. Prepare pi with section 6, steps 1 to 7. Then build the router and the message screen with section 11.

Path B with no second computer

Leave out steps 3, 4 and 7. Then every message goes to airframes.io, and to the file /var/log/hfdl.log as JSON. You have no message screen of your own. You cannot receive without sharing in this form.

10. Read one message

I never show a received message, because a real message can hold private details. I wrote this one myself. The flight, the aircraft number and the position do not exist.

EXAMPLE MESSAGE
[2026-01-01 12:00:00 UTC] [13324.0 kHz] [1.5 Hz] [-60.0/-75.0 dBFS] [15.0 dB] [300 bps] [S]
Downlink LPDU:
 Src AC: 42
 Dst GS: Molokai, Hawaii
 Type: Unnumbered data
 HFNPDU:
  Type: Performance data
  Flight ID: ZZ0000
  Lat: 30.0000000
  Lon: -140.0000000

The first line, from left to right (dumphfdl README):

Field Meaning
[2026-01-01 12:00:00 UTC] The time the frame arrived
[13324.0 kHz] The channel. In the table of section 5, only Molokai uses it
[1.5 Hz] How far the signal was off the channel frequency
[-60.0/-75.0 dBFS] Signal level, then noise level, relative to the full scale of the radio
[15.0 dB] Signal-to-noise ratio: the first number minus the second
[300 bps] The speed: 300, 600, 1200 or 1800 bits each second
[S] The frame fills one time slot. D means two slots

The lines below it:

  • Downlink means from an aircraft to the ground. Uplink means from a ground station.
  • Src AC is the aircraft. The number is a short ID that the ground station gave it at logon. It is not the aircraft’s registration.
  • Dst GS is the ground station. You see a name here only with the system table (section 12). Without the table you see a number.
  • Type: Performance data is an automatic report. It carries the flight identifier and the position.

Other kinds of block that you see often:

Block What it is
Uplink SPDU A squitter: the beacon of a ground station, with the frequencies in use
Logon request, Logon confirm An aircraft joins a ground station
Frequency data An aircraft reports which stations it can hear
A block with ACARS A text message, the same kind as on VHF

The dumphfdl README shows a full squitter. Mine is a simplified layout: a real block has more lines.

11. A message screen, and sharing with airframes.io

All of this section is optional. Two containers run on pi. acars_router takes in the messages, removes duplicates and sends them on. ACARS Hub stores them and shows them in a browser.

Sharing makes your station name public. airframes.io shows <STATION_ID> to everyone, with the messages you send. It also sees the internet address of your house. Choose a name that does not name you or your street. The line AR_SEND_TCP_HFDL is the only one that sends data out of your house. Leave it out to keep everything at home.

  1. Add the two services to /opt/station/docker-compose.yml on pi, under services:.

      acars_router:
        image: ghcr.io/sdr-enthusiasts/acars_router:latest
        container_name: acars_router
        restart: unless-stopped
        ports:
          - 5556:5556/udp          # path B: HFDL arrives here from the hf computer
        environment:
          - TZ=${FEEDER_TZ}
          - AR_ENABLE_DEDUPE=true
          - AR_SKEW_WINDOW=30
          - AR_RECV_ZMQ_HFDL=dumphfdl:45555          # path A only
          - AR_SEND_TCP_HFDL=feed.airframes.io:5556  # sharing: optional
        tmpfs:
          - /run:exec,size=64M
          - /var/log:size=64M
    
      acarshub:
        image: ghcr.io/sdr-enthusiasts/docker-acarshub:latest
        container_name: acarshub
        restart: unless-stopped
        ports:
          - 80:80
        volumes:
          - /opt/station/acars_data:/run/acars
        tmpfs:
          - /database:exec,size=64M
          - /run:exec,size=64M
          - /var/log:size=64M
        environment:
          - TZ=${FEEDER_TZ}
          - ENABLE_HFDL=true
          - HFDL_CONNECTIONS=zmq://acars_router:45556
    
  2. Path A: keep the line AR_RECV_ZMQ_HFDL and delete the two ports lines of acars_router.

  3. Path B: delete the line AR_RECV_ZMQ_HFDL. Keep the ports lines.

  4. Start the containers.

    cd /opt/station && docker compose up -d
    
  5. Open http://pi/ in a browser on your home network.

    Result: the ACARS Hub page. New HFDL messages appear at the top as they arrive.

  6. To share: create an account at https://app.airframes.io. Find your station by its name and claim it. Do this from your home network: the ka9q-radio document says the claim must come from the address that sends the data.

Facts to know:

  • AR_SKEW_WINDOW=30. The default is 5 seconds. The router rejects a message that is older than this. Its README says HFDL needs a larger value. 30 is the value on my station.
  • Share one time only. In path B, do not keep the airframes.io output in the helper and also set AR_SEND_TCP_HFDL. Each message would then arrive two times.
  • Do not send HFDL positions to an aircraft tracking network. The dumphfdl README says this in strong words. HFDL positions are late, and they make a mess on a map of live aircraft.

12. The system table

The system table is the list of ground stations: number, name, position and frequencies. A message carries only numbers. With the table, dumphfdl prints “Molokai, Hawaii” in place of a number, and kHz in place of a frequency number.

The table changes from time to time. The network then raises its version number. Every squitter carries the current number, in the line System table version.

How both paths keep it current. dumphfdl runs with two options that name the same file: --system-table reads the file at the start, and --system-table-save writes a new version to it. Ground stations send the full table over the air when an aircraft asks for it. When dumphfdl receives all parts of a newer table, it replaces the file. You do nothing.

Path A Path B
The file /opt/station/dumphfdl-data/systable.conf on pi /var/lib/hfdl/systable.conf on hf
Where it first comes from The container downloads it from the dumphfdl repository if the file is missing You copied it in section 9, step 6
  1. Read the version of your file. Use the path for your build.

    head -1 /var/lib/hfdl/systable.conf
    

    Result: version = 52; or a higher number. On 2026-10-10 the dumphfdl repository and the ka9q-radio repository both held version 52.

  2. Compare it with the number in a new squitter. If the squitter has a higher number, wait. The new table arrives when an aircraft asks for it.

  3. After an update, look for a station with no name. A table from the air has positions but no names. dumphfdl copies each name from the old table when the station number and the position match. A new station has no name: open the file in a text editor and add one.

Do not change the frequencies in the file by hand. The file must match the table that the network uses.

13. Run it unattended

Path A. The line restart: always starts the container again after an error and after a restart of the computer. To get a newer version of the container:

cd /opt/station && docker compose pull && docker compose up -d

Path B. sudo systemctl enable --now hfdl in section 9 made the service start with the computer. Its service file starts it again 5 seconds after an error.

  1. In the PC’s firmware settings, set it to start again after a power cut.

  2. Check that the log is rotated. The file /var/log/hfdl.log grows all day.

    ls /etc/logrotate.d/ | grep hfdl
    

    Result: one file name. ka9q-radio has a rule file that keeps 30 daily logs. If the command prints nothing, copy ~/ka9q-radio/aux/hfdl.rotate to /etc/logrotate.d/.

  3. Write down the number of messages for one normal day. That number is your baseline. Change one thing at a time, and compare with it.

14. Check that it works

# Check Command or page Pass Wait
1 Path A: the container runs docker ps --filter name=dumphfdl Status “Up” 1 minute
2 Path A: the scanner chose a band docker logs dumphfdl 2>&1 | grep wins One line with a group name, such as 11M13Mx2 wins About 13 minutes
3 Path A: messages arrive docker logs -f dumphfdl Text blocks as in section 10 Up to 30 minutes
4 Path B: the service runs systemctl is-active hfdl active At once
5 Path B: 12 decoders run pgrep -c dumphfdl 12 1 minute
6 Path B: messages arrive tail -f /var/log/hfdl.log New JSON lines My first came after 20 minutes
7 The table loaded docker logs dumphfdl 2>&1 | grep "System table loaded", or the same grep in /var/log/hfdl.log One line for each decoder At the start
8 The message screen http://pi/ Messages in the HFDL list Minutes
9 Sharing https://app.airframes.io Your station name, with a recent message Minutes

What to expect in numbers: my station, path B with an indoor loop, decodes about 6,000 messages a day. That is 4 to 8 a minute. Path A hears one band, so expect a fraction of that, and long quiet times on a wrong band. Ground stations with names, not numbers, show that the system table works.

15. If it does not work

Symptom Likely cause What to do
Path A: “No messages, repeating scan.” again and again No signal reaches the radio, or the radio is overloaded Check the injector has power. Move the loop away from electronics. Try at another time of day
Path A: the container stops at once A required setting is missing. The log names it Read docker logs dumphfdl. SOAPYSDRDRIVER, SOAPYSAMPLERATE and FEED_ID must be set
The radio runs, the band is busy, and nothing decodes The sample rate is one the radio does not support. The radio then runs at another rate with no error (dumphfdl README) Use a rate from the radio’s own list
Some channels of a band never decode They are too near the edge of what the radio hears Keep all channels inside 80 % of the sample rate. Leave out the outer ones
usb_claim_interface error -6 with an RTL radio The kernel’s TV driver took the radio Run the install script of section 6 again. Restart the computer
An RTL-SDR Blog V4L opens and decodes nothing A driver older than August 2026 does not know its tuner. I saw this on VHF docker compose pull && docker compose up -d
Messages only by day, or only at night The band does not fit the time Section 5. In path A, remove FREQUENCIES and let the scanner choose
Ground stations show as numbers No system table Check the file and its path (section 12)
The container has no table after a restart The volume points at the wrong folder. The example in the container’s README maps /opt/dumphfdl, but its scripts use /opt/dumphfdl-data Use the volume line from section 7
Path B: hfdl is active, but the log has no decoder lines The DUMPHFDL line points at /usr/bin/dumphfdl, and your build is in /usr/local/bin Section 9, step 6
Path B: no data on any band radiod has no HFDL channels, or the old [HFDL] section is still on Section 9, step 2. Then sudo systemctl restart radiod@hf hfdl
Path B: shortwave is full of signals that should not be there No 30 MHz low-pass filter Fit the filter (section 4)
Path B: radiod reports dropped data The RX-888 is on a hub or a USB 2 socket Use a USB 3.0 socket on the main board
The loop has no signal The limiter blocks the loop’s power, or the injector is in the wrong place Injector first on the loop cable
The log has messages, and ACARS Hub shows none The router rejects them as too old Set AR_SKEW_WINDOW=30
Path B: nothing reaches pi hf cannot find the name pi.local, or the UDP line is missing Use the fixed address of pi. Check the ports lines of acars_router
Fewer messages after you add an amplifier Strong signals now overload the radio, and the weak ones are lost Remove it

16. What I did wrong

  • The loop is still indoors. It sits near the computer, in the noise of the house. It works, and I expect more when it moves outside. Put yours outside from the start.
  • Do not count on the nearest station. The California station is nearer to me than Hawaii. Most of my traffic is for Hawaii. Shortwave does not go by distance.
  • “Heard” is a strong word. A message on a station’s frequency can come from an aircraft that talks to that station. So I say “traffic for” a station, not “I heard the station”.

17. Not run and not confirmed

  • All of path A. My station does not run the docker-dumphfdl container, and I own no Airspy HF+ Discovery. Sections 6 to 8 come from the container’s README and its scripts, read on 2026-10-10. No command in them was run.
  • The line DUMP_HFDL_COMMAND_EXTRA=--output decoded:text:file:path=-. The dumphfdl README says path=- prints to standard output. I did not confirm that the text reaches docker logs.
  • The sample rate 250000 for an RTL-SDR Blog V4 or V4L, and any RTL radio on shortwave. I did not try the V4L on shortwave.
  • That the automatic gain of each radio suits HFDL. The container’s README marks GAIN as required, but its start script accepts a file without it.
  • The scan time of “about 13 minutes”. I computed it from the script: 8 groups, 90 seconds each, plus pauses.
  • The price of the Airspy HF+ Discovery and of the RX-888 Mk II. The other prices are from 2026-10-07 and were not checked again.
  • Path B on one new computer. The steps are the settings on my station, checked against each project’s documents. They were not run on a new, empty computer as written.
  • That the newest ka9q-radio builds and behaves the same. I use commit b5bbb9aa. On 2026-10-10 the HFDL helper, service file and channel file were the same in both versions.
  • The ka9q-radio document says make install puts a first system table in /var/lib/hfdl/. I copy the file by hand, and did not check which is true for my commit.
  • That 12 copies of dumphfdl can all write one table file with no fault. This is the project’s own arrangement. My table has not changed version since the start, so I have not seen an update happen.
  • That version 52 is the table in use on the air today.
  • The channel lists in section 5 do not match table version 52 exactly. They include 10075 and 13354 kHz, which no station in the table has. They leave out 2986 kHz (Bahrain) and 3900 kHz (Reykjavik). The scanner of the container has a few more differences.
  • The ACARS Hub settings without the aircraft-map lines. My station runs it with ACARS, VDL2 and an aircraft map as well.
  • The logrotate rule in path B. I did not check that the install put it in place.
  • Checks 5 and 7 of section 14 (pgrep -c dumphfdl, and the “System table loaded” line in each log). I wrote them from the documents and did not run them.
  • “Path B with no second computer”. It is the form the project ships. My station has never run it.
  • The body of the example message in section 10. The first line and the names Src, Dst, Type and Performance data are in the dumphfdl README. I wrote the rest from memory of the layout, and simplified it.
  • The day and night table in section 5. It is a general rule plus ten days of my own counts, not a forecast.
  • That a squitter repeats every 32 seconds, as the episode shows. I found no source for it today, so this guide gives no number.
  • How airframes.io lets you claim a station. The rule about the same address is from the ka9q-radio document. The airframes.io feeding pages did not load on 2026-10-10.
  • The site hfdl.observer. I did not read it.

18. Sources

All read on 2026-10-10, unless a line says another date.

The decoder. dumphfdl README, etc/systable.conf (version 52) and the option list in src/main.c: https://github.com/szpajder/dumphfdl. Release 1.7.0, 2025-11-02.

Path A. docker-dumphfdl README and the scripts in rootfs/: https://github.com/sdr-enthusiasts/docker-dumphfdl. Docker install script: https://github.com/sdr-enthusiasts/docker-install (read 2026-10-07 for the full station guide).

Path B. ka9q-radio docs/hfdl.md, aux/start-hfdl, config/hfdl.conf, service/hfdl.service.in, config/examples/fragments/hfdl.conf and aux/hfdl.rotate, at commit b5bbb9aa and at the newest commit: https://github.com/ka9q/ka9q-radio. The receiver: /guides/shortwave-receiver/.

The message screen and sharing. acars_router README: https://github.com/sdr-enthusiasts/acars_router. ACARS Hub README: https://github.com/sdr-enthusiasts/docker-acarshub. Airframes, introduction to HFDL: https://docs.airframes.io/docs/technology/hfdl/intro/.

My station. The commands of path B, the parts and the prices: /guides/build-the-station/, checked against my station on 2026-10-07. The counts and shares: the episode’s fact sheet, from my station on 2026-10-06.

Rules. 47 U.S.C. 605: https://www.law.cornell.edu/uscode/text/47/605 (read 2026-10-07).

SpurMy station runs only the wideband path. I wrote the one-radio path from each project's documents, and I did not run it.