SDR-Shark is an applied RF signal-intelligence platform and web-based software defined radio console for live spectrum monitoring, waterfall visualization, protocol-aware signal activity, and decoder-assisted RF discovery. It combines a Python/Flask backend with a React frontend and can receive samples either directly through SoapySDR or through sdr-gateway.
The project demonstrates the system layer around RF ML: live device streaming, browser visualization, signal feature extraction, decoder plugin orchestration, service deployment, and integration points for models from rf-signal-intelligence.
The project is intended for lawful RF engineering, lab validation, education, spectrum monitoring, and passive signal-awareness workflows. Operators are responsible for complying with all applicable radio, privacy, and computer misuse laws in their jurisdiction.
SDR-Shark includes a hardware-free public demo that generates deterministic synthetic IQ replay data locally. The demo is public-safe: it shows a stationary receiver watching a Bluetooth-like frequency-hopping emitter move across the passband, along with tones, moving noise floor, and burst activity, without committing real RF captures or requiring SDR hardware.
Portfolio case study: RTG Spectrum SDR-Shark
Run the public Docker demo in one command:
docker compose -f docker-compose.demo.yml up --buildThen open the LAN URL for this machine, usually:
http://<machine-ip>:8080
Stop it with:
docker compose -f docker-compose.demo.yml downLocal source demo:
./scripts/demo.shThe script binds to 0.0.0.0, tries port 80 first, and falls back to 8080 when low-port bind is unavailable without elevated permissions. Open the LAN URL printed by the script, usually:
http://<machine-ip>:8080
Stop the demo with:
./scripts/demo_stop.shSee docs/demo.md for API checks, troubleshooting, and replay details.
- One-command Docker path for reviewers, customers, and collaborators.
- Stationary receiver view of a Bluetooth-like frequency-hopping 2.4 GHz emitter.
- Browser-based spectrum and waterfall UI driven by replayed IQ.
- Backend FFT, max-hold, persistence, and replay session plumbing.
- Hardware-aware SDR architecture that can run live, gateway-backed, or replay-backed.
- A safe portfolio demo path for RF workflow review without exposing local RF environment data.
The captures below were generated from the Docker demo using the synthetic public-demo-2p4ghz replay session. The receiver stays centered while the synthetic Bluetooth-like emitter hops across the passband.
| Live replay dashboard | Spectrum and waterfall detail | Signal activity panel |
|---|---|---|
![]() |
![]() |
![]() |
| Scanner setup | SDR settings | Signal analysis |
|---|---|---|
![]() |
![]() |
![]() |
- Displays a live spectrum trace and waterfall with GPU-backed rendering support.
- Supports direct SoapySDR receive and gateway-backed receive through
sdr-gateway. - Shares one wideband IQ stream with multiple decoder plugins.
- Shows decoded signal activity cards for Bluetooth Low Energy, Bluetooth Classic, WiFi/802.11, Zigbee/802.15.4, FM broadcast, ADS-B, and GPS status.
- Provides scanner mode for repeated dwell plans across 2.4 GHz ISM, FM, sub-GHz, ADS-B, LTE awareness bands, and WiFi 5.8 GHz.
- Tracks Pattern-of-Life information in the activity panel, including multi-day seen/streak pills.
- Provides optional FM station verification and playback from the live wideband IQ stream.
- Supports top-right modal workflows for settings, scanner, analysis, classifiers, GPS, and related controls.
- Provides integration points for RF/IQ classifiers and streaming inference.
SDR-Shark has three main layers:
frontend/: React UI for the live plot, waterfall, scanner, settings dialogs, GPS dialog, and decoded signal activity panel.backend/src/sdr_plot_backend/: Flask API, SDR adapter, scanner controller, protocol plugin adapters, and shared IQ tap plumbing.scripts/: local start, service management, gateway mode, and one-script installation helpers.
Receive modes:
SDR_BACKEND=gateway: SDR-Shark connects tosdr-gatewayusingSDR_SERVER_URLand an optionalSDR_GATEWAY_API_TOKEN. This is the packaged default because it supports shared-radio deployments.SDR_BACKEND=soapy: SDR-Shark opens the radio locally using SoapySDR.replay: internal/plugin workflows can consume recorded or replayed IQ where supported.
The direct SoapySDR path can work with any radio supported by the installed SoapySDR modules. Common devices include HackRF, bladeRF, RTL-SDR, Airspy, Sidekiq, and other Soapy-compatible receivers.
High-rate features such as 60 MHz 2.4 GHz scanning require hardware and host I/O that can sustain the requested bandwidth. For narrowband features such as ADS-B, FM, and sub-GHz monitoring, lower bandwidth devices may be sufficient.
A container build also exists (root Dockerfile, not the legacy one
under docker/ - see docker/README.md), deployed on station1 and
dev-desktop. See docker/README.md for the deploy commands (default
rfiq mode vs. direct-SoapySDR/gateway overrides) and a list of real
bugs found and fixed getting the original Dockerfiles working, before
building your own image from scratch.
On Debian/Ubuntu-like systems, the recommended one-script install is:
cd /home/jake/workspace/SDR/SDR-Shark
chmod +x scripts/install.sh
./scripts/install.shThis installs common system dependencies when apt-get is available, creates .venv, installs the backend, installs frontend packages, and builds the frontend.
To install and start SDR-Shark as a systemd service in one command:
cd /home/jake/workspace/SDR/SDR-Shark
./scripts/install.sh --enable-serviceTo skip system package installation, for example on a prepared machine:
./scripts/install.sh --no-system-packagesInstall system dependencies:
sudo apt-get update
sudo apt-get install -y \
build-essential cargo curl git gpsd gpsd-clients gunicorn libliquid-dev \
npm python3-dev python3-pip python3-venv soapysdr-tools sox tshark wireshark-commonCreate and populate the Python environment:
cd /home/jake/workspace/SDR/SDR-Shark
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip wheel setuptools
python -m pip install -r requirements.txt
python -m pip install -e backendInstall and build the frontend:
cd /home/jake/workspace/SDR/SDR-Shark/frontend
npm install
npm run buildOptional FM channelizer build:
cd /home/jake/workspace/SDR/SDR-Shark
bash backend/src/sdr_plot_backend/native/build_fm_channelizer.shStart the backend from the repository root:
cd /home/jake/workspace/SDR/SDR-Shark
source .venv/bin/activate
./scripts/start.shFor frontend development:
cd /home/jake/workspace/SDR/SDR-Shark/frontend
npm startThe development frontend normally runs on http://localhost:3000 and proxies API calls to the backend. The backend normally listens on 0.0.0.0:5000.
Install or refresh the service:
cd /home/jake/workspace/SDR/SDR-Shark
./scripts/sdr-shark-service.sh installEnable and start it:
./scripts/sdr-shark-service.sh enable
./scripts/sdr-shark-service.sh startCommon service commands:
./scripts/sdr-shark-service.sh status
./scripts/sdr-shark-service.sh logs
./scripts/sdr-shark-service.sh restart
./scripts/sdr-shark-service.sh stopThe helper writes the unit to /etc/systemd/system/sdr-shark.service and service defaults to /etc/default/sdr-shark.
Example /etc/default/sdr-shark:
SDR_BACKEND='gateway'
SDR_SHARK_LOG_DIR='/var/log/sdr-shark'
SDR_SHARK_BLUETOOTH_LOG_DIR='/var/log/sdr-shark'
GPSD_HOST='127.0.0.1'
GPSD_PORT='2948'For direct SoapySDR mode:
SDR_BACKEND='soapy'For gateway mode with a non-default gateway URL or authenticated gateway:
SDR_BACKEND='gateway'
SDR_SERVER_URL='http://127.0.0.1:8080'
SDR_GATEWAY_API_TOKEN='replace-with-your-token-if-required'After editing /etc/default/sdr-shark, restart:
sudo systemctl restart sdr-sharkDirect SoapySDR mode:
SDR_BACKEND=soapy ./scripts/start.shVerify SoapySDR:
SoapySDRUtil --find
python -c "import SoapySDR; print('SoapySDR ok')"Limit device probing:
export SDR_SOAPY_DRIVERS=hackrf,bladerf,rtlsdr,airspy,sidekiqGateway mode:
SDR_BACKEND=gateway SDR_SERVER_URL=http://127.0.0.1:8080 ./scripts/start.shOr use the helper:
./scripts/run_gateway.shSoapySDR warnings and vendor output are written to /var/log/sdr-shark/soapysdr.log by default. To show them on stderr while debugging:
export SDR_SOAPY_LOG_STDERR=1Decoder plugins have additional dependencies. See Plugin Installation for detailed setup of:
- RF Sentinel-backed Bluetooth, Zigbee, WiFi, and FM support.
- WiFi MAC frame decoding through GNU Radio, gr-ieee802-11, tshark/pyshark-compatible JSONL/PCAP flows.
- ADS-B Rust decoder support.
- GPSD service setup.
- Liquid-DSP FM channelizer support.
Most plugins are enabled by default and become active only when the tuned receive window overlaps their supported frequency range.
Install GPSD:
sudo apt-get install -y gpsd gpsd-clientsConfigure /etc/default/gpsd. A common USB GPS setup is:
START_DAEMON="true"
USBAUTO="true"
DEVICES=""
GPSD_OPTIONS="-n"Enable and start GPSD:
sudo systemctl enable --now gpsdVerify GPSD:
gpspipe -w
ss -ltnp | grep gpsdConfigure SDR-Shark in /etc/default/sdr-shark:
GPSD_HOST='127.0.0.1'
GPSD_PORT='2948'Some GPSD installs listen on 2947; set GPSD_PORT='2947' if that is what your system exposes.
Disable the GPS plugin:
SDR_SHARK_GPS_PLUGIN='0'Open Scanner from the top-right toolbar. Scanner mode builds a repeated dwell plan and retunes SDR-Shark while decoders run.
Key behavior:
- 2.4 GHz ISM protocols share one dwell percentage because Zigbee, Thread, WiFi 2.4 GHz, Bluetooth Classic, and BLE overlap.
- 2.4 GHz ISM scanning uses two wideband passes: low and high portions of the band at up to 60 MHz bandwidth.
- FM discovery is capped at 5% of the scan cycle so broadcast discovery does not dominate multi-protocol scanning.
- Other selected bands keep individual percentages.
- The scan plan table shows order, center frequency, bandwidth, protocols, dwell time, and revisit period.
- When scanner mode retunes, SDR-Shark auto-levels the Y axis for the new band.
The Signal Activity panel groups decoded protocol activity into cards. Device-oriented detections can be folded by protocol and manufacturer/type. SDR-Shark also records a browser-local Pattern-of-Life cache that tracks compatible fields such as seen_days, seen_day_count, first_seen_date, and last_seen_date.
Pattern-of-Life pills show whether something was seen today, how many recent days it appeared, and whether it has a multi-day streak. This is intended as a field-use convenience and can later be backed by a shared database or RF Sentinel-compatible history store.
Default log locations:
- Service logs:
journalctl -u sdr-shark -f - SDR-Shark logs:
/var/log/sdr-shark - SoapySDR vendor output:
/var/log/sdr-shark/soapysdr.log - Bluetooth events:
/var/log/sdr-shark/bluetooth-events-current.jsonl - Bluetooth archive:
/var/log/sdr-shark/archive/<date-time>/ - WiFi decoder PCAP/JSONL paths: configurable; see Plugin Installation
Backend development:
cd /home/jake/workspace/SDR/SDR-Shark
source .venv/bin/activate
python3 -m sdr_plot_backendFrontend development:
cd /home/jake/workspace/SDR/SDR-Shark/frontend
npm startProduction frontend build check:
cd /home/jake/workspace/SDR/SDR-Shark/frontend
npm run buildRecommended before submitting changes:
git status --short
npm run buildContributions should be scoped, testable, and respectful of existing operator workflows. Good changes usually include:
- A short description of the operational problem being solved.
- A clear default behavior that does not break existing receivers or services.
- Environment variables for hardware- or site-specific settings.
- Documentation updates for new service, plugin, or decoder requirements.
- A build or smoke-test result in the pull request notes.
When working on SDR or decoder changes, avoid assuming exclusive access to a radio. SDR-Shark often runs alongside sdr-gateway and other consumers, so shared IQ tap behavior and clean shutdown are important.
Potential areas for future work:
- Persistent backend Pattern-of-Life storage shared with RF Sentinel.
- More complete WiFi MAC management frame enrichment and SSID/BSSID history.
- Additional protocol plugins for cellular awareness, LoRa, TPMS, VLF/LF/MF, and other ISM bands.
- Better replay/session recording tools for detector validation.
- More GPU rendering options and waterfall palette controls.
- Role-based access control for multi-user deployments.
- Packaged releases for Debian/Ubuntu and containerized lab deployments.
- Automated hardware capability detection for bandwidth, gain ranges, and safe scanner plans.
SDR-Shark is source-available for personal, educational, research, evaluation, and other non-commercial use. All commercial rights are retained by Jacob Ramey. Commercial use, paid deployment, commercial hosting, integration into commercial products or services, contract deliverables, managed service offerings, or other revenue-generating use requires prior written permission.
This project may interoperate with third-party datasets, models, SDR drivers, decoder projects, protocol specifications, and external tools. Jacob Ramey makes no ownership claim over those third-party materials; they remain subject to their original licenses, terms, and redistribution restrictions.
For commercial licensing, integration, support, or permission inquiries, contact:
- Jacob Ramey: rameyjm7@gmail.com






