**TP2 Simulation des convertisseurs** -------------------------------------------------------------------------------------------------------- {{https://bvdp.inetdoc.net/files/iut/tp_pic/warning.jpeg}} Polycopié du cours architecture pour le TNS {{https://bvdp.inetdoc.net/files/iut/tp_tns/cours_tns.pdf}} A FAIRE A LA FIN DE CHAQUE SEANCE POUR COPIER VOS FICHIERS SUR UN DISQUE PARTAGE, ET PERMETTRE LA RECUPERATION DES FICHIERS SI UN MEMBRE DU BINOME EST ABSENT, SINON TANT PIS POUR VOUS!\\ \\ copier coller dans une console: rsync -av --delete ~/TP_ARCHI_TNS_ETU /mnt/etu/s4 et compléter la ligne en appuyant 3 fois sur la touche Tabulation, puis entrée. =====Fonctions simulant les convertisseurs===== Dans la démarche qui consiste à se rapprocher des conditions réelles dans lesquelles la méthode TraiteUnEchantillon sera utilisée, nous souhaitons maintenant intégrer les convertisseurs dans la chaîne de traitement en les simulant par des fonctions: - **simuADC** dont le rôle est de convertir un nombre représentant une tension en une valeur numérique quantifiée. - **simuDAC** dont le rôle est de convertir une valeur numérique quantifiée en un nombre représentant une tension. Le schéma suivant représente l'agencement de ces deux fonctions relativement à **TraiteUnEchantillon**. {{https://bvdp.inetdoc.net/files/iut/tp_tns/quantif1_2019.png}} Les fonctions **simuADC** et **simuDAC** doivent être définies dans les fichiers **convertisseurs.cpp et .h ** que vous devez compléter dans votre projet: double SimuADC ( double Ve, double Vmin, double Vmax, int nbBits); double SimuDAC ( double M, double Vmin, double Vmax, int nbBits); #include /*! * \brief SimuADC simule un ADC avec sortie non signée */ double SimuADC ( double Ve, double Vmin, double Vmax, int nbBits) { double q = (Vmax-Vmin)/(pow(2,nbBits)-1); double ekQuant; if (VeVmax) ekQuant = pow(2,nbBits)-1; else ekQuant = round((Ve-Vmin)/q); return ekQuant; } /*! * \brief SimuDAC simule un DAC avec entrée non signée */ double SimuDAC ( double M, double Vmin, double Vmax, int nbBits) { double q = (Vmax-Vmin)/(pow(2,nbBits)-1); return (Vmin + q*( (unsigned int)M % (1< Une directive **#include "convertisseur.h"** est présente dans le fichier filtretrace.h pour pouvoir appeler ces fonctions. void test_conv(void) { const double vmin = -3.3; const double vmax = 3.3; const int nbbits = 4; const int nbpts = 1000; double ve[nbpts], caractADC[nbpts] ; double M[(int) pow(2,nbbits)], caractDAC[(int) pow(2,nbbits)]; for(int i=0;iplot(dataADC,style2); w1->setLegend(0,"Ve","M"); w1->setWindowTitle("caractéristique E/S ADC"); w1->show(); w2->plot(dataDAC,style1); w2->setLegend(0,"M","Vs"); w2->setWindowTitle("caractéristique E/S DAC"); w2->show(); } === Visualisation de signaux quantifiés (45' max) === - On souhaite visualiser sur une même fenêtre mais sur 2 axes différents (car les échelles sont différentes) l'impulsion et l'impulsion quantifiée pour 7 échantillons. Vous devez donc utiliser **simuADC()** pour quantifier échantillon par échantillon tout le signal impulsion et stocker le résultat dans un tableau impQuant. Simulez un CAN ayant une plage de conversion de 0 à 3,3V sur 4 bits (déclarez vmin, vmax, nbbits comme constantes globales). - Créez une nouvelle fonction **void code_tparchi2(void)** dans le fichier tparchi1.cpp. - Afficher alors les deux signaux demandés. - Faites de même ensuite pour l'échelon et l'échelon quantifié. - Vous pouvez constater que l'impulsion et l'échelon sont à la limite de la dynamique du CAN. Comme lors de l'utilisation de montage à AOp (souvenez-vous du télémètre !), il est préférable de centrer les signaux d'entrée sur la tension $(vmax+vmin)/2$ plutôt que sur 0V. Modifiez les signaux impulsion et echelon en conséquence. Quelle est la nouvelle valeur de repos des signaux quantifiés ? - Générez un signal sinusoïdal d'amplitude 1,5V, de fréquence 1 kHz correctement centré. Dans une nouvelle fenêtre, visualisez ce signal, ce signal quantifié sur 4 bits et ce signal quantifié sur 8 bits (dynamique 0 à 3,3V). - Faites valider votre travail. === Ajout des convertisseurs dans la méthode ReponseEnLigne() === Comme cela a été dit en introduction de ce TP (relisez là si vous avez oublié...) il faut maintenant inclure les convertisseurs analogique<->numérique dans **ReponseEnLigne()**. Voici les opérations à effectuer: - Ajouter **#include "convertisseur.h"** dans filtretrace.h pour pouvoir appeler les fonctions de simulation de convertisseurs depuis filtretrace. - Dans le fichier filtretrace.cpp, intégrez dans la méthode **ReponseEnLigne** l'appel de ces 2 fonctions (dynamique 0 à 3,3V , 12 bits) pour que la méthode **TraiteUnEchantillon** traite des échantillons quantifiés en entrée et en sortie: - appeler **simuADC** sur chaque échantillon du tableau **e[k]** et stocker sa valeur de retour dans une variable **ekquant** du bon type. - appeler **TraiteUnEchantillon** en lui fournissant en paramètre la variable précédemment calculée afin d'obtenir l'échantillon quantifié **skquant**. - appeler **simuDAC** en lui fournissant la valeur fournie par **TraiteUnEchantillon** et ranger la valeur de sortie de **simuDAC** dans le tableau **s[k]**. - Vérifier le bon fonctionnement des 2 filtres du TP1. Expliquez l'amplitude de la réponse impulsionnelle du filtre RIF. {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console: echo commence cd ~/TP_ARCHI_TNS_ETU git commit -a -m'ADC/DAC working' gitk & echo fini === Prise en compte de l'offset numérique des échantillons=== - Ajouter aux échantillons d'entrée (pour les signaux impulsion et échelon définis dans le fichier **tparchi1.cpp**) un offset de 3,3V/2. - - Calculer à la main la valeur de l'échantillon de sortie du filtre à $k=3$ pour le RIF de l'exercice 2 du TP1 pour le signal impulsion avec offset défini en 1) et comparer avec la valeur fournie par **ReponseEnLigne()**. Interpréter les résultats. - Ce phénomène est provoqué par l'offset numérique de **ek_quant** (sa valeur de repos est différente de 0). Modifiez **TraiteUnEchantillon()** pour respecter le schéma de la P11 du cours (en entrée __et__ en sortie !!). Pour cela, vous devrez calculer les bonnes valeurs pour les offsets. Ces offset seront accessibles dans la classe **Filtre** grâce aux attributs suivants: **offsetEntree** et **offsetSortie**. - Pour que ces deux attributs soient correctement initialisés, vous veillerez à ajouter les valeurs effectives pour les paramètres du constructeur de l'objet filtre **offsetEntreeInit** et **offsetSortieInit**. Par exemple la ligne: FiltreTrace filtre_echo_RIF(NB_COEFF_B,coeffB,NB_COEFF_A,coeffA); devra être remplacée par: FiltreTrace filtre_echo_RIF(NB_COEFF_B,coeffB,NB_COEFF_A,coeffA,0,NULL,valeur_pour_offsetEntreeInit,valeur_pour_offsetSortieInit); - Vérifiez que les deux premiers filtres fournissent les mêmes réponses impulsionnelles qu'avant ajout des convertisseurs (à la précision de la quantification près). Remarque: C'est le même phénomène que lors de l'utilisation de montage à AOp (souvenez-vous du télémètre !), où il a fallu centrer les signaux d'entrée sur la tension $(vmax+vmin)/2$ plutôt que sur 0V. Note bertrand: réponse indicielle du filtre RIF deborde 1.65 + 1 + 1 =3.65V {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console: echo commence cd ~/TP_ARCHI_TNS_ETU git commit -a -m'offset working' gitk & echo fini ====Version 2018==== - Tester à nouveau le fonctionnement de **ReponseEnLigne()** sur le filtre passe-bande du second ordre de paramètres H0=2, f0=1000, Q=0,7. Il a été numérisé par transformée bilinéaire avec Fech=48000 : b[3]={0.1703 , 0.0000 , -0.1703}; a[3]={1.0000 , -1.8140 , 0.8297}; - Que constatez-vous ? - Ce phénomène est provoqué par l'offset numérique de **ek_quant** (sa valeur de repos est différente de 0). Modifiez **TraiteUnEchantillon()** pour respecter le schéma de la P11 du cours. - Comme lors de l'utilisation de montage à AOp (souvenez-vous du télémètre !), il est préférable de centrer les signaux d'entrée sur la tension $(vmax+vmin)/2$ plutôt que sur 0V. Modifiez les signaux impulsion et échelon en conséquence. Vérifiez que le fonctionnement du filtre est maintenant correct. - Vérifiez que les deux premiers filtres fournissent les mêmes réponses impulsionnelles et indicielles que précédemment. === Saturation du calcul de l'équation de récurrence=== - Définissez le nouveau filtre $s_k=2e_k$ - Tracez sa réponse indicielle. Quel problème constatez-vous ? - Pour corriger ce problème, vous devez saturer le résultat du calcul de l'équation de récurrence avant de le retourner (donc avant la fin de **TraiteUnEchantillon()**). Pour cela, vous utiliserez les attributs de la classe **Filtre** suivants: **valeurSortieMax** et **valeurSortieMin**. Pour que ces deux attributs soient correctement initialisés, vous veillerez à ajouter les valeurs effectives pour les paramètres du constructeur de l'objet filtre **valeurSortieMaxInit** et **valeurSortieMinInit**. Par exemple la ligne: FiltreTrace filtre_echo_RIF(NB_COEFF_B,coeffB,NB_COEFF_A,coeffA,0,NULL,valeur_pour_offsetEntreeInit,valeur_pour_offsetSortieInit); devra être remplacée par: FiltreTrace filtre_echo_RIF(NB_COEFF_B,coeffB,NB_COEFF_A,coeffA,0,NULL,offsetEntreeInit,offsetSortieInit,valeur_pour_valeurSortieMaxInit,valeur_pour_valeurSortieMinIit); - Testez le bon fonctionnement de l'ensemble sur la sinusoïde {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console: echo commence cd ~/TP_ARCHI_TNS_ETU git commit -a -m'saturation working' gitk & echo fini Proposition Bvdp: pour pouvoir utiliser plusieurs filtres, tout en gardant les variables globales, qui permettent gain en perf : il faut ajouter le pointeur d'écriture dans la structure filtre et utiliser une fonction choixFiltre, qui met à jour les variables globales avec les valeurs de la structure passée en arguments ===BAZAR=== =Travail à effectuer= Compiler et exécuter le projet. - Donner l'équation de récurrence du filtre décrit dans la fonction void code_tparchi1(void) du fichier tparchi1.cpp. Indiquer le type de filtre (RII ou RIF). - Dans le fichier **filtre.cpp**, implémenter la fonction TraiteUnEchantillon qui applique l'équation de récurrence pour un échantillon du signal comme décrit en TD. ===BAZAR=== Pour l'instant, vous simulez le filtre grâce aux étapes suivantes: Si on veut pouvoir réaliser des filtres différents et les chainer (egaliseurs, visu puissance) il ne faut pas utiliser des variables globales pour le calcul du filtre. On crée une structure buffer à côté ? Vous pouvez constater en lisant le code que le tableau sk est rempli echantillon par échantillon. Pour l'instant ce code simule l'écoulement du temps en appelant filtreUnEchantillon qui calcule l'équation de récurence (je préfèrerais calcEquationRecurrence() qui est plus explicite) pour tous les échantillons $k\in[0,nbEch-1]$. Il vous reste à coder filtreUnEchantillon(double ek, sFiltre *pFiltre,sBuffer *pbuffer) qui est le coeur du filtre numérique.(On doit sans doute ajouter une explication détaillée de la structure buffer en début de séance ou au début du TP ?) Vous devez coder la forme canonique du filtre utilisant un seul buffer. TODO 2018: - faire le rif d'exemple sur 4 coeffs au lieu de 6 pour éviter qu'ils implémentent directement l'exemple du cours avec des constantes nommer les filtres et y faire référence dans le texte