System Architecture
Passive RF Intelligence Collection Node
Signal Flow — Voice Transcription Pipeline
RF Input Processing AI Inference Output
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ RTL-SDR │ │ 16kHz PCM │ ┌───→│ Audio │────────→│ Browser │
│ Blog V4 │────────→│ Pipeline │────┤ │ Router │ WAV │ <audio> │
│ (rtl_fm) │ FM/AM │ │ │ └──────────────┘ └──────────────┘
└──────────────┘ │ or │ │
│ │ │ ┌──────────────┐ ┌──────────────┐
┌──────────────┐ │ ffmpeg │ └───→│ Whisper │────────→│ Socket.IO │
│ Web Stream │────────→│ resample │ │ Hailo-8L │ text │ Transcript │
│ (ffmpeg) │ HTTP │ │ │ NPU │ │ Feed │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
InputSource Transcriber Flask App
Signal Flow — ADS-B Tracking
Default: Single-dongle time-share Optional: Dual-dongle
┌──────────────┐ 60s listen 30s scan ┌──────────────┐ ┌──────────────┐
│ RTL-SDR │───→ rtl_fm ─────→ pause ─────→│ dump1090 │───→│ ADS-B │
│ (device 0) │←── resume ←───── stop ←──────│ 1090 MHz │ │ Correlator │
└──────────────┘ └──────────────┘ │ │
AdsbScanScheduler │ Callsign │
alternates rtl_fm ↔ dump1090 │ extraction │
on a single dongle │ + flight │
│ matching │
┌──────────────┐ runs continuously │ │
│ RTL-SDR #2 │─── 1090 MHz ──→ dump1090 ──→ JSON ──────────────→│ │──→ Leaflet.js
│ (device 1) │ (no scheduling needed) └──────────────┘ Map Panel
└──────────────┘
ADSB_DUAL_DONGLE=true AdsbReceiver
Signal Flow — NOAA APT Satellite Imaging
Orbital Prediction Recording Decoding
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Celestrak │ TLE │ AptScheduler│ trigger │ rtl_fm │ WAV │ noaa-apt │
│ TLE Feed │────────→│ PyEphem │────────→│ 137 MHz FM │────────→│ CLI decode │
│ │ │ pass predict│ │ 60k/11025Hz │ sox │ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│
┌──────────────┐ │ PNG
│ InputSource │ enter_apt_mode() ▼
│ pauses VHF │ exclusive SDR access ┌──────────────┐
│ scanning │ for 15-minute pass │ Satellite │
└──────────────┘ │ Panel UI │
└──────────────┘
Signal Flow — WEFAX Weather Fax (HF)
Schedule HF Reception Decoding
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ NMC / NOJ │ UTC │ WefaxSched │ trigger │ rtl_fm │ WAV │ fldigi │
│ broadcast │────────→│ time-of-day │────────→│ -D 2 USB │────────→│ --wefax-only│
│ timetable │ │ freq select │ │ HF direct │ sox │ via Xvfb │
└──────────────┘ └──────────────┘ │ sampling │ │ │
│ -1.9kHz ofs │ └──────────────┘
┌──────────────┐ └──────────────┘ │
│ InputSource │ enter_wefax_mode() │ PNG
│ pauses VHF │ APT pass has priority ┌──────────────┐
│ scanning │ │ WEFAX │
└──────────────┘ │ Panel UI │
└──────────────┘
Frequencies: NMC 4346/8682/12786/17151 kHz · NOJ 2054/4298/8459/12412 kHz
Day: 8–12 MHz Night: 2–4 MHz IOC 576 · 1809px width · greyscale
Signal Flow — Meteor Scatter Detection
Carrier Monitor Detection Analysis
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Distant FM │ forward │ rtl_fm │ PCM │ Meteor │ event │ Meteor │
│ carrier │ scatter │ 143.050 MHz │────────→│ Detector │────────→│ Analyzer │
│ (below │─ ─ ─ ─→│ -g 40 │ │ │ │ │
│ horizon) │ meteor │ 11025 Hz │ │ 30s rolling │ │ shower │
└──────────────┘ trail └──────────────┘ │ baseline │ │ calendar │
80-120km │ threshold │ │ 7 showers │
altitude │ dB detect │ │ rate stats │
│ │ │ │
┌──────────────┐ Ionized plasma │ duration: │ │ Perseids │
│ Meteoroid │ column reflects │ 50ms – 30s │ │ Geminids │
│ 11–72 km/s │ radio waves │ │ │ Leonids ... │
└──────────────┘ │ U: <0.5s │ └──────────────┘
│ O: >0.5s │ │
┌──────────────┐ └──────────────┘ ▼
│ RTL-SDR #2 │ METEOR_DUAL_DONGLE=true ┌──────────────┐
│ (device 1) │ 24/7 independent monitor │ Meteor │
│ or device 0 │ lowest SDR priority │ Panel UI │
└──────────────┘ │ rate chart │
└──────────────┘
SDR Mode Priority
Priority Mode Preempts
1 (highest) APT Satellite Pass Everything — orbital window is fixed
2 WEFAX Broadcast Voice, Meteor — scheduled HF window
3 Voice Monitoring Meteor — user-selected frequency
4 (lowest) Meteor Detection Nothing — runs in idle gaps
Single-dongle: modes are mutually exclusive, higher priority preempts lower.
Dual-dongle: meteor detection runs on device 1 independently.
Target Hardware
Raspberry Pi 5
Single-board computer running the full pipeline. Raspberry Pi OS Bookworm 64-bit.
Hailo AI Hat (8L)
13 TOPS neural processing unit. Runs Whisper-tiny encoder/decoder inference via HEF models.
RTL-SDR Blog V4
R828D tuner + RTL2832U with 1PPM TCXO. VHF/UHF 24MHz–1.7GHz via rtl_fm. HF 500kHz–24MHz via Q-branch direct sampling (-D 2).
Environment Configuration
| Variable | Default | Description |
|---|---|---|
| ADS-B Tracking | ||
ADSB_ENABLED | true | Enable ADS-B receiver (single-dongle time-share by default) |
ADSB_DUAL_DONGLE | false | Use dedicated RTL-SDR on device 1 — no time-sharing needed |
ADSB_SCAN_INTERVAL | 60 | Seconds of rtl_fm listening between ADS-B scans (single-dongle only) |
ADSB_SCAN_DURATION | 30 | Seconds per ADS-B scan window (single-dongle only) |
| Meteor Scatter Detection | ||
METEOR_ENABLED | false | Enable passive meteor scatter detection |
METEOR_DUAL_DONGLE | false | Use dedicated RTL-SDR on device 1 for 24/7 meteor monitoring |
METEOR_FREQUENCY | 143050000 | Carrier frequency in Hz (143.050 MHz = amateur meteor scatter) |
Technology Stack
| Layer | Technology |
|---|
API Endpoints
| Method | Route | Description |
|---|---|---|
| GET | / | Serve web UI |
| GET | /api/presets | List frequency presets |
| POST | /api/tune | Tune to frequency or preset |
| POST | /api/stop | Stop reception |
| POST | /api/squelch | Set squelch level |
| POST | /api/gain | Set tuner gain |
| POST | /api/retry | Restart current source after crash |
| GET | /api/stats | Inference stats (latency, RTF, tokens) |
| GET | /api/status | Pipeline status |
| GET | /api/adsb/flights | Current ADS-B aircraft list |
| GET | /audio-stream | Chunked WAV audio stream |
| GET | /api/weather/current | Latest parsed NOAA weather conditions |
| GET | /api/satellite/passes | Next 24h predicted satellite passes |
| GET | /api/satellite/latest-image | Most recent decoded APT image + metadata |
| GET | /api/ais/vessels | Current AIS vessel list |
| GET | /api/wefax/latest | Most recent WEFAX chart (?chart_type= filter) |
| GET | /api/wefax/schedule | Next 6h of scheduled WEFAX broadcasts |
| GET | /api/wefax/history | Last 10 decoded WEFAX charts |
| GET | /api/meteor/events | Paginated meteor detections (?shower=&trail_type=) |
| GET | /api/meteor/stats | Hourly rate, session stats, active shower |
| GET | /api/meteor/showers | Full annual meteor shower calendar |
| POST | /api/sample_rate | Set capture sample rate |
| POST | /api/deemp | Set de-emphasis (auto/on/off) |
| POST | /api/ppm | Set PPM crystal correction |
| POST | /api/direct_sampling | Set direct sampling mode (off/I/Q) |
Socket.IO Events
| Event | Direction | Description |
|---|---|---|
transcript | Server → Client | New transcription text |
status | Server → Client | Pipeline status update |
signal_level | Server → Client | Signal strength (RMS) |
mode | Server → Client | SDR or WEBSTREAM mode |
error | Server → Client | Error notification |
adsb_update | Server → Client | ADS-B flight list (every 2s) |
callsign_match | Server → Client | Transcript-to-flight callsign match |
inference_stats | Server → Client | Inference latency/RTF/tokens stats |
weather_update | Server → Client | Parsed NOAA weather conditions |
priority_alert | Server → Client | Weather warning/watch/advisory alert |
satellite_pass_upcoming | Server → Client | Satellite pass starting in 10 minutes |
apt_image_ready | Server → Client | Decoded APT satellite image available |
ais_update | Server → Client | AIS vessel list (every 2s) |
wefax_broadcast_upcoming | Server → Client | WEFAX broadcast starting in 5 minutes |
wefax_image_ready | Server → Client | Decoded WEFAX weather chart available |
meteor_detection | Server → Client | Real-time meteor scatter burst detected |
meteor_stats_update | Server → Client | Meteor hourly rate & session stats (every 60s) |