Python vs PIPE в задаче RTL-SDR
Доброго времени суток!
Ставлю эксперимент с донглом rlt-sdr, задача - получить код, который непрерывно читает пачки сэмплов с донгла.
Пробую реализовать следующим образом: запустить при помощи Popen процесс rtl_sdr с выходом на stdout, затем - бесконечно захватывать чанки нужного размера.
Пробую:
import time
from subprocess import Popen, PIPE
fs = 240e3
ts = 1. / fs
chunk_size = 1024 * 2
n_chunks = 256
with Popen(['rtl_sdr', '-f', '433e6', '-s', str(fs), '-d', '0', '-'], stdout=PIPE) as rtl_sdr:
previous_t = time.time()
for i in range(n_chunks):
t = time.time()
approx_ts = 2 * (t - previous_t) / chunk_size # coefficient 2 is for two IQ components
previous_t = t
print(f'~ts = {1e6 * approx_ts:0.6f} us\t'
f'error = {1e6 * (approx_ts - ts):0.6f} us ({100. * (approx_ts - ts) / ts:0.6f}%)')
buffer = rtl_sdr.stdout.read(chunk_size)
Код начинает выдавать последовательности типа
~ts = 0.008382 us error = -4.158285 us (-99.798834%)
~ts = 0.006519 us error = -4.160147 us (-99.843538%)
~ts = 0.008615 us error = -4.158052 us (-99.793246%)
~ts = 0.006752 us error = -4.159915 us (-99.837950%)
Каким образом промежутки между rtl_sdr.stdout.read-ами могут быть меньше, чем период дискретизации, умноженный на количество принимаемых сэмплов?!
В рамках эксперимента начинают брать чанки бОльше, параметр chunk_size = 1024 * 256:
~ts = 4.168489 us error = 0.001822 us (0.043733%)
~ts = 4.164660 us error = -0.002007 us (-0.048162%)
~ts = 4.165357 us error = -0.001310 us (-0.031442%)
О, чудо! Нормальные показатели. Для референса пробую тоже самое при помощи https://github.com/roger-/pyrtlsdr:
import time
from rtlsdr import RtlSdr
from contextlib import closing
fs = 240e3
ts = 1. / fs
chunk_size = 1024 * 2
n_chunks = 256
with closing(RtlSdr()) as sdr:
# configure device
sdr.sample_rate = fs
sdr.center_freq = 433e6
sdr.gain = 'auto'
previous_t = time.time()
for i in range(n_chunks):
t = time.time()
approx_ts = (t - previous_t) / chunk_size # coefficient 2 is for two IQ components
previous_t = t
print(f'~ts = {1e6 * approx_ts:0.6f} us\t'
f'error = {1e6 * (approx_ts - ts):0.6f} us ({100. * (approx_ts - ts) / ts:0.6f}%)')
buffer = sdr.read_samples(chunk_size)
И показатели нормальные:
~ts = 4.217378 us error = 0.050711 us (1.217069%)
~ts = 4.208996 us error = 0.042329 us (1.015903%)
~ts = 4.207715 us error = 0.041049 us (0.985169%)
даже для chunk_size = 1024 * 2!
Вопрос: что за фигня у меня с Popen? Откуда у него данных больше, чем физически должен выдавать девайс и только при случае маленького буфера в read???!!
Чем меня не устраивает подход с pyrtlsdr? Тем, что я (пока) уверен, что после каждого read_samples я буду получать случайную начальную фазу, и, как следствие, читаемые чанки будут некогерентными.
Призываю радиолюбителей и технарей!