Automatisez vos mesures en utilisant l’USB

Hackable n° 024 | mai 2018 | Jean-Baptiste Vioix
Creative Commons
  • Actuellement 0 sur 5 étoiles
0
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
La marque Rigol est bien connue des hackers du monde entier. Elle propose des appareils de laboratoire pour l'électronique (oscilloscopes, générateurs...) ayant un prix accessible pour les amateurs. Dans cet article, nous allons présenter un oscilloscope et un générateur basses fréquences de ce fabricant, pilotables par le port USB pour automatiser les mesures. Cette automatisation va être utilisée (via Python) pour écrire un programme permettant de mesurer et tracer le diagramme de Bode d'un montage.

Les appareils utilisés sont tous les deux de la marque Rigol. Cette marque totalement inconnue il y a une dizaine d'années est maintenant très présente dans le milieu de la bidouille. Son très bon rapport qualité-prix (qui produit même des oscilloscopes pour Agilent) n'y est pas étranger.

1. Présentation des appareils Rigol

1.1 Oscilloscope numérique DS1052E

Pour environ 300€ l'oscilloscope numérique DS1052E est l'un des rares oscilloscopes numériques accessibles à l'amateur en électronique.

La base de temps est réglable de 5 ns à 50 s par division pour une bande passante de 50 MHz. Les signaux les plus rapides visibles à l'oscilloscope seront donc représentés sur 4 carreaux, ce qui permet une lecture correcte. La base de temps la plus lente pourra être utilisée pour observer des variations lentes comme par exemple des capteurs de température ou de courant.

Les signaux acquis par les deux voies peuvent être combinés dans une troisième voie (MATH) à l'aide des opérateurs arithmétiques usuels. L'appareil propose aussi le calcul de la transformée de Fourier de l'une des deux voies (au choix) via le même menu (il est possible de choisir différentes fenêtres de pondération).

L'appareil est équipé de deux prises USB : une femelle A en façade qui permet de stocker des captures d'écran (ou des données brutes) sur une clé USB et une femelle B qui permet de contrôler l'oscilloscope depuis un PC.

L'une des rares critiques que l'on peut faire pour ce prix est que le ventilateur est un peu bruyant.

Pour 350€, Rigol propose le DS1102E qui est le même oscilloscope avec une bande passante étendue à 100 MHz. Les hackers les plus intrépides peuvent aussi trouver un firmware sur le Web permettant d'étendre la bande passante du 1052 à 100 MHz. Évidemment, cette modification invalidera instantanément la garantie de l'appareil…

1.2 Générateur basses fréquences DG1022

Après l'oscilloscope, le second appareil le plus utile dans un laboratoire d'électronique (surtout en électronique analogique) est le générateur de fonctions ou générateur basses fréquences. Cet appareil permet de générer différents signaux périodiques (au minimum sinusoïdaux, triangulaires, rectangulaires) à différentes tensions (avec ou sans décalage par rapport à 0).

