Topic hub

Software-defined radio

How a software-defined radio turns RF into complex samples on a host, the driver and framework layers above it, choosing sample rates, and recording and replaying IQ with SigMF.

Updated 15 Nov 2026 · SDR, GNU Radio, UHD, SoapySDR, IQ samples, sample rate, SigMF

Overview

A software-defined radio (SDR) does in software what older radios did with fixed analogue circuits. The hardware converts between RF and a stream of complex baseband samples. Everything after that, from filtering to demodulation and decoding, runs on a general-purpose processor, an FPGA or both. Joseph Mitola described the architecture in The software radio architecture (IEEE Communications Magazine, 1995). Today the same idea ranges from receive-only USB dongles to multi-channel radios with FPGAs.

This hub is for engineers who want to receive, transmit, record or prototype a waveform on real hardware. SDR is also how most of the lessons on this site connect to the air. A modulation scheme you simulate in NumPy can go through a real radio with little change to the code.

Key ideas

The signal chain and where the software starts

A typical SDR has an RF front end (filters, a low-noise amplifier, a mixer and local oscillator), a pair of converters, an FPGA and a link to the host. The FPGA usually performs digital down-conversion and decimation so that the host link carries only the bandwidth you asked for. The host sees IQ samples at a chosen rate and centre frequency.

Radio hardwareantennaRF front endLNA, filters, mixerADC and DACI and Q branchesFPGADDC, decimationHost linkUSB 3.0 or EthernetIQ samplesDriverUHD, SoapySDR, libiioFrameworkGNU Radio, PythonIQ recordingSigMF data + metaAnalysisNumPy, SciPyHost computer
Receive path of a typical SDR. The radio hardware converts RF to complex samples and reduces their rate, the host link carries them to a driver, and a framework such as GNU Radio processes them or writes them to a SigMF recording for later analysis. Transmit runs the same chain in reverse.

Hardware ranges widely. The RTL-SDR Blog V4 is a receive-only dongle covering 500 kHz to 1.766 GHz with an 8-bit RTL2832U converter and 2.56 MHz of stable sample rate, according to its datasheet. The USRP B210 covers 70 MHz to 6 GHz with up to 56 MHz of instantaneous bandwidth and 2 TX and 2 RX channels over USB 3.0, according to the Ettus Research product page. That page names the AD9361 transceiver but does not list converter bits. The hardware table compares more devices.

Drivers and frameworks

Each hardware family has its own driver. UHD (GPL-3.0 for the host code) drives the USRP range. libiio (LGPL-2.1) drives Analog Devices devices that use the Linux IIO framework. SoapySDR (Boost Software License 1.0) is a vendor-neutral layer with modules for many devices, so one program can open different radios by changing an argument string.

GNU Radio (GPL-3.0) is the framework most engineers start with. A flowgraph connects blocks, and the scheduler moves sample buffers between them. The code on this site runs on GNU Radio 3.10.12. GNU Radio 4.0 is a rewrite. Its third release candidate came out on 13 October 2026, according to the project’s news page.

With complex sampling at rate fs, you see fs of spectrum centred on the tuned frequency, from −fs/2 to +fs/2. There is no separate negative-frequency image to waste, which is why complex rather than real sampling is the norm. Pick fs a little above the signal bandwidth and let a digital filter do the rest. Too high a rate costs CPU and link capacity. Too low a rate aliases neighbouring signals into your band.

The arithmetic is simple and often forgotten. One complex64 sample is 8 bytes, so 20 MS/s on the host is 160 MB/s of memory traffic, before any processing. If the host cannot keep up, the driver drops samples and reports an overflow. Check for overflows before you trust any measurement.

Recording and replaying IQ

Recording raw IQ lets you capture once and analyse many times, share a capture with a colleague, or replay a signal through a transmitter in a shielded setup. A bare .bin file is ambiguous. Nobody knows the sample rate, the centre frequency or the sample format a month later. SigMF solves this with a data file and a JSON metadata file. The specification is licensed CC BY-SA 4.0, and the repository example uses version 1.2.0.

The block below writes a synthetic tone as a SigMF pair, reads it back and finds the tone. It needs no radio.

import json
from pathlib import Path

import numpy as np

rng = np.random.default_rng(7)
fs = 1_000_000.0  # sample rate, Hz
n = 100_000
t = np.arange(n) / fs
# complex64 baseband: a tone 125 kHz above the centre frequency plus noise
iq = np.exp(2j * np.pi * 125e3 * t) + 0.05 * (rng.standard_normal(n) + 1j * rng.standard_normal(n))
iq = iq.astype(np.complex64)

base = Path("tone_capture")
iq.tofile(base.with_suffix(".sigmf-data"))  # interleaved little-endian float32 I, Q
meta = {
    "global": {"core:datatype": "cf32_le", "core:sample_rate": fs, "core:version": "1.2.0",
               "core:description": "synthetic tone, 125 kHz offset"},
    "captures": [{"core:sample_start": 0, "core:frequency": 433.92e6}],
    "annotations": [],
}
base.with_suffix(".sigmf-meta").write_text(json.dumps(meta, indent=2))

# read it back the way any other tool would
m = json.loads(base.with_suffix(".sigmf-meta").read_text())
x = np.fromfile(base.with_suffix(".sigmf-data"), dtype=np.complex64)
spec = np.fft.fftshift(np.abs(np.fft.fft(x[:4096])))
freqs = np.fft.fftshift(np.fft.fftfreq(4096, 1 / m["global"]["core:sample_rate"]))
peak_hz = freqs[np.argmax(spec)]
rf_hz = m["captures"][0]["core:frequency"] + peak_hz
print(f"{x.size} samples, {x.nbytes} bytes, peak at {peak_hz / 1e3:.1f} kHz offset = {rf_hz / 1e6:.4f} MHz RF")

It prints 100000 samples, 800000 bytes, peak at 125.0 kHz offset = 434.0450 MHz RF.

Where to start

Begin with Complex baseband and IQ, which explains what the samples mean. Then build Your first GNU Radio flowgraph and work through Recording and reading IQ. The GNU Radio FM receiver project puts the pieces together. For FPGA-side signal processing in an SDR, FPGA Guide has a wireless and SDR hub.

Tools and platforms

Tool What for Licence
GNU Radio Flowgraph framework for signal processing and radio control GPL-3.0
UHD Driver and API for USRP radios GPL-3.0 (host code)
SoapySDR Vendor-neutral SDR API with device modules Boost Software License 1.0
libiio Driver library for Analog Devices IIO devices LGPL-2.1
SigMF Metadata format for IQ recordings CC BY-SA 4.0

Platform hubs: GNU Radio, NI and Ettus Research, Analog Devices and open-source tools. The software matrix lists versions and operating system support.

Common mistakes

  • Setting the sample rate equal to the signal bandwidth, with no room for filter roll-off.
  • Ignoring the DC spike and IQ imbalance of direct-conversion front ends. Tune slightly off the signal and shift it digitally.
  • Saving IQ without metadata, then guessing the format later.
  • Mixing up int16, float32 and 8-bit unsigned sample formats when reading a file.
  • Not checking the driver for dropped samples or overflows.
  • Transmitting without a licence or outside an allowed band. Use cables, attenuators and a shielded box for transmit tests.
  • Overdriving the receiver. A strong nearby signal compresses the front end and creates spurs that look like real signals.

Going deeper