Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

38 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ“ก RTL-SDR Signal Analyzer & Jamming Detector

Python License RTL-SDR

A real-time spectrum analyzer and signal detection tool leveraging RTL-SDR hardware for RF monitoring and jamming detection.

Features โ€ข Installation โ€ข Usage โ€ข Configuration โ€ข Commands โ€ข Examples โ€ข Contributing


๐Ÿ“‘ Table of Contents


โœจ Features

  • ๐Ÿ“Š Real-time Visualization: Advanced spectrum analysis with waterfall display
  • ๐Ÿ” Smart Detection: Automatic signal anomaly and jamming detection
  • ๐Ÿ“ˆ Dynamic Analysis: Adaptive baseline calculation and threshold adjustment
  • โš™๏ธ Flexible Configuration: Validated YAML config, env vars, and CLI overrides
  • ๐ŸŒ Network Support: Built-in RTL-TCP compatibility for remote operation
  • ๐Ÿ–ฅ๏ธ GUI & Headless: Interactive matplotlib plots or console-only daemon mode
  • ๐Ÿ“ค Event Export: Save detections to CSV or JSON Lines
  • ๐Ÿ’พ SQLite Storage: Persistent event storage with rich statistics dashboard
  • ๐Ÿ“ป IQ Recording: Capture raw IQ samples for offline analysis
  • ๐Ÿ”„ Frequency Sweeping: Scan wide frequency ranges automatically
  • ๐Ÿงช Well Tested: 60+ tests with 85%+ coverage

๐Ÿš€ Installation

Prerequisites

Requirement Version Notes
Python 3.9+ Required for modern type hints
RTL-SDR Any USB dongle with RTL2832U chipset
Docker Latest For RTL-TCP server container
Docker Compose Latest Included with Docker Desktop

Setup with uv (Recommended)

We recommend using uv for fast environment management:

# Clone the repository
git clone https://github.com/msalexms/rtl-sdr-analyzer.git
cd rtl-sdr-analyzer

# Create virtual environment and install
uv venv
source .venv/bin/activate  # Linux/Mac
# .venv\Scripts\activate   # Windows

# Install core dependencies + dev tools
uv pip install -e ".[dev,test]"

# Verify installation
rtl-sdr-analyzer --help

Optional: GUI Backend

For interactive matplotlib plots, install a GUI backend:

uv pip install -e ".[gui]"  # Installs PyQt6

If no GUI backend is available, the analyzer automatically falls back to headless mode with a warning.

Alternative: Using pip

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,test]"

๐Ÿ’ป Usage

Quick Start (3 steps)

1. Start the RTL-TCP server

The server connects to your RTL-SDR hardware and streams IQ data over TCP:

cd docker
docker-compose up -d

Verify it's running:

docker ps
nc -zv 127.0.0.1 1234

2. Choose your mode

Mode Use Case Command
GUI Interactive analysis with plots rtl-sdr-analyzer analyze --freq 98e6
Headless Server/daemon, remote monitoring rtl-sdr-analyzer analyze --headless --freq 98e6
Export Log detections to file Add --export-format csv --export-path events.csv
Database Persistent storage + stats Add --db-path events.db

3. Run the analyzer

# Basic GUI mode (local server)
rtl-sdr-analyzer analyze --freq 98e6 --host 127.0.0.1

# Headless mode with CSV logging
rtl-sdr-analyzer analyze --headless \
  --freq 446e6 \
  --host 127.0.0.1 \
  --export-format csv \
  --export-path events.csv

# With SQLite persistence for later stats
rtl-sdr-analyzer analyze --headless \
  --freq 915e6 \
  --db-path events.db

๐ŸŽฎ Commands

analyze โ€” Real-time Spectrum Analysis

The main command. Connects to RTL-TCP, processes IQ samples, detects signals, and visualizes or logs results.

Syntax:

rtl-sdr-analyzer analyze [OPTIONS]

Connection Options

Option Short Description Default
--host RTL-TCP server hostname/IP 192.168.31.34
--port RTL-TCP server port 1234

Receiver Options

Option Short Description Default
--freq Center frequency in Hz (e.g. 98e6, 446000000) 915e6
--sample-rate Sample rate in Hz 2.048e6
--fft-size FFT size (power of 2) 2048

Detection Options

Option Description Default
--power-threshold Minimum signal power in dB -70
--bandwidth-threshold Minimum signal bandwidth in Hz 100000
--z-score-threshold Statistical deviation threshold 1.5
--detection-window Frames for baseline calculation 5
--min-duration Minimum event duration in seconds 0.1
--test-mode Enable sensitive detection (any criterion triggers) false

