Real-time AI denoising for ham radio. No cloud. No compromises. Just clean QSOs from the noisy RF aether.
. . .
. /|\ _..._ / \ _..._ /|\ .
/_|_\ .' '. / _ \ .' '. /_|_\
|O| / RFW \/ /_\ \/ 73! \|O|
[___]'.._____.' (_____) '.._____.'[___]
RFWhisper — cleaner copy, calmer bands.
RFWhisper is a fully local, open-source, real-time ML-powered noise-reduction tool built specifically for amateur radio. The goal: wrap a ham-tuned deep learning denoiser (DeepFilterNet3 primary, RNNoise fallback) inside a GNU Radio + SoapySDR + ONNX Runtime pipeline, so you can pull weak signals out of the modern RFI soup without streaming your audio to a cloud service you don't trust.
Everything runs on your machine. Your shack. Your GPU. Your rules. 73.
The CLI, DSP core, fixture generator, metrics harness, and model registry all work and are tested. The thing in the middle that actually removes noise is still a placeholder: a classical spectral-subtraction stub measuring +1.1 dB SNR gain at best, against a v0.1 target of +3 dB average and +6 dB on powerline buzz.
Do not expect this to clean up your audio today. It is a working pipeline with a placeholder in the denoiser slot. See #117 for the measurements and #10 for the real backend.
- Why RFWhisper?
- Features
- How It Works
- Quick Start
- Hardware Requirements
- Testable Success Examples
- Project Status & Roadmap
- Contributing
- Community
- License
- 73 & Acknowledgments
The amateur bands are noisier than they've ever been. If you've tried to work a POTA station on 40m from a townhouse, chased DX through a neighbour's plasma TV, or decoded FT8 next to an EV charger, you know the modern noise floor is unrecognizable compared to a decade ago. The culprits:
- Switch-mode power supplies and LED drivers (broadband hash, 20 kHz spurs)
- Solar inverters and MPPT controllers (rhythmic buzz across HF)
- VDSL / PLC / Ethernet-over-powerline (wideband raised noise floor)
- Plasma TVs, grow lights, touch lamps (narrowband carriers)
- Neighbor electric fences, thermostats, doorbells (pulsing crashes)
- Solar weather, static crashes, atmospheric QRN on low bands
Traditional DSP tools (analog NB/NR, classical Wiener filters, basic spectral subtraction) either:
- Don't catch modern complex impulsive + stationary mixtures, or
- Wreck the signal, destroy CW attack transients, or introduce "underwater" artifacts that confuse FT8/WSJT-X decoders.
RFWhisper's approach: use a deep neural network that was designed for speech denoising (DeepFilterNet3) and fine-tune it on real amateur-radio noise (recorded powerline buzz, inverter hash, static crashes) so it learns to preserve SSB phonemes, CW keying transients, and FT8 tones while nuking the QRM.
And because it's local-first and open-source (GPLv3), you can:
- Run it airgapped on a Raspberry Pi 5 in the field
- Inspect and retrain every model
- Tune it for your exact noise environment
- Use it commercially, modify it, fork it, hack on it — as long as you keep it open.
The neural denoiser is not built yet.
--model deepfilternet3currently warns and falls back to a classical spectral-subtraction stub that measures +1.1 dB SNR gain at its very best — against a v0.1 target of +3 dB average and +6 dB on powerline buzz. The stub exists to wire and test the pipeline, not to clean up your audio. Tracked in #117; the real backend is #10.Everything below is honest about what runs. If you are here for working noise reduction on air, star the repo and come back for v0.1 final.
- Offline WAV denoise CLI (
rfwhisper denoise) with a JSON metrics report - Deterministic fixture synthesis (
rfwhisper samples synth) — SSB / CW / FT8 / VHF-FM signals and powerline / inverter / VDSL / QRN noise, generated from a seed - Measurement harness: matched-filter SNR gain, keying-onset RMS, RTF and latency probes
- ONNX model registry, execution-provider auto-select, and SHA-pinned fetch manifest — wired and tested, awaiting a backend to feed
- Audio device enumeration (
rfwhisper audio list); realtime duplex path implemented, not yet gate-verified - Cross-platform build: Linux, macOS, Windows
- Real-time audio denoising with DeepFilterNet3 (ONNX Runtime) — #10
- RNNoise fallback for ultra-low-power devices (RPi Zero 2, old laptops) — #11
- Virtual audio cable output (VB-Cable on Windows, BlackHole on macOS, JACK/ALSA loopback on Linux) → drop-in for WSJT-X, fldigi, JS8Call, SDR#, SDRuno, Quisk — #4
- Minimal GUI with before/after A/B toggle — #18 (
rfwhisper guicurrently prints a pointer to the roadmap) - Latency < 100 ms end-to-end on a modern laptop (target 40–60 ms) — #22
- Before/after WAV recording for sharing and testing — #77
- Raspberry Pi 5 verified
Coming in v0.2–v1.0 (see ROADMAP.md)
- GNU Radio 3.10 flowgraph with SoapySDR source + gr-dnn ONNX block
- Mode profiles: SSB, CW, FT8/FT4, RTTY, AM/FM, VHF FM
- Adaptive narrowband notch (carriers, birdies) that plays nicely with the NN
- Before/after waterfall + SINAD / SNR-gain / CPU / latency telemetry
- Dataset generator + fine-tuning pipeline for your noise environment
- Signed installers for Win/macOS,
.deb/.rpm/AUR packages, RPi OS image - Model hub: community-trained variants (HF contester, VHF-FM mobile, 630m etc.)
- GNU Radio 4.0 native port + plugin architecture
┌─────────────┐ ┌──────────┐ ┌───────────────────┐ ┌──────────┐ ┌────────────┐
│ SDR / Rig │──▶│ SoapySDR │──▶│ GNU Radio 3.10.x │──▶│ gr-dnn │──▶│ Virtual │
│ RTL, Pluto, │ │ + liquid │ │ demod (SSB/FM/...)│ │ ONNX RT │ │ audio cable│
│ Airspy, IC- │ │ + VOLK │ │ → 16k/48k audio │ │ DFN3/RNN │ │ → WSJT-X, │
│ 7300 audio │ │ │ │ │ │ (CPU/GPU)│ │ fldigi, │
│ │ │ │ │ │ │ │ │ headphns │
└─────────────┘ └──────────┘ └───────────────────┘ └──────────┘ └────────────┘
│
▼
┌───────────────────────────┐
│ Telemetry: SNR gain, │
│ SINAD, latency, CPU, │
│ spectrogram before/after │
└───────────────────────────┘
The diagram is the v0.2+ target architecture. Today the chain is
WAV or audio device → DSP → denoise engine → WAV or audio device; the SDR and
GNU Radio legs are v0.2 (#29–#38).
Planned primary denoiser: DeepFilterNet3. A two-stage deep-filtering network trained on speech + noise. It beats RNNoise on PESQ and STOI while staying fast enough for realtime on a laptop CPU. The plan is to ship a ham-fine-tuned ONNX export and make it easy to swap in your own — not yet implemented (#10).
Planned fallback: RNNoise. 40 kHz-ish features, GRU-based, runs on a potato. Intended as the backup for RPi Zero-class hardware (#11).
Shipping today: a spectral-subtraction stub. Stationary-noise Wiener-ish masking, ~+1 dB SNR gain. It exists so the framing, overlap-add, realtime threading, and metrics have something to carry end to end while the neural backends are built.
Why ONNX Runtime? Cross-platform, great CPU performance with XNNPACK/CoreML/DirectML, optional CUDA/TensorRT/ROCm on beefier rigs, and it lets the community swap in new models without recompiling anything.
Why Rust? The runtime (DSP, realtime audio, CLI) is a single static binary — no interpreter, no virtualenv, no GC pauses in the audio path. cargo build --release and you can drop it on a Pi in a POTA tent. Model training stays in Python/PyTorch where the ML ecosystem lives; the two meet at the ONNX boundary. (Fitting, since DeepFilterNet's own realtime reference implementation is Rust.)
Status: v0.1 audio-only MVP. GNU Radio integration lands in v0.2. See ROADMAP.md.
- The Rust toolchain (stable, via rustup)
- A working audio stack (WASAPI / CoreAudio / ALSA or JACK;
libasound2-devto build on Linux) - (Optional) A virtual audio cable:
git clone https://github.com/jakenherman/rfwhisper.git
cd rfwhisper
cargo build --release # single binary at target/release/rfwhisperrfwhisper models fetch pulls the pinned ONNX artifacts, but nothing consumes them
yet (#117) — skip it for now.
No downloads and no sample pack: the fixtures are generated from a seed, so these commands produce byte-identical audio on any machine.
rfwhisper samples list # available signals, noise types, and presets
# An S3 SSB signal buried under an S7 powerline buzz (-24 dB SNR).
# --out is the noisy mix; --clean-out is the reference it was mixed from.
rfwhisper samples synth --kind mix --preset ssb_powerline_s3_s7 \
--out ssb.wav --clean-out ssb.clean.wavrfwhisper denoise \
--input ssb.wav \
--output cleaned.wav \
--reference ssb.clean.wav \
--model spectral_stub \
--report report.jsonreport.json carries the measured SNR gain against the reference, inference time,
and RTF. Listen to ssb.clean.wav, ssb.wav, and cleaned.wav back to back —
and note that on this build the third file will not sound much better than the
second. That is #117, and it
is the whole reason v0.1 has not shipped.
Implemented, but not yet verified against the latency and stability gates.
rfwhisper audio list # list audio devices
# Pipe rig audio (input 3) → denoiser → virtual cable (output 5)
rfwhisper denoise-live --in 3 --out 5 --model spectral_stub --blocksize 480Then point WSJT-X / fldigi / JS8Call at the virtual cable as their input.
Not built yet — rfwhisper gui prints a pointer to the roadmap. Device picker, A/B
bypass, dual-stream recording, and live telemetry are
#18 and the v0.4 GUI epic
(#70–#78).
RFWhisper is designed to be ruthlessly lightweight so field ops (POTA, SOTA, EmComm) aren't left out.
| Scenario | Minimum | Recommended |
|---|---|---|
| RNNoise CPU-only | RPi Zero 2 W, any x86 from 2012+ | Anything newer |
| DeepFilterNet3 CPU-only | RPi 5 (4 GB), Intel i5-8xxx, Apple M1 | Ryzen 5600 / i5-12xxx / M2+ |
| DeepFilterNet3 GPU | Any CUDA GPU (GTX 1050+), Apple Silicon (CoreML), DirectML on Windows | RTX 3060+ / M2 Pro |
| Real-time SDR pipeline (v0.2+) | RTL-SDR v4 + RPi 5 | Airspy HF+ / Pluto+ on a laptop |
Supported SDRs (planned v0.2+): RTL-SDR (all variants), Airspy (R2 / Mini / HF+), HackRF, ADALM-Pluto, SDRplay RSP1A/RSPdx (via SoapySDRPlay3), LimeSDR, USRP B-series, KiwiSDR — anything SoapySDR supports. Also: audio from IC-7300 / IC-705 / FT-991 / FTDX10 / K3 over USB CODEC.
Every milestone in this project has an explicit, measurable success criterion. If you can't demo it to another ham and have them say "that's clearly better", it doesn't ship. Some concrete examples for v0.1.
None of these pass today — they are the definition of done for v0.1, not a description of the current build. The harness that measures them exists and runs; the denoiser it measures does not (see #117).
- Setup: Record 60 s of a DX station at S3 with S7 powerline buzz. Process with RFWhisper. Play both for 5 volunteer hams, blind.
- Pass criterion: ≥ 4 of 5 hams prefer the denoised version AND can copy ≥ 1 additional word per sentence on average.
- Metric floor: ≥ +3 dB effective SNR gain (measured via matched-filter correlation with a clean reference), no more than 0.5 point PESQ degradation on reference clean speech (no-op test).
- Setup: Replay a 15-minute FT8 cycle containing known weak stations through WSJT-X, once raw and once through RFWhisper → virtual cable.
- Pass criterion: Decoder recovers at least as many stations on the denoised pass. Zero regressions on strong-station decodes. Ideally +1 to +3 marginal decodes per cycle.
- Metric floor: No increase in false decodes. Latency added by RFWhisper ≤ 100 ms (FT8 tolerates this easily).
- Setup: Feed a 25 WPM CW recording with atmospheric QRN and static crashes.
- Pass criterion:
cw_decoder(fldigi / CW Skimmer) copy accuracy does not drop vs raw, and operator can hear crashes reduced by ≥ 6 dB. - Metric floor: RMS of keying-transient region unchanged within ±1 dB (we are not allowed to soften keying).
- Setup: Measure round-trip latency from audio in → denoised audio out.
- Pass criterion: < 100 ms p99 on an Intel i5-8xxx / Apple M1 / RPi 5 at 48 kHz. Stretch: < 50 ms by v0.3.
The metrics behind these live in src/dsp/metrics.rs, the fixtures they run against in src/samples/, and the tests in tests/. Gate tests are #[ignore]-marked and run with cargo test --release -- --ignored gate_. See ROADMAP.md for the full list.
RFWhisper is in alpha. We are shipping tiny, testable increments. The short version:
| Version | Theme | Status |
|---|---|---|
| v0.1 | Audio-only denoiser → virtual cable | 🚧 in progress |
| v0.2 | GNU Radio + SoapySDR flowgraph | ⏳ designed |
| v0.3 | Mode profiles (SSB/CW/FT8/VHF) + adaptive notch | ⏳ planned |
| v0.4 | UI: before/after waterfall + metrics | ⏳ planned |
| v0.5 | Fine-tuning tools + dataset generator | ⏳ planned |
| v1.0 | Polished: installers, 8+ SDRs tested, model hub | 🎯 target |
| v1.1+ | Plugins, GR4 native, propagation extras | 💭 exploring |
See ROADMAP.md for exact deliverables, acceptance criteria, and testable success metrics for every version.
We love contributions from hams, DSP engineers, ML folks, embedded wizards, UI designers, documentation nerds, and anyone in between. Some specific callouts:
- Hams with QRM samples: please upload noisy recordings (any band, any mode) with metadata (rig, antenna, band, noise source if known). These are gold for training.
- DSP engineers: VOLK / liquid-dsp / SIMD contributions are welcome, especially for the feature-extraction stage.
- ML engineers: help us ship ham-tuned DFN3 / hybrid architectures, and quantized variants (INT8, FP16) for edge.
- Radio operators on exotic hardware: if you own a weird SDR, please run the v0.2 flowgraph and file an issue with results.
- UI / UX designers: the v0.4 spectrogram UI is wide open for help.
Read CONTRIBUTING.md and CODE_OF_CONDUCT.md first. When working with AI coding assistants, point them at AGENTS.md — it has specialized system prompts for DSP, ML, GNU Radio, embedded, UI, and ham-domain work.
First-time contributor? Look for issues tagged good-first-issue or help-wanted.
- GitHub Discussions: design debates, RF samples, benchmark reports.
- Issues: bugs, feature requests, hardware compatibility reports.
- Matrix / Discord: (TBD — link when community room spins up)
- On the air: if you use RFWhisper for a QSO and it pulls a station out of the mud, drop a note in Discussions — that's the best feedback we get.
RFWhisper is licensed under the GNU General Public License v3.0 or later — see LICENSE.
This means:
- You can use, modify, and redistribute it freely.
- If you ship modifications, you must ship the source.
- No warranty, no liability, de-facto "use at your own risk" — see full text.
We chose GPLv3 specifically to keep the ham radio ecosystem healthy: improvements benefit everyone, and nobody can take the project closed-source and wall it off from the operators who made it possible.
Dependencies retain their own licenses (GNU Radio: GPLv3; SoapySDR: Boost; ONNX Runtime: MIT; DeepFilterNet: MIT/Apache-2.0; RNNoise: BSD-3-Clause; liquid-dsp: MIT; VOLK: GPLv3).
RFWhisper stands on the shoulders of giants:
- GNU Radio — the DSP framework this project could not exist without.
- SoapySDR — making "works with any SDR" actually true.
- ONNX Runtime — honest, fast, cross-platform inference.
- DeepFilterNet (Schröter et al.) — the model architecture we're building on.
- RNNoise (Jean-Marc Valin / Xiph.Org) — the granddaddy of real-time neural denoising.
- VOLK / liquid-dsp — speed when we need it.
- The amateur radio community — for 100+ years of hacker culture, open specs, and the patience to teach newcomers.
To every ham who has ever pulled a signal out of the noise with a shrug and a paper pad: this is for you. We're just automating the superpower you already had.
73 de the RFWhisper project.
(If this tool helps you make a contact you'd otherwise have missed — POTA, DX, emergency traffic, a friend's ragchew — please tell us. Stories like that are why we're building this.)