Advanced RF spectrum monitoring and direction finding system using bladeRF xA9 for coherent dual-channel acquisition
This system provides real-time RF spectrum monitoring, signal analysis, and 2-channel direction finding using a bladeRF xA9 SDR. The server runs on a LattePanda Sigma or similar platform, performs coherent dual-channel sampling at 40 MHz, FFT processing, cross-correlation analysis, and serves an advanced web interface with multiple workspaces over HTTP. Features include TAKX-RF integration for tactical systems, real-time spectrum analysis, and recording capabilities.
┌────────────────────────────────────────────────────┐
│ LattePanda Sigma / Aircraft / Mobile Platform │
│ ┌──────────────────────────────┐ │
│ │ bladeRF xA9 (Dual RX) │ │
│ │ • RX1 @ 40 MHz (coherent) │ │
│ │ • RX2 @ 40 MHz (coherent) │ │
│ │ • Phase-locked for DF │ │
│ └──────────┬───────────────────┘ │
│ │ USB 3.0 │
│ ┌──────────▼─────────────────────────────────┐ │
│ │ C++ Server (bladerf_server) │ │
│ │ • Dual-channel acquisition (40 MHz) │ │
│ │ • 4096-point FFT (FFTW) │ │
│ │ • Cross-correlation & DF processing │ │
│ │ • Direction finding (phase-based) │ │
│ │ • Mongoose HTTP/SSE server │ │
│ │ • Binary data streaming │ │
│ │ • CoT message generation (TAKX-RF) │ │
│ └──────────┬─────────────────────────────────┘ │
└─────────────┼──────────────────────────────────────┘
│
├─ HTTP/SSE (~0.9 Mbps)
│ Tactical IP Link
│ (Silvus/Doodle Labs/etc)
│
┌─────────────▼──────────────────────────────────────┐
│ Ground Station - Web Browser UI │
│ ┌──────────────────────────────────────────────┐ │
│ │ LIVE: Waterfall + Spectrum + IQ + Controls │ │
│ │ DIRECTION: Phase-Based DF + CoT Streaming │ │
│ │ SCANNER: Frequency Scanning & Detection │ │
│ │ • Toast notifications │ │
│ │ • Connection status monitoring │ │
│ │ • Request throttling & error handling │ │
│ │ • Keyboard shortcuts & state persistence │ │
│ └──────────────────────────────────────────────┘ │
└─────────────┬──────────────────────────────────────┘
│
│ UDP CoT Messages
│ (LoB + Platform Position)
│
┌─────────────▼──────────────────────────────────────┐
│ TAKX-RF / TAK Client │
│ • Platform icon on map │
│ • Line of bearing (LoB) display │
│ • Real-time bearing updates │
└────────────────────────────────────────────────────┘
- Coherent dual-channel RX from bladeRF xA9 (MIMO mode)
- 40 MHz sample rate, 40 MHz bandwidth
- Configurable center frequency (70 MHz - 6 GHz)
- Phase-coherent sampling for direction finding
- 4096-point FFT on both channels with FFTW
- Cross-correlation analysis (frequency domain)
- DC offset removal with EWMA filtering
- Configurable window functions (Hamming, Hanning, Blackman, Kaiser)
- Magnitude-to-dB conversion with 120 dB dynamic range
- Real-time averaging and persistence modes
- 10-20 Hz update rate
- 2-Channel Phase-Based DF using interferometry
- Real-time azimuth calculation with phase unwrapping
- 180° ambiguity detection (inherent to 2-element arrays)
- Polar plots with bearing timeline history
- Configurable antenna spacing (wavelength-based)
- SNR and coherence metrics
- TAKX-RF CoT streaming for TAK integration
- Multiple platform types (UAV, UGV, USV, Ground Station)
- Real-time waterfall display with color gradients (Viridis palette)
- Spectrum analyzer with gradient fill and color-coded traces
- Dual-channel display (RX1/RX2/Both)
- Interactive zoom (mouse selection, keyboard shortcuts)
- IQ constellation plots for both channels
- Cross-correlation visualization
- RF parameter controls (frequency, gain, sample rate, bandwidth)
- Preset management with import/export
- Link quality monitoring (RTT, bandwidth, packet loss)
- Connection status indicator (real-time monitoring)
- Interactive spectrum display with frequency selection
- Real-time polar azimuth plot with dual ambiguity display
- Bearing timeline showing history
- Phase difference metrics (unwrapped, std deviation)
- Confidence and quality indicators
- CoT streaming configuration (UDP/TCP)
- Platform position (static or MGRS)
- Calibration controls
- DoA polar plot and timeline visualization
- Frequency scanning with configurable parameters
- Dwell time control per frequency
- Signal detection and logging
- Scan result visualization
- Toast notification system - Non-blocking notifications (info, success, warning, error)
- Connection status indicator - Real-time monitoring with color-coded states
- Loading indicators - Visual feedback for async operations
- Enhanced input validation - Clear, specific error messages
- DOM safety - Null pointer protection throughout
- Request throttling - Prevents request pile-ups on all endpoints
- Automatic timeout handling - 5-second timeout on all fetch operations
- Connection recovery - Automatic reconnection detection
- Bandwidth monitoring - Real-time link quality metrics
- Keyboard shortcuts:
-: Zoom out to full spectrum0: Reset zoomEscape: Cancel selection / Reset zoom?: Show keyboard shortcuts help
- UI state persistence - Settings saved between page reloads:
- Waterfall intensity & contrast
- Spectrum min/max dB range
- Channel selection
- Display visibility states
- Signal analysis preferences
- Preset management - Import/export with validation
- localStorage safety - Quota handling with 5MB limit
- Configuration constants - Centralized CONFIG object
- Safe storage operations - Quota and validation checks
- Comprehensive logging - Console messages for debugging
- Error recovery - Graceful degradation on failures
- Spectrum recording to WAV format
- Full-band or selective bandwidth recording
- Metadata export (JSON with RF parameters)
- Audio conversion from FFT magnitude
- Spectrum mask testing with violation detection
- Signal classification (narrowband, wideband, OFDM)
- Activity timeline tracking signal presence
- Bookmark system for signals of interest
- CSV export for offline analysis
- Cursor on Target (CoT) message generation
- Line of Bearing (LoB) format compliance
- Platform position events (separate from LoB)
- UDP/TCP streaming to TAK clients
- MIL-STD-2525 symbology support
- Real-time bearing updates at configurable rates
- Binary data format (no JSON overhead)
- Direct HTTP streaming via Server-Sent Events
- 8-bit magnitude compression (120 dB dynamic range mapped to 0-255)
- Configurable update rates (1-20 Hz)
- Target bandwidth: <1 Mbps for full operation
On LattePanda:
- Ubuntu/Debian Linux
- bladeRF xA9 with FPGA loaded
- Network connection
# Install dependencies
sudo apt-get update
sudo apt-get install -y cmake build-essential pkg-config \
libfftw3-dev libbladerf-dev libbladerf2
# Build server
cd server
mkdir build && cd build
cmake ..
make -j$(nproc)
# Run server
./bladerf_server # Uses default 915 MHz
# or
./bladerf_server 2450000000 # Specify frequency in HzOpen your browser to:
http://<latte-panda-ip>:8080
You should see:
- Real-time waterfall display
- Frequency spectrum
- RF parameter controls
Edit server/include/bladerf_sensor.h:
constexpr uint32_t SAMPLE_RATE = 40000000; // 40 MHz
constexpr uint32_t BANDWIDTH = 40000000; // 40 MHz
constexpr uint64_t CENTER_FREQ = 915000000; // 915 MHz
constexpr uint32_t FFT_SIZE = 4096; // FFT points
constexpr uint32_t UPDATE_RATE_HZ = 10; // Updates/sec
constexpr uint32_t GAIN_RX1 = 40; // RX1 gain (dB)
constexpr uint32_t GAIN_RX2 = 40; // RX2 gain (dB)
constexpr int WEB_SERVER_PORT = 8080; // Web interface portAfter changes: cd build && make
For tactical radio links reduce bandwidth:
Option 1: Reduce FFT size
constexpr uint32_t FFT_SIZE = 2048; // Half the binsBandwidth: ~0.5 Mbps
Option 2: Reduce update rate
constexpr uint32_t UPDATE_RATE_HZ = 5; // Half the rateBandwidth: ~0.45 Mbps
Option 3: Both Combine for ultra-low bandwidth (~0.25 Mbps)
- Bandwidth: ~0.9 Mbps (configurable down to 0.1 Mbps)
- Latency: Works over high-latency tactical links (100-500ms)
- Connection: TCP/IP over any IP backhaul
- Ports:
- Web UI: 8080 (HTTP/SSE)
- Data port: 5555 (TCP, for external clients)
Device not found:
bladeRF-cli -p # Verify device is detected
sudo dmesg | grep -i blade # Check USB connectionPermission denied:
sudo usermod -a -G plugdev $USER
# Log out and back inFPGA not loaded:
bladeRF-cli -l /path/to/hostedxA9.rbfCannot connect to web UI:
ping <latte-panda-ip> # Test connectivity
telnet <latte-panda-ip> 8080 # Test port
# Check firewall on LattePandaNo data in browser:
- Open browser console (F12) and check for errors
- Verify server is running
- Check that bladeRF is detected
Choppy display over tactical link:
- Reduce FFT_SIZE to 2048 or 1024
- Reduce UPDATE_RATE_HZ to 5 or 2
- Enable link quality monitoring
High CPU on server:
- Reduce FFT_SIZE
- Reduce UPDATE_RATE_HZ
- Enable performance CPU governor
bladerfsensor/
├── README.md # This file
├── deploy.sh # Automated deployment script
└── server/ # C++ server
├── CMakeLists.txt
├── README.md
├── include/
│ ├── bladerf_sensor.h
│ └── web_server.h
└── src/
├── main.cpp
├── web_server.cpp
├── mongoose.c # Embedded web server
└── mongoose.h
- Acquisition: bladeRF xA9 samples at 40 MHz on both RX channels in MIMO mode
- Deinterleaving: Server separates interleaved I/Q samples (I1,Q1,I2,Q2)
- DC Offset Removal: EWMA filter removes DC bias
- Window Function: Applied to reduce spectral leakage (Hamming default)
- FFT: 4096-point FFT computed on both channels using FFTW
- Compression: Convert complex FFT to 8-bit magnitude (120 dB range → 0-255)
- Cross-correlation: Computed in frequency domain for DF
- Streaming: Binary data sent via HTTP/SSE to browsers
- Visualization: JavaScript canvas rendering with WebGL acceleration
The 2-channel direction finding uses phase interferometry:
Phase Difference Calculation:
Δφ = phase(CH2) - phase(CH1)
= atan2(Q₂, I₂) - atan2(Q₁, I₁)
Interferometer Equation:
sin(θ) = (Δφ × λ) / (2π × d)
Where:
θ = angle of arrival
Δφ = measured phase difference (radians)
λ = wavelength (meters)
d = antenna spacing (meters)
180° Ambiguity:
For a 2-element array, sin(θ) = sin(180° - θ), creating two possible solutions:
- Primary bearing: θ
- Ambiguous bearing: 180° - θ
Example:
Antenna spacing: 0.5λ (half-wavelength)
Measured phase: 45°
sin(θ) = (45° × π/180 × λ) / (2π × 0.5λ) = 0.25
θ₁ = arcsin(0.25) = 14.5°
θ₂ = 180° - 14.5° = 165.5°
Both bearings are displayed on the polar plot. Requires 3+ channels to resolve ambiguity.
Confidence Metrics:
- Phase Std Dev: Lower = more stable signal
- Coherence: Measure of phase consistency (0-1)
- SNR: Signal-to-noise ratio in dB
- Confidence: Combined metric (0-100%)
dB Conversion:
dB = (raw / 255.0) × 120.0 - 100.0
Range: -100 dBFS to +20 dBFS (120 dB dynamic range)
Occupied Bandwidth (-3dB):
threshold_raw = peak_raw - 6.375
(Correct for quantized dB space, not linear amplitude)
Cross-Correlation Phase:
xcorr = conj(CH1) × CH2
Gives: phase(CH2) - phase(CH1)
(Critical for correct DF bearing direction)
IQ Power:
power = sqrt((I² + Q²) / N)
(Both I and Q components, not just I alone)
Zoom Coordinate Mapping:
bin = zoomStartBin + (canvasX / canvasWidth) × zoomedBins
(Respects current zoom state for nested zooming)
All formulas verified against theory and tested with real signals.
Spectrum data per frame:
- CH1 magnitude: 4096 bytes (8-bit)
- CH2 magnitude: 4096 bytes (8-bit)
- Total: 8192 bytes per frame
At 10 Hz update rate:
- Data rate: 81920 bytes/sec
- With HTTP overhead: ~90 KB/s
- Bandwidth: 0.87 Mbps
Uses Mongoose embedded HTTP server:
- Single-threaded event loop
- Server-Sent Events for real-time updates
- Binary data endpoints
- RESTful control API
- Embedded HTML/CSS/JavaScript
As link quality degrades:
- Reduce FFT size (4096 → 2048 → 1024)
- Reduce update rate (10 → 5 → 2 Hz)
- Drop to waterfall-only mode
- Buffer data during brief outages
- Open web interface at
http://<device-ip>:8080 - Navigate to LIVE tab
- Adjust frequency, gain, and sample rate as needed
- Enable Spectrum view for real-time analysis
- Use mouse to zoom into signals (drag to select)
- Keyboard shortcuts:
- Press
-to zoom out - Press
0to reset zoom - Press
Escto cancel selection - Press
?for help
- Press
- Settings automatically save on page unload
- Navigate to DIRECTION tab
- Click and drag on spectrum to select frequency range
- Click Start to begin direction finding
- View azimuth on polar plot (shows both ambiguous bearings)
- Monitor confidence, SNR, and coherence metrics
- Configure Stream Out for TAK integration
- Open Stream Out Configuration
- Set Endpoint IP and Port (default: 8089 for TAKX-RF)
- Select Protocol: UDP
- Choose Format: CoT
- Enter Platform Position (Lat/Lon or MGRS)
- Select Platform Type (UAV, UGV, USV, etc.)
- Click Start Streaming
- Platform icon and bearing lines appear in TAKX-RF
- Click Record button in header
- Choose Mode: Full Band or Selective Band
- For selective, specify center frequency and bandwidth
- Click Start Recording
- Recording saved as WAV file with metadata JSON
- 2-Channel DF: Inherent 180° ambiguity (requires 3+ channels to resolve)
- MGRS Conversion: Uses simplified approximation (errors of 100m-1km depending on location)
- Multi-client: Single client recommended for best performance (connection sharing not optimized)