A modern GTK4 software-defined-radio application for HPSDR / ANAN transceivers, built on the proven piHPSDR engine with a new, high-detail user interface.
sdr-for-linux is a GPLv3 fork-in-spirit of
piHPSDR: it reuses piHPSDR's excellent
engine — the HPSDR Protocol 1 and 2 radio links and the WDSP DSP library — and
replaces the front-end with a native GTK4/libadwaita control surface and a
full-resolution floating-point panadapter. No DSP is reimplemented; WDSP
does the heavy lifting.
Status: 0.x — young but real. Everything below is implemented and verified live on an Apache Labs ANAN G2E, an ANAN 10E and a Hermes Lite 2 (all RX + TX), including CW and RTTY contest deployments; see Supported hardware.
Receive
-
Full-float panadapter + waterfall straight from the WDSP analyzer — no quantisation, one column per display pixel (up to 8192, so a wide window gets a sharper waterfall, not a stretched one); trace resolution adjustable; 6 colour palettes, adjustable averaging & FPS
-
SSB / CW / AM / SAM / DIGU / DIGL / RTTY demodulation with piHPSDR filter presets, passband drawn on the spectrum (RTTY: dial = FSK pair centre, audio pitch adjustable — 800 Hz by default, 2210 = the classic 2125/2295). SAM = WDSP synchronous AM: PLL-locked carrier (capture ±2 kHz about the dial), both sidebands or LSB/USB only (a phasing selector in the Filter dialog, not a filter — QRM on one side goes away without re-tuning), and carrier levelling against fading for AM and SAM (Preferences → Audio)
-
Filter and AGC dialogs behind two header-bar icons: a passband graph you drag (edges or the whole band), the mode's presets + Var1/Var2, Low/High rows; AGC Off/Long/Slow/Med/Fast with a live gain bar and the AGC-T threshold. Any preset's edges also drag right on the spectrum (a dragged preset becomes Var1); LSB-family filters read as audio Hz
-
Parametric equalizer (header-bar icon or
e): up to eight bands per side — peak, low shelf, high shelf with frequency, gain and Q — edited on a drawn response curve (drag a node, wheel for Q, double-click to add, right-click to remove) with a row per band; one profile for RX (ahead of the AGC, bypassed in digi modes so decoders hear the raw audio) and one for TX (the pre-EQ ahead of PROC, live mic in voice modes only). The curve is computed here and realized by WDSP's continuous-gain FIR equalizer -
Two VFOs: A/B swap and A=B, the other VFO shown under the frequency readout, free across bands; CTUN: drag pans the spectrum while the dial stays put — the green passband is the tuning handle
-
Noise reduction — ANR (LMS), NR2 (spectral), NNR (WDSP's neural noise reduction: two built-in models, the CW-trained ones switched in automatically in CW modes; model and mask floor in Preferences → Audio) and NR4 (libspecbleach); noise blanker (ANB, NB2), auto-notch (ANF), binaural mode — the NR and NB buttons cycle through the algorithms
-
Low-latency native PipeWire audio (~15 ms), 48/96/192 kHz; the AF slider's floor is a true mute
-
Scroll/drag/click-to-tune, octave-snap zoom, draggable spectrum/waterfall divider, band buttons, band-plan overlay (IARU R1/R2/R3 + country overrides), DX-spot overlay with click-to-tune
-
CW BFO offset done right: the dial reads the carrier, spots sound at your sidetone pitch
Transmit (SSB voice, CW, RTTY, digi via TCI)
- MOX / TUNE with separate drive levels, per-band PA calibration, true-PEP wattmeter, SWR metering with automatic drive-drop protection
- Mic via PipeWire with mic gain / noise gate / phase rotator (WDSP PHROT, with its auto-optimizer and asymmetry readout) / parametric pre-EQ / speech processor controls (digi audio stays a bit-exact clean chain, enforced by the engine), faithful TX monitor (plays the processed on-air audio), footswitch PTT (the pedal counts only while the radio's status packets are live, and a radio-link loss while keyed releases TX — the host never re-keys by itself); Drive and TUNE power remembered per band
- CW keying with clean first-dit and contest-grade latency (TCI→RF ~35 ms, turnaround ~200 ms), adjustable WPM / sidetone / break-in hang; mode-aware TX HUD (CW/RTTY sent-text with playhead, digi TX level)
- Native RTTY: direct-FSK modulator (45.45 Bd / 170 Hz, phase-continuous),
keyed from text over TCI (
rtty_macros:) — pair with a TCI logger and the skimmer for decode - PureSignal linearization with Thetis-style auto-attenuate — calibrates continuously on voice, converges in seconds after drive/band changes (G2E, G2 and Hermes Lite 2; on the G2E it needs the WDSP patch listed under Known limitations; not available on old Hermes-class P2 firmware — see the hardware table)
- TX panadapter + waterfall of the transmitted spectrum, with the TX filter footprint drawn in red (the display's colour language: RX green, TX red)
Integration
- TCI server (ExpertSDR3-compatible): control, CW macros,
RX audio, TX audio (digimodes), wideband IQ with optional per-block
centre stamps for skimmers (TCI 2.1 stream headers with the per-stream
packet counter), spots — verified live with SDC,
CW Skimmer and Decodium (complete FT8 QSOs on the air);
dds/vfogo out on every tuning step. Two listeners, each with its own switch (Preferences → TCI): a Unix socket for clients on the same machine ($XDG_RUNTIME_DIR/sdr-for-linux/tci.sock, mode 0600, no network port involved) and TCP port 40001 for third-party clients and other machines, bound to all interfaces or to 127.0.0.1 only - CAT/hamlib applications are covered through the third-party tciadapter bridge (WSJT-X, fldigi, CQRLOG verified by its author) — no serial-port emulation needed here
Companion apps (same author, same stack — C, GTK4/libadwaita, TCI): skimmer-for-linux, a multi-channel CW/RTTY/PSK skimmer fed by this app's TCI IQ stream, and log-for-linux, a logbook that follows the dial over TCI.
Policy: a radio model is enabled only after it has been tested on real hardware. A wrong relay or filter bit in the HPSDR control words can physically damage a PA, so untested models are refused by a whitelist in the radio picker rather than left to luck.
| Radio | Protocol | Status |
|---|---|---|
| Apache Labs ANAN G2E | HPSDR Protocol 2 | ✅ supported, developed & verified on this radio. Gateware 11.0.5 recommended: 11.1.0 was measured here (A/B flash, 2026-10-24) to put about 1.4 W of RF on the antenna whenever the DUC data is non-zero — i.e. during SSB pauses — which also makes an auto-tuner re-tune between words; 11.0.5 gives 0 W in the same condition. Reported as TAPR/OpenHPSDR-Firmware#4. PureSignal 3.0 (WDSP 2.11) calibrates on this radio only with the local WDSP patch described under Known limitations |
| Apache Labs ANAN 10E / 100B (Hermes) | HPSDR Protocol 2 | ✅ supported — RX + TX live-verified (fw 10.3; last live run on 0.5.x, before the WDSP 2.11 re-sync); per-radio PA calibration & 10 W scale. PureSignal disabled: the old Hermes firmware locks up on the P2 feedback-DDC switch mid-TX (power-cycle recovery); details in docs/TX-DESIGN.md §9 |
| Hermes Lite 2 | HPSDR Protocol 1 | ✅ supported — RX + TX + PureSignal live-verified (gw 73.2; last live run on 0.5.x, before the WDSP 2.11 re-sync): panadapter, audio, LNA gain (−12..+48 dB), N2ADR filter-board band switching, die temperature + 60 °C thermal TX trip, ADC-overload badge, TCI/SDC skimming, 5 W PA with per-band calibration (20 m calibrated, other bands under-drive until walked in), CW/voice, PureSignal over P1 (RX3/RX4 feedback; PS needs a sample rate ≤ 192 kHz). Rates 48–384 kHz, 0–38.4 MHz |
| Apache Labs ANAN G2 (Saturn) | HPSDR Protocol 2 | 🟢 RX + TX + PureSignal — live-tested by an external operator (W1IZZ, issue #3, two rounds, 2026-08-22/24): RX probes clean, per-band PA calibration against an LP-100A with our wattmeter within 1–2 W, SWR tracking, a voice QSO; PureSignal correcting with the feedback inside its target window; the per-model supply readout confirmed on his radio. We still do not own a G2: the per-device values (two Alex boards, two ADCs, DDC2, ANAN-7000 band-pass knees and wattmeter constants, ps_setpk 0.6121) come from piHPSDR, pinned by an offline byte gate, and are confirmed by one operator's runs, not calibrated by us. It starts safe — PA off, ANT1, 1 W, no stored PA calibration — so ⛔ your first transmission still belongs into a dummy load: dry key, then 1 W, then walk the calibration up per band while watching the SWR (his numbers landed at 43–53 dB). Step-by-step in docs/RADIOS-SCOPE.md §7 (§7.1–7.2 = what his runs showed) |
| Other ANAN / Hermes P2 boards (ORION2: 7000/8000/DLE 7000) | Protocol 2 | ⛔ blocked until tested — the Saturn work above already carries their wire bytes, so this is mostly a whitelist + live test away; open an issue if you can lend hardware + a dummy load |
| Older P1 boards (HL1, Metis…) | Protocol 1 | ⛔ blocked until tested |
Each radio keeps its own TX calibration (PA calibration per band, wattmeter trim, drive/antenna/PA-enable) in its own config section — calibrating one model never touches another. A newly connected TX-capable model starts safe: PA off, ANT1, 1 W. Drive and TUNE power are remembered per band: the footer sliders show and edit the current band, a band change restores that band's two values.
- A supported HPSDR radio on your LAN — ANAN or Hermes Lite 2 (see above)
- Linux with PipeWire as the sound server (standard on 2024+ distros)
- For the AppImage: glibc ≥ 2.43 (Ubuntu 26.04+, Fedora 44+, Arch, …)
- To build from source: GTK ≥ 4.12 (enforced by meson) and libadwaita ≥ 1.5. GPU rendering additionally wants GTK ≥ 4.22, but the app runs fine below it on the Cairo renderer
Grab the latest from Releases — three formats, pick one:
AppImage (any current distro, glibc ≥ 2.43):
chmod +x SDR_for_Linux-*.AppImage
./SDR_for_Linux-*.AppImage.deb (Ubuntu 26.04+):
sudo apt install ./sdr-for-linux_*_amd64.deb.rpm (Fedora 44+):
sudo dnf install ./sdr-for-linux-*.x86_64.rpmBoth packages are install-tested in fresh containers by the release CI.
Arch Linux (AUR) — sdr-for-linux:
paru -S sdr-for-linux # or: yay -S sdr-for-linuxOr without a helper: git clone https://aur.archlinux.org/sdr-for-linux.git && cd sdr-for-linux && makepkg -si. The AppImage also runs fine on Arch.
Build from source — the DSP engine (WDSP 2.11, plus
libspecbleach) is vendored in vendor/ and built from source; only
ubiquitous platform libraries come from your distribution:
| Need | Arch | Debian/Ubuntu | Fedora |
|---|---|---|---|
| GTK4 ≥ 4.12 + libadwaita ≥ 1.5 | gtk4 libadwaita |
libgtk-4-dev libadwaita-1-dev |
gtk4-devel libadwaita-devel |
| FFTW (single + double) | fftw |
libfftw3-dev |
fftw-devel |
| PipeWire client | libpipewire |
libpipewire-0.3-dev |
pipewire-devel |
| libwebsockets (TCI) | libwebsockets |
libwebsockets-dev |
libwebsockets-devel |
| Opus, OpenSSL, zlib | opus openssl zlib |
libopus-dev libssl-dev zlib1g-dev |
opus-devel openssl-devel zlib-devel |
| Build tools | base-devel meson |
build-essential meson |
gcc meson |
meson setup build
meson compile -C build
./build/sdr-for-linux # run in place, or:
sudo meson install -C build # install binary + desktop integration- FFTW wisdom build (~8 minutes, once). On first start the app plans
FFTW transforms for every panadapter FFT size (a progress window shows
the state) and caches them in
~/.config/sdr-for-linux/wisdom/. Every later start imports the cache instantly. Without this, deep zoom would freeze for up to half a minute at a time — same approach as piHPSDR and Thetis. Updating from 0.5.x to 0.6.0 rebuilds the cache once (WDSP 2.11 plans one more transform per size and names the cache differently). - Radio picker. The app broadcast-discovers HPSDR radios on the LAN (one entry per radio even when it answers on several interfaces; the data link takes the in-subnet one); pick yours, or add by IP for a different subnet. One client owns the radio at a time — close piHPSDR/Thetis first.
- Transmit is conservative by default: the PA is disabled until you enable it in Preferences → TX, and TX is gated (out-of-band, high SWR, or missing prerequisites refuse to key). Check Preferences → TX before your first transmission.
Settings persist in ~/.config/sdr-for-linux/config.ini.
Mouse & keys. Wheel = tune by the footer Step; left-drag = pan
(with CTUN on, the spectrum pans and the dial stays — drag the passband to
tune); right-drag = zoom; drag a passband edge to reshape the filter; drag
the spectrum/waterfall separator to resize (double-click resets). Keys:
u/l/c/a/r = USB/LSB/CW/AM/RTTY (a again = SAM), b = VFO A/B, e =
Equalizer dialog, Esc = leave select mode / abort a TX over.
Display rendering is chosen automatically: on GTK ≥ 4.22 the app uses
GTK's GPU (GL) renderer — the waterfall history is scaled by the graphics
card, the spectrum fill and trace are drawn by it, and the frame pacing is
much steadier at high FPS; on older GTK it stays on the CPU Cairo renderer.
The AppImage carries its own GTK (4.22 since 0.5.2), so it uses the GPU
renderer too. The startup log prints the choice
(renderer: GSK_RENDERER=…), and setting GSK_RENDERER yourself always
wins — GSK_RENDERER=cairo is the fallback if the GPU path misbehaves on
your graphics stack. Details in docs/RENDERING.md.
- Radios: ANAN G2E, ANAN 10E/100B, Hermes Lite 2 (all live-verified here), ANAN G2/Saturn (enabled from an audit; live-tested by an external operator in two rounds, 2026-08, not calibrated by us) — whitelist, see above; one RX (RX2 planned)
- No FM yet, no built-in CAT (use tciadapter, see above)
- Audio flows through the PC only — the radio's own phones/mic jacks are not wired up
- Wattmeter uses a single per-band calibration factor — accurate on HF, over-reads ~25 % on 6 m (a guided nonlinear calibration is planned)
- GPU rendering needs GTK ≥ 4.22; on older GTK (source builds on an older
distribution) the display stays on the CPU Cairo renderer (set
GSK_RENDERERyourself to override — seedocs/RENDERING.md) - PureSignal 3.0 on the ANAN G2E calibrates only with a one-line local
patch to the vendored WDSP 2.11 (
PS_NF_MAG_PREFILT_YMAX1.8 → 4.0 incalcc.c; what, why and the measurements invendor/wdsp/VENDOR.md, reported upstream as TAPR/OpenHPSDR-wdsp#10). Every build and package of this project carries the patch - The
--serverremote head speaks the piHPSDR 3.0 client/server protocol; a piHPSDR 3.1 server refuses the connection
Open an issue and paste the debug info from the app: menu → About → Troubleshooting → Debugging Information → Copy Text. It carries the app version, the GTK/libadwaita/WDSP/FFTW/PipeWire versions actually in use, the active renderer, the connected radio and protocol, and the config and log paths — which is most of what a diagnosis needs.
Run log. For anything that happened during operation (a stuck TX, a
lost radio link, a TCI client misbehaving), switch the run log on first:
Preferences → TCI → Diagnostics → Run log (restart to apply), or start
the app with SDRFL_LOG=1. The app then writes
~/.local/state/sdr-for-linux/sdr-for-linux.log (the last five runs are
kept, every line stamped with the time of day so it lines up with
journalctl); the path is shown in the debug info above. It is off by
default — nothing is written unless you switch it on.
Radio (ANAN G2E / G2 / 10E — P2, Hermes Lite 2 — P1)
│ Ethernet (raw IQ)
▼
sdr-for-linux (single GTK4 process)
├─ HPSDR Protocol 1 + 2 links ┐
├─ WDSP DSP (demod, filters, AGC, │ engine (headless, GLib-only),
│ NR, TX chain, PureSignal, FFT) │ adapted from piHPSDR
├─ PipeWire audio I/O, TCI server ┘
└─ GTK4/libadwaita UI: panadapter, waterfall, controls (new)
Design notes live in docs/ — the TX safety rules
(docs/TX-SAFETY.md) and TX design, the per-radio
scope (docs/RADIOS-SCOPE.md), PureSignal, TCI,
RTTY, Protocol 1/2, rendering, band plans.
- piHPSDR — Christoph van Wüllen (DL1YCF) and John Melton (G0ORX) — the engine this project builds on.
- WDSP — Warren Pratt (NR0V) — the DSP library.
- Thetis — the PureSignal auto-attenuate behaviour follows its design.
- Dr. Lawrence W. Gray (W1IZZ) — live-tested and helped debug the ANAN G2/Saturn support on his radio (issue #3): RX probes, per-band PA calibration against an LP-100A, PureSignal numbers, and the fixes his two test rounds surfaced.
- Vendored: libspecbleach (Luciano Dato). (rnnoise left with the WDSP 2.11 re-sync — WDSP's own neural NNR took its slot.)
GPLv3. Builds on and derives from piHPSDR and WDSP, both GPLv3.
Richard Fakenberg — OK1BR — rifak.cz