Display Options

Option Description Default
--waterfall-length Waterfall history length 50
--update-interval Plot update interval in ms 50
--headless Run without GUI (console only) false

Export Options

Option Description Default
--export-format Export format: csv or json โ€”
--export-path File path for exported events โ€”

Storage Options

Option Description Default
--db-path SQLite database path for persistent event storage โ€”

Logging Options

Option Description Default
--log-level Logging level: DEBUG, INFO, WARNING, ERROR INFO
--log-format Log format: text or json text
--config -c Path to YAML config file

Examples:

# Monitor FM radio band with GUI
rtl-sdr-analyzer analyze --freq 98e6 --host 127.0.0.1

# Monitor walkie-talkies (446 MHz) headless with CSV export and SQLite
rtl-sdr-analyzer analyze --headless \
  --freq 446e6 \
  --host 127.0.0.1 \
  --export-format csv \
  --export-path walkie_events.csv \
  --db-path events.db

# High-sensitivity detection for weak signals
rtl-sdr-analyzer analyze --headless \
  --freq 915e6 \
  --power-threshold -80 \
  --z-score-threshold 1.0 \
  --min-duration 0.05

# Test mode (more sensitive, good for debugging)
rtl-sdr-analyzer analyze --headless \
  --freq 98e6 \
  --test-mode \
  --log-level DEBUG

# Remote server (not localhost)
rtl-sdr-analyzer analyze \
  --host 192.168.1.50 \
  --port 1234 \
  --freq 446e6

Output Example (Headless):

2026-04-27T09:19:07.821925Z [info     ] Starting signal analyzer...
2026-04-27T09:19:07.822081Z [info     ] Connecting to RTL-TCP server at 127.0.0.1:1234
2026-04-27T09:19:07.822307Z [info     ] Successfully connected to RTL-TCP server
2026-04-27T09:19:08.123456Z [info     ] Spectrum stats [10] | mean=-78.5 dB | min=-92.1 dB | max=-45.2 dB
2026-04-27T09:19:08.234567Z [info     ] DETECTION | freq=445.987 MHz | power=-45.2 dB | bw=12500 Hz | dur=0.15 s | conf=2.34

record โ€” IQ Sample Recording

Record raw IQ samples to a file for offline analysis with GNU Radio or custom scripts.

rtl-sdr-analyzer record output.raw --duration 30 --freq 915e6 --host 127.0.0.1
Option Description Default
output Output file path (required) โ€”
--duration Recording duration in seconds 10.0
--format Output format: raw or numpy raw
--freq Center frequency 915e6
--host RTL-TCP host 192.168.31.34
--port RTL-TCP port 1234

Formats:

  • raw: Interleaved uint8 I/Q data. Compatible with rtl_sdr, GNU Radio, and most SDR tools.
  • numpy: .npz file with complex64 array + metadata (sample rate, frequency, timestamp).

Examples:

# Record 60 seconds for later analysis
rtl-sdr-analyzer record capture.raw --duration 60 --freq 446e6 --host 127.0.0.1

# Record in NumPy format
rtl-sdr-analyzer record capture.npz --duration 30 --format numpy --freq 915e6

sweep โ€” Frequency Range Scanning

Automatically scan a frequency range with configurable step and dwell time, detecting signals at each stop.

rtl-sdr-analyzer sweep START_HZ END_HZ [OPTIONS]
Option Description Default
start_freq Start frequency in Hz (required) โ€”
end_freq End frequency in Hz (required) โ€”
--step Frequency step in Hz 1e6
--dwell Dwell time per frequency in seconds 2.0
--host RTL-TCP host 192.168.31.34
--port RTL-TCP port 1234
--sample-rate Sample rate 2.048e6
--power-threshold Power threshold -70
--headless Run without GUI true
--export-format Export format โ€”
--export-path Export file path โ€”
--db-path SQLite database path โ€”

Examples:

# Scan 400-500 MHz for walkie-talkies
rtl-sdr-analyzer sweep 400e6 500e6 --step 1e6 --dwell 2.0 --host 127.0.0.1

# Fine-grained sweep with CSV export
rtl-sdr-analyzer sweep 88e6 108e6 \
  --step 0.5e6 \
  --dwell 1.0 \
  --export-format csv \
  --export-path fm_sweep.csv

# Sweep with database persistence
rtl-sdr-analyzer sweep 400e6 500e6 --step 1e6 --db-path sweep.db

stats โ€” Statistics Dashboard

Display rich statistics from a SQLite database created with --db-path.