Le DG1022 regroupe toutes ces fonctions avec d'autres formes d'ondes (et la possibilité d'en charger des nouvelles depuis le port USB en façade) et surtout la présence de deux sorties totalement indépendantes. La fréquence du signal généré peut aller jusqu’à 20 MHz. À cela s'ajoutent plusieurs modulations : AM, FM, FSK... Le tout pour 320€.

Comme pour l'oscilloscope, une version supérieure existe : le DG1022A qui coûte environ 450 € pour une fréquence maximale de 25 MHz. Les derniers MHz sont chers ! Par contre, je n'ai pas trouvé trace d'un firmware permettant de récupérer les derniers MHz manquants d'un DG1022.

Les deux appareils peuvent être couplés pour que le générateur « rejoue » une séquence capturée par l'oscilloscope. Il est ainsi possible de travailler sur des séquences numériques que l'on souhaite décoder avec un microcontrôleur. Pour l'instant, je n'ai pas encore utilisé cette option.

Fig. 1 : Les appareils en situation avec un filtre RC câblé « en l’air ».

2. Contrôle des appareils par PC

Les appareils étant alimentés et reliés au port USB du PC (éventuellement via un hub), ils sont allumés. La commande dmesg permet ensuite de vérifier que les liaisons USB sont montées.

[100569.628422] usb 8-2.2: new full-speed USB device number 25 using xhci_hcd

[100573.861035] usb 8-2.2: New USB device found, idVendor=0400, idProduct=09c4

[100573.861038] usb 8-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3

[100573.861040] usb 8-2.2: Product: DG1000 SERIES

[100573.861042] usb 8-2.2: Manufacturer: Rigol Technologies

[100573.861044] usb 8-2.2: SerialNumber: DG1**********

[100573.948098] usb 8-2.3: new full-speed USB device number 26 using xhci_hcd

[100574.076498] usb 8-2.3: New USB device found, idVendor=1ab1, idProduct=0588

[100574.076501] usb 8-2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3

[100574.076504] usb 8-2.3: Product: DS1000 SERIES

[100574.076505] usb 8-2.3: Manufacturer: Rigol Technologies

[100574.076507] usb 8-2.3: SerialNumber: DS1**********

La commande lsub confirme que tout est bien à sa place…

Bus 008 Device 026: ID 1ab1:0588 Rigol Technologies DS1000 SERIES

Bus 008 Device 025: ID 0400:09c4 National Semiconductor Corp. Rigol Technologies DG1022 Arbitrary Waveform Generator

2.1 Interface de programmation VISA

Les instruments actuels sont très souvent compatibles avec l'interface de programmation VISA (Virtual Instrument Software Architecture). Les instruments Rigol sont compatibles et d'après la documentation du constructeur, il suffit d'installer le pilote VISA de National Instrument pour pouvoir contrôler les appareils.

2.1.1 Installation de VISA

Les éléments logiciels sont distribués par NI sur la page http://www.ni.com/download/ni-visa-5.4.1/4629/en/. Il faut ensuite télécharger le fichier NI-VISA-5.4.1.iso. Il est nécessaire de créer un compte chez NI pour pouvoir avoir accès au lien de téléchargement. NI annonce clairement la couleur lors de la création du compte, je ne peux que vous conseiller d'utiliser une adresse mail « poubelle » réservée à ce type d'usage…

Note

J'accepte que mes données personnelles soient recueilles, traitées et utilisées par NI selon les termes de sa déclaration de confidentialité.

Je recevrai périodiquement des e-mails concernant les produits et services NI, et pourrai modifier mes préférences de communication à tout moment.

L'image disque téléchargée est ensuite montée avec l'utilitaire du système (sur Ubuntu et dérivées l'application Monteur d'images disque est utilisée). Sinon une ligne de terminal est efficace aussi : mount -o loop NI-VISA-5.4.1.iso /media/cdrom.

Normalement seules les distributions Red Hat (et dérivées) sont reconnues par NI. Toutefois dans le fichier expliquant l'installation, il est proposé d'utiliser l'option no-deps et donc la commande sudo ./INSTALL --nodeps pour les autres distributions. Un kilomètre de licence s'affiche ensuite et l'installation échoue :-( Il va donc falloir trouver une autre solution.

Il existe une implémentation libre de VISA : LibreVISA, mais le projet n'est pas mis à jour depuis plusieurs années.

2.1.2 Installation de PyVISA-py

Puisque la solution propriétaire recommandée par le fabricant a échoué, il est temps de se pencher sur les solutions libres ! Pour contrôler des appareils de mesure avec Python, il est possible d'utiliser pyvisa qui nécessite un pilote VISA opérationnel ou pyvisa-py qui est une implémentation complète en Python de VISA. Les paquets pyserial et pyusb sont aussi nécessaires, les communications VISA pouvant se faire aussi bien en RS232 qu'en USB. L'installation se fait avec la ligne suivante :

sudo pip3 install pyserial pyusb pyvisa-py

3. Prise en main de la librairie

3.1. Premier programme

Pour utiliser l'interface VISA, il faut commencer par importer le paquet visa. Ensuite, une librairie doit être spécifiée avec la fonction ResourceManager, pour l'implémentation Python la chaîne @py doit être utilisée. Il ne reste plus qu'à obtenir une liste des instruments connectés avec la méthode list_ressources.

import visa

rm = visa.ResourceManager('@py')

instruments = rm.list_resources()

print(instruments)

La liste des périphériques compatibles VISA s'affiche et on retrouve l'oscilloscope et le GBF dans la liste avec les identifiants DS et DG suivis ensuite de leurs numéros de série. Une recherche dans la liste permet ensuite d'associer chaque appareil à un objet de la classe USBInstrument.

for _ in instruments:

 if 'DS' in _:        

  oscilloscope = rm.open_resource(_)

 if 'DG' in _:        

  generator = rm.open_resource(_)

Ensuite, il est préférable de réinitialiser les différents appareils avant d'envoyer d'autres commandes en envoyant une commande *RST avec la méthode query de la classe USBInstrument.

generator.query("*RST")

oscilloscope.query("*RST")

3.2. Contrôle  du générateur

La documentation du constructeur présente l'ensemble des instructions possibles pour contrôler le générateur. Dans la suite de ce document, nous n'en utiliserons que deux :

  • OUTP qui permet de contrôler l'état de la sortie (activée ou non) ;
  • APPL:SIN est utilisée pour générer un signal sinusoïdal caractérisé par sa fréquence, son amplitude crête-à-crête et son décalage (par rapport à zéro).

Les commandes sont simples à utiliser, ce sont des chaînes de caractères que l'on envoie à l'appareil via la méthode query :

generator.query("APPL:SIN 440,1.0,0.0")

generator.query("OUTP ON")

Le générateur produit maintenant une sinusoïde de fréquence 440 Hz avec une tension crête-à-crête de 1 V et un décalage nul.

3.3 Contrôle de l'oscilloscope

Les oscilloscopes numériques sont souvent équipés d'un mode de réglage automatique (autoset) qui permet souvent de « dégrossir » les réglages. Il très simple d'activer le mode automatique via python :

oscilloscope.query(":AUTO")

Un petit claquement de relais se produit comme lorsque le mode automatique est activé manuellement. Le réglage automatique affiche les deux voies (même si rien n'est branché sur la seconde voie). Les mesures automatiques peuvent ensuite être utilisées pour relever la fréquence et la tension du signal de chaque voie. Pour l'instant, seule la première voie est utilisée, deux lignes sont nécessaires pour lire les valeurs.

print(u"Fréquence : %f Hz"%(float(oscilloscope.query(":MEAS:FREQ? CHAN1"))))

print(u"Tension (CàC) : %f V"%(float(oscilloscope.query(":MEAS:VPP? CHAN1"))))  

La méthode query retourne les données lorsque la commande est une requête (généralement terminée par ?). Les données retournées sont des chaînes de caractères, elles doivent donc être converties en flottant avant des calculs (pour un simple affichage ce n'était pas nécessaire, mais autant prendre de bonnes habitudes tout de suite...).

3.4 Accès non root

L'accès direct aux périphériques USB n'est pas possible pour l'utilisateur de base. Il est donc nécessaire d’utiliser sudo pour exécuter le script.

Il est possible de donner l'accès direct aux périphériques USB en ajoutant une règle pour le gestionnaire de périphérique udev. Les opérations à réaliser sont les suivantes (en super-utilisateur) :

  • créer un groupe usbusers et ajouter l'utilisateur à ce groupe (soit en ligne de commandes, soit avec l'interface graphique…) ;
  • créer un fichier 00-usbusers.rules dans le répertoire /etc/udev/rules.d ;
  • dans ce fichier, ajouter les lignes suivantes :

L'utilisateur doit ensuite se déconnecter et se reconnecter pour qu'il puisse accéder aux périphériques USB sans utiliser la commande sudo.

4. Construction du diagramme de Bode

4.1 Présentation du diagramme de Bode

Le diagramme de Bode est une représentation graphique utilisée en électronique analogique pour caractériser le comportement d'un montage en fonction de la fréquence du signal d'entrée. Il est composé de deux graphes :

  • Le diagramme du gain qui représente l'évolution du gain (ou de l'atténuation) du montage en fonction de la fréquence. L'évolution de la tension de sortie en fonction de la tension d'entrée est exprimée en décibels (dB) avec la formule de calcul suivante : Une amplification est donc représentée par des valeurs positives, une atténuation par une valeur négative. L'utilisation des décibels permet d'avoir des valeurs numériques « compactes », ainsi un gain de 10000 est représenté par +80 dB.
  • Le diagramme de phase représente le décalage temporel entre la sortie et l'entrée du montage. Comme le signal d'entrée est une fonction sinusoïdale, le déphasage est exprimé sous la forme d'un angle en radians. Ainsi, un décalage d'une demi-période est représenté par -π.

En pratique, le diagramme de phase est moins utilisé que le diagramme de gain.

4.2 Parcours des fréquences

Les diagrammes de Bode utilisent une échelle logarithmique pour les fréquences. Il est donc nécessaire de parcourir l'étendue des fréquences de manière non linéaire, sinon les points ne seront pas répartis de manière homogène sur le diagramme.

Dans le paquet numpy, la fonction logspace retourne un ensemble de valeurs réparties de manière logarithmique sur une base (qui est 10 par défaut), les bornes étant des puissances de la base. Le dernier paramètre obligatoire est le nombre de valeurs souhaitées. Pour construire un diagramme de Bode entre 100 Hz et 100 kHz avec un total de 30 points la fonction sera appelée de la manière suivante logspace(2,5,30).

NB = 30

results = np.zeros((NB, 3))

generator.query("OUTP ON")

for idx, f in enumerate(np.logspace(2, 5, NB)):

 generator.query("APPL:SIN %f,3.0,0.0" % (f,))

 oscilloscope.query(":AUTO")

 time.sleep(5)

 results[idx, 0] = float(oscilloscope.query(":MEAS:FREQ? CHAN1"))

 results[idx, 1] = float(oscilloscope.query(":MEAS:VRMS? CHAN1"))

 results[idx, 2] = float(oscilloscope.query(":MEAS:VRMS? CHAN2"))

À chaque itération de la boucle, la nouvelle valeur de fréquence est envoyée au GBF puis l'oscilloscope est reconfiguré automatiquement. Une pause de quelques secondes est nécessaire pour que la fonctionautoset se termine avant de demander les mesures de fréquence et de tensions (ici il s'agit de la tension efficace Root Mean Square en anglais).

