<figure><img src="image_1.png" /></figure>

HAL
open science

# Passage en production et diffusion du logiciel StreamPU sur le python package index

Flavien Romanetti

► To cite this version:

Flavien Romanetti. Passage en production et diffusion du logiciel StreamPU sur le python package index. Informatique [cs]. 2025. hal-05311915

HAL Id: hal-05311915

https://inria.hal.science/hal-05311915v1

Submitted on 13 Oct 2025

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_2.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
# Rapport Technique de Stage

## Passage en production et diffusion du logiciel StreamPU sur le
python package index

### Auteur :

ROMANETTI Flavien

### Maître de stage :

AUMAGE Olivier

### Rapporteur :

TAJAN Romain
# Table des matières

<table><tr><td>1 Introduction</td><td>3</td></tr><tr><td>2 PyStreamPU – Interface de programmation en langage de haut niveau</td><td>5</td></tr><tr><td>2.1 Contexte initial : l'interface C++ StreamPU)</td><td>5</td></tr><tr><td>2.2 Construction d'une interface de programmation Python au-dessus de l'API C++ à l'aide de Pybind11</td><td>6</td></tr><tr><td>2.3 Éléments d'implémentation</td><td>6</td></tr><tr><td>3 Déploiement sur l'archive publique PyPI.org</td><td>8</td></tr><tr><td>3.1 Construction d'un paquet importable dans un programme Python</td><td>8</td></tr><tr><td>3.2 Pipelines de construction automatique sur l'environnement GitLab</td><td>8</td></tr><tr><td>3.3 Job de déploiement</td><td>9</td></tr><tr><td>4 Mise en pratique sur le protocole de surveillance de l'aviation civile ADS-B</td><td>10</td></tr><tr><td>4.1 Modules utilisateurs</td><td>10</td></tr><tr><td>4.2 Message ADS-B</td><td>10</td></tr><tr><td>4.3 Chaîne de traitement</td><td>12</td></tr><tr><td>4.4 Evaluation</td><td>14</td></tr><tr><td>4.5 Discussion</td><td>15</td></tr><tr><td>5 Conclusion</td><td>16</td></tr></table>

# Table des figures

<table><tr><td>1 Diagramme UML simplifié</td><td>5</td></tr><tr><td>2 Exemple de Séquence</td><td>6</td></tr><tr><td>3 Extrait de l'arborescence du dossier Module dans src/ avant l'ajout de Stateful</td><td>7</td></tr><tr><td>4 Extrait de l'arborescence du dossier Module dans src/ après l'ajout de Stateful</td><td>7</td></tr><tr><td>5 Exemple de Pipeline</td><td>9</td></tr><tr><td>6 StreamPU sur test PyPI</td><td>10</td></tr><tr><td>7 trame ADS-B</td><td>11</td></tr><tr><td>8 Capture d'écran du site FlightRadar24</td><td>11</td></tr><tr><td>9 Début de la chaîne de traitement, démodulation de message ADS-B</td><td>12</td></tr><tr><td>10 Fin de la chaîne de traitement, décodage de message ADS-B</td><td>13</td></tr><tr><td>11 Résultat sur le terminal de l'exécution de la petite chaîne</td><td>14</td></tr><tr><td>12 Résultat affiché sur le terminal du test du décodage</td><td>14</td></tr><tr><td>13 Résultat affiché sur le terminal du test portant sur le module Filtre CCR</td><td>15</td></tr><tr><td>14 Résultat affiché sur le terminal du test portant sur le module Filtre RRR</td><td>15</td></tr></table>
# Résumé

Ce rapport présente les étapes réalisées pour faciliter l'utilisation de StreamPU, une librairie C++ d'ordonnancement de tâches, via une interface Python : PyStreamPU. L'objectif est de combiner la performance du C++ avec la simplicité de Python, tout en permettant un déploiement sur l'archive officielle de Python pour une installation plus propre.

Trois étapes principales ont été abordées : la mise à jour du projet interface PyStreamPU pour suivre les versions de StreamPU, le déploiement du projet sur un dépôt nommé PyPI, et l'utilisation en pratique de l'interface en développant une chaîne de traitement.

PyStreamPU répond au besoin initial en offrant une interface de haut niveau pour StreamPU, mais des travaux complémentaires sont nécessaires pour finaliser le déploiement, optimiser les performances et étendre la compatibilité. Ce projet illustre l'intérêt des interfaces (C++/Python) pour les outils scientifiques, où flexibilité et efficacité sont crucales.

# 1 Introduction

