← BACK TO MONITOR
RFAI MONITOR Radio Frequency Artificial Intelligence
GitHub ↗

Every transmission. Understood.

An open-source SDR intelligence platform that captures radio transmissions, transcribes them with local AI, and surfaces patterns in real time — no cloud, no subscriptions, no hardware limit beyond your antenna.

Local AI — No cloud HackRF One · Airspy · RTL-SDR 1 MHz – 6 GHz Apache 2.0

What it does

RFAI is a six-layer intelligence stack sitting on top of a software-defined radio. Each layer adds understanding — from raw electromagnetic signal to searchable, queryable insight.

🔊
CAPTURE
SDR hardware samples RF spectrum at up to 20 Msps. VAD detects voice — squelch opens, recording begins. Saved as WAV automatically.
✍️
TRANSCRIBE
Faster-Whisper runs locally (tiny.en → small → medium). Streaming partial transcripts appear within seconds of speech. No data leaves your machine.
🧠
UNDERSTAND
Entity extraction pulls callsigns, frequencies, locations, Q-codes. Intent classification labels each transmission: convoy, emergency, check-in, navigation…
🔗
CORRELATE
Voice biometrics (MFCC + CTCSS) cluster transmissions by probable radio hardware. The same physical radio — same fingerprint — even across frequencies.
🚨
ALERT
Urgency scoring flags mayday, emergency, all-stations traffic. Alerts via desktop notification and Kokoro TTS spoken readback — hands-free monitoring.
🗄️
ARCHIVE
SQLite + FTS5 stores every transmission forever. Full-text search, frequency filter, intent filter, date range — all queryable in milliseconds.

Frequency coverage

Any band the HackRF (or Airspy / RTL-SDR) can receive. Current presets cover Australian domestic bands — add any frequency with the custom VFO.

476–477 MHz
UHF CB
NFM · 40 channels
Trucking, tradies, convoys. Australia's busiest radio band.
118–137 MHz
Aviation VHF
AM · 25 kHz spacing
ATC, ATIS, pilot comms. 121.5 MHz international guard.
156–174 MHz
Marine VHF
FM · ITU channels
Coastal and harbour traffic. Ch16 = distress.
144–148 MHz
2m Amateur
FM · repeaters + simplex
Ham radio. 146.52 MHz national simplex calling.
88–108 MHz
FM Broadcast
WFM · 200 kHz spacing
Commercial FM radio. Wide-band demodulation.
26–28 MHz
HF CB (27 MHz)
AM · 40 channels
Long-range CB. Skip conditions during solar max.
162–163 MHz
NOAA / BOM
FM · continuous broadcast
Weather alerts, hazard warnings, storm data.
430–440 MHz
70cm Amateur
FM / digital
Ham radio. Digital modes, APRS, repeaters.
1 MHz – 6 GHz
Custom VFO
WFM / NFM / AM / SSB
Tune to any frequency. LNA/VGA gain configurable.

Technology stack

Hardware

HackRF OnePrimary SDR — 1 MHz to 6 GHz, 20 Msps, half-duplex TX/RX
Airspy MiniFuture: 24–1700 MHz, 12-bit ADC, true IQ — enables RF fingerprinting Tier 2b
RTL-SDR v3Budget option — 500 kHz–1.75 GHz, 8-bit, receive-only

Signal Processing

libhackrf (ctypes)Direct hardware access — no GNU Radio dependency
numpy / scipyFFT, FIR decimation, demodulation chains (WFM/NFM/AM)
SoapySDRHardware abstraction — same code drives HackRF, Airspy, RTL-SDR
sounddeviceLow-latency audio output, 400ms ring buffer, PortAudio backend

AI / ML

faster-whisperCTranslate2-optimised Whisper. tiny.en → small → medium. ROCm GPU supported.
Kokoro-82MTTS readback and transmit synthesis. Apache 2.0. am_michael voice.
Ollama (local LLMs)Intent classification. phi4:14b, qwen2.5-coder:7b, gemma2:2b. Falls back to keyword rules.
BERT NERdslim/bert-base-NER — entity extraction (locations, organisations)
HDBSCANVoice + CTCSS biometric clustering — identifies probable transmitter hardware

Backend

