Pulling radio data out of thin air

Pycon Israel 2018

Yuval Adam

  • Full stack developer and systems architecture consultant
  • But I also like to play with radios
  • https://yuv.al
  • @yuvadm

This talk

Agenda

  • What are radio waves?
  • Hardware vs software radio

Hardware Radio

static/radio.jpg

Software-Defined Radio

rtlsdr.jpg

What's it good for

  • Digital TV broadcast ("Idan+", DVB-T)
  • Airplane tracking (ADS-B)
  • Weather satellites
  • IoT project integration
  • FM radio broadcast

Airplane Location Tracking (ADSB)

static/adsb.png

Weather Satellites

static/noaa.jpg

I/Q Sampling

static/cosample.png

Source: http://whiteboard.ping.se/SDR/IQ

I/Q Sampling

static/corkscrew.png

Source: http://whiteboard.ping.se/SDR/IQ

In [ ]:
# pyrtlsdr provides us bindings to work with the RTL-SDR driver

from rtlsdr import RtlSdr

sdr = RtlSdr()
sdr.sample_rate = 1.2e6       # 1,200,000 samples per second
sdr.center_freq = 91.8e6      # 91,800,00 Hz frequency for the radio station
sdr.gain = 'auto'             # tune the gain (AKA "volume") automatically

samples = sdr.read_samples(1.2e6 * 8)  # collect samples during 8 seconds
sdr.close()

print(samples[:5])
In [ ]:
# Load the samples into a numpy array

import numpy as np

samples = np.array(samples).astype('complex64')
In [ ]:
# We captured too many samples so we need to apply a low pass filter
# In other words, we have a too large window and we want to make it smaller

import scipy.signal as signal

BANDWIDTH = 200e3
DECIMATION_RATE = int(1.2e6 / BANDWIDTH)

samples = signal.decimate(samples, DECIMATION_RATE)
In [ ]:
# Apply the demodulation, we use a polar discriminator

samples = np.angle(samples[1:] * np.conj(samples[:-1]))
In [ ]:
# De-emphasis filter - too "sciency"
# MAKE THINGS SOUND BETTER

d = BANDWIDTH * 75e-6
x = np.exp(-1/d)
b, a = [1-x], [1,-x]
samples = signal.lfilter(b, a, samples)
In [ ]:
# Decimate the signal down to something an audio driver can handle
# We only catch the mono part of the signal

AUDIO_RATE = 50e3
DECIMATION_RATE = int(1.2e6 / BANDWIDTH / AUDIO_RATE)

samples = signal.decimate(samples, DECIMATION_RATE)
In [ ]:
# HIT IT

whatever.play(samples)

Caveats

  • Python, NumPy and SciPy are very good at doing fast processing of static data
  • When handling real-time data, buffering becomes a serious issue
  • GNU Radio
    • top-notch signal processing framework
    • implemented many DSP primivites
    • has a great scheduling engine
    • actually generates flowgraphs in Python

Where to go from here

  • Buy an RTL-SDR dongle, they start at less than $10
    • eBay, AliExpress
  • Learn more about SDR, signal processing
  • Explore the radio waves!

Thank you! Questions?