Dans les années 1990, l'idée de radio logicielle naît, composée de seulement trois éléments, une antenne, un convertisseur analogique-numérique et un processeur pour le traitement numérique. Ce dispositif se distingue des radios traditionnelles en étant configurable et paramétrable pour différents traitements. Une radio traditionnelle est composée de cartes physiques dédiées, permettant une vi- tesse de calcul accrue. Cependant, modifier un circuit physique dédié pour traiter une autre tâche est impossible. L'intérêt de la radio logicielle réside dans sa flexibilité et sa facilité d'utilisation.

AFF3CT[1] est un ensemble de module développé en C++ porté vers le traitement du signal. Cette application est principalement destinée à des utilisateurs voulant tester leur algorithme de communication numérique, comme des chercheurs. En 2016 la première version d'AFF3CT est pu- bliée en collaboration avec notamment l'Université de Sorbonne, l'IMS[9], et l'équipe STORM[11] de l'Inria. J'ai effectué mon stage dans cette même équipe à l'Inria, un centre de recherche sur l'informatique et les mathématiques situé à Bordeaux. L'Inria se divise en plusieurs équipes tra- vaillant dans un domaine spécifique. L'équipe STORM est spécialisée dans la recherche en HPC (High Performance Calculation, Calcul de Haute Performance).

La technologie de parallélisme de tâches d'AFF3CT a été séparée de ce dernier et développée sous une libraire nommée StreamPU[7]. AFF3CT est utilisé tant pour la simulation que pour traiter des signaux réels. La principale contrainte de cette application repose sur la vitesse d'exécution soit avec le debit pour la simulation, soit avec la latence pour le traitement en temps réel. Le langage compilé C++ répondait à cette exigence. Néanmoins ce langage de programmation est complexe à utiliser et peut être difficile à prendre en main. Des langages de plus haut niveau comme MATLAB ou python sont préférés par des chercheurs en traitement du signal.

En effet, Python est un langage de haut niveau, un des plus répandu au monde. Ce langage est intuitif et très facile à utiliser avec une abstraction importante. Pouvoir profiter de la facilité d'utilisation de python et de la rapidité de calcul du C++ présente un sérieux avantage dans le développement d'outils de traitement du signal.

Comment permettre l'utilisation et l'installation de StreamPU en alliant prise en main intuitive et rapidité d'exécution ? Grâce à la libraire pybind11[12], on peut lier C++ et python en exposant les types d'un langage à l'autre. Cela nous permet de développer des classes en C++ pour les
instancier en python et d'utiliser leurs méthodes. Le projet liant l'outil StreamPU (C++) à python s'appelle PyStreamPU.

Python possède d'autres avantages, sa manière de déployer et d'importer des librairies permet une installation rapide et simple. En déployant une librairie sur un dépôt et en l'installant avec la commande "pip". Ce dépôt s'appelle PyPI[5] (Python Package Index), il est l'archive officiel du langage de programmation python, permettant de librement déployer son projet parmi un catalogue de paquets.

AFF3CT et StreamPU sont construits sur la faculté de développer ses propres codes et algorithmes. Ainsi permettre à StreamPU, et par extension PyStreamPU, d'être modulables est aussi un objectif dans sa facilité d'utilisation. C'est à dire, faire en sorte que l'utilisateur puisse ajouter et utiliser ses classes et fonctions parmi celles de StreamPU.

Mes tâches dans ce projet consisteront à terminer la liaison entre StreamPU et Python, de faire en sorte qu'il puisse être déployé sur PyPI, et développer une chaîne de démodulation pour montrer en pratique l'utilisation de StreamPU en python. Cette chaîne servira à décoder des messages ADS-B, messages automatiques émis par les avions pour connaître des informations comme sa positon.

Ainsi, dans une première section j'aborderai l'utilisation de pybind11 dans le développement de PyStreamPU, puis dans une deuxième section le déploiment du projet sur PyPI et dans une troisième section l'utilisation en pratique de StreamPU avec le décodage de message ADS-B.
# 2 PyStreamPU – Interface de programmation en langage de haut niveau

## 2.1 Contexte initial : l'interface C++ StreamPU)

L'application AFF3CT dépend désormais de StreamPU. Dans cette librairie est implémenté la logique de traitement des données et d'ordonnancement des tâches.

StreamPU repose sur des modules, des classes servant de contenaires pour des tâches et données. Un module peut être de deux types, Stateful, s'il contient des données internes, il va conserver des informations d'état au fur et à mesure de l'exécution de la chaîne, et Stateless, qui ne possède pas de données internes, absence d'état. Si l'utilisateur veut créer un module, il le fera hériter de l'une de ces classes (Stateful ou Stateless).

