Installing Substation
By the end of this chapter, Substation is installed on your computer with the driver your receiver needs, and it can list every band it knows.
Installing means typing commands into a terminal, the window where you give your computer commands by name, and this chapter gives every one of them. Each command is a line starting with $, which you leave out when you type it.
Does Substation work with your receiver already? Skip to A first scan.
What you need
- Linux. Substation is tested on Linux, and this chapter gives the commands for Debian, Ubuntu and Raspberry Pi OS, and for Fedora, where they differ. Nothing in Substation's own code is tied to Linux, but it has not been tested on macOS, or on Windows under WSL, so this guide does not cover them. On Linux, it has been tested:
- on Ubuntu 24.04, on a 64-bit PC, in September 2026, with an RTL-SDR Blog V4, a HackRF One and both Airspys;
- on Debian 12, Raspberry Pi OS (Bookworm) and Fedora 43 Server, in April 2026, and not since;
- on a Raspberry Pi 5 with an RTL-SDR Blog V3, with an early version of Substation, around March or April 2026, and not since.
- A terminal, which every Linux desktop has, and which you reach over SSH on a machine with no screen.
- Python 3, which all four systems come with. Substation is written in it, but using Substation needs no Python of your own. If yours is too old for Substation, the install step says so and installs nothing.
- Your receiver, for checking its driver once that is installed. The rest needs no receiver at all.
Your receiver's driver
A driver is the software your computer reaches a receiver through. Install the one for your receiver, or one for each if you have several.
An RTL-SDR
RTL-SDR Blog makes a driver of its own, a version of the standard RTL-SDR driver, librtlsdr, that knows the V4's tuner and its converter for the HF bands, and switches a V3 into direct sampling below 24 MHz. Most Linux systems' own packages hold the standard driver, so remove any you have, and build RTL-SDR Blog's from its source.
On Debian, Ubuntu and Raspberry Pi OS, remove any RTL-SDR driver already installed:
Example not checked: it is not run when this site is built.
sudo apt purge ^librtlsdr
sudo rm -rvf /usr/lib/librtlsdr* /usr/include/rtl-sdr* /usr/local/lib/librtlsdr* /usr/local/include/rtl-sdr* /usr/local/include/rtl_* /usr/local/bin/rtl_*
Install what building it needs, then fetch its source, build it and install it:
Example not checked: it is not run when this site is built.
sudo apt update
sudo apt install -y libusb-1.0-0-dev git cmake pkg-config build-essential
git clone https://github.com/rtlsdrblog/rtl-sdr-blog.git rtl-sdr
cd rtl-sdr
mkdir build && cd build
cmake ../ -DINSTALL_UDEV_RULES=ON
make
sudo make install
sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
sudo ldconfig
cd ../..
The rules copied into /etc/udev/rules.d/ let you use the receiver without sudo.
On Fedora, remove any RTL-SDR driver already installed, and install what building it needs:
Example not checked: it is not run when this site is built.
sudo dnf remove 'rtl-sdr*' 'librtlsdr*'
sudo rm -rvf /usr/lib/librtlsdr* /usr/lib64/librtlsdr* /usr/include/rtl-sdr* /usr/local/lib/librtlsdr* /usr/local/lib64/librtlsdr* /usr/local/include/rtl-sdr* /usr/local/include/rtl_* /usr/local/bin/rtl_*
sudo dnf group install -y development-tools
sudo dnf install -y gcc gcc-c++ libusb1-devel git cmake pkgconf
Then fetch, build and install it with the same lines as above, from git clone to cd ../... Fedora keeps 64-bit libraries in /usr/lib64: if a program later says a library is not found, check that /usr/local/lib64 is listed in a file in /etc/ld.so.conf.d/, and run sudo ldconfig again.
Linux takes an RTL-SDR for the television receiver it was made as, and claims it with a television driver of its own, dvb_usb_rtl28xxu. One line stops it, on every system:
Example not checked: it is not run when this site is built.
echo 'blacklist dvb_usb_rtl28xxu' | sudo tee --append /etc/modprobe.d/blacklist-dvb_usb_rtl28xxu.conf
Restart the computer, then plug the receiver in and run RTL-SDR Blog's test. It should find the receiver and start running, and Ctrl-C stops it:
Example not checked: it is not run when this site is built.
rtl_test
A HackRF One
Its driver and tools are packaged for all four systems. On Debian, Ubuntu and Raspberry Pi OS:
Example not checked: it is not run when this site is built.
sudo apt install -y libhackrf-dev hackrf
On Fedora:
Example not checked: it is not run when this site is built.
sudo dnf install -y hackrf hackrf-devel
Substation speaks to it through a Python library, python_hackrf, which installing Substation with its HackRF support brings, below. Two others work differently, hackrf and pyhackrf, and Substation works with either where python_hackrf is not installed.
With the HackRF One plugged in, hackrf_info describes it. If it says No HackRF boards found., the computer cannot see it.
Example not checked: it is not run when this site is built.
hackrf_info
An Airspy, or another receiver through SoapySDR
SoapySDR is one library that reaches many makers' receivers, each through a module of its own. Substation reaches both Airspy receivers through it, and any other receiver that has a module.
On Debian, Ubuntu and Raspberry Pi OS, install SoapySDR and its Python library, then the module for your receiver: soapysdr-module-airspy for the Airspy R2, and soapysdr-module-airspyhf for the Airspy HF+ Discovery.
Example not checked: it is not run when this site is built.
sudo apt install -y soapysdr-tools python3-soapysdr
sudo apt install -y soapysdr-module-airspy
sudo apt install -y soapysdr-module-airspyhf
Raspberry Pi OS may have no soapysdr-module-airspyhf. Build it from its source instead:
Example not checked: it is not run when this site is built.
sudo apt install -y libairspyhf-dev libsoapysdr-dev cmake
git clone https://github.com/pothosware/SoapyAirspyHF.git
cd SoapyAirspyHF
mkdir build && cd build
cmake ..
make
sudo make install
cd ../..
On Fedora, install SoapySDR, its Python library and the HF+ Discovery's module:
Example not checked: it is not run when this site is built.
sudo dnf install -y SoapySDR SoapySDR-devel python3-SoapySDR
sudo dnf install -y soapy-airspyhf
Fedora has no module for the Airspy R2, so build it from its source:
Example not checked: it is not run when this site is built.
sudo dnf install -y airspyone_host-devel SoapySDR-devel cmake
git clone https://github.com/pothosware/SoapyAirspy.git
cd SoapyAirspy
mkdir build && cd build
cmake ..
make
sudo make install
cd ../..
With the receiver plugged in, SoapySDR lists every receiver it can see:
Example not checked: it is not run when this site is built.
SoapySDRUtil --find
On Fedora, if a receiver is not found even with its module installed, SELinux may be refusing it, and sudo ausearch -m avc -ts recent shows what it refused.
What else your system needs
Substation writes its recordings with libsndfile, a library for sound files, and a few of Python's own packages help it install. On Debian, Ubuntu and Raspberry Pi OS, where python3-venv is what makes the environment below:
Example not checked: it is not run when this site is built.
sudo apt install -y libsndfile1 libsndfile1-dev python3-setuptools python3-dev python3-venv
On Fedora:
Example not checked: it is not run when this site is built.
sudo dnf install -y libsndfile libsndfile-devel python3-setuptools python3-devel
Room for a wide band
A receiver hands over its IQ samples through memory that Linux sets aside for USB, and by default it sets aside too little for a wide band. A HackRF One at its widest needs more, and so does an RTL-SDR handing over a long stretch at a time. Without it, an RTL-SDR stops with Failed to submit transfer, and a HackRF One drops IQ samples.
The limit is a kernel parameter, a setting Linux reads as it starts: usbcore.usbfs_memory_mb=1000. To try it before you change anything for good, this sets it until the computer next restarts:
Example not checked: it is not run when this site is built.
echo 1000 | sudo tee /sys/module/usbcore/parameters/usbfs_memory_mb
To keep it, add it where your system reads its kernel parameters, then restart.
- Raspberry Pi OS:
/boot/firmware/cmdline.txtholds them on a single line. Open it withsudo nano /boot/firmware/cmdline.txtand addusbcore.usbfs_memory_mb=1000to the end of that line, after a space. - Debian and Ubuntu: open
/etc/default/grubwithsudo nano /etc/default/grub, addusbcore.usbfs_memory_mb=1000inside the quotation marks of the line startingGRUB_CMDLINE_LINUX_DEFAULT, save it, and runsudo update-grub. - Fedora: one command adds it.
Example not checked: it is not run when this site is built.
sudo grubby --update-kernel=ALL --args="usbcore.usbfs_memory_mb=1000"
After restarting, cat /proc/cmdline prints the parameters Linux started with, and usbcore.usbfs_memory_mb=1000 should be among them.
An environment for Substation
A virtual environment is a folder that holds Substation and the Python packages it uses, apart from everything else on your computer. It is the usual way to install a program written in Python, and needs no Python of your own. Substation is run from a folder of its own, which holds its settings and what it records, so make that folder and the environment inside it:
mkdir radio
cd radio
python3 -m venv .venv
source .venv/bin/activate
The last line switches the environment on. It lasts until you close the terminal, so run it again from the radio folder each time you open a new one. Python's tutorial explains virtual environments in full.
With an Airspy, or any receiver through SoapySDR, make the environment with --system-site-packages instead, so it can see the SoapySDR library your system installed:
Example not checked: it is not run when this site is built.
python3 -m venv --system-site-packages .venv
An environment made without it can see the system's libraries too, by changing one line of its own settings, in .venv/pyvenv.cfg:
Example not checked: it is not run when this site is built.
sed -i 's/include-system-site-packages = false/include-system-site-packages = true/' .venv/pyvenv.cfg
Substation
With the environment switched on, install Substation:
pip install "substation==0.8.2"
That line installs the release this guide is checked against.
With a HackRF One, install Substation with its HackRF support instead, which builds the HackRF One's Python driver against the libhackrf-dev or hackrf-devel package you installed above:
Example not checked: it is not run when this site is built.
pip install "substation[hackrf]==0.8.2"
Check that it works
Ask Substation for every band it knows:
substation --list-bands
Each band has a name, amateur_2m for the 2m band, its range and modulation, and the spacing of its radio channels. Most bands only detect transmissions out of the box, saying when a radio channel is busy without recording it. A later chapter says which bands record by default, and how to change it.
With Substation installed, the next chapter scans the 2m band, with your receiver or with a test signal in place of one.