FastAPI + uvicornREST API + Server-Sent Events. Port 4310.
SQLite + FTS5All transmissions, full-text search, zero config. WAL mode.
watchdog (inotify)Transcribe daemon: inotify sentinel protocol watches audio dirs
httpx + SSE proxyDashboard proxies daemon SSE events to all browser clients

Frontend

Svelte 5 + SvelteKitReactive UI. SSE live updates. SPA build via adapter-static.
Server-Sent EventsLive feed: recording_started → partial_transcript → transmission_complete
Web Audio APIClick sounds, mic capture (hold-to-record PTT), waveform visualisation
MediaRecorder APIBrowser mic capture for transmit panel demo mode

Transmitter fingerprinting

RFAI can identify individual physical radios — not just voices — using a multi-tier biometric system. Each tier adds confidence.

Tier 0
Verified callsign
Whisper extracts a formal callsign (VK2ABC, etc.) from the transcript text. High confidence — the operator stated their identity on air.
VK2ABC · ✓
Tier 1
Spoken handle
Pattern matching extracts self-reported aliases ("this is Night Hawk"). Medium confidence — self-reported, not verified.
Night Hawk
Tier 2
Radio hardware cluster
18-dimensional feature vector: MFCC voice coefficients, fundamental pitch, spectral centroid, CTCSS sub-audible squelch tone, duration patterns. HDBSCAN clusters transmissions by probable physical radio.

CTCSS is the strongest discriminator — it is programmed into the radio itself, so the same hardware always emits the same sub-audible tone regardless of speaker.
~C1042 · ≈
Tier 2b
IQ RF fingerprinting Coming — needs Airspy
With raw IQ data from the Airspy Mini: carrier frequency offset, phase noise signature, transmitter turn-on transient. True hardware fingerprinting that works even without voice or CTCSS.

Pages in this app

Demo mode — no SDR required

RFAI runs without any radio hardware. Three ways to inject audio:

1
🎙 MIC DEMO button
Click 🎙 MIC DEMO in the Dashboard Live Status panel or Chat Room. Records from your computer microphone on the server side. Writes a WAV file to /tmp/rfai-demo/ which the transcribe daemon picks up automatically via the sentinel protocol. Your voice appears in the live feed as a real transmission.
POST /api/demo/mic-record · POST /api/demo/mic-stop
2
🎙 Hold-to-record PTT (Chat Room)
In the Chat Room transmit panel, hold the 🎙 HOLD button. Uses the browser's MediaRecorder API to capture from your microphone. On release, the audio blob is sent to POST /api/transmit/audio. Played through the soundbar and logged to the DB as source='transmitted'.
3
✍️ Text transmit (Chat Room)
Type a message in the Chat Room and press ▶ TRANSMIT. Kokoro TTS synthesises it as the am_michael radio voice, plays through your soundbar, and the transmission is logged to the DB.
POST /api/transmit/text · body: { text, band, frequency_hz }

Roadmap

✅ DoneP0 — Scanner Foundation
  • HackRF One — live IQ capture via ctypes
  • Spectrum + waterfall display (PyQt5)
  • WFM / NFM / AM demodulation with FIR decimation chains
  • RMS VAD + adaptive squelch gate
  • Auto-record WAV on transmission detect
  • Band presets: UHF CB, Aviation, Marine, Amateur, FM
✅ DoneP1–P5 — Intelligence Core
  • faster-whisper STT — streaming partial transcripts via SSE
  • Kokoro-82M TTS — spoken readback and transmit synthesis
  • Entity extraction — callsigns, Q-codes, locations, phonetic alphabet
  • Intent classification — 8 categories + urgency score (0–1)
  • SQLite + FTS5 — all transmissions, full-text search
  • 7-model intent bakeoff (Claude, phi4, qwen, gemma, keyword)
✅ DoneP6 — Web UI Showcase
  • Svelte 5 SPA — Dashboard, Log Room, Chat Room, Scanner, Analysis, TX ID
  • Live SSE feed — recording_started → partial transcript → complete
  • MIC DEMO mode — showcase without SDR hardware
  • Transmit panel — TTS synthesis + soundbar playback + DB logging
  • Transmitter fingerprinting UI — cluster browser, identity tiers
  • FastAPI backend + uvicorn + CORS on ports 4310/4311/4312