Les modules traitent des données successivement. Ainsi les tâches d'un module Stateless peuvent être répliquées pour traiter des trames en parallèle alors que ce mécanisme ne peut pas s'appliquer aussi facilement pour des modules Stateful.

<figure><img src="image_3.png" /><figcaption>FIGURE 1 – Diagramme UML simplifié</figcaption></figure>

Voici un diagramme UML pour illustrer l'héritage entre Module, Stateless, Stateful et d'autres classes. La majeure partie des classes implémentées héritent de Stateful, comme Incrementer, De- layer ou Source.

Chaque module contient au moins une tâche. La tâche représente le code exécuté dans le flux de données. Elle possède au moins une donnée d'entrée et une donnée de sortie. Les sockets modélisent ces données d'entrée et de sortie, en servant d'espace de stockage pour les données. Elles sont reliées d'une entrée à une sortie, d'une tâche à une autre. Un ensemble de module avec leur tâches reliées par des sockets forme une séquence.

Un module est défini par sa ou ses tâches, lesquelles sont définies par leur code à exécuter et leurs sockets.
<figure><img src="image_4.png" /><figcaption>FIGURE 2 – Exemple de Séquence</figcaption></figure>

Cette Séquence contient 5 modules, sous forme de boîte, et différentes sockets comme points d'entrées et de sorties des tâches contenu dans les modules.

## 2.2 Construction d'une interface de programmation Python au-dessus de l'API C++ à l'aide de Pybind11

Pybind11 s'inspire de Boost.Python, utilisé pour lier Python à C++. Cette bibliothèque open-source permet de créer des "bindings" pour exposer des classes, fonctions et types de C++ à python. Published in 2020, pybind11 a été largement adopté pour sa simplicité et ses performances. Elle possède donc une large communauté. De plus, pybind11 peut facilement être intégré à CMake.

Une des premières choses à faire pour exposer des éléments C++ est d'écrire des macros. C'est à dire un ou plusieurs fichiers C++ avec lesquels nous importons la bibliothèque que l'on veut exposer et `#include <pybind11/pybind11.h>`. Dans ces fichiers, nous explicitons quelles classes, fonctions et types nous voulons exposer.

Ensuite pendant la compilation, le préprocesseur C++ élargit ces macros en code C++ pur appelées wrappers. Par abus de langage dans la suite de ce rapport nous nommerons macros également wrap-pers. A la fin de la compilation nous obtenons une bibliothèque partagée sous un fichier de type `.so`. Nous pouvons alors importer ce fichier comme un module natif dans python.

Dans le projet PyStreamPU, les fichiers servant de wrapper pour StreamPU sont partagés entre les dossiers `include/` pour les headers `.cpp` et `src/` pour les fichiers source `.cpp`. Un dossier nommé `"streampu"` est également présent dans le projet, contenant notamment le fichier `__init__.py`. Ce fichier python permet une importation plus propre de streampu dans python, en effectuant des importations intermédiaires afin d'avoir une interface unifiée utilisable dans python. D'autres fichiers se trouvent dans le dossier `"streampu"` servant à la documentation, l'import et à l'ajout de code python. Chacun des modules développés se trouve sous la forme `_module.py` par exemple.

## 2.3 Éléments d'implémentation

StreamPU et PyStreamPU sont développés en parallèle, PyStreamPU dépend d'une certaine version de StreamPU. Une de mes premières tâches a été de mettre à jour PyStreamPU pour prendre en compte l'arrivée de Stateful.
**Organisation du code source** Ainsi pour être conforme à la structure du projet, j'ai ajouté le répertoire intermédiaire "Stateful" dans include/ et src/ pour y développer les fichiers Stateful.hpp et Stateful.cpp. La majorité des modules développés dans PyStreamPU sont considérés comme Stateful, il faut donc les faire hériter de cette classe et non plus de Module. Les fichiers gérants les includes doivent aussi être modifiés pour que les modules développés ne dépendent plus de la classe Module.

Pour compléter l'introduction de Stateful au projet, il ne faut pas oublier d'ajouter un fichier _stateful.py et préciser son import dans _init__.py .

<figure><img src="image_5.png" /><figcaption>FIGURE 3 – Extrait de l'arborescence du dossier Module dans src/ avant l'ajout de Stateful</figcaption></figure>

<figure><img src="image_6.png" /><figcaption>FIGURE 4 – Extrait de l'arborescence du dossier Module dans src/ après l'ajout de Stateful</figcaption></figure>

