# Numbers Stations

At the end you know when and where each numbers station should appear, and your radio records it on time. You also know where to find the navy's letter beacons, which reached my station on the first night.

Spurious Emissions · Rev A · checked 2026-10-23 · https://spurious-emissions.net/guides/numbers-stations/

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.

## 1. What this guide builds

A listening position for numbers stations: shortwave broadcasts of groups of digits, read by a voice, sent in Morse code, or sent as tones. A volunteer group, Priyom, publishes when and where each station should appear. You tune to the listed frequency at the listed time, and you record what comes.

| Signal | Frequency | Antenna | Radio | Decoder | Computer |
|---|---|---|---|---|---|
| Numbers stations on Priyom's schedule | 3 to 21 MHz, one listed frequency for each transmission | Any shortwave antenna, outdoors | An SDR radio, or the RX-888 Mk II | Your ears. Nothing decodes the content | A PC with a screen, or `hf` with none |
| Russian navy letter beacons | Ten clusters from 3594.7 to 20047.7 kHz, upper sideband | The same | The same | Your eyes on a waterfall, and your ears | The same |
| The Buzzer | 4625 kHz, upper sideband | The same | The same | Your ears | The same |

In the episode, my station records every transmission on the schedule with a program that I wrote. It also has a letter-beacon receiver and a picture of all of shortwave for 30 days. Those three programs are not public. This guide uses free public programs for the same jobs, and it says where you must do the work yourself.

There are two paths. **Path A** is the lowest-cost one: one RTL-SDR radio, a PC with a screen, and you at the dial. **Path B** is my hardware: a receiver that hears all of shortwave at once, on a PC with no screen, with commands that open a channel at the listed time.

```
 Path A (lowest cost)
 --------------------
 wire or loop antenna -- coax -- RTL-SDR Blog V4L -- USB -- PC with a screen
                                                            SDR++:
                                                              waterfall, USB or CW by ear
                                                              Recorder (audio file)

 Path B (what I use)
 -------------------
 loop -- RG-6 -- power injector -- 30 MHz low-pass filter -- RF limiter -- RX-888 Mk II
                                                                              |
                                                          own USB 3.0 socket  |
                                                                              v
                                              hf (x86 PC, no screen): ka9q-radio
                                                "tune" opens one channel for one transmission
                                                "pcmrecord" writes it to a sound file
                                                a fixed channel for each letter-beacon cluster
```

## 2. What you need

Prices are US dollars unless the cell says otherwise. Each price has its seller and the date I read it. They change. A part marked ◆ is what I use. "A similar one" is a link to a part like mine, not the one I have. A blank box is for your pencil.

### Lowest-cost path (Path A)