🔧 In ProgressP7 — UI Polish
  • Light mode + alternate dark themes (CSS variable swap)
  • Audio playback — inline player for archived transmissions
  • Compact message density — reduce row padding
  • Frequency filter pills + colour-coded by freq or ID
  • CB/Marine/Aviation channel lookup table (477.125 → "UHF CB Ch40")
  • Flag SSE broadcast — live sync across browser tabs
  • Svelte source committed to git (currently only build is tracked)
📋 NextP8 — RF Fingerprinting Tier 2b
  • Airspy Mini integration — 12-bit IQ, true carrier phase data
  • Carrier frequency offset extraction — per-radio systematic offset
  • Transmitter turn-on transient — unique hardware signature
  • Phase noise floor — distinguishes radio model + unit
  • Combined IQ + voice + CTCSS fingerprint — high-confidence ID without callsign
📋 NextP9 — Multi-band Correlation
  • Cross-band operator tracking — same voice heard on UHF + Marine
  • Channel-hop detection — "go to 5" → auto-follow to ch5
  • Convoy/group session stitching — link related transmissions
  • Temporal pattern analysis — who transmits when, at what cadence
🔮 FutureP10 — qalarc.com Public Demo
  • Deploy on qalarc.com — live demo of the full UI and stack
  • Demo data: curated synthetic transmissions covering all intent types
  • Read-only public view — no live SDR in cloud (legal/practical)
  • Replay mode — watch a stored session play back in real time
  • Shareable permalinks — link to a specific transmission or time range

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│  HARDWARE LAYER                                                      │
│  HackRF One ──────────────────── USB ──────────────── Desktop PC   │
│  (1MHz–6GHz · 20Msps · half-duplex)      AMD ROCm iGPU available   │
└─────────────────────┬───────────────────────────────────────────────┘
                      │ IQ samples (int8 → complex64)
                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│  SCANNER (hackrf_scanner_v9.py · PyQt5 GUI)                         │
│  Engine thread: FFT → spectrum/waterfall → demodulate (WFM/NFM/AM) │
│  AudioOut: 400ms ring buffer → sounddevice → speakers               │
│  VAD + squelch → auto-record WAV → sentinel file created           │
└─────────────────────┬───────────────────────────────────────────────┘
                      │ WAV + .inprogress sentinel
                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│  TRANSCRIBE DAEMON (port 4311)                                       │
│  inotify watches /tmp/rfai-test-audio/ + /tmp/rfai-demo/            │
│  sentinel created → emit recording_started SSE                      │
│  sentinel deleted → queue WAV for processing                        │
│  faster-whisper tiny.en (streaming) → partial_transcript SSE       │
│  faster-whisper small (final) → transcription_complete SSE         │
│  entities.py → callsigns, Q-codes, locations                       │
│  intent_llm.py → Ollama/keyword → intent + urgency                 │
│  → INSERT INTO transmissions (SQLite · WAL mode)                    │
└─────────────────────┬───────────────────────────────────────────────┘
                      │ SSE proxy + DB queries
                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│  WEB DASHBOARD (FastAPI · port 4310)                                 │
│  GET /api/transmissions  GET /api/stats  GET /api/operators         │
│  GET /api/events  ← SSE proxy from daemon + DB poll                │
│  GET /api/clusters  ← fingerprint.py clusters                      │
│  POST /api/demo/mic-record  POST /api/transmit/text                │
│  POST /api/transmit/audio   GET /api/daemon/health                 │
│  Serves ui/build/ SPA at / (catch-all → index.html)                │
└─────────────────────┬───────────────────────────────────────────────┘
                      │ HTTP/SSE · CORS
                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│  BROWSER UI (SvelteKit SPA · port 4312 / 4310)                      │
│  /dashboard  — live feed · stats · band chart · MIC DEMO            │
│  /log        — searchable table · flag · notes · export             │
│  /chat       — IRC-style · live bubble · transmit panel             │
│  /scanner    — waterfall · VFO · hardware config                    │
│  /analysis   — stats · model bakeoff · intent arena                 │
│  /fingerprint — cluster browser · identity tiers · label            │
│  /about      — this page                                            │
└─────────────────────────────────────────────────────────────────────┘