# pyrtlsdr: Why is my output different than universal radio hacker?

I'm trying to build a script to do some signal processing from my RTLSDR. But, the bits I'm getting is not what I would expect.

The preamble using 'Universal Radio Hacker' looks like this:

But after plotting all values my script is seeing (-1 until +1) it looks like this:

Often I'm also getting plots that don't make any sense. At least the last one has some resemblance of the URH preamble, but also a lot of plots don't.

What am I missing.. 'Universal radio hacker' also uses pyrtlsdr, so I know it can work. - Complex, real, imaginary - Can't say that I understand it fully. Something wrong there ? - Noise, gain.. Not 100% sure what to do there. URH seems to set gain to 25, but when I do that I don't get anything, so I left it at 'auto' - I should be getting (almost) all of the samples. In the beginning I did lose some, but after I moved the postprocessing logic into separate processes it seems fine.

My script:

from rtlsdr import RtlSdr
from datetime import datetime
import asyncio
import matplotlib.pyplot as plt
from multiprocessing import Process, Queue

async def get_samples(sdr, q1):
counter = 0
timestamp1 = datetime.now()
# Get this many samples every time
async for samples in sdr.stream():
q1.put(samples)
counter += 1
timestamp2 = datetime.now()
if (timestamp2 - timestamp1).total_seconds() > 1:
# To see if we missed any samples. Should be close to srate samples p/s
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 'GETSAMPLES -', int((counter * 131072) / (timestamp2 - timestamp1).total_seconds()), 'samples p/s')
counter = 0
timestamp1 = datetime.now()

def check_samples(q1, q2, noise, samplesperbit):
while True:
values = []
withinnoisecounter = 0
signal = False
if q1.qsize() > 10:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 'CHECKSAMPLES - Warning: Queue depth is', q1.qsize())
samples = q1.get()
for sample in samples:
if not signal:
# Start when signal breaks out of noise range
if sample.real > noise or sample.real < -noise:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 'CHECKSAMPLES - signal detected')
signal = True
values.append(sample.real)
else:
values.append(sample.real)
if not (sample.real > noise or sample.real < -noise):
withinnoisecounter += 1
elif withinnoisecounter > 0:
withinnoisecounter = 0
if withinnoisecounter > samplesperbit * 3:
# Break when signal is within noise range 3 * samplesperbit
break
if signal:
q2.put(values)

def decode_fsk(q2, srate):
# ToDo, now it just plots
while True:
values = q2.get()
plt.figure(figsize=(20, 5))
# Preamble should be in here
plt.plot(values[:2000])
plt.show()

def main():
noise = 0.9
# 38400 * 30 to get exactly 30 samples per bit.
srate = 1152000
samplesperbit = 1000000 / 38400 / (1000000 / srate)
sdr = RtlSdr()
# Just like in URH
sdr.freq_correction = 1
sdr.sample_rate = srate
sdr.center_freq = 868.200e6
sdr.gain = 'auto'
# Run check_samples in another thread to make sure we don't miss any samples
q1 = Queue()
q2 = Queue()
p1 = Process(target=check_samples, args=(q1, q2, noise, samplesperbit))
p1.start()
# Run decode_fsk in another thread to make sure we don't miss any samples
p2 = Process(target=decode_fsk, args=(q2, srate))
p2.start()
# This is the main loop
loop = asyncio.get_event_loop()
loop.run_until_complete(get_samples(sdr, q1))

if __name__ == "__main__":
main()


Thanks!