Voici un extrait de l'arborescence du dossier Module de src/ avant et après l'ajout de Stateful. Dans le premier cas, Stateless/ est présent au même niveau que Incrementer/ puis au même niveau que Stateful/ dans le deuxième cas. La structure est la même dans le fichier include/, hormis que les fichiers .cpp sont des fichiers header .ATICPP .

**Cas particulier des attributs et méthodes C++ protégées (protected)** Afin de vérifier le bon fonctionnement des modules et de Stateful, des tests sont mis en place. J'ai ajouté le test de Stateful, test_stateful.py, pour contrôler l'héritage du module par une classe python et son utilisation. J'ai également ajouté un test similaire pour stateless.

Lorsque j'ai testé Stateful, j'ai rencontré un problème au niveau de la protection des méthodes utilisées par Stateful. En C++, les membres d'une classe peuvent être privés (private), publiques (public) ou protégés (protected). Ces protections limitent ou non l'accès d'une méthode aux autres classes. Certaines méthodes de Module dont hérite Stateful étaient protégées, et certains attributs étaient privés. Pour le bon fonctionnement d'une classe héritant de Stateful en python, nous avions
besoin d'utiliser ces méthodes.

J'ai donc mis en place une classe intermédiaire Stateful.Publicist, à l'image de ce qui a été fait dans le reste du projet. Cette classe permet d'exposer des méthodes protégées/privées de Stateful héritées de Module. La classe _Publicist permet aussi d'ajouter des "getter" et "setter" afin de proprement accéder aux attributs d'une classe.

# 3 Déploiement sur l'archive publique PyPI.org

Créé au début des années 2020, PyPI (le Python Package Index) compte désormais, en 2024, plus de 500 000 paquets d'installation disponibles. Ce dépôt permet de déployer ses projets sous la forme de fichier d'archive "sdists" ou "wheels". Cet index sert à chercher et trouver facilement différents paquets pour les utilisateurs de Python.

En créant un environnement python, "python3 -m venv nom", un utilisateur peut utiliser la commande "pip" pour chercher un paquet sur le Python Package Index et l'installer, "pip install packet".

Nous voudrions donc pouvoir distribuer PyStreamPU en utilisant ce dépôt pour faciliter l'installation du projet, tout en faisant en sorte que ce déploiement soit automatique à chaque release de PyStreamPU.

## 3.1 Construction d'un paquet importable dans un programme Python

Afin d'obtenir une archive wheels déployable sur le Python Package Index, le projet que l'on veut déployer doit être compilé. Il est compilé tout d'abord comme un paquet .so importable depuis un programme Python. Trois outils sont utilisés pour la compilation et l'installation du projet :

* CMake[2] va permettre de gérer les dépendances C++ et les différents flags de compilation

* Ninja[3] va efficacement compiler la partie C++ du projet PyStreamPU

* scikit-build-core[6] va permettre d'intégrer Cmake dans pip via pyproject.toml.

CMake unifie la compilation de projet sous différent OS, CMake pour Cross-plateform Make. Ninja est créé pour répondre à un besoin de compilation rapide, les builds avec Make étaient trop lents et ne prenaient pas efficacement en compte la parallélisation. L'outil scikit-core-build fait suite à scikit-build publié en 2015 pour intégrer proprement CMake dans pip install.

CMake et Ninja sont utilisés, via le fichier CMakeLists.txt. Ce fichier permet aussi de préciser la position des fichiers qui doivent être compilés.

Le fichier .so peut directement être utilisé pour importer streampu dans python. Un fichier wheels contient notamment le ou les fichiers .so et les meta données. Les commandes nécessaires pour générer les fichiers wheels sont effectuées via un serveur distant.

## 3.2 Pipelines de construction automatique sur l'environnement GitLab

Pour développer StreamPU et PyStreamPU, un outil de suivi de version est utilisé, gitlab. Cet outil ou plus largement plateforme permet de placer des tests ou "Jobs", exécutés lorsque l'on souhaite push un commit ou merge vers la branche principale.
Ces différents Jobs forment des pipelines qui sont exécutés sur des machines distantes.

Mettre en place ces tests nous permet de vérifier que notre manière de coder respecte des standards, qu'il n'y a pas d'erreur de compilation et que l'on peut build le projet, et ainsi apporter les modifications commit au projet.

<figure><img src="image_7.png" /><figcaption>FIGURE 5 – Exemple de Pipeline</figcaption></figure>

