W4HO · AMATEUR RADIO STATION · DN70
LICENSED
FT8
·
CALLW4HO
·
GRIDDN70
·
73!
Station (W4HO)
W4HO
WHISKEY FOUR HOTEL OSCAR
Amateur radio operator. I make FT8 stuff:
Statio, my FT8 TUI — see the post ↗
Vox Tenuis (clean-room · pure Rust)
A from-scratch FT8 decoder in pure Rust, built clean-room — from the published protocol specification alone (Franke, Somerville & Taylor, QEX 2020), never from WSJT-X source.
Head-to-head with the WSJT-X–derived reference on real off-air FT8, it decodes 100% of the strong signals, hears hundreds more weak ones out of the noise, and produces zero false decodes. Each decoder also catches a few the other doesn’t.
It hears FT8 in raw audio end to end: FFT candidate search, Costas sync, 8-FSK demodulation, LDPC belief propagation, and CRC-gated decodes. No C, no FFI — and provably thread-safe (zero unsafe).
A live time-budget mode — Decoder::with_budget(1300ms) — returns inside a fixed wall-clock deadline, so a station decodes and fires its reply within the FT8 slot. Field-proven: ten QSOs on its maiden voyage, now also first live-air validated against a mature reference on hundreds of real windows.
Open source, MIT licensed. Versioning is CalVer (YYYY.M.D). Package and CLI are vox-tenuis. Clone it over plain git:
git clone https://w4ho.com/vox-tenuis.git
Using it from Rust? Add the dependency to Cargo.toml:
vox-tenuis = { git = "https://w4ho.com/vox-tenuis.git" }
The repo is served as plain static files (git's “dumb HTTP” protocol), which Cargo's built-in fetcher won't clone. Point it at the git CLI — add this to .cargo/config.toml (per-project or in ~/.cargo/):
[net]
git-fetch-with-cli = true
Or grab the source the old-school way — a plain tarball:
↓ download vox-tenuis.tar.gz
Release: 21 July 2026 — Vox Tenuis 2026.7.21
Vox Tenuis — “the thin voice.” The whole art of FT8 is hearing it. see the post ↗
Release Notes (21 July 2026)
ARRL Field Day message decoding and multi-signal subtraction for three-way pileups works.
Release Notes (18 July 2026)
First live-air validation, a 26% faster decoder, and a wider listening window. Versioning is now CalVer; the package and CLI rename from vt to vox-tenuis is finalized, MIT remains the license.
Performance (26% faster at full depth)
- The belief-propagation LDPC engine moved from
f64 to f32 with the algorithm exactly preserved; subtraction reuses scratch buffers instead of reallocating; candidate/cell hunts and spectrogram FFTs now run in parallel.
- Full-depth decode wall time dropped ~26%. Because the live budget is fixed at 1300 ms (an FT8 slot-timing constraint, not a hardware one), every millisecond saved converts into deeper search — the same deadline digs roughly a quarter deeper per window.
- The zero-false-decode record was re-verified from scratch on the new engine: 168,820 adversarial decode attempts on noise and off-air audio, zero CRC leaks.
Wider passband (decode-side only)
- Candidate search now covers 100–4000 Hz audio (previously capped at 3150 Hz), after field recordings showed a strong pileup at 3232–3318 Hz the old ceiling never examined, plus genuine signals as high as 3500 Hz.
- Receive-side only — transmit stays within the standard band.
Correctness (external code review — all five findings fixed)
- The time-budget deadline now propagates through every stage of the decode ladder (closing a case where one pass could overrun the 1300 ms contract).
- Duplicate detection keys on the exact 77-bit payload rather than display text — two different hashed callsigns that render identically no longer merge.
- WAV input is format-validated (stereo/float files are rejected instead of silently misread).
- Crowded-band candidate filtering no longer starves cells that later decode passes exist to re-examine.
- A message-type classification comment/taxonomy error was corrected.
First live-air validation
- Three real operating sessions (654 recorded 15-second windows, 20 m band) were decoded head-to-head against a mature WSJT-X–derived reference that logged 12,290 decodes on the same audio.
- Vox Tenuis matched 98.0% of them (99.8% of signals at −10 dB SNR and stronger) and additionally produced 1,649 CRC-valid decodes the reference did not find.
- Put symmetrically: Vox Tenuis captures 98% of the reference’s decodes, while the reference captures 88% of Vox Tenuis’s. False decodes on noise: zero.
- Recall on this fresh, never-before-seen audio matched the historical test corpus almost exactly — evidence the decoder generalizes rather than overfitting its test data.
- The a-priori decoding column earned its first live-air catches, including a −3 dB signal provably undecodable by parity alone in its window.
- The corpus harness understands the new capture-directory layout and no longer misclassifies a missing metadata sidecar as a noise-only recording.
Release Notes (14 July 2026)
The first release of a clean-room, pure-Rust FT8 decoder — and on real off-air signals it stands competitive with the WSJT-X–derived reference decoder.
By the numbers (measured on real off-air FT8, head-to-head with the reference)
- 100% of strong signals — every signal the reference decoded at −10 dB or stronger, Vox Tenuis decoded too (2,222 of 2,222 in testing).
- +611 in one night — over a single evening of 20-meter activity it pulled 611 additional CRC-verified decodes out of the noise, beyond the reference’s log. Each decoder also catches a few the other doesn’t — run both and hear more.
- Zero false decodes — across more than 169,000 adversarial trials, band noise never once forged a callsign. CRC-14 is the gate.
- ~1.4 seconds a slot — a full 15-second FT8 window decodes in about 1.4 s on a laptop, comfortably before the reply window.
Decoding
- A complete FT8 receive pipeline: FFT candidate search, Costas synchronization, 8-FSK demodulation to soft bits, LDPC(174,91) belief propagation, and a CRC-14 gate. Multi-pass with signal subtraction to pull weak signals out from under strong ones.
- On real off-air recordings, at equal decoding depth, it matches the reference on strong signals and surfaces hundreds of weak-signal decodes the reference misses. (Each decoder finds some the other doesn’t — run both and keep the union.)
- Zero false decodes: every result is CRC-14 verified, so band noise never invents a phantom callsign.
Live time budget
- An anytime decode mode the reference doesn’t offer:
Decoder::with_budget(1300ms) returns inside a fixed wall-clock deadline, so a station decodes and fires its reply within the FT8 slot. Faster hardware simply digs deeper within the same budget — the deadline never moves.
- Field-proven: ten QSOs on its maiden voyage.
Clean room & pure Rust
- Built from the published protocol specification alone (Franke, Somerville & Taylor, QEX 2020) — never from WSJT-X source.
- No C, no FFI, and provably thread-safe (zero
unsafe) — safe to run a live decoder and a full-depth capture decoder side by side.
Speaks fluent FT8 (encode & decode — every message type)
- Every message type: CQ and directed calls, grid squares, signal reports and R-reports, RRR / RR73 / 73.
- Every callsign form: standard, compound & portable (e.g. EA8/S53K), and 22-bit hashed calls (
<...>) for special-event and nonstandard stations.
- Interoperable with WSJT-X: every message Vox Tenuis transmits, WSJT-X decodes exactly — and Vox Tenuis reads virtually all the FT8 the reference does. Same protocol, same 77-bit payloads — transmit at any tone from 200 to 2950 Hz.
Get it
- MIT licensed, served as a thin git repo over HTTPS:
git clone https://w4ho.com/vox-tenuis.git (Rust users: see the net.git-fetch-with-cli note above).
Tegmen Library (FT8 lib for C & Rust)
Write your own FT8 software while delegating to WSJT-X for FT8 encoding and decoding.
Tegmen is a C and Rust library wrapper for WSJT-X's FT8 encoder and decoder.
This wrapper API can encode an FT8 message and then decode the generated .wav file.
It wraps WSJT-X General Availability Release 3.0.1.
Tegmen is open source. License is the same as WSJT-X, GPL v3.
Release: 21 July 2026 — Tegmen 2026.7.21, matching WSJT-X 3.0.1 GA.
↓ download tegmen.tar.gz
Tegmen Release Notes (21 Jul 2026)
FT8 decoding adds selectable depth, a priori hints, cross-cycle memory, a targeted search for your QSO partner, streaming early/mid/final stages, cursor re-decode, and scan-band limits. Encoding adds selectable tone frequency. All opt-in via new API options. Existing APIs unchanged.
Waterfall