rtl-sdr-analyzer stats DB_PATH [OPTIONS]
Option Description Default
db_path Path to SQLite database rtl_sdr_analyzer.db
--top-freqs Show top frequencies by activity true
--hourly Show hourly activity chart true
--recent Number of recent events to show 10
--export-csv Export events to CSV file โ€”
--since-hours Filter events by last N hours โ€”

Examples:

# Show full dashboard
rtl-sdr-analyzer stats events.db

# Export last 24h to CSV
rtl-sdr-analyzer stats events.db --export-csv yesterday.csv --since-hours 24

# Show only summary and recent events
rtl-sdr-analyzer stats events.db --top-freqs=false --hourly=false --recent 20

Dashboard Output:

๐Ÿ“Š RTL-SDR Analyzer Statistics
==================================================
Total detection events: 1542
Events in last 24h: 87
Recent sessions: 3

๐Ÿ”ฅ Top Frequencies by Activity
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Frequency (MHz) โ”ƒ Detections โ”ƒ Avg Power (dB) โ”ƒ Max Power (dB) โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ 445.987         โ”‚ 523        โ”‚ -52.3          โ”‚ -30.1          โ”‚
โ”‚ 98.100          โ”‚ 412        โ”‚ -65.1          โ”‚ -45.2          โ”‚
โ”‚ 446.125         โ”‚ 607        โ”‚ -48.7          โ”‚ -28.9          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“ˆ Hourly Activity (Last 24h)
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Hour                โ”ƒ Detections โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ 2026-04-27 10:00    โ”‚ 12         โ”‚
โ”‚ 2026-04-27 11:00    โ”‚ 35         โ”‚
โ”‚ 2026-04-27 12:00    โ”‚ 40         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

config-validate โ€” Validate Configuration

Validate a YAML configuration file against the Pydantic schema.

# Validate default config
rtl-sdr-analyzer config-validate config/default.yml

# Validate custom config
rtl-sdr-analyzer config-validate my-config.yml

Output:

Configuration is valid.
{
  "rtl_tcp": {
    "host": "192.168.31.34",
    "port": 1234
  },
  "receiver": {
    "frequency": 915000000.0,
    ...
  }
}

If invalid, you'll see detailed error messages:

Configuration error: 1 validation error for Settings
receiver.frequency
  Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int]

config-show โ€” Display Resolved Configuration

Shows the final configuration after merging all sources (defaults โ†’ YAML โ†’ env vars โ†’ CLI).

# Show as YAML (default)
rtl-sdr-analyzer config-show

# Show as JSON
rtl-sdr-analyzer config-show --format json

# Show with custom config file
rtl-sdr-analyzer config-show --config my-config.yml --format json

Useful for debugging to verify that your env vars and CLI flags are being applied correctly.


โš™๏ธ Configuration

Configuration follows a cascading priority (lowest โ†’ highest):

Code Defaults โ†’ YAML File โ†’ Environment Variables โ†’ CLI Flags

1. YAML Configuration File

Create a custom config file:

# my-config.yml
rtl_tcp:
  host: "127.0.0.1"
  port: 1234

receiver:
  frequency: 98000000    # 98 MHz - FM Radio
  sample_rate: 2048000   # 2.048 MHz
  fft_size: 2048

detector:
  power_threshold: -70.0
  bandwidth_threshold: 100000    # 100 kHz
  z_score_threshold: 1.5
  detection_window: 5
  min_duration: 0.1
  test_mode: false

display:
  waterfall_length: 50
  update_interval: 50

Use it:

rtl-sdr-analyzer analyze --config my-config.yml

2. Environment Variables

Prefix with RTL_SDR__ and use double underscores for nesting:

# Override frequency
export RTL_SDR__RECEIVER__FREQUENCY=446000000

# Override host
export RTL_SDR__RTL_TCP__HOST=192.168.1.50

# Enable test mode
export RTL_SDR__DETECTOR__TEST_MODE=true

# Then run (picks up env vars automatically)
rtl-sdr-analyzer analyze

See .env.example for all available variables.

3. CLI Flags

Highest priority. Override any other source:

# Override just frequency and threshold
rtl-sdr-analyzer analyze \
  --config my-config.yml \
  --freq 915e6 \
  --power-threshold -65

๐Ÿ“š Examples

Example 1: FM Radio Monitoring

# Monitor 98 MHz with GUI
rtl-sdr-analyzer analyze --freq 98e6 --host 127.0.0.1

# Monitor with CSV export for later analysis
rtl-sdr-analyzer analyze --headless \
  --freq 98e6 \
  --host 127.0.0.1 \
  --export-format csv \
  --export-path fm_events.csv \
  --power-threshold -60

