Outils pour utilisateurs

Outils du site


tptns2017

Cours architecture pour le TNS cours_Archi_TNS_intro5_6ppf.pdf

TP1 Codage du calcul de l'équation de récurrence

Principes

La démarche de développement est composée de deux grandes étapes. La première étape consiste en l'implémentation d'un filtre logiciel qui permet de vérifier si le filtre possède bien les propriétés temporelles et/ou fréquentielles souhaitées. Cette étape réalisée lors des séances de TNS est composée de la façon suivante:

  1. définition du filtre (coefficients stockés dans des tableaux, initialisation d'un sFiltre avec initFiltre() )
  2. définition des signaux (création de tableaux pour l'impulsion, l'échelon, sinus…) pour une durée fixée
  3. calcul de la réponse du filtre (avec calculReponseFiltre() )
  4. affichage des signaux d'entrée et de sortie
  5. affichage éventuel de la fonction de transfert
  6. fin du programme

La seconde étape consiste en la réalisation concrète du filtre en tenant compte du matériel utilisé, le programme devant assurer les tâches suivantes:

  1. définition du filtre
  2. acquisition d'un échantillon ek en effectuant une conversion analogique→numérique
  3. calcul de sk en appliquant l'équation de récurrence sur cet échantillon
  4. restituer sk en effectuant une conversion numérique→analogique
  5. recommencer indéfiniment en 2. jusqu'à l'arrêt du système !

Récupération du projet Qt de départ

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Pour récupérez le fichier zip du projet la première fois, ouvrir une console (alt+F2 et taper lxterm) puis taper dedans:

cd /mnt/etu/s4en/..... à compléter pour aller dans votre dossier étudiant, en pressant 2 fois la touche TAB

puis ENSUITE SEULEMENT copier coller (sélectionner le code qui suit puis clic sur le bouton central de la souris dans le terminal) :

wget http://homepages.laas.fr/bvandepo/files/iut/tp_tns/TP_ARCHI_TNS_2017.zip
unzip TP_ARCHI_TNS_2017.zip
cd TP_ARCHI_TNS
qtcreator TP_ARCHI_TNS.pro &
echo "C est bon !"

à l'ouverture de qtcreator, cliquer sur “Configurer le projet”

Description de la structure du projet

  1. filtre.h: contient les définitions de la structure de filtres (coefficients…), les prototypes des fonctions de filtrage et d'évaluation du filtre.
  2. filtre.cpp: contient l'implémentation des fonctions de filtrage et d'évaluation du filtre. C'est principalement ce fichier que vous devrez compléter.
  3. tparchi1.cpp: contient la fonction de test void code_tparchi1(void) qui appelle vos fonctions après avoir créé des échantillons pour les signaux d'entrée et trace les réponses impulsionnelle, indicielle et le module de la réponse fréquentielle.
  4. prototype_tp.h: contient les prototypes des fonctions de test
  5. main.cpp: contient le programme principal, qui appelle la fonction de test.
  6. mainwindow.h et mainwindow.cpp: contiennent la classe qui permet l'affichage de la fenêtre principale de l'application
  7. qcustomplot.h et qcustomplot.cpp: contiennent les classes qui permettent l'affichage de tracé graphique

Implémentation des fonctions pour un exemple simple

Jusqu'à ce TP, vous avez utilisé la fonction void calculReponseFiltre(sFiltre * pFiltre, double * ek, double * sk, int nbPts) pour appliquer le calcul de la réponse d'un filtre. Pour réaliser un filtre capable de traiter des échantillons en ligne, il faut que le processeur effectue le calcul de l'équation de récurrence échantillon par échantillon. La première partie du TP consiste donc à implémenter une fonction double filtreUnEchantillon(double ek) qui réalise le calcul de cette équation de récurrence.

Afin de pouvoir tester cette fonction, la fonction void calculReponseFiltreEnLigne(sFiltre * pFiltre, double * ek, double * sk, int nbPts):

  1. appelle la fonction initFiltreUnEchantillon(pFiltre)
  2. traite tous les échantillons du tableau ek (pour $k\in[0,nbEch-1]$) à l'aide de la fonction double filtreUnEchantillon(double ek) et range le résultat dans le tableau sk
void calculReponseFiltreEnLigne(sFiltre * pFiltre, double * ek, double * sk, int nbPts)
{
   initFiltreUnEchantillon(pFiltre);
    for (int k=0; k < nbPts; k++)    {
        sk[k] = filtreUnEchantillon(ek[k]);
    }
}

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Implémenter la fonction filtreUnEchantillon pour qu'elle retourne la valeur de l'échantillon e_k multiplié par 3. Compiler et exécuter le programme. Interpréter les réponses affichées. Quelle est l'équation correspondant à ce filtre.

Codage de l'équation de récurrence pour un filtre à réponse impulsionnelle finie (RIF)

On cherche maintenant à implémenter l'équation: $s_k=\sum_{i=0}^{N}b_i.e_{k-i}$.

Afin de faciliter la transition vers les filtres RII, on supposera que les $e_k$ sont équivalents aux $v_k$ et l'équation à coder sera donc: $s_k=\sum_{i=0}^{N}b_i.v_{k-i}$.

Pour calculer $s_k$, il est nécessaire de disposer des valeurs des coefficients du filtres $b_i$ et des échantillons d'entrée courant et précédents, stockés dans un buffer circulaire tel que présenté dans le cours.

La figure suivante illustre le fonctionnement d'un tel buffer de taille 6:

Le tableau memoireVk est utilisé pour stocker les échantillons. La variable globale indice_ecr est utilisée pour indiquer le numéro (indice d'écriture) de la case dans laquelle ranger l'échantillon le plus récent.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Compléter la fonction double filtreUnEchantillon(double ek) pour qu'elle:

  1. range l'échantillon $e_k$ au bon endroit dans le buffer circulaire.
  2. calcule la valeur de $s_k$ en remontant les échantillons à partir de $e_k$. Pour cela, vous utiliserez une variable locale servant d'indice de lecture. Les coefficients du filtre sont au nombre de NB_COEFF_B et leurs valeurs se trouvent dans le tableau b.
  3. prépare l'itération suivante en mettant à jour l'indice d'écriture.

Dans le codage, vous tiendrez compte du fait que le tableau memoireVk est circulaire et de taille MEMORYSIZE éléments pour la mise à jour des indices de lecture et d'écriture.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Tester votre fonction à l'aide du filtre dont les coefficients sont définis dans le tableau coeffB du fichier tparchi1.cpp.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Vérifier l'exactitude des réponses impulsionnelles et indicielles pour le filtre fourni jusque $k=6$.

homepages.laas.fr_bvandepo_files_iut_tp_tns_bonus.jpg Appliquer ce filtre à deux sinusoïdes de fréquence 50 Hz et 500 Hz. Expliquez le résultat en vous aidant du module de la fonction de transfert.

Codage de l'équation de récurrence pour un filtre à réponse impulsionnelle infinie (RII)

On cherche maintenant à implémenter l'équation: $s_k=\sum_{i=0}^{N}b_i.e_{k-i}-\sum_{j=1}^{M}a_j.s_{k-j}$.

Pour cela, nous utiliserons la forme vue en cours: $s_k=\sum_{i=0}^{N}b_i.v_{k-i}$ faisant intervenir les termes $v_k$. Pour l'échantillon $k$, il est nécessaire d'évaluer la valeur de $v_k=e_k-\sum_{j=1}^{M}a_j.v_{k-j}$ qui utilise les valeurs des $v_k$ précédemment calculés.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Compléter la fonction double filtreUnEchantillon(double ek) pour qu'elle permette de gérer ce type de filtre. Pour cela, vous y ajouterez avant le calcul de $s_k$:

  1. le calcul de $v_k$ à partir des valeurs précédentes de $v_k$ stockées dans le tableau memoireVk. Vous utiliserez le même principe que pour le calcul de $s_k$ réalisé pour le filtre RIF. Les coefficients du filtre à utiliser sont au nombre de NB_COEFF_A et sont situés dans le tableau a.
  2. l'enregistrement du $v_k$ calculé dans le tableau memoireVk, qui remplacera l'enregistrement de $e_k$.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Tester l'implémentation de la fonction de calcul sur le filtre.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Déclarer les variables nécessaires pour ajouter un second filtre d'équation de récurrence: $ s_k=e_k+0.3s_{k-7} $

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Calculer les réponses impulsionnelles et indicielles en utilisant la fonction calculReponseFiltreEnLigne et ajouter le code permettant de les afficher. Superposer l'affichage du module de la fonction de transfert de ce filtre à l'affichage précédent.

TP2 Simulation des convertisseurs

Fonctions simulant les convertisseurs

Dans la démarche qui consiste à se rapprocher des conditions réelles dans lesquelles la fonction FiltreUnEchantillon sera utilisée, nous souhaitons maintenant intégrer les convertisseurs dans la chaîne de traitement en les simulant par des fonctions:

  1. simuADC dont le rôle est de convertir un nombre représentant une tension en une valeur numérique quantifiée.
  2. 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 à FiltreUnEchantillon.

Les fonctions simuADC et simuDAC sont définies dans les fichiers convertisseurs.cpp et .h que vous devez créer dans votre projet ​(Nouveau Fichier → C++ → source ou entête) et dans lesquels vous copier/collerez le contenu suivant:

convertisseurs.h
double SimuADC ( double Ve, double Vmin, double Vmax, int nbBits);
double SimuDAC ( double M, double Vmin, double Vmax, int nbBits);
convertisseurs.cpp
#include <math.h>
/*!
 * \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 (Ve<Vmin)
        ekQuant = 0;
    else if (Ve>Vmax)
        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<<nbBits)) );
 
 
}

Ajout des convertisseurs dans la fonction calculReponseFiltreEnLigne()

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 calculReponseFiltreEnLigne(). Déclarez vmin, vmax, nbbits comme constantes globales.

  1. Reprenez le fichier filtre.cpp et intégrez dans la fonction calculReponseFiltreEnLigne l'appel de ces 2 fonctions (dynamique 0/3,3V , 8 bits) pour les utiliser avec la fonction filtreUnEchantillon:
    1. appeler simuADC et stocker sa valeur de retour dans une variable du bon type.
    2. appeler filtreUnEchantillon en lui fournissant en paramètre la variable précédemment calculée.
    3. appeler simuDAC en lui fournissant la valeur fournie par filtreUnEchantillon et ranger la valeur de sortie de simuDAC dans le tableau sk.
  2. Vérifier le bon fonctionnement des 2 filtres du TP1. Expliquez l'amplitude de la réponse impulsionnelle du filtre RIF.

Prise en compte de l'offset numérique des échantillons

  1. Tester à nouveau le fonctionnement de calculReponseFiltreEnLigne() sur le filtre passe-bande 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};
    1. Que constatez-vous ?
  2. Ce phénomène est provoqué par l'offset numérique de ek_quant (sa valeur de repos est différente de 0). Modifiez filtreUnEchantillon() pour respecter le schéma de la P11 du cours.
    1. 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. Vérifiez que le fonctionnement du filtre est maintenant correct.
    2. 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

  1. Définissez le nouveau filtre $s_k=2e_k$
    1. Tracez sa réponse indicielle. Quel problème constatez-vous ?
  2. 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 filtreUnEchantillon())
    1. Testez le bon fonctionnement de l'ensemble sur la sinusoïde
tptns2017.txt · Dernière modification: 2017/03/15 16:15 par hgilliard