Un des Jobs de cet Pipeline n'est pas passé après avoir commit une modification au projet. Exécuter ces pipelines prend une dizaine d'heures avant d'avoir le résultat du commit. Les Jobs comme l'installation qui prennent le plus de temps ne sont exécutés que lorsque l'on veut merge sur la branche "develop". C'est dans le fichier gitlab-ci.yml que l'on modifie le contenu des Jobs.

Un dernier Job vient s'ajouter à la pipeline pour construire les wheels. Isolé dans un docker pour un meilleur contrôle, la commande "cibuildwheel" est utilisée pour générer les fichiers wheels adaptées à une certaine plateforme, ici linux.

## 3.3 Job de déploiement

Afin de déployer le projet sur PyPI, il doit respecter une certaine structure[4].

<figure><img src="image_8.png" /></figure>

Voici l'arborescence de fichiers d'un exemple minimaliste de projet. Le fichier LICENSE précise les règles de copie du projet, pour StreamPU, la license est MIT, logicielles open-source. Le fichier pyproject.toml indique aux outils front-end, comme pip ou build, quel back-end utiliser pour le projet. C'est dans ce fichier que sont configurés les meta-data.

Maintenant que le fichier wheel est disponible, je vais pouvoir mettre au point un nouveau job afin de le déployer sur PyPI.

Après inscription sur la plateforme PyPI, on peut alors créer un token servant d'authentification et de sécurité pour déployer un projet spécifique. Dans le cadre de ce stage, une version de StreamPU a seulement été déployée sur "test PyPI". Cette instance fonctionne comme PyPI et permet d'essayer les outils et les processus de publication.

Grâce à la sous commande "twine" de python, je peux envoyer le fichier wheel sur le dépôt test PyPI en précisant comme username : _token_ et comme password le contenu du token.
python -m twine upload --repository-url https://test.pypi.org/legacy/ --verbose wheelhouse/* -u $TWINE_USERNAME -p $TWINE_PASSWORD

Ce Job n'est exécuté que lorsqu'une nouvelle version de PyStreamPU est publiée, cela correspond
sur gitlab à l'attribution d'un tag au commit.

<figure><img src="image_9.png" /><figcaption>FIGURE 6 – StreamPU sur test PyPI</figcaption></figure>

Une capture d'écran du site testpypi.org permet de vérifier la présence de streamPU sur le dépôt. Test PyPI étant une archive de test, les projets non mis à jour sont effacés, il se peut donc que StreamPU ne soit plus présent sur test PyPI.

# 4 Mise en pratique sur le protocole de surveillance de l'aviation civile ADS-B

## 4.1 Modules utilisateurs

AFF3CT et StreamPU se veulent modulaires. Ayant la possibilité d'ajouter des modules et classes fonctionnant et interagissant avec les modules propres déjà implémentés. Avec PyStreamPU, l'utilisateur peut ajouter de deux manières un module qui soit externe à StreamPU, en python, ou en C++. En python, moins d'étapes et de lignes de code sont nécessaires afin de créer un module. section 5

Il suffit, en Python, de créer une classe, de la faire hériter de Stateful ou Stateless et de lier une fonction à la tâche de ce module. Tandis qu'en C++, on doit initialiser en détail les sockets avant de spécifier leurs utilisations dans une fonction tâche. Puis un fichier wrapper doit être développé pour exposer les tâches et attributs de la fonction. En C++ aussi, un module hérite de Stateful ou Stateless.

Les modules C++ doivent être compilés, nous utilisons alors un fichier CMakeLists.txt afin d'obtenir un fichier.so importable dans le langage de programmation Python.

Nous pouvons ensuite, instancier et utiliser les modules créer en C++ ou en python de la même manière. Le choix de faire un module en python ou C++ dépend de l'efficacité voulue et la simplicité de mise en place du module. Ces choix sont faits par l'utilisateur.

## 4.2 Message ADS-B

J'ai utilisé cette notion de modularité pour développer différents modules afin de décodeur des messages ADS-B ou Automatic Dependent Surveillance - Broadcast [10]. Ce système de surveillance est mis en place pour que les avions transmettent régulièrement leurs positions, leurs altitudes, leurs vitesses, leurs indicatifs permettant de les identifier. Ce message est transmis vers les stations au sol et les autres avions à proximité.
<figure><img src="image_10.png" /><figcaption>FIGURE 7 – trame ADS-B</figcaption></figure>

Une trame ADS-B dure 120 micro secondes, avec un temps symbole de 1 micro seconde par bits. Afin de la décoder plusieurs étapes vont être nécessaires, une synchronisation temporelle grâce au préambule, une démodulation pour obtenir des bits à partir du signal réel, une vérification de l’intégrité de la trame avec le CRC (Code de Redondance Cyclique) et un décodage des bits en information [8].