Example 2: Walkie-Talkie Detection

# Headless monitoring with JSON export and SQLite
rtl-sdr-analyzer analyze --headless \
  --freq 446e6 \
  --host 127.0.0.1 \
  --export-format json \
  --export-path walkie_events.jsonl \
  --db-path walkie.db \
  --bandwidth-threshold 50000 \
  --min-duration 0.2

# View stats afterward
rtl-sdr-analyzer stats walkie.db

Example 3: GSM/LTE Signal Analysis

# Monitor GSM band (around 900-1800 MHz depending on region)
rtl-sdr-analyzer analyze --headless \
  --freq 950e6 \
  --sample-rate 2.4e6 \
  --power-threshold -75 \
  --detection-window 10

Example 4: Debug Mode

# Very sensitive detection with debug logging
rtl-sdr-analyzer analyze --headless \
  --freq 915e6 \
  --test-mode \
  --log-level DEBUG \
  --log-format text

Example 5: Remote Server Setup

# Server runs RTL-TCP on 192.168.1.50
# Client connects from another machine
rtl-sdr-analyzer analyze \
  --host 192.168.1.50 \
  --port 1234 \
  --freq 446e6 \
  --headless

Example 6: Custom Config per Band

Create config/fm-radio.yml:

receiver:
  frequency: 98000000
  sample_rate: 2048000

detector:
  power_threshold: -60
  bandwidth_threshold: 150000

Create config/walkie-talkie.yml:

receiver:
  frequency: 446000000
  sample_rate: 2048000

detector:
  power_threshold: -70
  bandwidth_threshold: 25000
  min_duration: 0.2

Switch between them:

rtl-sdr-analyzer analyze --config config/fm-radio.yml
rtl-sdr-analyzer analyze --config config/walkie-talkie.yml

Example 7: IQ Recording for Offline Analysis

# Record 60 seconds of raw IQ data
rtl-sdr-analyzer record capture.raw \
  --duration 60 \
  --freq 446e6 \
  --host 127.0.0.1

# Record in NumPy format for Python analysis
rtl-sdr-analyzer record capture.npz \
  --duration 30 \
  --format numpy \
  --freq 915e6

# Load in Python later
python -c "import numpy as np; d = np.load('capture.npz'); print(d['iq'][:10])"

Example 8: Frequency Sweep

# Scan 400-500 MHz for walkie-talkies
rtl-sdr-analyzer sweep 400e6 500e6 \
  --step 1e6 \
  --dwell 2.0 \
  --host 127.0.0.1 \
  --export-format csv \
  --export-path sweep_results.csv

# Fine-grained FM radio sweep
rtl-sdr-analyzer sweep 88e6 108e6 \
  --step 0.5e6 \
  --dwell 1.0 \
  --db-path fm_sweep.db

# View sweep stats
rtl-sdr-analyzer stats fm_sweep.db --top-freqs --hourly

Example 9: SQLite Storage and Stats

# Run analyzer with persistent storage
rtl-sdr-analyzer analyze --headless \
  --freq 915e6 \
  --host 127.0.0.1 \
  --db-path monitoring.db

# Let it run for a while, then check stats
rtl-sdr-analyzer stats monitoring.db

# Export last 24 hours to CSV
rtl-sdr-analyzer stats monitoring.db \
  --export-csv yesterday.csv \
  --since-hours 24

# Show only top frequencies
rtl-sdr-analyzer stats monitoring.db --hourly=false --recent=0

๐Ÿ”ง Common Signal Patterns

Signal Type Frequency Range Characteristics
๐Ÿ“ป FM Radio 88-108 MHz Strong, stable, wide bandwidth
๐Ÿ“ฑ GSM/LTE 700-2600 MHz Wide-band, intermittent
๐Ÿ›œ Wi-Fi 2.4/5 GHz Periodic bursts (need downconverter)
๐ŸŽฎ RF Remotes 315/433/868 MHz Brief, narrow-band
๐Ÿš— Walkie-Talkies 446 MHz Short bursts, medium bandwidth

๐Ÿงช Development

# Run all tests with coverage
pytest

# Run specific test file
pytest tests/unit/test_detector.py -v

# Linting
ruff check src tests
ruff format src tests

# Type checking
mypy --strict src

# Run with coverage report
pytest --cov=rtl_sdr_analyzer --cov-report=html

๐Ÿค Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'feat: add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


Developed with โค๏ธ by RF enthusiasts

Report Bug โ€ข Request Feature

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages