8. RTL-SDR en Python

El RTL-SDR es, con diferencia, el SDR m谩s barato, alrededor de 30 d贸lares, y un excelente SDR para empezar. Si bien es solo de recepci贸n y solo puede sintonizar hasta ~1,75 GHz, existen numerosas aplicaciones para las que se puede utilizar. En este cap铆tulo, aprendemos c贸mo configurar el software RTL-SDR y utilizar su API Python.

Example RTL-SDRs

Antecedentes RTL-SDR

El RTL-SDR surgi贸 alrededor de 2010 cuando la gente descubri贸 que pod铆an piratear dongles DVB-T de bajo costo que conten铆an el chip Realtek RTL2832U. DVB-T es un est谩ndar de televisi贸n digital utilizado principalmente en Europa, pero lo interesante del RTL2832U fue que se pod铆a acceder directamente a las muestras de IQ sin procesar, lo que permit铆a utilizar el chip para construir un SDR de uso general y solo para recepci贸n.

El chip RTL2832U incluye el convertidor anal贸gico a digital (ADC) y el controlador USB, pero debe emparejarse con un sintonizador de RF. Los chips sintonizadores populares incluyen Rafael Micro R820T, R828D y Elonics E4000. El rango de frecuencia sintonizable se basa en el chip sintonizador y suele estar entre 50 y 1700 MHz. La frecuencia de muestreo m谩xima, por otro lado, est谩 determinada por el RTL2832U y el bus USB de su computadora, y suele ser de alrededor de 2,4 MHz sin perder demasiadas muestras. Tenga en cuenta que estos sintonizadores son de costo extremadamente bajo y tienen una sensibilidad de RF muy pobre, por lo que a menudo es necesario agregar un amplificador de bajo ruido (LNA) y un filtro de paso de banda para recibir se帽ales d茅biles.

El RTL2832U siempre utiliza muestras de 8 bits, por lo que la m谩quina host recibir谩 dos bytes por muestra de IQ. Los RTL-SDR premium suelen venir con un oscilador con temperatura controlada (tambi茅n conocido como TCXO) en lugar del oscilador de cristal m谩s econ贸mico, que proporciona una mejor estabilidad de frecuencia. Otra caracter铆stica opcional es una T de polarizaci贸n (tambi茅n conocida como diagonal-T), que es un circuito integrado que proporciona ~4,5 V CC en el conector SMA, que se utiliza para alimentar c贸modamente un LNA externo u otros componentes de RF. Esta compensaci贸n de DC adicional se encuentra en el lado de RF del SDR, por lo que no interfiere con la operaci贸n de recepci贸n b谩sica.

Para aquellos interesados en la direcci贸n de llegada (DOA) u otras aplicaciones de beamforming, el KrakenSDR es un SDR de fase coherente fabricado a partir de cinco RTL-SDR que comparten un oscilador y un reloj de muestra.

Configuraci贸n del software

Ubuntu o WSL (Ubuntu)

En Ubuntu 20, 22 y otros sistemas basados en Debian, puede instalar el software RTL-SDR con el siguiente comando.

sudo apt install rtl-sdr

Esto instalar谩 la biblioteca librtlsdr y herramientas de l铆nea de comandos como rtl_sdr, rtl_tcp, rtl_fm y rtl_test.

A continuaci贸n, instale el contenedor Python para librtlsdr usando:

sudo pip install pyrtlsdr

Si est谩 utilizando Ubuntu a trav茅s de WSL, en el lado de Windows descargue la 煤ltima versi贸n Zadig y ejec煤telo para instalar el controlador 鈥淲inUSB鈥 para RTL-SDR (puede haber dos interfaces masivas, en cuyo caso instale 鈥淲inUSB鈥 en ambas). Desenchufe y vuelva a enchufar el RTL-SDR una vez que finalice Zadig.

A continuaci贸n, deber谩 reenviar el dispositivo USB RTL-SDR a WSL, primero instalando la 煤ltima versi贸n usbipd utility msi (esta gu铆a supone que tiene usbipd-win 4.0.0 o superior), luego abre PowerShell en modo administrador y ejecuta:

# (unplug RTL-SDR)
usbipd list
# (plug in RTL-SDR)
usbipd list
# (find the new device and substitute its index in the command below)
usbipd bind --busid 1-5
usbipd attach --wsl --busid 1-5