4.3 Calcul et affichage de l’évolution du gain

Les données étant stockées dans un tableau ndarray, la lecture des fréquences se fait en accédant à la première colonne, le calcul du gain se fait à partir de la deuxième et de la troisième colonne.

L'affichage avec un axe des abscisses logarithmique utilise la fonction semilogx de matplotlib. Les autres éléments permettent de mettre en forme le diagramme :

plt.figure(figsize=(15, 10))

plt.semilogx(results[:, 0], 20*np.log10(results[:, 2]/results[:, 1]), '-o')

plt.grid(True, 'minor')

plt.grid(True, 'major')

plt.ylabel('Amplitude [dB]')

plt.xlabel(u'Fréquence [Hz]')

plt.title("Diagramme de Bode du filtre")

plt.savefig("TeBNC.pdf")

plt.show()

En utilisant un té BNC les deux entrées de l'oscilloscope sont reliées à la sortie du générateur. Le diagramme de Bode obtenu est le suivant :

Fig. 2 : Diagramme de Bode du té BNC.

En théorie, le diagramme de Bode serait parfaitement plat. Les légères ondulations qui sont de l'ordre de +/- 0,01 dB sont principalement dues à la précision des mesures automatiques de l'oscilloscope.

4.4 Sauvegarde des données

En plus de l’enregistrement de la figure du diagramme de Bode, les données sont sauvegardées dans un fichier CSV pour pouvoir éventuellement être réutilisées ultérieurement. Le module csv de Python propose toutes les fonctions utiles pour manipuler les fichiers CSV. Afin de pouvoir retrouver le rôle des différentes colonnes dans le fichier, la première ligne contient le nom des différentes variables mesurées. Le caractère # est utilisé comme marqueur pour la signaler comme une entête.

