RTL-SDR en Python

Le RTL-SDR est de loin le SDR le plus abordable, Ă  environ 40 €, et un excellent choix pour dĂ©buter. Bien qu’il ne permette que la rĂ©ception et que sa bande passante soit limitĂ©e Ă  environ 1,75 GHz, il offre de nombreuses applications. Dans ce chapitre, nous apprendrons Ă  configurer le logiciel RTL-SDR et Ă  utiliser son API Python.

Exemples de RTL-SDR

Contexte du RTL-SDR

Le RTL-SDR a vu le jour vers 2010, lorsque certains ont dĂ©couvert qu’il Ă©tait possible de pirater des dongles DVB-T bon marchĂ© Ă©quipĂ©s de la puce Realtek RTL2832U. Le DVB-T est une norme de tĂ©lĂ©vision numĂ©rique principalement utilisĂ©e en Europe. L’intĂ©rĂȘt du RTL2832U rĂ©sidait dans l’accĂšs direct aux Ă©chantillons IQ bruts, permettant ainsi de concevoir un SDR (rĂ©cepteur audio numĂ©rique) polyvalent.

La puce RTL2832U intĂšgre le convertisseur analogique-numĂ©rique (CAN) et le contrĂŽleur USB, mais elle doit ĂȘtre associĂ©e Ă  un tuner RF. Parmi les tuners les plus courants, on trouve les Rafael Micro R820T et R828D, ainsi que l’Elonics E4000. La plage de frĂ©quences rĂ©glables dĂ©pend du tuner et se situe gĂ©nĂ©ralement entre 50 et 1700 MHz. La frĂ©quence d’échantillonnage maximale, quant Ă  elle, est dĂ©terminĂ©e par le RTL2832U et le bus USB de votre ordinateur. Elle est gĂ©nĂ©ralement d’environ 2,4 MHz, sans perte significative d’échantillons. Notez que ces tuners sont extrĂȘmement bon marchĂ© et prĂ©sentent une trĂšs faible sensibilitĂ© RF. L’ajout d’un amplificateur Ă  faible bruit (LNA) et d’un filtre passe-bande est donc souvent nĂ©cessaire pour recevoir des signaux faibles.

Le RTL2832U utilise toujours des Ă©chantillons 8 bits ; l’ordinateur hĂŽte recevra donc deux octets par Ă©chantillon IQ. Les RTL-SDR haut de gamme sont gĂ©nĂ©ralement Ă©quipĂ©s d’un oscillateur Ă  tempĂ©rature contrĂŽlĂ©e (TCXO) en remplacement de l’oscillateur Ă  quartz, moins coĂ»teux, ce qui assure une meilleure stabilitĂ© de frĂ©quence. Une autre option est le circuit de polarisation (bias-T), un circuit intĂ©grĂ© fournissant environ 4,5 V CC sur le connecteur SMA. Ce circuit permet d’alimenter facilement un LNA externe ou d’autres composants RF. Ce dĂ©calage CC supplĂ©mentaire se situe cĂŽtĂ© RF du SDR et n’interfĂšre donc pas avec le fonctionnement de rĂ©ception.

Pour ceux qui s’intĂ©ressent Ă  la direction d’arrivĂ©e (DOA) ou Ă  d’autres applications de formation de faisceaux, le KrakenSDR est un SDR Ă  cohĂ©rence de phase composĂ© de cinq RTL-SDR partageant un oscillateur et une horloge d’échantillonnage.

Installation du logiciel

Ubuntu (ou Ubuntu sous WSL)

Sur Ubuntu 20, 22 et autres systÚmes basés sur Debian, vous pouvez installer le logiciel RTL-SDR avec la commande suivante.

sudo apt install rtl-sdr

Cela va installer la bibliothĂšque librtlsdr , et les outils en lignes de commande suivants rtl_sdr, rtl_tcp, rtl_fm, and rtl_test.

Ensuite, installez le wrapper Python pour librtlsdr en utilisant :

sudo pip install pyrtlsdr

Si vous utilisez Ubuntu via WSL, tĂ©lĂ©chargez sous Windows la derniĂšre version de Zadig et exĂ©cutez-la pour installer le pilote « WinUSB » pour le RTL-SDR (il peut y avoir deux interfaces Bulk-In ; dans ce cas, installez « WinUSB » sur les deux). DĂ©branchez puis rebranchez le RTL-SDR une fois l’installation de Zadig terminĂ©e.

Ensuite, vous devrez configurer WSL pour qu’il prenne en charge le pĂ©riphĂ©rique USB du RTL-SDR. Pour cela, installez d’abord la derniĂšre version de l’utilitaire usbipd (fichier MSI) (ce guide suppose que vous disposez de usbipd-win 4.0.0 ou version ultĂ©rieure), puis ouvrez PowerShell en mode administrateur et exĂ©cutez la commande suivante :

# (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

Du cÎté WSL, vous devriez pouvoir exécuter la commande lsusb et voir un nouvel élément nommé RTL2838 DVB-T ou un nom similaire.

Si vous rencontrez des problĂšmes d’autorisation (par exemple, le test ci-dessous ne fonctionne qu’avec sudo), vous devrez configurer des rĂšgles udev. Commencez par exĂ©cuter lsusb pour trouver l’ID du RTL-SDR, puis crĂ©ez le fichier /etc/udev/rules.d/10-rtl-sdr.rules avec le contenu suivant, en remplaçant idVendor et idProduct par ceux de votre RTL-SDR si nĂ©cessaire :

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

Pour actualiser udev, exécutez :

sudo udevadm control --reload-rules
sudo udevadm trigger

Si vous utilisez WSL et que le message d’erreur suivant s’affiche Failed to send reload request: No such file or directory, cela signifie que le service udev n’est pas en cours d’exĂ©cution et que vous devrez exĂ©cuter la commande sudo nano /etc/wsl.conf et ajouter les lignes suivantes :

[boot]
command="service udev start"

RedĂ©marrez ensuite WSL Ă  l’aide de la commande suivante dans PowerShell en tant qu’administrateur : wsl.exe --shutdown.

Il peut Ă©galement ĂȘtre nĂ©cessaire de dĂ©brancher puis de rebrancher le RTL-SDR (pour WSL, vous devrez relancer la commande usbipd attach).

Windows

For Windows users, see https://www.rtl-sdr.com/rtl-sdr-quick-start-guide/.

Test du RTL-SDR

Si l’installation du logiciel a fonctionnĂ©, vous devriez pouvoir exĂ©cuter le test suivant, qui rĂ©glera le RTL-SDR sur la bande radio FM et enregistrera 1 million d’échantillons dans un fichier nommĂ© recording.iq dans /tmp.

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

Si vous obtenez le message No supported devices found, mĂȘme aprĂšs avoir ajoutĂ© sudo au dĂ©but de la commande, Linux ne dĂ©tecte pas le RTL-SDR. Si la dĂ©tection fonctionne avec sudo, il s’agit d’un problĂšme de configuration udev. Essayez de redĂ©marrer l’ordinateur aprĂšs avoir suivi les instructions de configuration udev ci-dessus. Vous pouvez Ă©galement utiliser sudo pour toutes les opĂ©rations, y compris l’exĂ©cution de Python.

Vous pouvez tester la capacitĂ© de Python Ă  dĂ©tecter le RTL-SDR Ă  l’aide du script suivant :

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()

qui devrait afficher :

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

Code Python RTL-SDR

Le code ci-dessus constitue un exemple d’utilisation basique du RTL-SDR en Python. Les sections suivantes dĂ©taillent les diffĂ©rents paramĂštres et astuces d’utilisation.

PrĂ©venir les dysfonctionnements du RTL-SDR

À la fin de notre script, ou une fois l’acquisition des Ă©chantillons terminĂ©e, nous appellerons sdr.close(). Cela permettra d’éviter que le RTL-SDR ne se bloque et nĂ©cessite d’ĂȘtre dĂ©branchĂ©/rebranchĂ©. MalgrĂ© l’utilisation de close(), un blocage peut survenir ; vous le constaterez si le RTL-SDR se bloque pendant l’appel Ă  read_samples(). Dans ce cas, vous devrez dĂ©brancher et rebrancher le RTL-SDR, et Ă©ventuellement redĂ©marrer votre ordinateur. Si vous utilisez WSL, vous devrez reconnecter le RTL-SDR Ă  l’aide de usbipd.

RĂ©glage du gain

