PlutoSDR en Python

_images/pluto.png

Dans ce chapitre, nous apprenons Ă  utiliser l’API Python pour le PlutoSDR, qui est une radio SDR Ă  faible coĂ»t d’Analog Devices. Nous couvrirons les Ă©tapes d’installation du PlutoSDR afin de faire fonctionner les pilotes et le logiciel, puis nous discuterons de la transmission et de la rĂ©ception avec le PlutoSDR en Python.

Installation de logiciels/pilotes

Configuration de la VM

Bien que le code Python fourni dans ce manuel devrait fonctionner sous Windows, Mac et Linux, les instructions d’installation ci-dessous sont spĂ©cifiques Ă  Ubuntu 18. Si vous avez des difficultĂ©s Ă  installer le logiciel sur votre OS en suivant les instructions fournies par Analog Devices, je vous recommande d’installer une VM Ubuntu 18 et d’essayer les instructions ci-dessous.

  1. Installez et ouvrez VirtualBox.

  2. CrĂ©ez une nouvelle VM. Pour la taille de la mĂ©moire, je recommande d’utiliser 50% de la RAM de votre ordinateur.

  3. CrĂ©ez le disque dur virtuel, choisissez VDI, et allouez dynamiquement la taille. 15 Go devraient suffire. Si vous voulez ĂȘtre vraiment sĂ»r, vous pouvez utiliser plus.

  4. Téléchargez Ubuntu 18 Desktop .iso- http://releases.ubuntu.com/18.04/

  5. DĂ©marrez la VM. Il vous demandera le support d’installation. Choisissez le fichier .iso du bureau Ubuntu 18. Choisissez « installer ubuntu », utilisez les options par dĂ©faut, et une fenĂȘtre pop-up vous avertira des changements que vous ĂȘtes sur le point d’effectuer. Cliquez sur continuer. Choisissez le nom/mot de passe et attendez que la VM finisse de s’initialiser. AprĂšs avoir terminĂ©, la VM va redĂ©marrer, mais vous devez Ă©teindre la VM aprĂšs le redĂ©marrage.

  6. Allez dans les paramùtres de la VM (l’icîne de l’engrenage).

  7. Sous systÚme > processeur > choisissez au moins 3 processeurs. Si vous avez une carte vidéo réelle, alors dans affichage > mémoire vidéo > choisissez quelque chose de beaucoup plus élevé.

  8. Démarrez votre VM.

  9. Je recommande d’installer des addons d’invitĂ©s VM. Dans la VM, allez dans Devices > Insert Guest Additions CD > cliquez sur run quand une boĂźte apparaĂźt. Suivez les instructions. RedĂ©marrez la VM. Le presse-papiers partagĂ© peut ĂȘtre activĂ© via Dispositifs > Presse-papiers partagĂ© > Bidirectionnel.

Connecter la PlutoSDR

  1. Si vous utilisez OSX, dans OSX, et non dans la VM, dans les prĂ©fĂ©rences systĂšme, activez « kernel extensions ». Puis installez HoRNDIS (vous devrez peut-ĂȘtre redĂ©marrer aprĂšs).

  2. Si vous utilisez Windows, installez ce pilote : https://github.com/analogdevicesinc/plutosdr-m2k-drivers-win/releases/download/v0.7/PlutoSDR-M2k-USB-Drivers.exe

  3. Si vous utilisez Linux, vous ne devriez pas avoir à faire quoi que ce soit de spécial.

  4. Branchez Pluto sur la machine hĂŽte via le port USB. Veillez Ă  utiliser le port USB central de Pluto, car l’autre ne sert qu’à l’alimentation. Le branchement de Pluto devrait crĂ©er une carte rĂ©seau virtuelle, c’est-Ă -dire que Pluto apparaĂźt comme un adaptateur Ethernet USB.

  5. Sur la machine hĂŽte (pas la VM), ouvrez un terminal ou votre outil ping prĂ©fĂ©rĂ© et effectuez un ping sur 192.168.2.1. Si cela ne fonctionne pas, arrĂȘtez et dĂ©boguez l’interface rĂ©seau.

  6. Dans la VM, ouvrez un nouveau terminal

  7. Effectuez un Ping sur 192.168.2.1. Si cela ne fonctionne pas, arrĂȘtez ici et dĂ©boguez. Si cela continue, c’est que quelque chose d’autre Ă  cette adresse IP est sur le rĂ©seau, et vous devrez changer l’IP du Pluto (ou de l’autre appareil) avant de continuer.

  8. Notez l’adresse IP du Pluto car vous en aurez besoin lorsque nous commencerons à utiliser la Pluto en Python.

Installation du pilote PlutoSDR

Les commandes de terminal ci-dessous devraient construire et installer la derniĂšre version de :

  1. libiio, la bibliothĂšque « multiplateforme » d’Analog Device pour l’interfaçage du matĂ©riel.

  2. libad9361-iio, AD9361 est la puce RF spécifique du PlutoSDR.

  3. pyadi-iio, l’API Python du Pluto, c’est notre objectif final, mais il dĂ©pend des deux bibliothĂšques prĂ©cĂ©dentes.

sudo apt-get install build-essential git libxml2-dev bison flex libcdk5-dev cmake python3-pip libusb-1.0-0-dev libavahi-client-dev libavahi-common-dev libaio-dev
cd ~
git clone --branch v0.23 https://github.com/analogdevicesinc/libiio.git
cd libiio
mkdir build
cd build
cmake -DPYTHON_BINDINGS=ON ..
make -j$(nproc)
sudo make install
sudo ldconfig

cd ~
git clone https://github.com/analogdevicesinc/libad9361-iio.git
cd libad9361-iio
mkdir build
cd build
cmake ..
make -j$(nproc)
sudo make install

cd ~
git clone https://github.com/analogdevicesinc/pyadi-iio.git
cd pyadi-iio
pip3 install --upgrade pip
pip3 install -r requirements.txt
sudo python3 setup.py install

Test des pilotes PlutoSDR

Ouvrez un nouveau terminal (dans votre VM) et tapez les commandes suivantes :

python3
import adi
sdr = adi.Pluto('ip:192.168.2.1') # ou quel que soit l'IP de votre Pluton
sdr.sample_rate = int(2.5e6)
sdr.rx()

Si vous parvenez à ce stade sans erreur, passez aux étapes suivantes.

Changer l’adresse IP de Pluton

Si, pour une raison quelconque, l’IP par dĂ©faut de 192.168.2.1 ne fonctionne pas parce que vous avez dĂ©jĂ  un sous-rĂ©seau 192.168.2.0, ou parce que vous voulez que plusieurs Pluto soient connectĂ©s en mĂȘme temps, vous pouvez changer l’IP en suivant les Ă©tapes suivantes :

  1. Modifiez le fichier config.txt sur le pĂ©riphĂ©rique de stockage de masse PlutoSDR (c’est-Ă -dire le dispositif ressemblant Ă  une clĂ© USB qui apparaĂźt aprĂšs avoir branchĂ© la Pluto). Entrez la nouvelle IP que vous voulez.

  2. Ejectez le pĂ©riphĂ©rique de stockage de masse (ne dĂ©branchez pas la Pluto !). Dans Ubuntu 18, il y a un symbole d’éjection Ă  cĂŽtĂ© du pĂ©riphĂ©rique PlutoSDR, lorsque vous regardez l’explorateur de fichiers.

  3. Attendez quelques secondes, puis faites un cycle d’alimentation en dĂ©branchant le Pluto et en le rebranchant. Retournez dans le config.txt pour dĂ©terminer si votre ou vos modifications ont Ă©tĂ© enregistrĂ©es.

Notez que cette procédure est également utilisée pour flasher une image de firmware différente sur la Pluto. Pour plus de détails, voir https://wiki.analog.com/university/tools/pluto/users/firmware.

« Hacker » PlutoSDR pour augmenter la plage RF

Les PlutoSDR sont livrĂ©s avec une gamme de frĂ©quences centrales et un taux d’échantillonnage limitĂ©s, mais la puce sous-jacente est capable de frĂ©quences beaucoup plus Ă©levĂ©es. Suivez ces Ă©tapes pour dĂ©bloquer la gamme de frĂ©quences complĂšte de la puce. S’il vous plaĂźt garder Ă  l’esprit que ce processus est fourni par Analog Devices, il est donc aussi faible risque que vous pouvez obtenir. La limitation de frĂ©quence du PlutoSDR est due au fait qu’Analog Devices utilisant l’AD9364 sur la base d’exigences strictes de performance Ă  des frĂ©quences plus Ă©levĂ©es. 
. En tant que passionnĂ©s de SDR et expĂ©rimentateurs, nous ne sommes pas trop concernĂ©s par ces exigences de performance.

Il est temps de pirater ! Ouvrez un terminal (hĂŽte ou VM, peu importe) :

ssh root@192.168.2.1

Le mot de passe par défaut est analogique.

Vous devriez voir l’écran de bienvenue de PlutoSDR. Vous avez maintenant SSH dans le CPU ARM sur la Pluto elle-mĂȘme ! Si vous avez une Pluto avec la version 0.31 ou infĂ©rieure du firmware, tapez les commandes suivantes :

fw_setenv attr_name compatible
fw_setenv attr_val ad9364
reboot

Et pour l’utilisation de 0.32 et plus :

fw_setenv compatible ad9364
reboot

Vous devriez maintenant ĂȘtre en mesure de tuner jusqu’à 6 GHz et de descendre jusqu’à 70 MHz, sans oublier d’utiliser une frĂ©quence d’échantillonnage jusqu’à 56 MHz ! Bravo !

RĂ©ception

L’échantillonnage en utilisant l’API Python du PlutoSDR est simple. Avec n’importe quelle application SDR, nous savons que nous devons lui indiquer la frĂ©quence centrale, la frĂ©quence d’échantillonnage et le gain (ou si nous voulons utiliser le contrĂŽle automatique du gain). Il peut y avoir d’autres dĂ©tails, mais ces trois paramĂštres sont nĂ©cessaires pour que le SDR ait suffisamment d’informations pour recevoir des Ă©chantillons. Certains SDR ont une commande pour leur indiquer de commencer Ă  Ă©chantillonner, tandis que d’autres, comme la Pluto, commencent Ă  Ă©chantillonner dĂšs que vous l’initialisez. Une fois que le tampon interne du SDR se remplit, les Ă©chantillons les plus anciens sont abandonnĂ©s. Toutes les API SDR ont une sorte de fonction « recevoir des Ă©chantillons », et pour la Pluto c’est rx(), qui renvoie un lot d’échantillons. Le nombre spĂ©cifique d’échantillons par lot est dĂ©fini par la taille du tampon dĂ©finie au prĂ©alable.

Le code ci-dessous suppose que vous avez installĂ© l’API Python du Pluto. Ce code initialise le Pluto, fixe la frĂ©quence d’échantillonnage Ă  1 MHz, fixe la frĂ©quence centrale Ă  100 MHz et fixe le gain Ă  70 dB avec le contrĂŽle automatique du gain dĂ©sactivĂ©. Notez que l’ordre dans lequel vous dĂ©finissez la frĂ©quence centrale, le gain et la frĂ©quence d’échantillonnage n’a gĂ©nĂ©ralement pas d’importance. Dans l’extrait de code ci-dessous, nous indiquons Ă  la Pluto que nous voulons qu’elle nous donne 10 000 Ă©chantillons par appel Ă  rx(). Nous affichons les 10 premiers Ă©chantillons.

import numpy as np
import adi

sample_rate = 1e6 # Hz
center_freq = 100e6 # Hz
num_samps = 10000 # nombre d'échantillons retournés par appel à rx()

sdr = adi.Pluto()
sdr.gain_control_mode_chan0 = 'manual'
sdr.rx_hardwaregain_chan0 = 70.0 # dB
sdr.rx_lo = int(center_freq)
sdr.sample_rate = int(sample_rate)
sdr.rx_rf_bandwidth = int(sample_rate) # largeur du filtre, il suffit de le mettre au mĂȘme niveau que la frĂ©quence d'Ă©chantillonnage pour l'instant.
sdr.rx_buffer_size = num_samps

samples = sdr.rx() # recevoir des échantillons de la Pluton
print(samples[0:10])

Pour l’instant, nous n’allons rien faire d’intĂ©ressant avec ces Ă©chantillons, mais le reste de ce manuel est rempli de code Python qui fonctionne sur des Ă©chantillons de QI comme ceux que nous avons reçus ci-dessus.

Gain de rĂ©ception

La Pluto peut ĂȘtre configurĂ© pour avoir un gain de rĂ©ception fixe ou automatique. Un contrĂŽle automatique de gain (CAG) ajustera automatiquement le gain de rĂ©ception pour maintenir un niveau de signal fort (-12dBFS pour ceux qui sont curieux). L’AGC ne doit pas ĂȘtre confondu avec le convertisseur analogique-numĂ©rique (CAN) qui numĂ©rise le signal. Techniquement parlant, l’AGC est un circuit de rĂ©troaction en boucle fermĂ©e qui contrĂŽle le gain de l’amplificateur en rĂ©ponse au signal reçu. Son objectif est de maintenir un niveau de puissance de sortie constant malgrĂ© un niveau de puissance d’entrĂ©e variable. En gĂ©nĂ©ral, le CAG ajuste le gain pour Ă©viter de saturer le rĂ©cepteur (c’est-Ă -dire d’atteindre la limite supĂ©rieure de la plage du CAN) tout en permettant au signal de « remplir » autant de bits CAN que possible.

Le circuit intĂ©grĂ© de radiofrĂ©quence, ou RFIC, Ă  l’intĂ©rieur de la PlutoSDR possĂšde un module CAG avec quelques rĂ©glages diffĂ©rents. (Un RFIC est une puce qui fonctionne comme un Ă©metteur-rĂ©cepteur : il Ă©met et reçoit des ondes radio). Tout d’abord, notez que le gain de rĂ©ception sur la Pluto a une gamme de 0 Ă  74.5 dB. En mode CAG « manuel », le CAG est dĂ©sactivĂ©, et vous devez indiquer au Pluto le gain de rĂ©ception Ă  utiliser, par exemple :

sdr.gain_control_mode_chan0 = "manual" # désactiver l'AGC
gain = 50.0 # allowable range is 0 to 74.5 dB
sdr.rx_hardwaregain_chan0 = gain # la gamme permise est de 0 Ă  74.5 dB

Si vous voulez activer le CAG, vous devez choisir l’un des deux modes suivants :

  1. sdr.gain_control_mode_chan0 = "slow_attack"

  2. sdr.gain_control_mode_chan0 = "fast_attack"

Et avec le CAG activĂ©, vous ne devez pas fournir une valeur Ă  rx_hardwaregain_chan0. Elle sera ignorĂ©e car le Pluto ajuste lui-mĂȘme le gain du signal. La Pluto a deux modes pour le CAG : attaque rapide et attaque lente, comme indiquĂ© dans le code ci-dessus. La diffĂ©rence entre les deux est intuitive, si vous y pensez. Le mode d’attaque rapide rĂ©agit plus rapidement aux signaux. En d’autres termes, la valeur du gain change plus rapidement lorsque le signal reçu change de niveau. L’ajustement aux niveaux de puissance des signaux peut ĂȘtre important, notamment pour les systĂšmes avec mutliplexage temporelle (TDD) qui utilisent la mĂȘme frĂ©quence pour Ă©mettre et recevoir. Le rĂ©glage de la commande de gain en mode d’attaque rapide pour ce scĂ©nario limite l’attĂ©nuation du signal. Dans l’un ou l’autre de ces modes, si aucun signal n’est prĂ©sent et qu’il n’y a que du bruit, la commande automatique de gain maximisera le rĂ©glage du gain ; lorsqu’un signal apparaĂźt, il saturera briĂšvement le rĂ©cepteur, jusqu’à ce que la commande automatique de gain puisse rĂ©agir et rĂ©duire le gain. Vous pouvez toujours vĂ©rifier le niveau de gain actuel en temps rĂ©el avec :

sdr._get_iio_attr('voltage0','hardwaregain', False)

Pour plus de détails sur la commande automatique de gain (CAG) de la Pluto, notamment sur la maniÚre de modifier les paramÚtres CAG avancés, reportez-vous à la rubrique the « RX Gain Control » section of this page.

Transmettre

Avant de transmettre un signal avec votre Pluto, assurez-vous de connecter un cĂąble SMA entre le port TX de la Pluto et l’appareil qui servira de rĂ©cepteur. Il est important de toujours commencer par transmettre sur un cĂąble, en particulier lorsque vous apprenez comment transmettre, pour vous assurer que la SDR se comporte comme vous le souhaitez. Maintenez toujours une puissance d’émission extrĂȘmement faible, afin de ne pas surcharger le rĂ©cepteur, car le cĂąble n’attĂ©nue pas le signal comme le fait le canal sans fil. Si vous possĂ©dez un attĂ©nuateur (par exemple 30 dB), c’est le bon moment pour l’utiliser. Si vous ne disposez pas d’un autre SDR ou d’un analyseur de spectre pour faire office de rĂ©cepteur, vous pouvez en thĂ©orie utiliser le port RX sur la mĂȘme Pluto, mais cela peut devenir compliquĂ©. Je vous recommanderais de vous procurer un RTL-SDR Ă  10$ pour faire office de SDR de rĂ©ception.

Transmettre est trĂšs similaire Ă  recevoir, sauf qu’au lieu de dire au SDR de recevoir un certain nombre d’échantillons, nous lui donnerons un certain nombre d’échantillons Ă  transmettre. Au lieu de rx_lo, nous allons dĂ©finir tx_lo, pour spĂ©cifier sur quelle frĂ©quence porteuse Ă©mettre. Le taux d’échantillonnage est partagĂ© entre le RX et le TX, donc nous allons le rĂ©gler comme d’habitude. Un exemple complet de transmission est montrĂ© ci-dessous, oĂč nous gĂ©nĂ©rons une sinusoĂŻde Ă  +100 kHz, puis transmettons le signal complexe Ă  une frĂ©quence porteuse de 915 MHz, ce qui fait que le rĂ©cepteur voit une porteuse Ă  915,1 MHz. Il n’y a pas vraiment de raison pratique de faire cela, nous aurions pu simplement rĂ©gler la center_freq sur 915.1e6 et transmettre un tableau de 1, mais nous voulions gĂ©nĂ©rer des Ă©chantillons complexes Ă  des fins de dĂ©monstration.

import numpy as np
import adi

sample_rate = 1e6 # Hz
center_freq = 915e6 # Hz

sdr = adi.Pluto("ip:192.168.2.1")
sdr.sample_rate = int(sample_rate)
sdr.tx_rf_bandwidth = int(sample_rate) # la coupure du filtre, il suffit de la rĂ©gler sur la mĂȘme frĂ©quence d'Ă©chantillonnage.
sdr.tx_lo = int(center_freq)
sdr.tx_hardwaregain_chan0 = -50 # Augmenter pour augmenter la puissance tx, la plage valide est de -90 Ă  0 dB

N = 10000 # nombre d'échantillons à transmettre en une seule fois
t = np.arange(N)/sample_rate
samples = 0.5*np.exp(2.0j*np.pi*100e3*t) # Simulez une sinusoïde de 100 kHz, qui devrait apparaßtre à 915,1 MHz au niveau du récepteur.
samples *= 2**14 # Le PlutoSDR s'attend à ce que les échantillons soient compris entre -2^14 et +2^14, et non -1 et +1 comme certaines SDRs.

# Transmettez notre lot d'échantillons 100 fois, ce qui devrait représenter 1 seconde d'échantillons au total, si l'USB peut suivre.
for i in range(100):
    sdr.tx(samples) # transmettre le lot d'échantillons une fois

Voici quelques notes sur ce code. Tout d’abord, vous voulez simuler vos Ă©chantillons IQ pour qu’ils soient entre -1 et 1, mais avant de les transmettre, nous devons les mettre Ă  l’échelle par 2^14 Ă  cause de la façon dont Analog Devices a implĂ©mentĂ© la fonction tx(). Si vous n’ĂȘtes pas sĂ»r des valeurs min/max, imprimez-les simplement avec print(np.min(samples), np.max(samples)) ou Ă©crivez une instruction if pour vous assurer qu’elles ne sont jamais supĂ©rieures Ă  1 ou infĂ©rieures Ă  -1 (en supposant que ce code vienne avant la mise Ă  l’échelle de 2^14). En ce qui concerne le gain d’émission, la gamme est de -90 Ă  0 dB, donc 0 dB est la puissance d’émission la plus Ă©levĂ©e. Nous voulons toujours commencer Ă  une faible puissance d’émission, puis augmenter si nĂ©cessaire, donc nous avons rĂ©glĂ© le gain Ă  -50 dB par dĂ©faut, ce qui est vers le bas. Ne vous contentez pas de le rĂ©gler sur 0 dB simplement parce que votre signal n’apparaĂźt pas; il y a peut-ĂȘtre un autre problĂšme et vous ne voulez pas griller votre rĂ©cepteur.

Transmettre des Ă©chantillons en rĂ©pĂ©tition

Si vous voulez transmettre continuellement le mĂȘme ensemble d’échantillons de maniĂšre rĂ©pĂ©tĂ©e, au lieu d’utiliser une boucle for/while dans Python comme nous l’avons fait ci-dessus, vous pouvez dire au Pluto de le faire en utilisant une seule ligne :

sdr.tx_cyclic_buffer = True # Activer les tampons cycliques

Vous transmettez alors vos Ă©chantillons comme d’habitude : sdr.tx(samples) une seule fois, et la Pluto continuera Ă  transmettre le signal indĂ©finiment, jusqu’à ce que le destructeur de l’objet sdr soit appelĂ©. Pour changer les Ă©chantillons qui sont transmis en continu, vous ne pouvez pas simplement appeler sdr.tx(samples) Ă  nouveau avec un nouveau jeu d’échantillons, vous devez d’abord appeler sdr.tx_destroy_buffer(), puis appeler sdr.tx(samples).

Transmettre par voie hertzienne en toute lĂ©galitĂ©ïƒ

D’innombrables fois, des Ă©tudiants m’ont demandĂ© sur quelles frĂ©quences ils Ă©taient autorisĂ©s Ă  Ă©mettre avec une antenne (aux États-Unis). La rĂ©ponse courte est aucune, pour autant que je sache. GĂ©nĂ©ralement, lorsque les gens font rĂ©fĂ©rence Ă  des rĂ©glementations spĂ©cifiques qui parlent de limites de puissance d’émission, ils se rĂ©fĂšrent aux frĂ©quences suivantes the FCC’s « Title 47, Part 15 » (47 CFR 15) regulations. Mais il s’agit de rĂ©glementations pour les fabricants qui construisent et vendent des appareils fonctionnant dans les bandes ISM, et ces rĂ©glementations traitent de la maniĂšre dont ils doivent ĂȘtre testĂ©s. Un appareil de la partie 15 est un appareil pour lequel une personne n’a pas besoin de licence pour le faire fonctionner dans le spectre qu’il utilise, mais l’appareil lui-mĂȘme doit ĂȘtre autorisĂ©/certifiĂ© pour montrer qu’il fonctionne conformĂ©ment aux rĂ©glementations de la FCC avant d’ĂȘtre commercialisĂ© et vendu. Les rĂ©glementations de la partie 15 spĂ©cifient les niveaux de puissance maximum d’émission et de rĂ©ception pour les diffĂ©rents Ă©lĂ©ments du spectre, mais rien de tout cela ne s’applique rĂ©ellement Ă  une personne transmettant un signal avec une radio SDR ou une radio de fabrication artisanale. Les seules rĂ©glementations que j’ai pu trouver concernant les radios qui ne sont pas rĂ©ellement des produits vendus Ă©taient spĂ©cifiques Ă  l’exploitation d’une station radio AM ou FM de faible puissance dans les bandes AM/FM. Il y a Ă©galement une section sur les « appareils de fabrication artisanale », mais il est spĂ©cifiquement dit qu’elle ne s’applique pas Ă  tout ce qui est construit Ă  partir d’un kit, et il serait exagĂ©rĂ© de dire qu’une plate-forme d’émission utilisant une radio logicielle est un appareil de fabrication artisanale. En rĂ©sumĂ©, les rĂ©glementations de la FCC ne sont pas aussi simples que « vous pouvez transmettre Ă  ces frĂ©quences uniquement sous ces niveaux de puissance », mais il s’agit plutĂŽt d’un Ă©norme ensemble de rĂšgles destinĂ©es aux tests et Ă  la conformitĂ©.

Une autre façon de voir les choses serait de dire « bien, ce ne sont pas des appareils de la Partie 15, mais suivons les rĂšgles de la Partie 15 comme s’ils l’étaient ». Pour la bande ISM de 915 MHz, les rĂšgles sont les suivantes : « L’intensitĂ© de champ de toute Ă©mission rayonnĂ©e dans la bande de frĂ©quence spĂ©cifiĂ©e ne doit pas dĂ©passer 500 microvolts/mĂštre Ă  30 mĂštres. La limite d’émission dans ce paragraphe est basĂ©e sur un instrument de mesure employant un dĂ©tecteur moyen. » Donc, comme vous pouvez le voir, ce n’est pas aussi simple qu’une puissance d’émission maximale en watts.

Maintenant, si vous avez votre licence de radio amateur (ham), la FCC vous permet d’utiliser certaines bandes rĂ©servĂ©es Ă  la radio amateur. Il y a toujours des directives Ă  suivre et des puissances d’émission maximales, mais au moins ces chiffres sont spĂ©cifiĂ©s en watts de puissance rayonnĂ©e effective. Ce graphique indique quelles bandes sont disponibles en fonction de votre catĂ©gorie de licence (Technicien, GĂ©nĂ©ral et Extra). Je recommande Ă  toute personne intĂ©ressĂ©e par la transmission avec des SDRs d’obtenir sa licence de radioamateur, cf. ARRL’s Getting Licensed page pour plus d’info.

Si quelqu’un a plus de dĂ©tails sur ce qui est autorisĂ© ou non, veuillez m’envoyer un email.

Transmettre et recevoir simultanĂ©ment

En utilisant l’astuce tx_cyclic_buffer, vous pouvez facilement recevoir et Ă©mettre en mĂȘme temps, en dĂ©clenchant l’émetteur, puis la rĂ©ception. Le code suivant montre un exemple fonctionnel de transmission d’un signal QPSK dans la bande 915 MHz, de rĂ©ception et d’affichage de la DSP.

import numpy as np
import adi
import matplotlib.pyplot as plt

sample_rate = 1e6 # Hz
center_freq = 915e6 # Hz
num_samps = 100000 # nombre d'échantillons par appel à rx()

sdr = adi.Pluto("ip:192.168.2.1")
sdr.sample_rate = int(sample_rate)

# Config Tx
sdr.tx_rf_bandwidth = int(sample_rate) # la coupure du filtre, il suffit de la rĂ©gler sur la mĂȘme frĂ©quence d'Ă©chantillonnage.
sdr.tx_lo = int(center_freq)
sdr.tx_hardwaregain_chan0 = -50 # Augmenter pour augmenter la puissance tx, la plage valide est de -90 Ă  0 dB

# Configurer Rx
sdr.rx_lo = int(center_freq)
sdr.rx_rf_bandwidth = int(sample_rate)
sdr.rx_buffer_size = num_samps
sdr.gain_control_mode_chan0 = 'manual'
sdr.rx_hardwaregain_chan0 = 0.0 # dB, augmenter pour augmenter le gain de réception, mais attention à ne pas saturer le CAN

# Créer une forme d'onde de transmission (QPSK, 16 échantillons par symbole)
num_symbols = 1000
x_int = np.random.randint(0, 4, num_symbols) # 0 to 3
x_degrees = x_int*360/4.0 + 45 # 45, 135, 225, 315 degrees
x_radians = x_degrees*np.pi/180.0 # sin() et cos() avec des angles en radians
x_symbols = np.cos(x_radians) + 1j*np.sin(x_radians) # ce qui produit nos symboles complexes QPSK
samples = np.repeat(x_symbols, 16) # 16 échantillons par symbole (impulsions rectangulaires)
samples *= 2**14 # Le PlutoSDR s'attend à ce que les échantillons soient compris entre -2^14 et +2^14, et non entre -1 et +1 comme certains SDRs.

# Start the transmitter
sdr.tx_cyclic_buffer = True # Activer les tampons cycliques
sdr.tx(samples) # début de la transmission

# Effacer le tampon juste pour ĂȘtre sĂ»r
for i in range (0, 10):
    raw_data = sdr.rx()

# Recevoir des échantillons
rx_samples = sdr.rx()
print(rx_samples)

# ArrĂȘter la transmission
sdr.tx_destroy_buffer()

# Calculer la densité spectrale de puissance (version du signal dans le domaine de la fréquence)
psd = np.abs(np.fft.fftshift(np.fft.fft(rx_samples)))**2
psd_dB = 10*np.log10(psd)
f = np.linspace(sample_rate/-2, sample_rate/2, len(psd))

# Tracer le domaine temporel
plt.figure(0)
plt.plot(np.real(rx_samples[::100]))
plt.plot(np.imag(rx_samples[::100]))
plt.xlabel("temps")

# Tracer le domaine freq
plt.figure(1)
plt.plot(f/1e6, psd_dB)
plt.xlabel("Frequences [MHz]")
plt.ylabel("DSP")
plt.show()

Vous devriez voir quelque chose qui ressemble à ceci, en supposant que vous avez des antennes appropriées ou un cùble connecté :

_images/pluto_tx_rx.svg

C’est un bon exercice que de rĂ©gler lentement sdr.tx_hardwaregain_chan0 et sdr.rx_hardwaregain_chan0 pour s’assurer que le signal reçu devient plus faible/fort comme prĂ©vu.

Exercices Python

Au lieu de vous fournir du code Ă  exĂ©cuter, j’ai créé plusieurs exercices oĂč 95 % du code est fourni et oĂč le code restant est du Python assez simple Ă  crĂ©er. Les exercices ne sont pas censĂ©s ĂȘtre difficiles. Il leur manque juste assez de code pour vous faire rĂ©flĂ©chir.

Exercice 1 : DĂ©terminer le dĂ©bit de votre USB

Essayons de recevoir des Ă©chantillons du PlutoSDR, et dans le processus, voyons combien d’échantillons par seconde nous pouvons pousser Ă  travers la connexion USB 2.0.

**Votre tĂąche consiste Ă  crĂ©er un script Python qui dĂ©termine le taux de rĂ©ception des Ă©chantillons en Python, c’est-Ă -dire compter les Ă©chantillons reçus et suivre le temps pour dĂ©terminer le taux. Ensuite, essayez d’utiliser diffĂ©rents taux d’échantillonnage et tailles de tampon pour voir comment cela affecte le taux le plus Ă©levĂ© rĂ©alisable.

Gardez Ă  l’esprit que si vous recevez moins d’échantillons par seconde que le taux d’échantillonnage spĂ©cifiĂ©, cela signifie que vous perdez/supprimez une certaine fraction d’échantillons, ce qui se produira probablement Ă  des taux d’échantillonnage Ă©levĂ©s. La Pluto utilise uniquement l’USB 2.0.

Le code suivant servira de point de départ mais contient les instructions dont vous avez besoin pour accomplir cette tùche.

import numpy as np
import adi
import matplotlib.pyplot as plt
import time

sample_rate = 10e6 # Hz
center_freq = 100e6 # Hz

sdr = adi.Pluto("ip:192.168.2.1")
sdr.sample_rate = int(sample_rate)
sdr.rx_rf_bandwidth = int(sample_rate) # la frĂ©quence de coupure du filtre, il suffit de la rĂ©gler sur la mĂȘme frĂ©quence d'Ă©chantillonnage.
sdr.rx_lo = int(center_freq)
sdr.rx_buffer_size = 1024 # c'est le tampon que le Pluto utilise pour mettre en mémoire tampon les échantillons
samples = sdr.rx() # recevoir des échantillons au large de Pluton

En outre, afin de dĂ©terminer la durĂ©e d’une opĂ©ration, vous pouvez utiliser le code suivant :

start_time = time.time()
# faire des chodes
end_time = time.time()
print('secondes écoulées:', end_time - start_time)

Voici quelques conseils pour vous aider à démarrer.

Conseil 1 : Vous devrez placer la ligne « samples = sdr.rx() » dans une boucle qui s’exĂ©cute plusieurs fois (par exemple, 100 fois). Vous devez compter combien d’échantillons vous obtenez Ă  chaque appel Ă  sdr.rx() tout en suivant le temps qui s’est Ă©coulĂ©.

Astuce 2 : Le fait que vous calculiez des Ă©chantillons par seconde ne signifie pas que vous devez effectuer exactement 1 seconde de rĂ©ception d’échantillons. Vous pouvez diviser le nombre d’échantillons reçus par le temps Ă©coulĂ©.

Conseil 3 : Commencez avec sample_rate = 10e6 comme le montre le code car ce taux est bien plus que ce que l’USB 2.0 peut supporter. Vous serez en mesure de voir combien de donnĂ©es sont transmises. Ensuite vous pouvez modifier rx_buffer_size. Faites-le beaucoup plus grand et voyez ce qui se passe. Une fois que vous avez un script fonctionnel et que vous avez modifiĂ© rx_buffer_size, essayez d’ajuster sample_rate. DĂ©terminez jusqu’oĂč vous devez descendre pour ĂȘtre capable de recevoir 100 % des Ă©chantillons en Python (c’est-Ă -dire Ă©chantillonner Ă  un cycle de service de 100 %).

Conseil 4 : Dans votre boucle oĂč vous appelez sdr.rx(), essayez d’en faire le moins possible afin de ne pas ajouter de dĂ©lai supplĂ©mentaire dans le temps d’exĂ©cution. Ne faites rien d’intensif comme afficher Ă  l’intĂ©rieur de la boucle.

Dans le cadre de cet exercice, vous aurez une idĂ©e du dĂ©bit maximal de l’USB 2.0. Vous pouvez vĂ©rifier vos rĂ©sultats en ligne.

En bonus, essayez de changer la fréquence centrale et la largeur de bande rx_rf_bandwidth pour voir si cela a un impact sur la vitesse à laquelle vous pouvez recevoir des échantillons du Pluto.

Exercice 2 : crĂ©er un spectrogramme

Pour cet exercice, vous allez crĂ©er un spectrogramme, comme nous l’avons appris Ă  la fin du chapitre Domaine frĂ©quentiel. Un spectrogramme est simplement un ensemble de FFT affichĂ©es empilĂ©es les unes sur les autres. En d’autres termes, c’est une image avec un axe reprĂ©sentant la frĂ©quence et l’autre axe reprĂ©sentant le temps.

Dans le chapitre Domaine frĂ©quentiel nous avons appris le code Python pour effectuer une FFT. Pour cet exercice, vous pouvez utiliser les extraits de code de l’exercice prĂ©cĂ©dent, ainsi qu’un peu de code Python de base.

Indices:

  1. Essayez de définir sdr.rx_buffer_size à la taille de la FFT de sorte que vous exécutez toujours 1 FFT pour chaque appel à sdr.rx().

  2. Construisez un tableau 2d pour contenir tous les rĂ©sultats de la FFT oĂč chaque ligne reprĂ©sente 1 FFT. Un tableau 2d rempli de zĂ©ros peut ĂȘtre créé avec : np.zeros((num_rows, fft_size)). AccĂ©dez Ă  la ligne i du tableau avec : waterfall_2darray[i, :].

  3. plt.imshow() est un moyen pratique d’afficher un tableau 2d. La couleur est mise Ă  l’échelle automatiquement.

Comme but ultime, faire la mise Ă  jour du spectrogramme en direct.