Cours:Elen4 TNS TP TpsReel : Différence entre versions
(→Compilation et installation) |
|||
| (8 révisions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 2 : | Ligne 2 : | ||
<center> | <center> | ||
| − | '''<big>TP6 : Temps réel : Codage d'un bloc en C++ / démodulation | + | '''<big>TP6 : Temps réel : Codage d'un bloc en C++ / démodulation </big>''' |
</center> | </center> | ||
| − | Le but de ce TP est de réaliser l'implémentation temps-réel en C++ de filtres IIR. | + | Le but de ce TP est de réaliser l'implémentation temps-réel en C++ de filtres IIR. Cette implémentation sera réalisée en créant un bloc Gnuradio qui execute un traitement codé en C++ |
=== Codage de bloc Gnuradio en c++ === | === Codage de bloc Gnuradio en c++ === | ||
| − | |||
| − | |||
Ce guide est inspirée du guide [https://wiki.gnuradio.org/index.php?title=Creating_C%2B%2B_OOT_with_gr-modtool Creating an OOT (C++ block example)] en l'adaptant pour nos besoins : | Ce guide est inspirée du guide [https://wiki.gnuradio.org/index.php?title=Creating_C%2B%2B_OOT_with_gr-modtool Creating an OOT (C++ block example)] en l'adaptant pour nos besoins : | ||
| Ligne 19 : | Ligne 17 : | ||
* Vous pourrez utiliser <code>gedit</code> pour éditer les divers fichiers. | * Vous pourrez utiliser <code>gedit</code> pour éditer les divers fichiers. | ||
| − | + | ==== Création d'un module externe ==== | |
Dans les lignes qui suivent, le <code>$</code> indique que l'on saisi une commande dans un terminal. Le <code>$</code> n'est pas à saisir. | Dans les lignes qui suivent, le <code>$</code> indique que l'on saisi une commande dans un terminal. Le <code>$</code> n'est pas à saisir. | ||
| Ligne 45 : | Ligne 43 : | ||
</source> | </source> | ||
| − | + | ==== Création d'un bloc dans ce module ==== | |
* Ajoutez un nouveau bloc nommé <code>passetout</code> : | * Ajoutez un nouveau bloc nommé <code>passetout</code> : | ||
| Ligne 96 : | Ligne 94 : | ||
* Le tout sera compilé par un <code>Makefile</code> généré par <code>cmake</code>. | * Le tout sera compilé par un <code>Makefile</code> généré par <code>cmake</code>. | ||
| − | + | ==== Fichier <code>passetout_impl.h</code> ==== | |
Le code utile généré est le suivant : | Le code utile généré est le suivant : | ||
| Ligne 123 : | Ligne 121 : | ||
Le travail sera réalisé dans la méthode <code>work()</code>, mais nous n'avons pas de modification à apporter dans les déclarations par défaut. | Le travail sera réalisé dans la méthode <code>work()</code>, mais nous n'avons pas de modification à apporter dans les déclarations par défaut. | ||
| − | + | ==== Fichier <code>passetout_impl.cc</code> ==== | |
| + | |||
Le code utile généré est le suivant : | Le code utile généré est le suivant : | ||
| Ligne 192 : | Ligne 191 : | ||
</source> | </source> | ||
| − | {{Todos| On spécifie ici le nombre d' | + | {{Todos| On spécifie ici le nombre d'entrées (1) et le nombre de sorties (1). Pas de modification non plus.}} |
{{Todos| Expliquez la syntaxe <code>passetout_impl::passetout_impl() : gr::sync_block(...)"</code> }} | {{Todos| Expliquez la syntaxe <code>passetout_impl::passetout_impl() : gr::sync_block(...)"</code> }} | ||
| Ligne 220 : | Ligne 219 : | ||
# changer <code>return noutput_items;</code> en <code>return 1;</code> (un seul échantillon a été consommé). | # changer <code>return noutput_items;</code> en <code>return 1;</code> (un seul échantillon a été consommé). | ||
| − | + | ==== Fichier <code>monModule_passetout.block.yml</code> ==== | |
Ce fichier au format YAML (''yet another markup language'') fait le lien entre le code c++ et le code python utilisé en interne par GnuRadio. | Ce fichier au format YAML (''yet another markup language'') fait le lien entre le code c++ et le code python utilisé en interne par GnuRadio. | ||
| Ligne 290 : | Ligne 289 : | ||
<source lang=yaml> | <source lang=yaml> | ||
inputs: | inputs: | ||
| − | - label: | + | - label: in |
domain: stream | domain: stream | ||
dtype: float | dtype: float | ||
| Ligne 299 : | Ligne 298 : | ||
<source lang=yaml> | <source lang=yaml> | ||
outputs: | outputs: | ||
| − | - label: | + | - label: out |
domain: stream | domain: stream | ||
dtype: float | dtype: float | ||
</source> | </source> | ||
| − | + | ==== Compilation et installation ==== | |
Voici les étapes : | Voici les étapes : | ||
| Ligne 322 : | Ligne 321 : | ||
{{Todos| Exécuter chacune de ces lignes, en contrôlant l'absence d'erreur. Dans le cas contraire, contrôler les fichiers <code>.h</code>, <code>.cc</code> et <code>.yaml</code>}} | {{Todos| Exécuter chacune de ces lignes, en contrôlant l'absence d'erreur. Dans le cas contraire, contrôler les fichiers <code>.h</code>, <code>.cc</code> et <code>.yaml</code>}} | ||
| − | ===== Utilisation du bloc et test | + | {{Todos| '''Après ces étapes, et avant de lancer gnuRadio, appeler l'enseignant qui va mettre à jours les bibliothèques partagées.'''}}. Sinon tenter : |
| + | <source> | ||
| + | $ export LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH | ||
| + | $ gnuradio-companion & | ||
| + | </source> | ||
| + | |||
| + | ==== Utilisation du bloc et test ==== | ||
| − | * Dans | + | * Dans Gnuradio, rafraichir la liste des bloc (bouton ''reload'') |
* le bloc <code>passetout</code> doit être présent dans la section <code>monModule</code> | * le bloc <code>passetout</code> doit être présent dans la section <code>monModule</code> | ||
* Tester le bon fonctionnement de ce bloc en lui envoyant une sinusoïde que vous devez observer identique à la sortie du bloc. Vérifier avec des graphes. | * Tester le bon fonctionnement de ce bloc en lui envoyant une sinusoïde que vous devez observer identique à la sortie du bloc. Vérifier avec des graphes. | ||
| − | === | + | === Démodulation === |
| + | |||
| + | En reprenant le signal modulé en amplitude et la fonction de transfert du filtre passe-bas du TP précédent : | ||
| − | = | + | * Obtenir l'équation aux différence du filtre, ''ie'' écrire ''y(n)='' en fonction de ''x(n)'', ''x(n-1)'', ''x(n-2)'', ''y(n-1)'' et ''y(n-2)''. |
| + | * Créer un nouveau bloc C++ (similaire au passe-tout précédent) dans le module <code>monModule</code> : | ||
| + | ** de type <code>sync</code> | ||
| + | ** une entrée en <code>float</code> | ||
| + | ** une sortie en <code>float</code> | ||
| + | * Écrire le code permettant d'obtenir ''y(n)'' dans la méthode <code>work()</code> : | ||
| + | ** ''x(n)'' est donné par <code>in0[0]</code> | ||
| + | ** il sera nécessaire d'affecter <code>out0[0]</code> pour produire ''y(n)''. | ||
| + | ** il sera nécessaire de stocker dans des '''attributs''' les valeurs de <code>in[0]</code> afin de disposer de ''x(n-1)'', ''x(n-2)'', ''y(n-1)'' et ''y(n-2)''. | ||
| + | ** On rappelle que les attributs doivent être déclarées dans le fichier <code>.h</code> et initialisés dans le constructeur de la classe. | ||
| + | |||
| + | {{Todos| Réaliser cette implémentation du passe-bas et contrôler que la démodulation est identique à celle obtenue au TP précédent}} | ||
| + | |||
| + | {{Todos| Modifier votre code pour implémenter le filtre complet de démodulation}} | ||
Version actuelle datée du 2 avril 2023 à 11:43
TP6 : Temps réel : Codage d'un bloc en C++ / démodulation
Le but de ce TP est de réaliser l'implémentation temps-réel en C++ de filtres IIR. Cette implémentation sera réalisée en créant un bloc Gnuradio qui execute un traitement codé en C++
Sommaire
[masquer]Codage de bloc Gnuradio en c++
Ce guide est inspirée du guide Creating an OOT (C++ block example) en l'adaptant pour nos besoins :
Nous allons créer un simple bloc qui recopie son entrée (en float) sur sa sortie. Donc le filtre caractérisé par y(n) = x(n) ou encore H(z)=1. Il s'agit donc d'une sorte de filtre passe-tout.
Suivez bien toutes les étapes, sans aller trop rapidement
- Vous pourrez utiliser
geditpour éditer les divers fichiers.
Création d'un module externe
Dans les lignes qui suivent, le $ indique que l'on saisi une commande dans un terminal. Le $ n'est pas à saisir.
- Ouvrez un terminal et placez-vous à la racine de votre dossier personnel :
$ cd $HOME- Créez un dossier de travail dédié à gnuradio et déplacez-vous à l'intérieur :
$ mkdir gnuradio
$ cd gnuradio- GNU Radio est livré avec gr_modtool, un utilitaire qui permet de créer des modules externes (OOT). Créons un module
monModule
$ gr_modtool newmod monModule- Le dossier
gr-monModuleest créé et contient tout le code squelette d'un module OOT, mais il n'a pas encore de blocs. Déplacez-vous dansgr-monModule:
$ cd gr-monModule- Vous pouvez afficher le contenu de ce dossier par
$ lsCréation d'un bloc dans ce module
- Ajoutez un nouveau bloc nommé
passetout:
$ gr_modtool add passetout- Quelques questions permettent alors de spécifier le type de bloc
GNU Radio module name identified: passetout
('sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock')Saisissez sync comme type de bloc, car le bloc que nous écrivons produira le même nombre d'échantillons en sortie que le nombre d'échantillons consommés depuis l'entrée.
Enter block type: sync- Spécifiez
cppcomme langage :
Language (python/cpp): cpp
Language: C++
Block/code identifier: passetout- Spécifiez un nom pour le copyright :
Please specify the copyright holder: Bibi- Il est possible de spécifier des paramètres d'entrée qui peuvent permettre de régler le fonctionnement du bloc. Ce ne sera pas notre cas, ne rien saisir sur cette question :
Enter valid argument list, including default arguments:- De même, on ne donnera pas de code permettant de tester le bon fonctionnement :
Add Python QA code? [Y/n] n
Add C++ QA code? [Y/n] n- Plusieurs fichers sont alors crées :
Adding file 'lib/passetout_impl.h'...
Adding file 'lib/passetout_impl.cc'...
Adding file 'include/gnuradio/monModule/passetout.h'...
Adding file 'python/monModule/bindings/docstrings/passetout_pydoc_template.h'...
Adding file 'python/monModule/bindings/passetout_python.cc'...
Adding file 'grc/monModule_passetout.block.yml'...
Editing grc/CMakeLists.txt...Quelques indications :
- le fichier
passetout_impl.hcontient l'entête de la classe de notre bloc - le fichier
passetout_impl.cccontient l'implémentation de la classe de notre bloc - le fichier
monModule_passetout.block.ymlva contenir des informations faisant le lien entre notre code c++ et le code python utilisé en interne par Gnuradio - Le tout sera compilé par un
Makefilegénéré parcmake.
Fichier passetout_impl.h
Le code utile généré est le suivant :
class passetout_impl : public passetout
{
private:
// Nothing to declare in this block.
public:
passetout_impl();
~passetout_impl();
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items);
};
Pour se réveiller les neurones sur la POO, qu'est-ce que sont
-
passetout_impl(), -
~passetout_impl(), -
private,public?
Le travail sera réalisé dans la méthode work(), mais nous n'avons pas de modification à apporter dans les déclarations par défaut.
Fichier passetout_impl.cc
Le code utile généré est le suivant :
passetout_impl.cc
Détaillons :
#pragma message("set the following appropriately and remove this warning")
using input_type = float;
#pragma message("set the following appropriately and remove this warning")
using output_type = float;
On spécifie ici le type des données d'entrée et de sortie. Pas de modification à apporter, il suffit de supprimer les deux #pragma
passetout_impl::passetout_impl()
: gr::sync_block("passetout",
gr::io_signature::make(
1 /* min inputs */, 1 /* max inputs */, sizeof(input_type)),
gr::io_signature::make(
1 /* min outputs */, 1 /*max outputs */, sizeof(output_type)))
{
}
On spécifie ici le nombre d'entrées (1) et le nombre de sorties (1). Pas de modification non plus.
Expliquez la syntaxe passetout_impl::passetout_impl() : gr::sync_block(...)"
int passetout_impl::work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
auto in = static_cast<const input_type*>(input_items[0]);
auto out = static_cast<output_type*>(output_items[0]);
#pragma message("Implement the signal processing in your block and remove this warning")
// Do <+signal processing+>
// Tell runtime system how many output items we produced.
return noutput_items;
}
Cette méthode work() implémente véritablement le filtrage.
- Les tableaux
inetoutcontiennent respectivement les données en entrée et les données en sortie. Il faut donc calculerouten fonction dein - Les données d'entrée arrivent par paquets dans un buffer. La variable
noutput_itemscontient le nombre de données disponibles en entrées. - à la fin de la méthode, on renvoie le nombre de données en sortie que l'on a calculé (entre 1 et
noutput_items). Les données d'entrées éventuellement non consommées seront conservées dans le buffer pour le prochain appel dework()
On souhaite ici seulement recopier l'entrée sur la sortie, donc
- Enlever la ligne
#pragma - ajouter le code
out[0] = in[0];(on recopie le premier échantillon disponible en entrée) - changer
return noutput_items;enreturn 1;(un seul échantillon a été consommé).
Fichier monModule_passetout.block.yml
Ce fichier au format YAML (yet another markup language) fait le lien entre le code c++ et le code python utilisé en interne par GnuRadio.
monModule_passetout.block.yml
Mettre à jour la section parameters (pas de paramètres, on commente) :
#parameters:
#- id: parametername_replace_me
# label: FIX ME:
# dtype: string
# default: You need to fill in your grc/customModule_testMod.block.yaml
Mettre à jour la section inputs :
inputs:
- label: in
domain: stream
dtype: float
Mettre à jour la section output :
outputs:
- label: out
domain: stream
dtype: float
Compilation et installation
Voici les étapes :
$ cd CHEMIN-DE-VOTRE-DOSSIER/gr-monModule
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install
-
cmake ..lance la création des fichiersMakefilequi permettent la compilation et l'installation -
makelance la compilation -
make installlance l'installation (copie des fichiers dans les dossiers gnuradio)
Exécuter chacune de ces lignes, en contrôlant l'absence d'erreur. Dans le cas contraire, contrôler les fichiers .h, .cc et .yaml
Après ces étapes, et avant de lancer gnuRadio, appeler l'enseignant qui va mettre à jours les bibliothèques partagées.. Sinon tenter :
$ export LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
$ gnuradio-companion &Utilisation du bloc et test
- Dans Gnuradio, rafraichir la liste des bloc (bouton reload)
- le bloc
passetoutdoit être présent dans la sectionmonModule - Tester le bon fonctionnement de ce bloc en lui envoyant une sinusoïde que vous devez observer identique à la sortie du bloc. Vérifier avec des graphes.
Démodulation
En reprenant le signal modulé en amplitude et la fonction de transfert du filtre passe-bas du TP précédent :
- Obtenir l'équation aux différence du filtre, ie écrire y(n)= en fonction de x(n), x(n-1), x(n-2), y(n-1) et y(n-2).
- Créer un nouveau bloc C++ (similaire au passe-tout précédent) dans le module
monModule:- de type
sync - une entrée en
float - une sortie en
float
- de type
- Écrire le code permettant d'obtenir y(n) dans la méthode
work():- x(n) est donné par
in0[0] - il sera nécessaire d'affecter
out0[0]pour produire y(n). - il sera nécessaire de stocker dans des attributs les valeurs de
in[0]afin de disposer de x(n-1), x(n-2), y(n-1) et y(n-2). - On rappelle que les attributs doivent être déclarées dans le fichier
.het initialisés dans le constructeur de la classe.
- x(n) est donné par
Réaliser cette implémentation du passe-bas et contrôler que la démodulation est identique à celle obtenue au TP précédent
Modifier votre code pour implémenter le filtre complet de démodulation