with open("Mesures.csv", "w") as f:

 writer = csv.writer(f, delimiter=',')

 writer.writerow(["#Freq. (Hz)", "In (Vrms)", "Out (Vrms)"])

 writer.writerows(results)

4.5 Évolution de la phase

Dans un diagramme de Bode complet, l'évolution de la phase en fonction de la fréquence est aussi tracée.

La phase ne peut pas être directement mesurée avec l'oscilloscope. Il est par contre possible de mesurer l'avance ou le retard d'une voie par rapport à l'autre. À partir de ces informations, il doit être possible de reconstruire la phase.

Les valeurs de décalage du front montant et du front descendant du canal 2 par rapport au canal 1 sont mesurées. Les mesures ne peuvent pas être directement converties en valeurs flottantes, car l'oscilloscope peut retourner des chaînes du type <1.0us.  La conversion nécessite donc un test sur la présence des symboles < ou > pour éviter une exception. Le tableau results a été agrandi en conséquence (à 5 colonnes) lors de sa construction.

_ = oscilloscope.query(":MEAS:PDEL? CHAN2")

results[idx, 3] = 0.0 if (("<" or ">") in _ ) else float(_)

_ = oscilloscope.query(":MEAS:NDEL? CHAN2")

results[idx, 4] = 0.0 if (("<" or ">") in _ ) else float(_)