En el lado WSL, deber铆a poder ejecutar lsusb y ver un nuevo elemento llamado RTL2838 DVB-T o algo similar.

Si tiene problemas de permisos (por ejemplo, la prueba a continuaci贸n solo funciona cuando se usa sudo), necesitar谩 configurar reglas de udev. Primero ejecute lsusb para encontrar el ID del RTL-SDR, luego cree el archivo /etc/udev/rules.d/10-rtl-sdr.rules con el siguiente contenido, sustituyendo el idVendor e idProduct de tu RTL-SDR si el tuyo es diferente:

SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666"

Para actualizar udev, ejecute:

sudo udevadm control --reload-rules
sudo udevadm trigger

Es posible que tambi茅n necesite desconectar y volver a conectar el RTL-SDR (para WSL tendr谩 que usbipd adjunto nuevamente).

Windows

Para usuarios windows, ver https://www.rtl-sdr.com/rtl-sdr-quick-start-guide/.

Probando el RTL-SDR

Si la configuraci贸n del software funcion贸, deber铆a poder ejecutar la siguiente prueba, que sintonizar谩 el RTL-SDR a la banda de radio FM y grabar谩 1 mill贸n de muestras en un archivo llamado Recording.iq en /tmp.

rtl_sdr /tmp/recording.iq -s 2e6 -f 100e6 -n 1e6

Si obtiene No supported devices found, incluso cuando agrega un sudo al principio, entonces Linux no puede ver el RTL-SDR en absoluto. Si funciona con sudo, entonces es un problema de reglas de udev, intente reiniciar la computadora despu茅s de seguir las instrucciones de configuraci贸n de udev anteriores. Alternativamente, puedes usar sudo para todo, incluso ejecutar Python.

Puede probar la capacidad de Python para ver RTL-SDR utilizando el siguiente script:

from rtlsdr import RtlSdr

sdr = RtlSdr()
sdr.sample_rate = 2.048e6 # Hz
sdr.center_freq = 100e6   # Hz
sdr.freq_correction = 60  # PPM
sdr.gain = 'auto'

print(len(sdr.read_samples(1024)))
sdr.close()

lo cual deber铆a mostrar:

Found Rafael Micro R820T tuner
[R82XX] PLL not locked!
1024

Codigo RTL-SDR en Python

El c贸digo anterior puede considerarse un ejemplo de uso b谩sico de RTL-SDR en Python. Las siguientes secciones entrar谩n en m谩s detalles sobre las diversas configuraciones y trucos de uso.

Evitar fallas en RTL-SDR

Al final de nuestro script, o cuando hayamos terminado de tomar muestras del RTL-SDR, llamaremos a sdr.close(), lo que ayudar谩 a evitar que el RTL-SDR entre en un estado de falla en el que es necesario desconectarlo/volverlo a enchufar. Incluso usando close() todav铆a puede suceder, lo sabr谩s si el RTL-SDR se detiene durante la llamada read_samples(). Si esto sucede, deber谩 desconectar y volver a conectar el RTL-SDR y posiblemente reiniciar su computadora. Si est谩 utilizando WSL, deber谩 volver a conectar el RTL-SDR mediante usbipd.

Configuraci贸n de ganancia

Al configurar sdr.gain = 'auto' estamos habilitando el control autom谩tico de ganancia (AGC), lo que har谩 que el RTL-SDR ajuste la ganancia de recepci贸n en funci贸n de las se帽ales que recibe, intentando completar el 8- bit ADC sin saturarlo. Para muchas situaciones, como por ejemplo hacer un analizador de espectro, es 煤til mantener la ganancia en un valor constante, lo que significa que tenemos que configurar una ganancia manual. El RTL-SDR no tiene una ganancia infinitamente ajustable; puede ver la lista de valores de ganancia v谩lidos usando print(sdr.valid_gains_db). Dicho esto, si lo configura en una ganancia que no est谩 en esta lista, seleccionar谩 autom谩ticamente el valor permitido m谩s cercano. Siempre puedes comprobar cu谩l est谩 configurada la ganancia actual con print(sdr.gain). En el siguiente ejemplo, configuramos la ganancia en 49,6 dB y recibimos 4096 muestras, luego las trazamos en el dominio del tiempo:

from rtlsdr import RtlSdr
import numpy as np
import matplotlib.pyplot as plt

sdr = RtlSdr()
sdr.sample_rate = 2.048e6 # Hz
sdr.center_freq = 100e6   # Hz
sdr.freq_correction = 60  # PPM
print(sdr.valid_gains_db)
sdr.gain = 49.6
print(sdr.gain)

x = sdr.read_samples(4096)
sdr.close()

plt.plot(x.real)
plt.plot(x.imag)
plt.legend(["I", "Q"])
plt.savefig("../_images/rtlsdr-gain.svg", bbox_inches='tight')
plt.show()
RTL-SDR manual gain example

Hay un par de cosas a tener en cuenta aqu铆. Las primeras muestras de ~2k no parecen tener mucha potencia de se帽al, porque representan transitorios. Se recomienda desechar las primeras 2k muestras de cada script, por ejemplo, usando sdr.read_samples(2048) y no hacer nada con la salida. La otra cosa que notamos es que pyrtlsdr nos devuelve las muestras como flotantes, entre -1 y +1. Aunque utiliza un ADC de 8 bits y produce valores enteros, pyrtlsdr divide por 127,0 para nuestra conveniencia.

Frecuencias de muestreo permitidas

La mayor铆a de los RTL-SDR requieren que la frecuencia de muestreo se establezca entre 230 y 300 kHz o entre 900 y 3,2 MHz. Tenga en cuenta que es posible que las velocidades m谩s altas, especialmente por encima de 2,4 MHz, no obtengan el 100% de las muestras a trav茅s de la conexi贸n USB. Si le asigna una frecuencia de muestreo no compatible, simplemente regresar谩 con el error rtlsdr.rtlsdr.LibUSBError: Error code -22: Could not set sample rate to 899000 Hz. Al configurar una frecuencia de muestreo permitida, notar谩 el mensaje de la consola que muestra la frecuencia de muestreo exacta; este valor exacto tambi茅n se puede recuperar llamando a sdr.sample_rate. Algunas aplicaciones pueden beneficiarse al utilizar un valor m谩s exacto en los c谩lculos.

Como ejercicio, estableceremos la frecuencia de muestreo en 2,4 MHz y crearemos un espectrograma de la banda de radio FM:

# ...
sdr.sample_rate = 2.4e6 # Hz
# ...

fft_size = 512
num_rows = 500
x = sdr.read_samples(2048) # get rid of initial empty samples
x = sdr.read_samples(fft_size*num_rows) # get all the samples we need for the spectrogram
spectrogram = np.zeros((num_rows, fft_size))
for i in range(num_rows):
    spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2)
extent = [(sdr.center_freq + sdr.sample_rate/-2)/1e6,
            (sdr.center_freq + sdr.sample_rate/2)/1e6,
            len(x)/sdr.sample_rate, 0]
plt.imshow(spectrogram, aspect='auto', extent=extent)
plt.xlabel("Frequency [MHz]")
plt.ylabel("Time [s]")
plt.show()
RTL-SDR waterfall (aka spectrogram) example

Configuraci贸n de PPM

Para aquellos curiosos sobre la configuraci贸n de ppm, cada RTL-SDR tiene un peque帽o desfase/error de frecuencia, debido al bajo costo de los chips sintonizadores y la falta de calibraci贸n. El desplazamiento de frecuencia debe ser relativamente lineal (no un cambio de frecuencia constante) en todo el espectro, por lo que podemos corregirlo ingresando un valor de PPM en partes por mill贸n. Por ejemplo, si sintoniza 100 MHz y configura PPM en 25, la se帽al recibida aumentar谩 en 100e6/1e6*25=2500 Hz. Las se帽ales m谩s estrechas tendr谩n un mayor impacto por error de frecuencia. Dicho esto, muchas se帽ales modernas implican un paso de sincronizaci贸n de frecuencia que corregir谩 cualquier compensaci贸n de frecuencia en el transmisor, el receptor o debido al desplazamiento Doppler.

Lecturas Futuras (RTL-SDR)

  1. P谩gina Acerca de de RTL-SDR.com

  2. https://hackaday.com/2019/07/31/rtl-sdr-seven-years-later/

  3. https://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr