First: thank you. RFWhisper exists because hams, DSP engineers, ML folks, and open-source contributors are willing to pour time into a project that helps operators pull weak signals out of an ever-noisier RF environment. Whether you're fixing a typo, recording some powerline buzz, or porting the whole pipeline to GNU Radio 4.0 — you are welcome here.
This document covers:
- Code of Conduct
- Ways to Contribute
- Getting Started (Dev Setup)
- Project Structure
- Workflow (Branching, Commits, PRs)
- Testing & Acceptance Criteria
- Style Guides
- Submitting RF/Audio Samples
- Submitting Trained Models
- Using AI Coding Assistants
- Reporting Bugs
- Requesting Features
- Hardware Testing
- Security
- Licensing & Copyright
- Questions
By participating in this project you agree to uphold the Code of Conduct. TL;DR: be kind, be patient, assume good intent, leave your ego at the door, and remember there are new hams reading every thread.
Not just code. Every one of these is gold:
- RF noise recordings from your QTH (powerline, solar, VDSL, inverters, plasma, neighbour's electric fence) — the more labeled, the better. See Submitting RF/Audio Samples.
- On-air recordings of weak signals we can use for evaluation (FT8 marginal decodes, DX SSB under QRM, CW under QRN).
- Hardware testing with any SoapySDR-supported SDR. Report back against the matrix.
- Model training / fine-tuning — ham-specific DeepFilterNet3 variants, RNNoise retunes, new architectures.
- DSP engineering — VOLK kernels, liquid-dsp integration, GR blocks.
- GNU Radio flowgraphs for new SDRs or modes.
- UI / UX — the v0.4 spectrogram UI has lots of room to help.
- Documentation — tutorials, quickstarts, per-OS install guides, translations.
- Packaging —
.deb/.rpm/ AUR / Homebrew / Windows installers / RPi OS images. - Bug reports and feature requests with reproducible steps.
- Community building — answering discussion questions, welcoming new hams, writing about RFWhisper on your blog / podcast / QRZ page.
If you want to do something big, file an issue or start a GitHub Discussion first so we can help scope it and avoid duplicate work.
- Git (and
git-lfsfor samples / models) - Rust (stable toolchain via rustup; MSRV is pinned in
Cargo.toml) - A working audio stack:
- Linux: ALSA + PipeWire or JACK (
libasound2-devfor building) - macOS: CoreAudio (built in); BlackHole for virtual cable
- Windows: WASAPI (built in); VB-Cable for virtual cable
- Linux: ALSA + PipeWire or JACK (
- For v0.2+ work: GNU Radio 3.10.x with
gr-soapy,gr-dnn, and SoapySDR modules for any SDR you own - C++ toolchain if you're touching native GR blocks (
gcc/clang/ MSVC, CMake ≥ 3.20) - Python 3.10+ only if you're working on the training pipeline (
train/) - Optional: a GPU (CUDA / CoreML / DirectML) for faster inference and training
git clone https://github.com/jakenherman/rfwhisper.git
cd rfwhisper
git lfs install # required for samples/ and models/
# Debug build + all tests
cargo build
cargo test
# Pre-commit hooks (mirror the CI fast lane: fmt, clippy, whitespace/yaml checks)
pre-commit install # get pre-commit via pipx/pip/brew if you don't have it
# Pull pre-converted ONNX models
cargo run -- models fetch# Fast unit + integration tests
cargo test
# Lints (CI enforces both)
cargo fmt --check
cargo clippy --all-targets -- -D warnings
# Full acceptance harness (audio quality gates — slow; needs models + samples)
cargo test --release -- --ignored gate_cargo run --release -- denoise \
--input samples/noisy_40m_ssb.wav \
--output /tmp/cleaned.wav \
--model deepfilternet3 \
--report /tmp/report.json
cat /tmp/report.json # RTF, seconds of audio, model used, etc.See AGENTS.md § Repo Layout for the canonical tree. The short version:
src/ Rust crate (CLI, DSP, denoise engines, models, realtime, GUI)
train/ Python training / fine-tuning pipeline (PyTorch; v0.5)
gr-rfwhisper/ GNU Radio OOT module (C++ blocks; v0.2+)
flowgraphs/ .grc + generated .py (v0.2+)
tests/ Integration tests + acceptance harness tied to ROADMAP criteria
samples/ Seed audio (Git LFS)
models/ ONNX models (Git LFS or fetched at runtime)
docs/ Tutorials, architecture, hardware matrix
notebooks/ Training + analysis notebooks
- Fork the repo (or get write access for trusted maintainers).
- Branch off
master. Naming:<type>/<short-slug>, e.g.feat/rnnoise-int8,fix/macos-audio-device-picker,docs/rpi5-quickstart. - Commit using Conventional Commits:
feat:new user-facing functionalityfix:bug fixperf:performance improvement with numbersdocs:documentation onlytest:adding / improving testsrefactor:code structure, no behavior changebuild:packaging, CI, depschore:everything else
- Reference the roadmap criterion in the commit body, e.g.
refs A4orcloses #123 (criterion B3). - Sign off your commits with
git commit -s(DCO). See Licensing & Copyright. - Push and open a PR against
master.
The repo template (.github/PULL_REQUEST_TEMPLATE.md) is mandatory. In particular:
- Testing criteria — exact commands a reviewer runs and the observable result that counts as a pass. If the change needs signal/noise audio, generate it deterministically with
rfwhisper samples synth(seeded — same flags, same file); don't assume sample files exist. - Physical-device verification — any realtime / audio-path change must name the hardware it was run against (
rfwhisper audio listindices), the exactdenoise-liveinvocation, and what was observed. If you couldn't run on hardware, say so explicitly — a reviewer with hardware must before merge. - Which roadmap criterion this moves forward (e.g., "Refs A2, C1").
- What you measured — hardware, numbers before/after, p50/p99 latency if realtime.
- Regression evidence — paste the output of the
gate_cw_transientandgate_ft8_regressionacceptance tests (or note why N/A). - Follow-ups — issues you opened for work you deliberately deferred.
Vague PRs without runnable verification steps will be sent back, not merged.
No PR is merged without green CI. Never disable a test to make CI pass. If a test is wrong, fix the test in a separate PR and justify it.
- Expect a first-pass response within a few days. RFWhisper is an all-volunteer project — maintainers have day jobs and radios to operate.
- Reviewers will focus on: correctness, latency impact, signal preservation (CW / FT8 / SSB), cross-platform parity, tests, and docs.
- We review kindly and directly. If feedback feels harsh, please assume tiredness not hostility and push back. See CODE_OF_CONDUCT.md.
RFWhisper is a testable-success project. Every feature is pinned to a criterion in ROADMAP.md. Your PR should:
- Declare which criterion/criteria it touches.
- Pass existing criteria (no regressions).
- Add tests for any new criterion coverage.
| Tier | Command | When it runs |
|---|---|---|
| Unit + integration | cargo test |
Every push + PR |
| Lint / format | cargo fmt --check && cargo clippy --all-targets -- -D warnings |
Every push + PR |
| Audio quality (slow) | cargo test --release -- --ignored gate_ |
Nightly + on-demand |
| Latency probe | rfwhisper bench latency <wav> |
Nightly on self-hosted runners (reference hardware) |
| Integration (SDR) | Manual, documented in PR | When flowgraphs change |
- CW keying transients (
gate_cw_transient) — RMS in the keying-onset window must be within ±1 dB of raw. - FT8 decodes (
gate_ft8_regression) — decoder must recover ≥ the number of stations that the raw audio gives, with zero false decodes.
If you break either, your PR will be blocked. These gates are why we exist.
- Edition 2021; stable toolchain (MSRV pinned in
Cargo.toml) - Formatter:
cargo fmt(enforced in CI) - Linter:
cargo clippy --all-targets -- -D warnings - Errors:
Result+thiserrorin the library; nounwrap()in runtime paths (tests are fine) - No allocations or blocking in audio callbacks (see AGENTS.md § Real-Time Constraints)
- Doc comments on public items; module docs explain the "why"
- Standard: C++17 minimum
- Formatter:
clang-formatusing the project.clang-format(LLVM base, 4-space indent) - Linter:
clang-tidywith project checks - RAII everything. No raw owning pointers.
- No exceptions in the audio callback path.
- Formatter:
ruff format; linter:ruff check;mypy --stricton new code - Docstrings: Google style
- Conventional Commits + roadmap criterion refs in body.
- Imperative mood: "add RNNoise fallback" not "added" / "adds".
- Wrap body at 72 cols.
- Sign off with
-s.
- Markdown with the same tone as README.md — accurate, welcoming, ham-friendly.
- Use headings, tables, and code blocks liberally. Assume a smart reader who is new to the specific topic.
- No emoji in technical docs unless a Ham Domain Expert review approves it.
High-quality labeled recordings are genuinely one of the most valuable contributions to this project.
- Noisy recordings of real ham operations (HF / VHF / UHF, any mode).
- Isolated noise (powerline, solar, plasma, PLC, thermostat clicks, atmospheric QRN) — unmodulated, no signal, just the noise.
- Clean reference audio where available (dummy load, studio ham speech, high-SNR CW / FT8).
- WAV (PCM 16-bit or 32-bit float), 48 kHz preferred, 16 kHz acceptable
- Mono unless stereo is meaningful (I/Q pair → document it)
- Keep clips ≤ 3 minutes (longer is fine; we'll split)
Every sample needs a sidecar .yaml or a row in samples/catalog.yaml:
filename: noisy_40m_ssb_koXYZ_2025-04-20.wav
description: 40m SSB DX station under powerline noise, suburban QTH
band: 40m
frequency_khz: 7185
mode: USB
rig: Icom IC-7300
antenna: EFHW-8010 at 8m
sdr_or_audio_source: rig USB CODEC
noise_sources_known: ["powerline", "VDSL"]
sample_rate_hz: 48000
duration_s: 62.0
recorded_at: "2025-04-20T19:30:00Z"
operator_callsign_or_anon: "anon"
license: "CC-BY-4.0" # or your choice; GPLv3-compatible required
notes: "S7 noise floor on raw, weak DX station at ~S3"We strongly prefer CC-BY-4.0 or CC0 for samples to maximize reuse. Any license that is GPLv3-compatible and allows redistribution is acceptable. You retain copyright.
- Do not submit samples containing third-party callsigns or identifying information without the other operator's consent.
- Anonymize / redact personal info where present.
- Put the file in
samples/<category>/(e.g.samples/ssb/,samples/noise/). - Add the metadata entry to
samples/catalog.yaml. git lfs track "*.wav"is already configured — justgit addnormally.- Open a PR tagged
samples.
See AGENTS.md § ML Training Engineer. In short: every ONNX you submit must ship with:
- SHA-256 pinned in source
- PyTorch↔ONNX Runtime parity check (RMS diff ≤ 1e-3)
- Eval table (PESQ, STOI, SI-SDR, ham SNR gain, RTF, latency p50/p99) on reference hardware
- Green CW + FT8 regression tests
- A model card in
docs/models/<your-model-name>.mdcovering: architecture, training data, training recipe, license, known failure modes, maintainer contact
AI coding tools (Claude, Cursor, Copilot, Aider, Codex CLI, etc.) are welcome here. Please:
- Point them at AGENTS.md. Load the role-specific system prompt that matches the area you're working in.
- Read the output. You are the contributor of record. Review every line.
- Run the tests locally. Don't rely on CI to catch regressions.
- Disclose significant AI assistance in the PR description. Example: "Drafted with Claude via Cursor; DSP review was human; tests manually verified on M1 + RPi 5." This helps reviewers and builds community trust.
- Never let an agent merge its own PR. A human must approve.
Open a GitHub Issue with the Bug report template. Include:
- RFWhisper version / commit SHA
- OS + version
- CPU / GPU / SDR model (if relevant)
- Minimal steps to reproduce
- Expected vs actual behavior
- Relevant logs (attach; do not paste multi-kilobyte dumps)
- A short recording or screenshot if it's about audio quality or UI
Security bugs: see Security below.
Open an Issue with the Feature request template. Include:
- What problem are you trying to solve? (the real-world ham scenario)
- Why the existing tooling / a different workflow isn't enough
- Proposed solution sketch (if any)
- Which roadmap version this might fit into (your best guess is fine)
For anything non-trivial, start a GitHub Discussion first so we can scope collaboratively.
If you own a SoapySDR-supported SDR not yet in the matrix, we'd love a test report.
- Run the nearest matching flowgraph (see
flowgraphs/). - File an Issue using the Hardware test template with:
- SDR make/model/firmware
- Sample rate + mode tested
- On-air audio file (before + after, trimmed to ≤ 30 s)
- Latency / CPU numbers from the telemetry panel (or CLI report)
- Any gotchas (driver install quirks, permissions, etc.)
- We'll update
docs/soapy-hardware-matrix.mdand credit you.
If you discover a security issue — privacy leak, RCE, supply-chain concern, signed-model tampering — do not open a public issue. Instead email the maintainers at security@rfwhisper.org (placeholder — will publish a real address on first release) with:
- Description of the issue
- Reproduction steps
- Potential impact
- Your preferred disclosure timeline
We aim to acknowledge within 72 hours and propose a coordinated disclosure timeline within 7 days. We credit reporters (or keep them anonymous if preferred).
- RFWhisper is licensed under GPL-3.0-or-later (LICENSE).
- By contributing, you agree your contributions will be licensed under the same terms.
- We use the Developer Certificate of Origin (DCO) 1.1 — please sign off every commit with
git commit -s. This means you wrote the code (or have rights to submit it) and you agree to license it under GPLv3-or-later. Full DCO text: https://developercertificate.org/. - Third-party code brought into the project must be GPLv3-compatible. When in doubt, ask before opening the PR.
- GitHub Discussions for open-ended design / "how do I?" questions.
- Issues for bugs and feature requests.
- Matrix / Discord (link TBD) for real-time chat.
- On the air — if RFWhisper helps you pull a signal, tell us in Discussions. That's the best feedback we get.
Thank you. 73.
— the RFWhisper maintainers