En dĂ©finissant sdr.gain = 'auto', vous activez le contrĂŽle automatique du gain (CAG). Le RTL-SDR ajustera alors le gain de rĂ©ception en fonction des signaux reçus, afin d’optimiser la capacitĂ© du convertisseur analogique-numĂ©rique (CAN) 8 bits sans le saturer. Dans de nombreuses situations, comme la rĂ©alisation d’un analyseur de spectre, il est utile de maintenir le gain Ă  une valeur constante, ce qui implique un rĂ©glage manuel. Le gain du RTL-SDR n’est pas rĂ©glable en continu ; vous pouvez consulter la liste des valeurs de gain valides avec print(sdr.valid_gains_db). Si vous dĂ©finissez un gain qui ne figure pas dans cette liste, le systĂšme choisira automatiquement la valeur autorisĂ©e la plus proche. Vous pouvez vĂ©rifier le gain actuel avec print(sdr.gain). Dans l’exemple ci-dessous, le gain est rĂ©glĂ© Ă  49,6 dB et 4 096 Ă©chantillons sont reçus, puis reprĂ©sentĂ©s dans le domaine temporel :

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

Il y a quelques points Ă  noter. Les 2 000 premiers Ă©chantillons environ semblent avoir une faible puissance de signal, car ils reprĂ©sentent des transitoires. Il est recommandĂ© de les ignorer Ă  chaque exĂ©cution de script, par exemple en utilisant sdr.read_samples(2048) et en ne traitant pas la sortie. Par ailleurs, pyrtlsdr renvoie les Ă©chantillons sous forme de nombres Ă  virgule flottante, compris entre -1 et +1. Bien qu’il utilise un convertisseur analogique-numĂ©rique 8 bits et produise des valeurs entiĂšres, pyrtlsdr effectue une division par 127.0 pour simplifier les calculs.

FrĂ©quences d’échantillonnage autorisĂ©es

La plupart des rĂ©cepteurs RTL-SDR nĂ©cessitent une frĂ©quence d’échantillonnage comprise entre 230 et 300 kHz, ou entre 900 et 3,2 MHz. Notez que les frĂ©quences Ă©levĂ©es, en particulier supĂ©rieures Ă  2,4 MHz, peuvent ne pas permettre d’obtenir 100 % des Ă©chantillons via la connexion USB. Si vous spĂ©cifiez une frĂ©quence d’échantillonnage non prise en charge, l’erreur suivante s’affichera : rtlsdr.rtlsdr.LibUSBError: Error code -22: Could not set sample rate to 899000 Hz. Lors de la configuration d’une frĂ©quence d’échantillonnage autorisĂ©e, le message de la console affichera la frĂ©quence exacte ; cette valeur peut Ă©galement ĂȘtre obtenue en appelant la fonction sdr.sample_rate. Certaines applications peuvent tirer parti d’une valeur plus prĂ©cise pour leurs calculs.

À titre d’exercice, nous allons configurer la frĂ©quence d’échantillonnage Ă  2,4 MHz et crĂ©er un spectrogramme de la bande 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

RĂ©glage PPM

Pour ceux qui s’intĂ©ressent au rĂ©glage PPM, sachez que chaque rĂ©cepteur RTL-SDR prĂ©sente un lĂ©ger dĂ©calage/erreur de frĂ©quence, dĂ» au faible coĂ»t des puces de tuner et Ă  l’absence d’étalonnage. Ce dĂ©calage de frĂ©quence est relativement linĂ©aire (et non constant) sur l’ensemble du spectre. On peut donc le corriger en saisissant une valeur PPM (parties par million). Par exemple, si vous syntonisez sur 100 MHz et que vous rĂ©glez le PPM sur 25, le signal reçu sera dĂ©calĂ© vers le haut de 100 x 10⁶ / (1 x 10⁶ * 25) = 2500 Hz. L’impact de l’erreur de frĂ©quence est plus important pour les signaux plus Ă©troits. Cela dit, de nombreux signaux modernes intĂšgrent une Ă©tape de synchronisation de frĂ©quence qui corrige tout dĂ©calage de frĂ©quence sur l’émetteur, le rĂ©cepteur ou dĂ» Ă  l’effet Doppler.

Pour en savoir plus

  1. RTL-SDR.com’s About Page

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

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