Rtlsdr
Elixir wrapper for librtlsdr - interface with RTL-SDR USB devices for software-defined radio applications.
Features
- Full NIF bindings to librtlsdr
- GenServer-based device management with automatic resource cleanup
- Synchronous and asynchronous sample reading
- Streaming support with subscriber pattern
- IQ sample conversion utilities
- Support for all RTL-SDR tuner types (R820T, E4000, FC001x, etc.)
Prerequisites
You need librtlsdr installed on your system:
macOS
brew install librtlsdrUbuntu/Debian
sudo apt-get install librtlsdr-devArch Linux
sudo pacman -S rtl-sdrInstallation
Add rtlsdr to your list of dependencies in mix.exs:
def deps do
[
{:rtlsdr, "~> 0.1.0"}
]
endThen run:
mix deps.get
mix compileQuick Start
# List available devices
Rtlsdr.list_devices()
#=> [%{index: 0, name: "Generic RTL2832U OEM", ...}]
# Start a device
{:ok, device} = Rtlsdr.Device.start_link(index: 0)
# Configure the device
:ok = Rtlsdr.Device.set_center_freq(device, 100_000_000) # 100 MHz
:ok = Rtlsdr.Device.set_sample_rate(device, 2_048_000) # 2.048 MS/s
:ok = Rtlsdr.Device.set_tuner_gain_mode(device, :manual)
:ok = Rtlsdr.Device.set_tuner_gain(device, 400) # 40.0 dB
# Read samples synchronously
{:ok, samples} = Rtlsdr.Device.read_samples(device, 262144)
# Convert to IQ float pairs
iq_samples = Rtlsdr.samples_to_iq(samples)
#=> [{0.0, 0.0039...}, {0.125, -0.0078...}, ...]
# Or start streaming
:ok = Rtlsdr.Device.start_streaming(device, self())
receive do
{:rtlsdr_samples, data} ->
# Process your samples here
IO.puts("Received #{byte_size(data)} bytes")
end
# Stop streaming
:ok = Rtlsdr.Device.stop_streaming(device)
# Close the device
:ok = Rtlsdr.Device.stop(device)IQ Sample Format
Samples are returned as a binary containing interleaved 8-bit unsigned I/Q data:
<<I0, Q0, I1, Q1, ...>>
Each I and Q value is in the range 0-255, with 127/128 being the center (zero) point.
To convert to normalized float values:
# To list of {I, Q} tuples (-1.0 to 1.0)
Rtlsdr.samples_to_iq(samples)
# To flat list of floats [I1, Q1, I2, Q2, ...]
Rtlsdr.samples_to_floats(samples)Using the Streamer
For pub/sub style streaming with multiple consumers:
{:ok, streamer} = Rtlsdr.Streamer.start_link(
device_index: 0,
center_freq: 100_000_000,
sample_rate: 2_048_000,
tuner_gain: 400
)
# Subscribe to receive samples
Rtlsdr.Streamer.subscribe(streamer)
# Start streaming
Rtlsdr.Streamer.start_streaming(streamer)
# Receive samples
receive do
{:rtlsdr_samples, data} -> process(data)
end
# Get statistics
{:ok, stats} = Rtlsdr.Streamer.stats(streamer)
#=> %{bytes_received: 1048576, samples_received: 4, ...}Device Configuration
Frequency
# Set center frequency (in Hz)
Rtlsdr.Device.set_center_freq(device, 433_920_000) # 433.92 MHz
# Get current frequency
{:ok, freq} = Rtlsdr.Device.get_center_freq(device)Sample Rate
Valid range: 225,001 - 3,200,000 Hz
Rtlsdr.Device.set_sample_rate(device, 2_048_000)
# Common sample rates
Rtlsdr.common_sample_rates()
#=> [250000, 1024000, 1800000, 2048000, 2400000, 2560000, 2880000, 3200000]Gain Control
# Get available gain values (in tenths of dB)
{:ok, gains} = Rtlsdr.Device.get_tuner_gains(device)
#=> [0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, ...]
# Set manual gain mode
Rtlsdr.Device.set_tuner_gain_mode(device, :manual)
# Set gain (in tenths of dB, so 400 = 40.0 dB)
Rtlsdr.Device.set_tuner_gain(device, 400)
# Or use automatic gain control
Rtlsdr.Device.set_tuner_gain_mode(device, :auto)
Rtlsdr.Device.set_agc_mode(device, true)Frequency Correction
# Set PPM correction for crystal offset
Rtlsdr.Device.set_freq_correction(device, 56) # 56 ppmDirect Sampling (HF mode)
# 0 = disabled (normal tuner mode)
# 1 = I-ADC input enabled
# 2 = Q-ADC input enabled
Rtlsdr.Device.set_direct_sampling(device, 1)Bias Tee
⚠️ Warning: Only enable if your setup requires bias tee power (e.g., for an LNA).
Rtlsdr.Device.set_bias_tee(device, true)Supported Tuners
| Tuner | Frequency Range |
|---|---|
| R820T/R820T2 | 24 MHz - 1766 MHz |
| E4000 | 52 MHz - 2200 MHz (gap at 1100-1250 MHz) |
| FC0012 | 22 MHz - 948.6 MHz |
| FC0013 | 22 MHz - 1100 MHz |
| FC2580 | 146 MHz - 308 MHz |
API Reference
Rtlsdr
device_count/0- Get number of connected deviceslist_devices/0- List all devices with infofind_device_by_serial/1- Find device by serial numbersamples_to_iq/1- Convert samples to {I, Q} tuplessamples_to_floats/1- Convert samples to flat float listcalculate_power_db/1- Calculate signal power in dB
Rtlsdr.Device
start_link/1- Start a device processstop/1- Stop device and release hardwareinfo/1- Get device info and current settingsset_center_freq/2,get_center_freq/1- Frequency controlset_sample_rate/2,get_sample_rate/1- Sample rateset_tuner_gain/2,get_tuner_gain/1- Gain controlset_tuner_gain_mode/2- :auto or :manual gainget_tuner_gains/1- List supported gain valuesget_tuner_type/1- Get tuner chip typeset_freq_correction/2- PPM correctionset_agc_mode/2- RTL2832 AGCset_direct_sampling/2- HF direct samplingset_bias_tee/2- Bias tee powerread_samples/2- Synchronous readstart_streaming/3,stop_streaming/1- Async streamingreset_buffer/1- Clear sample buffer
Rtlsdr.Streamer
start_link/1- Start streamer with devicesubscribe/2,unsubscribe/2- Manage subscribersstart_streaming/1,stop_streaming/1- Control streamingset_center_freq/2,set_tuner_gain/2- Runtime configstats/1- Get streaming statistics
License
MIT License - see LICENSE file for details.
Contributing
- Fork the repository
-
Create your feature branch (
git checkout -b feature/amazing-feature) -
Commit your changes (
git commit -am 'Add amazing feature') -
Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request