Source: http://whiteboard.ping.se/SDR/IQ
Source: http://whiteboard.ping.se/SDR/IQ
# 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,000 Hz frequency for the radio station
sdr.gain = 'auto' # tune the gain (AKA "volume") automatically
samples = sdr.read_samples(1.2e6 * 10)
sdr.close()
# Alternatively, load previously captured samples from rtl_sdr
# and convert them from unsigned 8-bit samples to a complex IQ array
import numpy as np
raw = np.fromfile('/tmp/samples.in', np.uint8).astype(np.float64)
raw += -127
raw /= 2**7
samples = (raw[0::2] + 1j * raw[1::2]).astype(np.complex64)
# 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) # Decimation factor of 6
samples = signal.decimate(samples, DECIMATION_RATE)
# Apply the Frequency DEmodulation
# We use something called a polar discriminator
samples = np.angle(samples[1:] * np.conj(samples[:-1]))
# De-emphasis filter
# Even I'm not sure exactly how/why this works
# 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)
# 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(BANDWIDTH / AUDIO_RATE) # Decimation factor of 4
samples = signal.decimate(samples, DECIMATION_RATE)
# Amplify the signal volume
samples *= 10000
samples = samples.astype('int16')
# HIT IT
import alsaaudio
device = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, device='default')
device.setchannels(1)
device.setrate(50000)
device.setformat(alsaaudio.PCM_FORMAT_S16_LE)
device.setperiodsize(120)
# Write data in chunks
for s in np.array_split(samples, 120):
device.write(s)