A modern, cross-platform decoder for Railroad Distributed Power Unit (DPU) telemetry using RTL-SDR receivers. Based on the GE Locotrol protocol used by major North American railroads (BNSF, UP, NS, CSX, etc.).
- RTL-SDR Support: Direct reception using RTL-SDR dongles via
rtl_fm - Multi-Channel Scanning: Wideband, scan-all, and dual-band modes
- Network Server/Client: Share decoded data over the network
- Web-Based GUI: Modern real-time web interface with packet display and movement tracking
- Protocol Decoding: Decodes Command (CM), Status (ST), Link (LK), and Link Reply (LR) packets
- Movement Tracking: Automatically groups packets by train and tracks movements
- Filtering: Filter packets by Train ID, Address, and packet type
- Statistics: Real-time packet counts and error rate tracking
- Demo Mode: Test the interface without hardware
DPU (Distributed Power Unit) technology allows freight trains to operate with unmanned helper locomotives in the middle or rear of the train. These remote locomotives are controlled via radio telemetry using the GE Locotrol protocol.
| Channel | Frequency | Band |
|---|---|---|
| 1 | 452.925 MHz | Low |
| 2 | 452.950 MHz | Low |
| 3 | 457.925 MHz | High |
| 4 | 457.950 MHz | High |
- Modulation: FSK (Frequency Shift Keying)
- Baud Rate: 4800 bps
- Frame: HDLC with 0x7E delimiters
- Encoding: NRZI (Non-Return-to-Zero Inverted)
- CRC: CRC-16-CCITT
RTL-SDR → rtl_fm (FM demod) → FSK Demodulator → HDLC Parser → Packet Display/Network
- CM (Command): Lead to Remote - Contains throttle, brake, and control commands
- ST (Status): Remote to Lead - Contains pressures, tractive effort, and alarms
- LK (Link): Link setup packets with locomotive information
- LR (Link Reply): Response to link packets
| Field | Description |
|---|---|
| ADDR | Unique DPU equipment address |
| TRID | Train ID (assigned at link time) |
| SEQ | Sequence number (0-31) |
| NRM | Number of remote consists |
| Power | Throttle (N1-N8), Dynamic Brake (B0.00-B8.00), or IDLE |
| REV | Reverser position (CT/FO/RE) |
| MTR | Motoring state |
| BP | Brake Pipe Pressure (PSI) |
| ER | Equalizing Reservoir Pressure (PSI) |
| MR | Main Reservoir Pressure (PSI) |
| BC | Brake Cylinder Pressure (PSI) |
| TRE | Tractive Effort (kilopounds) |
| Alarms | EMR, PEN, PCS, BPRS, BPDR |
- Download Python 3.10+ from python.org
- Run the installer
- IMPORTANT: Check "Add Python to PATH" at the bottom of the installer
- Click "Install Now"
- Verify installation by opening Command Prompt and typing:
python --version
-
Download RTL-SDR drivers from rtl-sdr.com
- Direct link: rtl-sdr-release.zip
-
Extract the ZIP file to a folder (e.g.,
C:\rtl-sdr) -
Add to Windows PATH:
- Press
Win + Xand select "System" - Click "Advanced system settings"
- Click "Environment Variables"
- Under "System variables", find "Path" and click "Edit"
- Click "New" and add
C:\rtl-sdr(or wherever you extracted) - Click "OK" to close all dialogs
- Press
-
Install USB drivers using Zadig:
- Download Zadig
- Plug in your RTL-SDR dongle
- Run Zadig
- Select "Bulk-In, Interface (Interface 0)" from the dropdown
- Select "WinUSB" as the driver
- Click "Install Driver"
Open Command Prompt and run:
pip install numpy aiohttpOption A: Web GUI (Recommended)
- Double-click
Start_DPU_Monitor.bat - Open your web browser to
http://localhost:8080
Option B: Command Line
- Double-click
Start_RTL-SDR_Decoder.bat - Follow the prompts to select scan mode
# Install RTL-SDR tools
sudo apt install rtl-sdr
# Install Python dependencies
pip install numpy aiohttp
# Run web GUI
python3 dpu_web_gui.py
# Or run command-line decoder
python3 dpu_decoder.py --rtlsdr --scan dual_band# Install RTL-SDR tools via Homebrew
brew install rtl-sdr
# Install Python dependencies
pip3 install numpy aiohttp
# Run web GUI
python3 dpu_web_gui.pyStart the web interface:
python dpu_web_gui.py [--port 8080] [--demo]Options:
--port: Web server port (default: 8080)--demo: Run in demo mode with simulated packets
Then open http://localhost:8080 in your browser.
# Single channel (Channel 4)
python dpu_decoder.py --rtlsdr -c 4
# Wideband mode (Channels 1 & 2)
python dpu_decoder.py --rtlsdr --scan wideband -c 1
# Scan all 4 channels
python dpu_decoder.py --rtlsdr --scan scan_all --dwell 2.0
# Dual-band scanning (RECOMMENDED - best coverage)
python dpu_decoder.py --rtlsdr --scan dual_band --dwell 2.0
# With gain and PPM correction
python dpu_decoder.py --rtlsdr -c 4 --gain 40 --ppm 55| Mode | Channels | Coverage | Packet Loss | Best For |
|---|---|---|---|---|
| Single | 1 | 25% | None | Known active channel |
| Wideband | 2 | 50% | Minimal | Busy areas |
| Scan All | 4 | 100% | During hops | Light traffic |
| Dual-Band | 4 | 100% | Minimal | General use (recommended) |
Mode Details:
-
Single: Monitors one channel continuously. Best signal quality but may miss activity on other channels.
-
Wideband: Uses 240 kHz bandwidth to capture 2 adjacent channels simultaneously (Ch 1&2 or Ch 3&4). Slight sensitivity reduction but no packet loss from switching.
-
Scan All: Hops through all 4 channels sequentially. Full coverage but may miss packets during channel switches.
-
Dual-Band: Alternates between low band (Ch 1&2) and high band (Ch 3&4) using wideband reception on each. Best balance of coverage and reliability.
Server Mode (share decoded packets):
python dpu_decoder.py --rtlsdr -c 4 --server --server-port 5555Client Mode (receive from server):
python dpu_decoder.py --client --client-host 192.168.1.100 --client-port 5555Decode from baseband IQ recordings (e.g., from SDR#, GQRX, or rtl_sdr):
# IQ file centered on channel 4
python dpu_decoder.py --baseband recording.wav
# IQ file with channel offset (e.g., Ch3 is -25kHz from Ch4 center)
python dpu_decoder.py --baseband recording.wav --offset -25000
# Typical SDR# recording centered between channels 3 & 4
python dpu_decoder.py --baseband 07-08-33_457950000Hz.wav --offset 0IQ File Requirements:
- Format: WAV or RF64 (for files >4GB)
- Channels: Stereo (I on left, Q on right)
- Sample rate: Any (typically 250kHz - 2MHz)
- The decoder performs FM demodulation internally
Channel Offsets:
| Recording Center | Target Channel | Offset |
|---|---|---|
| 457.950 MHz (Ch4) | Ch4 | 0 |
| 457.950 MHz (Ch4) | Ch3 | -25000 |
| 457.9375 MHz (between) | Ch4 | +12500 |
| 457.9375 MHz (between) | Ch3 | -12500 |
For testing with pre-demodulated audio (FM discriminator output):
python dpu_decoder.py --file recording.wavusage: dpu_decoder.py [-h] [--rtlsdr] [-c CHANNEL] [-f FREQ] [-d DEVICE]
[--gain GAIN] [--ppm PPM] [--scan {single,wideband,scan_all,dual_band}]
[--dwell DWELL] [--audio AUDIO] [--server] [--server-port PORT]
[--client] [--client-host HOST] [--client-port PORT]
[--log-binary FILE] [--log-text FILE]
Railroad DPU Decoder
options:
-h, --help show this help message and exit
--rtlsdr Use RTL-SDR input
-c, --channel CHANNEL DPU channel (1-4)
-f, --freq FREQ Frequency in MHz (overrides channel)
-d, --device DEVICE RTL-SDR device index
--gain GAIN RTL-SDR gain (auto or dB value)
--ppm PPM RTL-SDR frequency correction in PPM
--scan MODE Scan mode: single, wideband, scan_all, dual_band
--dwell SECONDS Dwell time for scanning modes (default: 2.0)
--audio FILE Audio file input (WAV)
--server Enable network server
--server-port PORT Server port (default: 5555)
--client Connect as network client
--client-host HOST Server hostname
--client-port PORT Server port (default: 5555)
--log-binary FILE Binary log file (SoftDPU compatible)
--log-text FILE Text log file
- Check frequency: Ensure trains are using the channel you're monitoring
- Adjust gain: Try
--gain 40or--gain auto - PPM correction: Use
--ppmto correct for RTL-SDR frequency error - Antenna: Use a proper antenna for 450 MHz band
- Location: DPU signals are relatively weak; get closer to rail lines
- Windows: Run Zadig and reinstall WinUSB driver
- Linux: Check udev rules and permissions (
sudomay be required) - Try unplugging and replugging the dongle
- Reduce system load
- Try a different USB port (avoid USB hubs)
- On Windows, disable USB power saving
- Check if port 8080 is in use:
netstat -an | find "8080" - Try a different port:
--port 8081 - Ensure firewall allows connections
| File | Description |
|---|---|
dpu_decoder.py |
Main decoder with RTL-SDR support |
dpu_web_gui.py |
Web-based GUI server |
Start_DPU_Monitor.bat |
Windows launcher for web GUI |
Start_RTL-SDR_Decoder.bat |
Windows launcher for CLI decoder |
requirements.txt |
Python dependencies |
Compatible with SoftDPU text log format:
# Time Received SIG ADDR TRID TP OR RP SEQ NRM RMID Power REV MTR ...
2024/01/15-14:30:22 10.5 12345 001 CM LD DI 15 1 - N5 FO 1 ...
- GE Locotrol is a trademark of GE Transportation
MIT License - See LICENSE file for details