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

VariableDefaultDescription
ADS-B Tracking
ADSB_ENABLEDtrueEnable ADS-B receiver (single-dongle time-share by default)
ADSB_DUAL_DONGLEfalseUse dedicated RTL-SDR on device 1 — no time-sharing needed
ADSB_SCAN_INTERVAL60Seconds of rtl_fm listening between ADS-B scans (single-dongle only)
ADSB_SCAN_DURATION30Seconds per ADS-B scan window (single-dongle only)
Meteor Scatter Detection
METEOR_ENABLEDfalseEnable passive meteor scatter detection
METEOR_DUAL_DONGLEfalseUse dedicated RTL-SDR on device 1 for 24/7 meteor monitoring
METEOR_FREQUENCY143050000Carrier frequency in Hz (143.050 MHz = amateur meteor scatter)

Technology Stack

LayerTechnology

API Endpoints

MethodRouteDescription
GET/Serve web UI
GET/api/presetsList frequency presets
POST/api/tuneTune to frequency or preset
POST/api/stopStop reception
POST/api/squelchSet squelch level
POST/api/gainSet tuner gain
POST/api/retryRestart current source after crash
GET/api/statsInference stats (latency, RTF, tokens)
GET/api/statusPipeline status
GET/api/adsb/flightsCurrent ADS-B aircraft list
GET/audio-streamChunked WAV audio stream
GET/api/weather/currentLatest parsed NOAA weather conditions
GET/api/satellite/passesNext 24h predicted satellite passes
GET/api/satellite/latest-imageMost recent decoded APT image + metadata
GET/api/ais/vesselsCurrent AIS vessel list
GET/api/wefax/latestMost recent WEFAX chart (?chart_type= filter)
GET/api/wefax/scheduleNext 6h of scheduled WEFAX broadcasts
GET/api/wefax/historyLast 10 decoded WEFAX charts
GET/api/meteor/eventsPaginated meteor detections (?shower=&trail_type=)
GET/api/meteor/statsHourly rate, session stats, active shower
GET/api/meteor/showersFull annual meteor shower calendar
POST/api/sample_rateSet capture sample rate
POST/api/deempSet de-emphasis (auto/on/off)
POST/api/ppmSet PPM crystal correction
POST/api/direct_samplingSet direct sampling mode (off/I/Q)

Socket.IO Events

EventDirectionDescription
transcriptServer → ClientNew transcription text
statusServer → ClientPipeline status update
signal_levelServer → ClientSignal strength (RMS)
modeServer → ClientSDR or WEBSTREAM mode
errorServer → ClientError notification
adsb_updateServer → ClientADS-B flight list (every 2s)
callsign_matchServer → ClientTranscript-to-flight callsign match
inference_statsServer → ClientInference latency/RTF/tokens stats
weather_updateServer → ClientParsed NOAA weather conditions
priority_alertServer → ClientWeather warning/watch/advisory alert
satellite_pass_upcomingServer → ClientSatellite pass starting in 10 minutes
apt_image_readyServer → ClientDecoded APT satellite image available
ais_updateServer → ClientAIS vessel list (every 2s)
wefax_broadcast_upcomingServer → ClientWEFAX broadcast starting in 5 minutes
wefax_image_readyServer → ClientDecoded WEFAX weather chart available
meteor_detectionServer → ClientReal-time meteor scatter burst detected
meteor_stats_updateServer → ClientMeteor hourly rate & session stats (every 60s)