rf-survey GitHub ↗

Open source · Chicago Offline

Directories go stale. The air doesn't lie.

Radio reference data mostly comes from aging directories and club pages — listings that outlive the systems they describe. rf-survey turns cheap SDRs into a disciplined surveying rig that checks the record against the spectrum itself: sweep, dwell, decode, and file location-tagged reception reports that validate or extend SSRF-Lite — the same data that builds codeplugs.

rf-survey logo: an antenna above spectrum bars

How it works

A declarative scan plan drives everything. Devices are claimed by serial, observations land in SQLite, and every record carries where and how it was heard.

  1. Sweepwide-band power scan; SNR against each bin's own long-term median — never raw dB
  2. Dwellbounded-lifetime listen on anything that clears the threshold — FM or digital
  3. Decodecolor codes, talkgroups, radio IDs — trusted only when the energy gate agrees
  4. ReportSSRF-Lite candidate stubs with cited observations; a human reviews before merge

The validation ladder

Every system/channel pair earns a verification tier per station — the higher the rung, the more a codeplug can trust it.

V3Recordedan archived clip backs the observation
V2Voiceconfirmed speech on dwell audio, not just a carrier
V1Decodedmetadata matches the SSRF-Lite record — contradictions get flagged
V0Heardenergy above the channel's noise median, activity-gated

A distributed survey network

Fixed stations around Chicagoland — plus mobile rigs — scan continuously and submit signed observation batches over MQTT. A central aggregator verifies signatures, stores append-only evidence, and promotes records: verified when multiple stations agree across days, flagged when a decode contradicts the record, stale when the air goes quiet. Stations keep themselves honest by measuring shared beacons — NWS 162.55, ATSC pilots — so hardware drift is caught automatically. The payoff lands in codeplugger: program only channels somebody actually heard, recently, near you.

Receive-only, always. Surveyed systems are licensed to other people. Full design in NETWORK.md.

How the data flows

One pipeline, antenna to programmed radio: measured reception reports keep the database honest, profiles keep the radios yours.

flowchart LR
  rf["📡 rf-survey"] -- "reception reports" --> ssrf["🗃 ssrf-lite"]
  ov["overlays · shared + private"] --> ssrf
  ssrf -- "validated RF data" --> cp["⚙ codeplugger"]
  prof["👤 profiles"] --> cp
  cp -- "CHIRP · qdmr · dmrconf" --> radios(["📻 radios"])
  click rf "https://chicago-offline.github.io/rf-survey/" _blank
  click ssrf "https://chicago-offline.github.io/ssrf-lite/" _blank
  click cp "https://chicago-offline.github.io/codeplugger/" _blank
  click prof "https://chicago-offline.github.io/chioff-codeplugger-profiles-shared/" _blank
        

Quick start

Python 3.9+, rtl-sdr tools on the path, optional dsd-fme for digital dwell.

Install and list devices

pip install git+https://github.com/Chicago-Offline/rf-survey
survey devices
# 0: SN=BENCH  Realtek RTL2838UHIDIR  digital
# 1: SN=SONDE  Realtek RTL2838UHIDIR  analog

Run a scan plan

survey run examples/plan-uhf-dmr.yml --serial BENCH
survey report
survey candidates   # ssrf-lite stubs, cited evidence