Le signal reçu est un signal complexe. Dans un premier temps, afin de se synchroniser en temps et de repérer la trame, j'ai implémenté différents modules servant à calculer la corrélation du signal avec le préambule. Ensuite il faut démoduler le signal en le convoluant par le filtre adapté. Puis une fois qu'une séquence de bits est obtenue, il faut les associer et les convertir en information. Nous pouvons alors grâce aux coordonnées de l'avion, afficher sa position sur une carte.

<figure><img src="image_11.png" /><figcaption>FIGURE 8 – Capture d'écran du site FlightRadar24</figcaption></figure>
Voici une capture d'écran d'un site proposant de visualiser la position des avions sur une carte interactive en ligne. Les positions des avions sont issues des informations de vols transmis dans les messages ADS-B émis.

## 4.3 Chaîne de traitement

<figure><img src="image_12.png" /><figcaption>FIGURE 9 – Début de la chaîne de traitement, démodulation de message ADS-B</figcaption></figure>

Voici un diagramme représentant le début de la chaîne implémentée. Les différents modules et la taille du signal y sont représentés. F est le facteur de suréchantillonnage.

Les boîtes oranges sont différentes instanciations de la même classe. Cette classe a été développée
en C++ et correspond à un Filtre avec comme entrée un signal complexe, en sortie un signal complexe, et un noyau réel.

La boîte verte correspond à un module prenant la valeur absolue du signal au carré. Tandis que les boîtes bleues sont deux modules effectuant des tâches étroitement liées :

* La Sélection de la trame dans le signal en s'aidant de la valeur maximale de la corrélation

* L'extraction, en s'aidant d'un buffer, des échantillons exactes menant à une séquence de bits dans une prochaine tâche.

Le module Décision permet de passer d'un signal à deux échantillons par bit à une suite de bits.

<figure><img src="image_13.png" /><figcaption>FIGURE 10 – Fin de la chaîne de traitement, décodage de message ADS-B</figcaption></figure>

Voici la fin de la chaîne de traitement, cette partie correspond au décodage. Tout d'abord je réalise une vérification du CRC de la trame. J'effectue la division binaire de la trame, sans le CRC, par le polynome générateur du CRC-24 puis je compare le reste de cette division au CRC de la trame.

Une trame ADS-B donne soit l'information sur le nom du vol soit sur sa position, altitude, longitude, latitude. Nous pouvons savoir quelle sera l'information de la trame grâce à des bits d'indication après la fin du préambule. Un module nommé, non représenté ici, nommé switcher est utilisé permettant à la trame d'être traité par un module ou un autre, en fonction des infos qu'il contient. Le module switcher est aussi utilisé pour jeter les trames si le CRC est invalide.

Les différents petits modules nommés probe indiquent l'affichage d'une information sur le terminal.
## 4.4 Evaluation

J'ai implémenté différents tests afin de vérifier la partie démodulation et décodage de la chaîne. Mais aussi afin de vérifier les switchers et quelques modules spécifiques comme le Filtre.

Tout d'abord, j'ai testé StreamPU avec une petite chaîne permettant de moduler et de démoduler une suite de bits :

<figure><img src="image_14.png" /><figcaption>FIGURE 11 – Résultat sur le terminal de l'exécution de la petite chaîne</figcaption></figure>

La modulation utilisée est PPM pour Pulse Position Modulation où l'énergie du symbole est répartie au début de l'émission du symbole ou à la fin. Un bruit a été ajouté pour simuler un canal. L'entrée et la sortie de la chaîne sont identiques, la même suite de bits. Le test est concluant.

```
[[1]]
address : [[51 52 50 48 99 97]] | nom: [[0 0 0 0 0 0]] | longitude: [[-8.41925485]] | latitude: [[45.25245279]] | altitude: [[34950]]
[1]]
```

<caption>FIGURE 12 – Résultat affiché sur le terminal du test du décodage</caption>

Le test de décodage montre plusieurs lignes, ci-dessous un extrait. J'utilise un fichier .mat où sont stockées des suites de bits correspondant à des messages ADS-B. En s'aidant de ces suites de bits, je peux vérifier le module CRC et les modules suivant sans passer par une démodulation. L'adresse est affichée en ASCII (code représentant chaque symbole alphanumérique). Le "1" en haut
indique le résultat du module CRC, c'est à dire un CRC correcte, ce qui est attendu. Les valeurs retournées sont cohérentes.

<figure><img src="image_15.png" /><figcaption>FIGURE 13 – Résultat affiché sur le terminal du test portant sur le module Filtre CCR</figcaption></figure>