Les mesures obtenues ainsi sont incorrectes, le signe du décalage alternant en les valeurs positives et les valeurs négatives pour un filtre RC (voir paragraphe suivant). Lors des mesures, le mode AUTO de l'oscilloscope affiche plusieurs périodes à l'écran rendant les mesures automatiques des décalages temporels peu précises.

Pour améliorer la précision des mesures, la base de temps retenue par le mode AUTO est lue et modifiée (elle est divisée par 4 pour minimiser le nombre de périodes à l'écran) avant de demander les mesures de décalage. En même temps, le mode AC du canal 2 est activé pour faciliter la mesure de décalage du passage par zéro en supprimant l'éventuelle composante continue.

oscilloscope.query(":CHAN2:COUP AC")

time_base = oscilloscope.query(":TIM:SCAL?")

oscilloscope.query(":TIM:SCAL %f"%(float(time_base)/4.0))

La valeur de phase peut être calculée à partir de la période (l'inverse de la fréquence) et du retard du front montant.

periods = 1.0/results[:, 0]

phases = -2.0*np.pi*(results[:, 3]/periods)

Il serait aussi possible de régler automatiquement la base de temps en utilisant la valeur de la fréquence. Cette solution n'a pas été mise en œuvre, le diagramme de phase n'étant pas la partie la plus utilisée du diagramme de Bode.

5. Exemple d'utilisation : filtre RC

5.1. Éléments de théorie

Les filtres sont des montages électroniques dont le comportement dépend de la fréquence. Les plus simples sont réalisés avec une résistance et un condensateur. Selon le câblage, le filtre peut avoir l'un des deux comportements suivants :

  • passe bas : le filtre laisse passer les signaux ayant une fréquence inférieure à une certaine valeur (la fréquence de coupure). Les signaux ayant une fréquence supérieure sont atténués, plus leur fréquence est élevée, plus ils seront atténués.
  • passe haut : le comportement est le dual du précédent. Les signaux ayant une fréquence supérieure à la fréquence de coupure ne sont pas altérés. Sinon, l'atténuation est inversement proportionnelle à la fréquence (ainsi les signaux continus sont totalement atténués.)

Le câblage d'un filtre passe-bas est présenté ci-dessous :

Fig. 3 : Schéma d’un filtre passe-bas.

La fréquence de coupure d'un filtre RC est donnée par la formule : 

avec R la résistance en Ω et C la capacité en Farads (F). Avec une résistance de 100kΩ et un condensateur de 1,5 nF, la fréquence de coupure théorique est de 1,061 kHz (à cette valeur le gain vaut -3 dB).

Avec le module scipy.signal, il est possible de calculer le diagramme de Bode théorique du filtre. Un filtre composé d'une résistance et d'un condensateur est modélisé par la fonction de Butterworth ; cette fonction est nommée butter dans le module. Elle utilise 2 paramètres : l'ordre du filtre (1 pour un filtre RC) et la pulsation de coupure (qui vaut ω=1/(R.C), car ω=2 π.f). Les valeurs de retour de la fonction (de type ndarray) sont :

  • les pulsations pour lesquelles la fonction de transfert a été calculée,
  • les valeurs (sous forme complexe) de la fonction de transfert à ces pulsations.

À partir de ces valeurs, les fréquences sont calculées (avec la relation ci-dessus) ainsi que le gain en décibels (à partir du module de la fonction de transfert).

b, a = signal.butter(1, 1.0/(100e3*1.5e-9), 'low', analog=True)

w, h = signal.freqs(b, a)

f_th = w/2*np.pi

g_th = 20*np.log10(abs(h))

Les fréquences et le gain ont été placés dans des variables notées _th puisqu'ils correspondent à des valeurs théoriques.

5.2 Mesures pratiques

5.2.1 Affichage du gain

À partir des éléments de programme présentés dans le chapitre précédent, le gain du filtre a été mesuré entre 100 Hz et 100 kHz ; 30 points ont été mesurés. Les valeurs ont été stockées dans le fichier MesuresRC.csv. Le programme de calcul théorique du filtre est complété pour lire ces données et les afficher sur un diagramme de Bode avec les données théoriques.

# Lecture des données

resultats = []

with open("MesuresRC.csv", "r") as f:

    reader = csv.reader(f, delimiter=',')    

    next(reader, None) # pour supprimer la première ligne

    for line in reader:

        resultats.append([float(_) for _ in  line ])

results = np.array(resultats)

f_me = results[:, 0]

g_me = 20*np.log10(results[:, 2] / results[:, 1])

# Création de la figure

plt.figure(figsize=(15, 10))

plt.semilogx(f_th, g_th, '-')

plt.semilogx(f_me, g_me, '-o')

plt.grid(True, 'minor')

plt.grid(True, 'major')

plt.ylabel("Amplitude [dB]")

plt.xlabel("Fréquence [Hz]")

plt.title("Diagramme de Bode du filtre RC")

plt.legend(("Théorique","Pratique"))

plt.margins(0.1, 0.1)

plt.savefig("FiltreRC.png")

plt.show()

Le chargement des données est simple, il faut simplement passer la première ligne (avec la directive next) qui contient les noms de colonnes. Les données lues à partir des mesures sont notées avec _me (pour les différencier des données théoriques). Le gain du filtre est calculé à partir de la formule donnée dans la présentation théorique.

Ensuite, différentes fonctions de Matplotlib permettent de mettre le diagramme de Bode en forme. Pour la courbe représentant les données pratiques les points de mesure sont signalés par une marque ronde.

Fig. 4 : Diagramme de Bode (gain) pour un filtre RC.

La superposition sur le même graphique de la courbe théorique et des mesures permet de vérifier le comportement du filtre. Dans le cas de notre montage, les courbes sont presque confondues. Les valeurs des composants étaient très proches des valeurs théoriques : après mesure, la résistance fait exactement 100kΩ et le condensateur 1508 pF. Les résistances ont souvent une tolérance de +/-5 % et les condensateurs +/-10 %.  En prenant en compte les cas extrêmes, la fréquence de coupure pratique du filtre pourrait être comprise entre 918 Hz et 1,24 kHz.

5.2.2 Affichage de la phase

Comme pour le gain, la phase théorique et la phase mesurée vont être affichées sur le même graphique. La phase théorique est calculée avec la fonction angle de Python.

ph_th = np.angle(h)

Comme nous l'avons présenté ci-dessus, la phase pratique est calculée à partir du retard avec le passage par zéro :

periods = 1.0/results[:, 0]

ph_me = -2.0*np.pi*(results[:, 3]/periods)

Les mêmes éléments graphiques sont repris pour l'affichage des deux courbes.

Fig. 5 : Diagramme de Bode (phase) pour un filtre RC.

Comme nous l'avons évoqué dans le paragraphe présentant la mesure de la phase, les mesures sont moins précises que pour le gain.

Conclusion

Après avoir fait une présentation rapide des deux appareils utilisés, nous avons montré qu'il est simple de les contrôler par le port USB. L'application proposée (le relevé automatique du diagramme de Bode) permet d'automatiser des mesures assez longues si on les souhaite précises. Le relevé de la phase n'a pas pu être réalisé de manière aussi précise que le gain, il nécessiterait un programme plus complexe. La partie phase du diagramme de Bode étant moins utilisée, nous n'avons pas cherché d'autre solution.

Toutes les commandes étant accessibles via l'USB, beaucoup d'autres applications sont possibles comme la mesure des temps de montée d'un amplificateur, le taux de distorsion harmonique d'un montage...

Bibliographie

Tags : mesures, USB