| ☐ | Part | Job | Connector | Price | Note |
|---|---|---|---|---|---|
| ☐ | [RTL-SDR Blog V4L](https://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/) | The radio | SMA | $37.95, rtl-sdr.com, 2026-10-23 | The seller says it has a built-in converter for shortwave and needs the latest drivers. I have not used it on shortwave |
| ☐ | A shortwave antenna that you own: a dipole, a vertical, or a long wire | The antenna | Yours | Nothing | A receive-only wire of 10 m outdoors is a start |
| ☐ | 50 ohm coax, with an adapter to an SMA plug | Antenna to radio | SMA at the radio | See seller | |
| ☐ | A PC with a screen: Windows, macOS or Linux | Runs SDR++ | USB | Yours | |
| ☐ | A clock that shows UTC | The schedule is in UTC | | Nothing | The PC clock is enough if it is synchronized |

You may own a shortwave receiver or transceiver with USB and CW modes. Then you need no new radio to listen. Record its audio output with any sound program. The SDR radio adds the waterfall, which shows a signal before you hear it.

The older RTL-SDR Blog V4 is no longer made. The V4L replaces it.

What Path A gives up:

- **One transmission at a time.** The radio hears a slice about 2 MHz wide. Two stations at the same minute on far frequencies need two radios.
- **You at the dial.** Nothing in Path A tunes by itself at the listed time. You set the frequency and press Record.
- **No picture to go back to.** You see the waterfall only while it runs. A recording of the whole slice is possible, but it is very large (section 6).
- **8 bits.** Strong broadcast stations at night can cover weak signals.

### What I use (Path B)

| ☐ | Part | Job | Connector | Price | Note |
|---|---|---|---|---|---|
| ☐ | ◆ [MLA-30+ active loop](https://www.amazon.com/dp/B095K89WND?tag=spuriousemiss-20) with its power injector | The antenna | SMA | See listing, Amazon | The amplifier is in the loop head. Mine is just outside a window |
| ☐ | ◆ [Turn Island Systems F3060](https://turnislandsystems.com/product/f3060-filter-shelf-30-60-mhz-lpf/) low-pass filter | In front of the receiver | See listing | $80, Turn Island Systems, 2026-10-10 | Required at 64.8 MS/s (section 4) |
| ☐ | ◆ [TAPR RF Limiter](https://tapr.org/product/rf-limiter/) | Last part before the receiver | See listing | $20, TAPR, 2026-10-10 | Needed if you also transmit |
| ☐ | ◆ [RX-888 Mk II](https://opensourcesdrlab.com/products/rx888-mkii-16bit-sdr-receiver-radio-ltc2208-adc-upgrade-rx888?DIST=QU5PHQ%3D%3D), 16-bit, 10 kHz to 64 MHz direct | The receiver: all of shortwave at once | SMA | $152.79, OpenSourceSDRLab, 2026-10-11 | Copies exist. Mine is from OpenSourceSDRLab |
| ☐ | ◆ x86-64 desktop PC, 4 cores of Intel Haswell class (2013) or newer, 8 GB, a USB 3.0 socket on the main board (mine: HP EliteDesk 800 G1 SFF, Core i5-4570, 12 GB, bought used; [a similar one](https://www.amazon.com/dp/B094LJZ48K?tag=spuriousemiss-20)) | `hf` | USB 3.0 | Used market | |
| ☐ | ◆ SATA solid-state drive, 120 GB or more (mine: [Crucial MX500 500 GB](https://www.amazon.com/dp/B0786QNS9B?tag=spuriousemiss-20), bought used) | Storage for `hf` | | See seller | Recordings fill a drive (section 12) |
| ☐ | ◆ Battery backup (UPS), 1500 VA (mine: [CyberPower CP1500PFCLCD](https://www.amazon.com/dp/B00429N19W?tag=spuriousemiss-20)) | Keeps `hf` on through a short power cut | | See seller | Optional. A power cut during a schedule loses those recordings |

### Cable and small parts

| ☐ | Part | Job |
|---|---|---|
| ☐ | RG-6 quad-shield coax, and two F to SMA adapters | Loop to the receiver. On shortwave, 10 to 20 m of it loses under 1 dB |
| ☐ | Short SMA plug-to-plug jumpers, 3 or more | Injector to filter to limiter to receiver |
| ☐ | ◆ [Snap-on ferrites](https://www.amazon.com/dp/B0CSXZWGD6?tag=spuriousemiss-20) (an example) | Both ends of the antenna cable, and the USB cable |
| ☐ | Grounding block for the cable where it enters the house, and bonding wire | Section 4, "Ground the cable" |
| ☐ | 50 ohm SMA terminator | The noise test in section 7 |

Do not buy an amplifier at the start. An amplifier in front of a receiver that is already full makes reception worse.

## 3. Before you start

**Skills.** You know how to tune an SSB receiver and read UTC. For Path A you install one program. For Path B you type commands into a Linux terminal over SSH and edit a text file.

**Time.** Path A: one evening to set up, then one evening of listening for each try. Path B: one day to set up, of which 36 minutes is one command that runs by itself on my PC.

**Accounts.** None for listening. The download page of SDR++ needs a GitHub account (section 6).

**Values to choose first.** Write these down. The steps use them as placeholders.

| Placeholder | Meaning | Example form |
|---|---|---|
| `<NAME>` | A short text that describes the receiver. It contains no personal detail | `loop on the fence` |
| `<REC_DIR>` | The folder for your recordings | `/home/you/numbers` |
| `<FREQ>` | The frequency of one transmission, from the schedule, with a unit letter | `8680k` |
| `<SSRC>` | A channel number that no other channel on your receiver uses (Path B) | `900001` |

You do not need your position for any step. Do not enter it anywhere.

**The law, for the United States.** I am not a lawyer. Listening to shortwave broadcasts with a receiver is legal in the US, as far as I read. 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. Other countries differ. This guide receives only.

**My rules, which are stricter than that law.** They are the rules of this guide.

- Never transmit on a frequency in this guide. A numbers station or a military network is not an amateur station.
- Do not try to read a numbers message. The usual explanation is a one-time pad: without the sheet of random digits, every message of the same length is equally possible. Nobody can read it from the air, and this guide does not try.
- Log that a transmission came, when, on what frequency, and what kind it was: voice, Morse code or tones. That is what you may share.
- The Buzzer and the beacons are military networks. Listen, and log the time and frequency. Do not publish a transcript of a live voice message.

Every example of a voice or a message in this guide is one that I wrote. It has the tag "example".

## 4. The antenna and the radio-frequency chain

Numbers stations are weak and far away. The antenna and its place matter more than the radio.

### Path A

> **Caution.** A transmitter near the antenna can destroy the radio's input. Never connect the SDR radio to an antenna while another radio transmits into that antenna or one close to it. Disconnect the SDR radio before you transmit.

1. Put the antenna outside if you can. Distance from the electronics in the house matters more than height.
2. Connect the coax to the antenna.
3. Connect the SMA adapter to the radio end of the coax.
4. Connect the coax to the SMA socket of the radio.
5. Connect the radio to the PC with a short USB extension cable. The cable moves the radio away from the PC's noise.

Keep the radio's bias tee off. A bias tee puts DC on the coax. A dipole or a balun can short it.

### Path B

Build the chain in this order, antenna first.

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

The reasons for the order:

- **Injector first on the loop cable.** Every part after it then sees no DC. The limiter may block DC, so it must come after the injector.
- **Low-pass filter before the limiter.** A limiter makes harmonics when it clamps. TAPR's manual says to filter ahead of it.
- **The 30 MHz filter is not optional.** At 64.8 million samples each second, the receiver cannot tell a signal above 32.4 MHz from one below it. A signal from 32 to 65 MHz folds back onto shortwave. The F3060 removes it.
- **Leave the F3060 shelf filter bypassed.** It cuts 20 dB at 3.5 MHz. The lowest letter-beacon cluster is 3594.7 kHz, and night schedules use the low bands.
- **Bias tee off on the RX-888.** The loop takes its power from its own injector.

### Ground the cable

An outdoor antenna cable needs a path to ground where it enters the building. In the US the rule is National Electrical Code Article 810. Bond the grounding block to the building's own grounding electrode system. Never use a ground rod that stands alone: a surge then goes through your equipment. I read a published summary of the rule, not the code text.[^nec] Use a licensed electrician if you are not sure.

## 5. Read the schedule

Both paths start here. Priyom is a volunteer group that catalogues numbers stations and military signals. It publishes when and where each station should appear: more than a hundred transmissions a day. On 2026-10-23 the schedule held 115 entries for the next 24 hours.

1. Open [Priyom's schedule page](https://priyom.org/number-stations/station-schedule) in a browser.
2. Find the next entries. The times in the feed behind the page are UTC.
3. Pick an entry that starts in 15 minutes or more. Write down its time, frequency and mode.

Each entry is one line: the station's code, the frequency, and the mode. These are entries as the schedule gave them on 2026-10-23 (Priyom, CC BY-NC-SA 4.0).

```
2026-10-23 10:00 UTC   E11 9951kHz USB
2026-10-23 10:00 UTC   V13 19052kHz USB/AM [Target: East Asia]
2026-10-23 10:15 UTC   F01 11129kHz RTTY
2026-10-23 17:00 UTC   XPA2 Search
2026-10-23 18:00 UTC   V32 7910kHz USB
2026-10-23 19:00 UTC   M12 11135kHz CW
2026-10-23 19:40 UTC   M12 9235kHz CW (In case of traffic)
2026-10-23 22:30 UTC   F01 20966kHz RTTY [Target: North America]
```

### What the code says

The code names the station by what you hear. The letter is the kind of signal, and the number tells stations apart.

| Letter | You hear | An example on the schedule |
|---|---|---|
| E | A voice in English | E11, a Polish station. E07, a Russian one |
| S | A voice in a Slavic language | S11a, S06 |
| V | A voice in any other language | V13 (Mandarin, from Taiwan), V32 (Persian) |
| M | Morse code | M12 |
| F, P, XP | Digital tones, like an old modem | F01, F06a, P03, XPA, XPA2, XPB |

### How to set the radio for each mode

| Schedule says | Set the radio | Dial |
|---|---|---|
| USB | Upper sideband, about 3 kHz wide | The listed frequency |
| USB/AM | Upper sideband, or AM | The listed frequency |
| CW | CW mode, narrow | The listed frequency. With no CW mode, use upper sideband 800 Hz lower: the signal is an 800 Hz tone |
| RTTY | Upper sideband, about 3 kHz wide | 1.5 kHz below the listed frequency, so the tones fall near 1500 Hz |
| Search | Skip it | The entry has no fixed frequency |

### What the notes mean

- **"In case of traffic"** means the transmission comes only when there is a real message. M12 sends three times, 20 minutes apart, on different frequencies. It skips the third time when the message is a null.
- **"Target"** is the area that Priyom believes the station serves. "North America" entries are worth a try from North America.
- **"Last used"** on a Search entry is the frequency of the last time. It may move.

### How long to record

The schedule gives the start time only. Record from 1 minute before the listed time to 15 minutes after it. Some stations differ.

| Station | What Priyom says about its length |
|---|---|
| E11 | A null message (nothing to send today) lasts 3 minutes 10 seconds. Most of what it sends are nulls |
| V32 | Always 6 messages of exactly 20 minutes each: 2 hours |
| V13 | Opens with music. On the hour, then again on the half hour |
| M12 | Three sendings, 20 minutes apart, each 1 to 2 MHz away. The schedule lists each one |
| S06 | A test 10 minutes before each transmission |

Why the minute before? Because the frequency may already have a signal on it. A tone or a voice that starts at the listed time is the station. A signal that was there all along is not.

### Ask the schedule from a program (optional)

The page reads its entries from a public feed. A program can ask the same feed for a window of time. This is the request that I used on 2026-10-23. It asks for 24 hours from 10:00 UTC.

```bash
curl -s "https://calendar2.priyom.org/events?timeMin=2026-10-23T10:00:00Z&timeMax=2026-10-24T10:00:00Z&maxResults=300"
```

Result: one block of JSON text. Each entry has a start time and one line of text.

```
{"items":[{"summary":"E11 9951kHz USB","start":{"dateTime":"2026-10-23T10:00:00.000Z"}}, ...]}
```

Be polite to a volunteer service:

- Ask once a day. The schedule does not change by the minute.
- Ask for 300 entries or fewer. The feed refuses a larger number with an error.
- Keep the reply on your own computer. Priyom's content is CC BY-NC-SA 4.0: credit Priyom wherever you show it, and do not sell it.

## 6. Path A: listen and record with SDR++

Program: [SDR++](https://github.com/AlexandreRouma/SDRPlusPlus). It is free and open source, and runs on Windows, Linux and macOS. It drives the radio, draws the waterfall, demodulates USB, CW and AM, and has a recorder. I have not run it. The names of its controls below are from its source code, read on 2026-10-23.

### Install

1. Open the project's [nightly builds](https://www.sdrpp.org/nightly). The project's README recommends them. Its last numbered release is from 2021.
2. Log in to GitHub. GitHub requires an account to download the files.
3. Scroll to "Artifacts". Download the file for your system. Install it.
4. On Windows, install the radio's USB driver as the RTL-SDR Blog guide for the V4L says. On Linux, stop the kernel's TV driver from taking the radio: the same guide gives the file.
5. Synchronize the PC clock. Windows and macOS do this by default. On Ubuntu, install `chrony`.

   ```bash
   sudo apt install -y chrony
   ```

> **Caution.** The V4L needs a driver from 2026. An older driver opens the radio and receives nothing. I did not confirm that the driver inside SDR++ knows the V4L. If the waterfall is empty on every band, read section 15.

### Start the radio

1. Start SDR++.
2. In the "Source" menu, choose the RTL-SDR source and your radio.
3. Set "Direct Sampling" to **Disabled**. The V4L converts shortwave inside the radio. The direct-sampling modes are for older RTL radios with no converter.
4. Start the radio with the play button at the top of the window.

   Result: the waterfall moves.

5. Type 10000 kHz in the frequency display. Choose AM in the "Radio" menu.

   Result: in most of North America you hear a time signal with a tick each second. You have a working radio.

### Tune one transmission

1. Choose one entry from the schedule, as in section 5.
2. Three minutes before its time, type its frequency in the frequency display.
3. In the "Radio" menu, choose the mode from the table in section 5. Set the bandwidth near 3000 Hz for USB.
4. Watch the waterfall at the frequency. Note what is there before the listed time: a steady line, a buzz, or only noise.

### Record it

1. Open the "Recorder" menu.
2. Choose **Audio**, not Baseband.
3. Choose a folder in `<REC_DIR>`. The default folder is `recordings` in the program's own folder.
4. Set "Time zone" to **UTC**. The file name then has the same time as the schedule.
5. One minute before the listed time, press **Record**.

   Result: the menu shows "Recording" and a running time.

6. Leave it for 15 minutes, or longer for the stations in the table in section 5.
7. Press **Stop**.

   Result: one sound file. Its name holds the frequency and the time.

### What a good reception sounds like

- **A voice station.** A flat, automated voice that reads digits in groups. E11 reads five-figure groups. V13 opens with music. A null message from E11 is short: an ID, a word, "00", then "Out".
- **A Morse station.** Groups of Morse characters at a steady speed. M12 sends zero as a single dash, the letter T.
- **A digital station.** Two or more tones that switch fast, like an old modem. On the waterfall: two or more thin lines that start together.
- **Not the station.** A signal that was there before the listed time, a broadcast station with music and talk, or an amateur station that calls CQ.

This is an example that I wrote. The digits are invented and mean nothing.

```
EXAMPLE (invented)
"... 6 2 4 7 1 ... 0 9 3 5 8 ... 3 3 1 0 6 ..."
```

### A picture of the whole slice (optional)

The recorder's **Baseband** mode saves everything that the radio receives, not only one channel. You can then play the file again and tune any frequency in the slice. The file is very large. At 2.4 million samples each second with 16-bit samples, it is about 35 GB an hour. I computed that number. I did not measure it.

## 7. Path B: the computer and the receiver

Receiver program: [ka9q-radio](https://github.com/ka9q/ka9q-radio), free and open source. Its `radiod` service reads the whole of shortwave from the RX-888 Mk II. It gives each listener its own channel over the computer's internal network. I run these steps on my station. They build the version I run (commit `b5bbb9aa`, 2026-09-25). My [Shortwave guide](/guides/shortwave-receiver/) explains each step in more detail.

1. Install Ubuntu Server 24.04 LTS. Set the host name to `hf`. Turn SSH on. Use wired Ethernet.
2. Add the author's package source. Two of the libraries are only there.

   ```bash
   sudo wget -P /usr/share/keyrings http://www.ka9q.net/debian/ka9q-radio.asc
   echo "deb [signed-by=/usr/share/keyrings/ka9q-radio.asc arch=amd64] http://www.ka9q.net/debian noble main" \
     | sudo tee /etc/apt/sources.list.d/ka9q.list
   sudo apt update
   ```

3. Install the build tools and libraries. The list is from the project's `docs/INSTALL.md`.

   ```bash
   sudo apt install -y git avahi-utils build-essential make gcc libairspy-dev libairspyhf-dev \
     libbsd-dev libfftw3-dev libfftw3-bin libhackrf-dev libiniparser-dev libncurses-dev libopus-dev \
     librtlsdr-dev libusb-1.0-0-dev libusb-dev portaudio19-dev libasound2-dev rsync libogg-dev \
     libsamplerate0-dev libliquid-dev libncursesw5-dev libbladerf-dev libhydrasdr-dev libfobos-dev \
     libcsv-dev libsoapysdr-dev chrony
   ```

4. Build and install.

   ```bash
   cd ~ && git clone https://github.com/ka9q/ka9q-radio.git && cd ka9q-radio
   git checkout b5bbb9aa
   make -j && sudo make install
   sudo adduser $(whoami) radio
   sudo systemctl enable --now set_lo_multicast
   ```

   Result: the install creates the user and group `radio`, the service files, and the programs `radiod`, `control`, `monitor`, `tune` and `pcmrecord`. Log out and in again so the new group applies.

5. Connect the chain from section 4. Plug the RX-888 Mk II into a USB 3.0 socket on the PC. Never use a hub for it.

   ```bash
   lsusb | grep 04b4          # expect 04b4:00f1 "RX888mk2". 00f3 means the firmware did not load
   lsusb -t | grep -B2 usbfs  # the receiver's line must end in 5000M
   ```

6. Write the receiver settings. Start from the project's example.

   ```bash
   sudo cp ~/ka9q-radio/config/examples/radiod@rx888-generic.conf /etc/radio/radiod@hf.conf
   sudoedit /etc/radio/radiod@hf.conf
   ```

   Make the first two sections read as follows.

   ```ini
   [global]
   hardware = rx888
   status = hf.local
   data = hf-pcm.local
   samprate = 12k
   mode = usb

   [rx888]
   device = "rx888"
   description = "<NAME>"
   samprate = 64m8
   gain = 10
   ```

   The `data` and `mode` lines in `[global]` are necessary for this guide. With them, `radiod` can make a new channel while it runs. The project calls this the dynamic template. Every channel made this way sends its sound to `hf-pcm.local`.

   Always write `samprate = 64m8`. One of the project's default files uses the full rate, which makes more heat and needs a faster PC.

7. Make the speed tables for this PC. This took 36 minutes on my Core i5-4570. `radiod` must not run during it.

   ```bash
   cd /etc/fftw && sudo touch nwisdom && sudo chown $(whoami):radio nwisdom wisdomf 2>/dev/null
   time fftwf-wisdom -v -T 1 -o nwisdom rof1620000 cob1920 cob1200 cob960 cob800 cob600 \
     cob480 cob320 cob300 cob200 cob160 cob150
   ls -l nwisdom && cp nwisdom wisdomf
   ```

   Do not leave out `-T 1`. Do not copy the file from another computer.

8. Start the receiver and look at it.

   ```bash
   sudo systemctl enable --now radiod@hf
   systemctl is-active radiod@hf        # expect "active"
   control hf.local                     # the live panel. Press q to leave
   ```

   Result: the panel shows the receiver's levels and a list of channels. The service name is `radiod@hf`, not `radiod@hf.conf`.

9. Set the gain. In the panel, read the level of the analog-to-digital converter. The project's rule is an average of -20 to -25 dBFS. I run 10 dB of gain, which gives about -32 dBFS here. A count of "overranges" that keeps rising means too much gain.
10. Test that the antenna, not the receiver, sets the noise. Note the noise level on a quiet frequency. Replace the antenna cable with the 50 ohm terminator. The noise must fall by 6 dB or more.
11. Keep the receiver in its case, and keep air around it. It runs hot.

## 8. Path B: record one transmission

A ka9q-radio channel is one slice of the receiver's stream: a frequency, a mode and a width. The program `tune` asks `radiod` for a new channel. The program `pcmrecord` writes that channel's sound to a file. An **SSRC** is the number that names one channel.

> **Caution.** A channel that `tune` makes stays open until its lifetime ends. Without `--lifetime`, the lifetime is 0, which the project calls "immortal". Many immortal channels load the receiver. Always give `--lifetime`.

### Choose the numbers

1. Run `control hf.local`. Note the SSRC numbers in the list. Press `q`.
2. Choose a `<SSRC>` that is not in the list. I use numbers from 900001 up in this guide.
3. Compute the lifetime. The lifetime counts blocks of the receiver. The project's documents give 20 ms as the default block, so 50 blocks are one second. A lifetime of 48000 is 16 minutes.

### Do it by hand once

1. Three minutes before the listed time, open the channel. This example is a USB entry on 8680 kHz.

   ```bash
   tune -r hf.local -s 900001 -f 8680k -m usb --lifetime 48000
   ```

   Result: `tune` prints the channel's settings and stops. The lines include the SSRC, the preset `usb`, the sample rate, the frequency in Hz, and an SNR value.

2. Listen to it, if the computer has sound. Press `Q` to leave.

   ```bash
   monitor hf-pcm.local
   ```

3. One minute before the listed time, start the recorder.

   ```bash
   mkdir -p <REC_DIR>
   timeout 900 pcmrecord -d <REC_DIR> -S 900001 hf-pcm.local
   ```

   - `-d` names the folder.
   - `-S` selects the one channel with that SSRC.
   - `timeout 900` stops the recorder after 900 seconds. It is a standard Linux command, not part of ka9q-radio.

   Result: after 15 minutes, a sound file in `<REC_DIR>`. Its name starts with the SSRC and holds the UTC date and time.

For a CW entry, use the preset `cwu` and the listed frequency. The preset moves the Morse signal to a 500 Hz tone. For an RTTY entry, use `usb` and a frequency 1.5 kHz below the listed one.

```bash
tune -r hf.local -s 900002 -f 11135k -m cwu --lifetime 48000
```

Write every frequency with a unit letter. In ka9q-radio, `8680k` is 8680 kHz and `7m039` is 7.039 MHz. A number with no letter is a guess.

### A small script for one transmission

This script does the three steps for one entry. I wrote it for this guide from the documents and the source code of `tune` and `pcmrecord`, read on 2026-10-23. I did not run it.

```bash
sudoedit /usr/local/bin/record-one
```

```bash
#!/bin/sh
# EXAMPLE, not run. Record one scheduled transmission.
# Use: record-one <FREQ> <MODE> <MINUTES> <SSRC>
# Example: record-one 8680k usb 15 900001
set -e
FREQ="$1"; MODE="$2"; MIN="$3"; SSRC="$4"
DIR=/var/lib/numbers
SECS=$(( (MIN + 1) * 60 ))          # one more minute for the "before"
LIFE=$(( (SECS + 60) * 50 ))        # blocks of 20 ms, with one minute to spare
tune -q -r hf.local -s "$SSRC" -f "$FREQ" -m "$MODE" --lifetime "$LIFE"
timeout "$SECS" pcmrecord -d "$DIR" -S "$SSRC" hf-pcm.local || true
```

```bash
sudo chmod +x /usr/local/bin/record-one
sudo install -d -o radio -g radio /var/lib/numbers
```

Start it one minute before the listed time, as the user `radio`.

```bash
sudo -u radio record-one 8680k usb 15 900001
```

- `-q` makes `tune` print nothing.
- `|| true` keeps the script from failing when `timeout` stops the recorder, which is the normal end.
- Give two transmissions at the same time two different SSRC numbers.

## 9. Path B: a daily schedule reader (an idea)

My station reads the schedule once a day and records every entry by itself. That program is not public. You can build the same idea from section 5 and section 8. I give the logic in words, because I did not write and test a public version.

1. **Once a day, ask the feed.** Ask for the next 36 hours, with 300 entries or fewer, at a fixed time. I ask at 00:20 UTC. Also ask when the computer starts and the saved schedule ends in less than 12 hours.
2. **Keep the reply.** Save each day's reply in a folder. Then a broken day can be read again, and you can see what changed.
3. **Read each entry.** Take the start time, the station code, the frequency and the mode from the line of text. Skip an entry with "Search" or with no frequency.
4. **Choose the settings.** USB and USB/AM: preset `usb`, the listed frequency. CW: preset `cwu`, the listed frequency. RTTY: preset `usb`, 1.5 kHz lower.
5. **Choose the length.** Use the table in section 5. Use 15 minutes for a station you do not know.
6. **Give each recording its own SSRC.** Use a small pool of numbers, and free a number when its recording ends.
7. **Start each recording one minute early.** Use the system's timer, or a program that sleeps until the time. Run `record-one` from section 8.
8. **Set a limit.** Allow only a fixed number of recordings at once. My station allows 12. Log an entry that finds no free place, so you know what you missed.
9. **Judge each recording.** Compare the minute before the listed time with the minutes after it. A tone or a voice that starts on time counts as heard. A signal that was there all along does not.
10. **Delete old sound files.** Keep the ones you marked as heard. Section 12 has a delete command.

The feed's times end in `Z`, which is UTC. Your timer must use UTC too, or convert.

## 10. Signals that are always there

The scheduled stations are rare guests. Two other kinds of signal are on the air almost all the time. They show you, tonight, whether your station hears Russia at all.

### The Russian navy's letter beacons

Each Russian naval base sends one letter in Morse code, over and over. Ships use the beacons to find the best channel. The beacons sit side by side in slots 100 Hz apart, so one narrow slice shows which bases reach you.

| Letter | Base | Tone, dial 1 kHz below the D slot |
|---|---|---|
| D | Sevastopol | 1000 Hz |
| P | Kaliningrad | 1100 Hz |
| S | Severomorsk | 1200 Hz |
| C | Moscow | 1300 Hz |
| A | Astrakhan | 1400 Hz |
| F | Vladivostok | 1500 Hz |
| K | Petropavlovsk-Kamchatsky | 1600 Hz |
| M | Magadan | 1700 Hz |

From the Pacific Northwest, the nearest bases are Petropavlovsk-Kamchatsky (K) and Magadan (M), both about 5,300 to 5,400 km away.

**Where to tune.** Set upper sideband. Set the dial exactly 1 kHz below the first slot of a cluster. The letters are then tones from 1000 Hz up, in steps of 100 Hz.

| Cluster, first slot | Dial, USB | Letters, from 1000 Hz up |
|---|---|---|
| 3594.7 kHz | 3593.7 kHz | D P S C A F K M |
| 4557.7 kHz | 4556.7 kHz | D P S C A F K M |
| 5153.7 kHz | 5152.7 kHz | D P S C A F K M |
| 7039.2 kHz | 7038.2 kHz | F K M (F 1000, K 1100, M 1200 Hz) |
| 7508.7 kHz | 7507.7 kHz | D P S C A |
| 8494.7 kHz | 8493.7 kHz | D P S C A F K M |
| 10871.7 kHz | 10870.7 kHz | D P S C A F K M |
| 13527.7 kHz | 13526.7 kHz | D P S C A F K M |
| 16331.7 kHz | 16330.7 kHz | D P S C A F K M |
| 20047.7 kHz | 20046.7 kHz | D P S C A F K M |

Priyom's table puts the 7 MHz Pacific letters (F, K, M) at 7039.2 to 7039.4 kHz, not beside the other five. It does not say if that is a typing error. My station settled it: on the first night it heard K on 7039.3 kHz, 11 to 22 dB over the noise, within 1.5 Hz of its slot. Later that night it heard C, Moscow, on 8495.0 kHz at 9 and 14 dB. Priyom also says that not all channels are active at a given time.

**What it looks like.** On the waterfall: a thin line, on and off, exactly at its slot. It does not drift. A frequency error in your radio moves all the lines together. The 100 Hz steps between them stay.

**What it sounds like.** One Morse letter, again and again. K is dash dot dash. C is dash dot dash dot. M is dash dash.

**Path A.** Tune the dial in SDR++ as in the table. Set the bandwidth near 3000 Hz, so that 1000 to 1700 Hz is inside it. Look for the lines on the waterfall. Record with the Recorder, as in section 6.

**Path B.** Give `radiod` one fixed channel for each cluster. Add this section at the end of `/etc/radio/radiod@hf.conf`.

```ini
[LETTERS]
data = letters.local
mode = usb
samprate = 12k
freq = "3593k7 4556k7 5152k7 7038k2 7507k7 8493k7 10870k7 13526k7 16330k7 20046k7"
```

```bash
sudo systemctl restart radiod@hf
monitor letters.local
```

Result: a list of ten sessions. Use the arrow keys to select one. Press `M` to mute all, then `u` to open the selected one. Press `Q` to leave. I wrote this section for this guide in the form of the project's examples. My station makes its letter channels in another way.

To see the tones, record a few minutes with `pcmrecord -d <REC_DIR> letters.local`. Open the file in a sound editor that has a spectrogram view.

> **Caution.** 7039.2 kHz is inside the 40 m amateur band. An amateur CW station near it is not a beacon. A beacon sends one letter only, sits exactly on its slot, and keeps going for hours.

### The Buzzer

The Buzzer is a buzz on 4625 kHz, around the clock, since the 1970s. Now and then a live voice breaks in. It is not a spy station. Priyom believes it is a Russian military command network, and the buzz only holds the frequency. Its old name, UVB-76, is a mistranscription of a callsign.

1. Set upper sideband. Set the dial to 4625 kHz.
2. Listen for a short, rough buzz that repeats.
3. Try at night along the path. Saint Petersburg is about 7,800 km from the Puget Sound, across the Arctic.

Priyom says that most voice messages come in local daytime on weekdays, Moscow Time (UTC+3). Two sister networks hold frequencies the same way. The Pip uses 5448 kHz by day and 3756 kHz by night. The Squeaky Wheel uses 5367 kHz by day and 3363.5 kHz by night.

My station watches all five frequencies. A probe of 4 minutes at night, on 2026-10-23, heard no buzz on any of them.

## 11. What to expect from the Pacific Northwest

Be honest with yourself about the distance. Most of these stations are half a world away from the Puget Sound. The operators on the schedule are Russian (Moscow, and Pacific schedules from Khabarovsk), Polish, Taiwanese, and a V32 transmitter in Germany. Taiwan and Khabarovsk are across the Pacific, which is closer.

In my first night, my station judged 20 scheduled transmissions and heard none of them. My antenna is still a small loop just outside my window. The same night, it heard the K and C letter beacons.

So start with the beacons. They tell you which paths to Russia are open at that hour. Then try the entries that come from across the Pacific, and the ones marked "Target: North America".

## 12. Running it unattended

**Path A.** Path A is a person at the dial. SDR++ records only while you press Record. That is the honest limit of the lowest-cost path.

**Path B.** `radiod` is a service already. It starts with the PC. The fixed letter channels start with it. A daily reader, as in section 9, needs a timer that you build.

> **Caution.** The recordings fill the drive. A 12 kHz channel is about 2 GB each day if it records all the time. A full drive stops the receiver's other jobs.

Delete old recordings with this command. It removes files older than 3 days. Move the ones you want to keep to another folder first.

```bash
sudo -u radio find /var/lib/numbers -type f -mtime +3 -delete
```

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

### A spectrum picture, and two rules that keep `radiod` alive

My station also keeps a picture of all of shortwave, every fifteen seconds, for thirty days. Then I can look at any frequency after the fact, for example after someone reports a station. That program is not public. It asks `radiod` for spectrum data. ka9q-radio's own spectrum client is called `powers`.

> **Warning.** Two kinds of spectrum request crashed `radiod` on my station, on 2026-10-23. Every channel stopped each time, seven times in 48 seconds. Never change the bin count or the width of a spectrum channel that is live. Use a new SSRC for new settings. Never ask for more than 15000 bins in one channel.

The causes, as I read them in the source at commit `b5bbb9aa`:

1. **A live channel that grows.** The new bin count is recorded before the buffer check, so the buffer is not enlarged. Reusing one SSRC for 300, then 3000, then 30000 bins crashed it.
2. **Too many bins.** The status reply holds all the bins in a buffer of 65,536 bytes, with no size check. Each bin is 4 bytes, so about 16,000 bins fill it. 30000 bins crashed `radiod` even on a new channel.

The project has a newer commit, dated 2026-10-17, named "fix spectrum heap overrun". I did not test whether it fixes either crash. Keep both rules anyway. My station covers 0 to 30 MHz with two channels of 15000 bins of 1 kHz each.

## 13. Sharing (optional)

You do not need to share anything. If you do, read this first.

> **Your station becomes public.** A log or a recording that you post can carry your name, your callsign and the time zone of your house. Choose a name that does not name you or your street. Do not add your position.

- **Share the facts of a transmission.** The UTC time, the frequency, the station code, and what kind of signal it was. That is what listeners compare.
- **Do not share a reading of the content.** Nobody can read a one-time-pad message from the air. A guess presented as a reading is false.
- **Credit Priyom.** Its schedule and catalogue are CC BY-NC-SA 4.0: name Priyom, link it, and share under the same terms.
- **The Buzzer's voice messages.** Log the time and the frequency. Do not publish a transcript.

## 14. Check that it works

1. **The radio hears shortwave.** Tune 10000 kHz, AM. In most of North America you hear a time signal with a tick each second. Wait: 1 minute.
2. **The clock is right.** Compare the PC clock with that time signal. They must agree to one second.
3. **The letter beacons.** Tune the 7038.2 kHz cluster and the 8493.7 kHz cluster, USB, at night. Pass: a thin line on and off at 1100 Hz (K) or 1300 Hz (C), with a Morse letter. Wait: 10 minutes on each. Try other clusters and other hours if none.
4. **One scheduled transmission.** Record one entry from 1 minute before to 15 minutes after. Pass: a voice, Morse or tones that start at the listed time. With a small antenna this may fail many times. That is a result, not a fault.
5. **The file.** Play the recording. Pass: you hear the minute before, then the listed time.
6. **Path B only.** Run these.

   ```bash
   systemctl is-active radiod@hf            # expect "active"
   lsusb -t | grep -B2 usbfs                # the receiver's line ends in 5000M
   control hf.local                         # the new channel is in the list while it records
   ls -l /var/lib/numbers                   # new sound files
   ```

Then keep a log for one week: the entries you tried, and what came. Write "not heard" too. That is your baseline. Change one thing at a time, and compare with it.

## 15. If it does not work

| Symptom | Likely cause | What to do |
|---|---|---|
| SDR++ shows an empty waterfall on every band with a V4L | The driver is older than 2026 and does not know the V4L's tuner | Update the driver as the RTL-SDR Blog guide says. Try a newer nightly build |
| Linux: the radio is "busy" or cannot be opened | The kernel's TV driver took the RTL radio | Block the driver as the RTL-SDR Blog guide says. Restart the computer |
| Shortwave is silent with a V4L, and VHF works | "Direct Sampling" is set to I or Q branch | Set it to Disabled. The V4L uses its own converter |
| A strong false line sits on the frequency you want | The exact center of an RTL radio has a false signal | Move the center 10 to 50 kHz away, and tune inside the slice |
| Nothing at the listed time | Normal. The path is closed, or it was a null that you did not hear | Log "not heard". Try the beacons to see which paths are open |
| A signal is there, but it was there before the listed time | Another station on the frequency, or local noise | It is not the station. Compare the minute before with the minutes after |
| Wrong station, or one hour off | Local time in place of UTC, or summer time | Use UTC everywhere. Set the recorder's time zone to UTC |
| Voice sounds like a duck | Lower sideband, or the dial is off | Set upper sideband. Set the exact frequency |
| Morse is a tone too high or too low to hear | The dial is far off for CW in USB | Set the dial 800 Hz below the listed frequency, or use CW mode |
| The beacon lines are not at 1000, 1100 ... Hz | The dial is not exactly 1 kHz below the first slot, or the radio's frequency is off | Check the dial. The 100 Hz spacing still names the letter |
| A CW signal near 7039 kHz moves or calls CQ | An amateur station in the 40 m band | It is not a beacon. A beacon sends one letter, on its slot |
| `tune` waits and prints nothing | `radiod` does not run, or the status name is wrong | `systemctl is-active radiod@hf`. Use `-r hf.local` |
| `tune` says "--ssrc not specified" | No `-s`, or `-s 0` | Give an SSRC from 1 up that the list does not use |
| `radiod`'s log says "Dynamic create ... failed; is 'data =' set in [global]?" | `[global]` has no `data` line | Add `data = hf-pcm.local` and `mode = usb` to `[global]`. Restart |
| `pcmrecord` writes nothing | Wrong group, or wrong SSRC | Use `hf-pcm.local` and the same `-S` number as `tune` |
| Old channels stay in `control`'s list | They were made with no `--lifetime` | Give `--lifetime` every time. Restart `radiod@hf` to clear them |
| A channel hears nothing on its frequency | The frequency has no unit letter | Write `8680k`, not `8680` |
| `radiod` restarts again and again after a spectrum request | A live spectrum channel changed its bin count, or more than about 16,000 bins | Section 12: a new SSRC for new settings, 15000 bins or fewer |
| Shortwave is full of signals that should not be there (Path B) | No 30 MHz low-pass filter, so signals above 32.4 MHz fold back | Fit the filter (section 4) |
| `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 | DC is wrong: the limiter blocks it, or the injector has no power | Injector first on the loop cable. Check its power supply |
| The 3.6 MHz beacons and the night bands are weak (Path B) | The F3060 shelf filter is on | Bypass it |
| The drive is full | Recordings were never deleted | Run the delete command in section 12 each day |
| The feed returns an error | You asked for more than 300 entries | Ask for 300 or fewer, for a shorter window |

## 16. What I did wrong

- **I crashed my receiver seven times in one minute.** I tested the spectrum picture by asking one channel for 300, then 3000, then 30000 bins. `radiod` crashed each time, and every decoder on the station stopped for about 50 seconds. Use a new SSRC for new settings, and stay at 15000 bins or fewer.
- **My antenna is still a small loop just outside my window.** In my first night my station judged 20 scheduled transmissions and heard none. Put your antenna outside, away from the house, before you judge the stations.
- **I nearly trusted one table.** Priyom's table puts the 7 MHz Pacific letters at 7039.2 kHz and the others at 7508.7 kHz, and it leaves the question open. My station found K at 7039.3 kHz. Listen to both before you decide that a cluster is empty.

## 17. Not run and not confirmed

- **My own programs are not public.** My recorder, my letter-beacon receiver and my spectrum archive are not public. Every public method in this guide is a replacement that I did not run as written.
- **No reception of a numbers station.** My station has heard none so far. Every "what it sounds like" for a numbers station is from Priyom's descriptions, not from my receiver.
- Every SDR++ step in section 6. The names of the controls ("Direct Sampling", "Disabled", "Recorder", "Audio", "Baseband", "Time zone", "UTC", "Record", "Stop") are from its source code, read on 2026-10-23. I did not confirm the name of the "Source" and "Radio" menus or the look of the play button.
- That the driver inside an SDR++ nightly build knows the RTL-SDR Blog V4L. The seller says the V4L needs the latest drivers.
- The RTL-SDR Blog V4L on shortwave. Its built-in converter is the seller's statement. I have not used it below 24 MHz.
- The download of SDR++ nightly builds. The README says an account on GitHub is needed. I did not download one.
- The 35 GB an hour for a baseband file. I computed it for 16-bit samples. The recorder's default sample type may differ.
- `tune` and `pcmrecord` in section 8. I read their options in the source code at today's main branch and at commit `b5bbb9aa`. The manual page for `tune` is an empty template. I did not run these commands as written. My station makes its channels in another way.
- That `--lifetime` works as I describe. In `tune` the short form `-t` is not in the program's option list, so I give only the long form. That 0 means "immortal" is from the project's `help.txt`. The 50 blocks each second assumes the default block of 20 ms. I did not read the value on my station.
- That a channel made by `tune` stays open while `pcmrecord` reads it, and closes at the end of its lifetime. I read this in the source. I did not test it.
- The name of the file that `pcmrecord` writes. I read the pattern in the source: the SSRC, then the UTC date and time.
- The script `record-one` in section 8. I wrote it for this guide. I did not run it. The `timeout` command is from GNU coreutils, which Ubuntu includes. I did not confirm its exit code when it stops `pcmrecord`; `|| true` covers that case.
- Section 9 as a whole. It describes the logic of my own program in words. I did not write a public version.
- The tuning for RTTY entries, 1.5 kHz below the listed frequency. I did not confirm from Priyom whether the listed frequency of an RTTY entry is its center. My station sets its RTTY channels so the tones fall near 1500 Hz.
- The 800 Hz offset for CW in USB. It is a common practice, not from a source today.
- The ka9q-radio section `[LETTERS]` in section 10. I wrote it in the form of the project's examples. I did not run it. The ten dials are mine, from Priyom's table and my station's first result.
- That the letter beacons send Morse code. Priyom does not say. It is general knowledge, and my station measured K keyed on and off for about half the time.
- The distances to the bases and to Saint Petersburg. They are approximate figures from my own notes.
- That the Buzzer reaches the Puget Sound. My one short probe heard nothing.
- That the 2026-10-17 commit "fix spectrum heap overrun" fixes either spectrum crash. I read only its name and size. The status buffer of today's code still shows no size check that I could see.
- The 2 GB each day for one 12 kHz channel. I computed it for 16-bit samples.
- The look of Priyom's schedule page. The page builds its list in the browser, and I could read only its feed today. The feed's entries and the limit of 300 are what I read on 2026-10-23.
- The law paragraph. I am not a lawyer. I read 47 U.S.C. 605 for the other guides on 2026-10-07, not today.
- The price and the connector of the RX-888 Mk II, the F3060 and the limiter, and every "See listing" price. Read each listing.
- That the newest ka9q-radio builds with the steps in section 7. I built the commit named there. The project had new commits today.
- No step in this guide was run on a new, empty computer as written.

## 18. Sources

All were read on 2026-10-23, except where a date is given.

**The episode.** Its fact sheet, its script and its link list, in the series' private repository. The counts from my station are from the first night, 2026-10-23.

**My station.** My own runbook for the shortwave receiver, sections on the numbers-station recorder, the letter beacons, the spectrum archive and the spectrum crash, written 2026-10-23. It is private. Only facts that the episode also uses are in this guide.

**The full-station guide and the Shortwave guide.** [Build the station](/guides/build-the-station/), sections 2, 4, 11, 15 and 17, checked against my station on 2026-10-07. [Shortwave](/guides/shortwave-receiver/), sections 2, 5, 9 and 12 to 17, 2026-10-10. The parts, the prices, the ka9q-radio install steps and the law paragraph come from them.

**Priyom.** Content CC BY-NC-SA 4.0. The schedule page: <https://priyom.org/number-stations/station-schedule>. Its feed: <https://calendar2.priyom.org/events> (one request, for 24 hours from 2026-10-23 10:00 UTC: 115 entries). The catalogue: <https://priyom.org/number-stations>. The pages on E11, Russian 7, M12, V13, V32, S06, the station lists, the Buzzer (<https://priyom.org/military-stations/russia/the-buzzer>), The Pip, The Squeaky Wheel and the single-letter beacons (<https://priyom.org/military-stations/russia/single-letter-beacons>), all saved on 2026-10-06 and read through my notes.

**The one-time pad.** A public overview: <https://en.wikipedia.org/wiki/One-time_pad> (linked, not read today). Shannon's result is standard knowledge.

**ka9q-radio.** <https://github.com/ka9q/ka9q-radio>, main branch at commit `af940c5c` (2026-10-23), and commit `b5bbb9aa` for `tune` and `pcmrecord`. Read: `docs/utils/pcmrecord.md`, `docs/tune.1` (an empty template), `docs/ka9q-radio.md` (the `data` and `mode` lines of `[global]`), `docs/ka9q-radio-3.md` ("The Dynamic Template"), `share/presets.conf` (`usb`, `cwu`, `am`), `share/help.txt` (lifetime), `Makefile` (the programs it installs), and in `src/`: `tune.c`, `pcmrecord.c`, `parse.c` (frequency units), `radio_status.c`, `radio.c`, `radio.h`, `modes.c` and `defaults.h` (the lifetime), and the commit list of `spectrum.c`.

**SDR++.** <https://github.com/AlexandreRouma/SDRPlusPlus>: `readme.md` (nightly builds, module list), `misc_modules/recorder/src/main.cpp` and `source_modules/rtl_sdr_source/src/main.cpp` (the names of the controls), the release list. Read with `ctx7` and the GitHub API.

**The radio.** RTL-SDR Blog V4L: <https://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/> (the price, the built-in converter, the driver note).

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

[^nec]: Mike Holt's summary of NEC 810.21, 2020 edition: <https://www.mikeholt.com/files/PDF/20BG_810.21.pdf>.