Le module Filtre CCR ou FIRFilter CCR, prend en entrée un signal complexe (C) et donne en retour un signal complexe (C), avec un noyau réel (R). Le résultat obtenu n'est pas correcte lors de la convolution du signal complexe "sig" avec le noyau réel "h". Ainsi la partie démodulation ne fonctionne pas, limité par le mauvais fonctionnement du filtre.

J'ai alors développé un module Fitler_RRR, pour un filtre prenant une entrée réelle (R), une sortie réelle (R) et un noyau réel (R).

<figure><img src="image_16.png" /><figcaption>FIGURE 14 – Résultat affiché sur le terminal du test portant sur le module Filtre RRR</figcaption></figure>

Le signal "sig" et le noyau "h" sont interprétés comme des signaux réels. Ainsi le résultat est correcte. En modifiant la chaîne pour prendre en compte un filtre RRR, en ajoutant une norme2 après la source notamment, la démodulation présente le même problème. L'intercorrélation calculée possède des valeurs supérieurs à 1, ce qui est impossible pour une intercorrélation. Cela limite alors l'extraction d'un message ADS-B.

## 4.5 Discussion

La chaîne de traitement implémentée n'est qu'une chaîne parmi d'autres. Le choix d'utiliser un module décimation s'est posé, mais a rencontré des limites avec la restriction de python dans l'utilisation des threads. Cette limitation est un verrou appelé GIL.

Un module décimation est un module effectuant un sous échantillonnage. Nous pouvons l'utiliser pour renvoyer autant de signaux en sortie que le facteur de sous échantillonnage. Si nous voulons sous échantillonner d'un facteur 2, nous trouverons 2 signaux en sortie. Ces signaux peuvent alors être traités en parallèle dans la suite de la chaîne.

Différentes parallélisations sont possibles :

* par pipeline, parallélisation sur le temps, chaque module travail en même temps mais sur un message différent

* par réplication, répartition des messages à être traités, comme une deuxième chaîne de traitement, notre cas si nous pouvions utiliser la décimation

Lorsque nous détectons une valeur maximal au dessus d'un seuil avec le signal intercorrélation, nous souhaitons alors extraire un signal de 2 fois 112 échantillons, ce qui peut être fait de plusieurs façons différentes. Ce maximum indique le début d'une trame et est rarement au début de la fenêtre du signal, ainsi nous ne pouvons pas traiter ce morceau de trame incomplet. La manière choisie pour
résoudre ce problème est d'utiliser un buffer de taille 2 fois 112 échantillons pour stocker une partie du signal. Cette partie stockée dans le buffer sera traitée avec la suite du signal.

# 5 Conclusion

Ce stage a permis d'atteindre trois objectifs ; Tout d'abord, d'intégrer la classe Stateful dans PyStreamPU, en modifiant les héritages des classes, en ajoutant des tests et en implémentant une classe intermédiaire Stateful.Publicist afin de résoudre des problèmes d'accessiblité aux méthodes ; Puis, de configurer le déploiement automatisé du projet sur test PyPI ; Enfin, de montrer la mise en pratique de StreamPU via une chaîne de traitement démodulant les messages ADS-B.

Toutefois, les messages ADS-B n'ont pas pu être correctement démodulés. Malgré que j'ai implémenté différents tests pour isoler et vérifier les modules susceptibles de ne pas fonctionner. Élaborer d'autres tests aurait été nécessaire pour trouver le problème qui amène à des valeurs incohérentes dans le signal d'intercorrélation.

Cependant, le projet PyStreamPU permet d'allier efficacité et simplicité d'utilisation grâce à l'abstraction d'étape dans l'utilisation de StreamPU via l'interface Python, tout en exploitant des outils de développement comme Pybind11, CMake, la CI Gitlab. Il reste néanmoins différents aspects à améliorer. Dans un premier temps de finir de déployer le projet sur PyPI au lieu de test PyPI. Puis d'écrire une documentation complète afin d'avoir une prise en main rapide et efficace. Mais aussi de permettre de prendre en compte d'autres types de variables comme les complexes pour étendre les applications possibles de StreamPU. Et enfin de développer une gestion des threads en C++ pour leur utilisation en python et lorsque ce langage de haut niveau le permettra de développer directement une gestion des threads. Cette modification rendra possible une utilisation de la décimation efficace en python.

# Remerciement

Je remercie tout particulièrement M AUMAGE Olivier et M TAJAN Romain pour leur enca-
drement et conseils, ainsi que les membres de l'équipe STORM.
Références

[1] AFF3CT : Github.

