Cours:Elen4 TNS TP TpsReel : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(Fichier monModule_passetout.block.yml)
(Compilation et installation)
Ligne 306 : Ligne 306 :
 
===== Compilation et installation =====
 
===== Compilation et installation =====
  
 +
Voici les étapes :
 
<source lang=bash>
 
<source lang=bash>
 
$ cd CHEMIN-DE-VOTRE-DOSSIER/gr-monModule
 
$ cd CHEMIN-DE-VOTRE-DOSSIER/gr-monModule
Ligne 314 : Ligne 315 :
 
$ make install
 
$ make install
 
</source>
 
</source>
 +
 +
* <code>cmake ..</code> lance la création des fichiers <code>Makefile</code> qui permettent la compilation et l'installation
 +
* <code>make</code> lance la compilation
 +
* <code>make install</code> lance l'installation (copie des fichiers dans les dossiers gnuradio)
 +
 +
{{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 =====
  
 
* Dans GRC, rafraichir la liste des bloc (bouton ''reload'')
 
* Dans GRC, rafraichir la liste des bloc (bouton ''reload'')

Version du 28 mars 2023 à 11:23

Retour à la page du cours

TP6 : Temps réel : Codage d'un bloc en C++ / démodulation et PID numérique

Le but de ce TP est de réaliser l'implémentation temps-réel en C++ de filtres IIR.

Codage de bloc Gnuradio en c++

Première partie - guide de création d'un bloc 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 gedit pour é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-monModule est créé et contient tout le code squelette d'un module OOT, mais il n'a pas encore de blocs. Déplacez-vous dans gr-monModule :
$ cd gr-monModule
  • Vous pouvez afficher le contenu de ce dossier par
$ ls
Cré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 cpp comme 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.h contient l'entête de la classe de notre bloc
  • le fichier passetout_impl.cc contient l'implémentation de la classe de notre bloc
  • le fichier monModule_passetout.block.yml va 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 Makefile généré par cmake.
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

namespace monModule {

#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;
passetout::sptr passetout::make() { return gnuradio::make_block_sptr<passetout_impl>(); }


/*
 * The private constructor
 */
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)))
{
}

/*
 * Our virtual destructor.
 */
passetout_impl::~passetout_impl() {}

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;
}

} /* namespace monModule */

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;

    Todos.png 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)))
{
}

    Todos.png On spécifie ici le nombre d'entrée (1) et le nombre de sorties (1). Pas de modification non plus.

    Todos.png 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 in et out contiennent respectivement les données en entrée et les données en sortie. Il faut donc calculer out en fonction de in
  • Les données d'entrée arrivent par paquets dans un buffer. La variable noutput_items contient 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 de work()

    Todos.png On souhaite ici seulement recopier l'entrée sur la sortie, donc

  1. Enlever la ligne #pragma
  2. ajouter le code out[0] = in[0]; (on recopie le premier échantillon disponible en entrée)
  3. changer return noutput_items; en return 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

id: monModule_passetout
label: passetout
category: '[monModule]'

templates:
  imports: from gnuradio import monModule
  make: monModule.passetout()

#  Make one 'parameters' list entry for every parameter you want settable from the GUI.
#     Keys include:
#     * id (makes the value accessible as keyname, e.g. in the make entry)
#     * label (label shown in the GUI)
#     * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#     * default
parameters:
- id: parametername_replace_me
  label: FIX ME:
  dtype: string
  default: You need to fill in your grc/monModule_passetout.block.yaml
#- id: ...
#  label: ...
#  dtype: ...

#  Make one 'inputs' list entry per input and one 'outputs' list entry per output.
#  Keys include:
#      * label (an identifier for the GUI)
#      * domain (optional - stream or message. Default is stream)
#      * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#      * vlen (optional - data stream vector length. Default is 1)
#      * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
#- label: ...
#  domain: ...
#  dtype: ...
#  vlen: ...
#  optional: ...

outputs:
#- label: ...
#  domain: ...
#  dtype: ...
#  vlen: ...
#  optional: ...

#  'file_format' specifies the version of the GRC yml format used in the file
#  and should usually not be changed.
file_format: 1

    Todos.png 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

    Todos.png Mettre à jour la section inputs :

inputs:
- label: in0
  domain: stream
  dtype: float

    Todos.png Mettre à jour la section output :

outputs:
- label: out0
  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 fichiers Makefile qui permettent la compilation et l'installation
  • make lance la compilation
  • make install lance l'installation (copie des fichiers dans les dossiers gnuradio)

    Todos.png 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

Utilisation du bloc et test
  • Dans GRC, rafraichir la liste des bloc (bouton reload)
  • le bloc passetout doit être présent dans la section monModule
  • 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.

Seconde partie - codage d'un filtre RII

Démodulation