[2] Cmake. History.

[3] Ninja. github.

[4] Packaging python projects. lien.

[5] pypi. lien.

[6] scikit-build-core. github.

[7] Streampu. Documentation.

[8] Anthony Ghiotto Guillaume Ferré, Romain Tajan. Simulation d'un émetteur / récepteur ads-b et décodage temps réel à l'aide : de matlab, d'une radio logicielle et d'une antenne patch. lien.

[9] IMS. CSN.

[10] Cécilia Caamano Thomas Nieddu Léonard Cottin Léa Segaert, Léa Volpin. Optimisations de la réception de trames ads-b en temps réel. Projet Avancé, année 2021/2022.

[11] STORM. AFF3CT.

[12] D. Moldovan W. Jakob, J. Rhinelander and others. pybind11 – Seamless operability between C++11 and Python, 2017.
# Annexes

## Comparaison C++ / Python, création de module

Afin de créer un module avec ses tâches, il faut notamment expliciter les sockets qui vont être utilisées et leur type. En Python ou en C++, cette étape prend plus ou moins de ligne.

```python
def processing(_t, t, _):
    inp = t.sock_in numpy
    out = t.sock_out numpy
    out[:] = inp[:] + 1
    return 0

class Example_increase(Stateful):
    N = spu.array([0])

    def __init__(self, N, dtype):
        self.N = N
        super().__init__()
        self.create_task("incr")
        self.create_socket_in(self["incr"], "sock_in", n_elts, dtype)
        self.create_socket_out(self["incr"], "sock_out", n_elts, dtype)
        self.create_codelet(self["incr"], processing)

    def execut(self):
        self.N = self["incr"](self.N)
        return self.N
```

Voici sans les includes le code nécessaire pour créer un module en Python, le module ci-dessous va ajouter 1 à l'entrée. Nous définissons une fonction qui va servir de tâche, puis une classe qui hérite de Stateful. La création de la tâche et des sockets prend une ligne par élément. Une codelet est créé servant à faire le lien entre les sockets et la tâche, cet élément prend aussi une ligne à être écris.

```cpp
AbsolueCarre::AbsolueCarre(const int n_elmts)
    : Stateful()
    , n_elmts(n_elmts) {

    const std::string name = "AbsolueCarre";
    this->set_name(name);

    auto& p = this->create_task("process");
    size_t ps_input = this->template create_socket_in double>(p, "input",
        this->n_elmts);
    size_t ps_output = this->template create_socket_out double>(p, "output");
    this->n_elmts / 2);

    this->create_codelet(
        p,
        [ps_input, ps_output](spu::module::Module& m, spu::runtime::Task& t,
            const size_t frame_id) -> int
        {
            auto& absolueCarre = staticCastAbsolueCarre>(m);
            double* input = (double*)(t[ps_input].get_dataptr());
            double* output = (double*)(t[ps_output].get_dataptr());
```
```c
absolueCarre.process(input, output);
    return spu::runtime::status_t::SUCCESS;
});
}

void AbsolueCarre::process(const double* input, double* output) {
    for (size_t i = 0; i < n_elmts/2; ++i) {
        output[i] = (input[i*2]*input[i*2]) + (input[i*2 + 1]*input[i*2 + 1]);
    }
}
```

Et voici, le code C++ sans la partie header, pour pouvoir créer un module. Ce module permet d'appliquer une valeur absolue et de mettre au carré le signal d'entrée. Afin de créer la tâches et les sockets, plus d'étapes sont nécessaires qu'en python. Il y a une fonction process qui contient ce qui va être exécutée par la tâche. La partie codelet, qui fait le lien entre les sockets et la tâche, est plus détaillé.

Moins d'étape et de ligne de code sont nécessaires en python pour développer un module.

## CREGE

**Gestion de Projet** : Le laboratoire dans lequel j'ai effectué mon stage, l'Inria, partage les projets et domaines de recherche par groupe. Je me situais dans le groupe STORM spécialisé dans la recherche sur le calcul de haute performance.

Ce stage utilise une démarche agile, typique des projets de développement en informatique. L'outil GitLab a joué un rôle central, non seulement pour le versionnage du code, mais aussi pour la gestion des pipelines CI/CD, qui ont permis de vérifier automatiquement chaque modification, garantissant ainsi que le code reste fonctionnel et conforme aux standards du projet. Lors du développement, différents tests sont implémentés pour vérifier le bon fonctionnement du code venant d'être ajouté.

Un suivi régulier a été mis en place par une réunion hebdomadaire, afin d'encadrer le stage et de diriger le développement.