Outils pour utilisateurs

Outils du site


tptelecomnum

Projet Télécommunication Numérique HF : Mise en place d'une chaîne d'encodage pour la transmission radio


bvdp.inetdoc.net_files_iut_tp_pic_warning.jpeg

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 ~/Arduino /mnt/etu/s4

et auto-compléter la ligne jusque votre dossier personnel en appuyant 3 fois sur la touche Tabulation, puis entrée.


Objectifs :

  1. Prendre en main la maquette de génération de signaux Arduino
  2. Prendre en main le squelette de code
  3. Générer un signal NRZ (non retour à zéro) à partir d'une source de données
  4. Appliquer le codage Manchester à un signal binaire
  5. Coder des symboles de transmission à l'aide d'une table de correspondances
  6. Appliquer une méthode d'étalement de spectre à un signal binaire

Dans ce module nous appliquerons des méthodes logicielles pour générer des signaux pouvant piloter une chaîne de transmission HF (via un Modulateur I/Q). La maquette Arduino est équipée d'un shield de génération de signaux analogiques (DAC) et d'un module de mise en forme du signal pour piloter le modulateur I/Q (Adaptation d'impédance, atténuation, transformation en signaux symétriques). L'essentiel des TP consistera à écrire le code permettant de générer des modulations BPSK, BPSK + Manchester, BPSK + DSSS, QPSK.

Afin de simplifier votre travail, nous vous fournissons un programme incomplet implémentant le code de gestion de l'interface DAC, la gestion du temps et gestion de la synchronisation du calcul et de l'émission des symboles.

Le code est largement commenté, merci de de tenir compte des indications qui s'y trouvent.

Vous veillerez à bien copier tous vos fichiers de ~/Arduino/ vers votre compte étudiant en fin de séance pour pouvoir les récupérer aux séances suivantes!

Installation de la librairie permettant d'utiliser le convertisseur Numérique analogique

A faire uniquement à la première séance:

Afin de pouvoir utiliser le shield DAC (présenté sur: https://bvdp.inetdoc.net/wiki/doku.php?id=tpdacspi ), vous devez installer une librairie. Pour cela, copiez-collez dans une console après l'avoir ouverte avec ALT+F2 lxterm :

echo commence
mkdir -p ~/Arduino
cd ~/Arduino
mkdir -p libraries
cd libraries
wget https://bvdp.inetdoc.net/files/iut/tp_dacspi/Tlv5637.zip
unzip -o Tlv5637.zip
rm Tlv5637.zip
echo fini  

Installation du projet de base et du système de gestion de version

A faire uniquement à la première séance:

Copier et exécuter les instructions suivantes dans une console lxterm

echo commence
cd ~/Arduino
wget https://bvdp.inetdoc.net/files/iut/tp_telecomnum/telecom_num_a_trou_2.zip
unzip telecom_num_a_trou_2.zip
rm telecom_num_a_trou_2.zip
cd telecom_num_a_trou_2
git init
git add *
git commit -m'initial version'
arduino &
echo fini

Une fois l'IDE Ardiuno ouverte, ouvrez le projet telecom_num_a_trou_2 dans le dossier Arduino/.

Pour les séances suivantes, vous ouvrirez directement le projet telecom_num_a_trou_2 qui aura été complété.

Configuration de la base de temps

Le code de configuration de la base de temps (Timer) est déjà mis en place. Il ne vous reste qu'à configurer celle-ci pour générer une base de temps à 2kHz. La configuration de celle-ci se fait par l'intermédiaire des symboles:

#define PRESCALER_INDEX
#define TIMER_PERIOD

La fréquence de la base de temps peut être calculée par la formule :

FREQ = (16x10^6)/(PRESCALER*(TIMER_PERIOD + 1))

Le facteur de PRESCALER peut être sélectionné par le PRESCALER_INDEX avec :

PRESCALER_INDEX = 0 -> PRESCALER = 1
PRESCALER_INDEX = 1 -> PRESCALER = 8
PRESCALER_INDEX = 2 -> PRESCALER = 32
PRESCALER_INDEX = 3 -> PRESCALER = 64
PRESCALER_INDEX = 4 -> PRESCALER = 128
PRESCALER_INDEX = 5 -> PRESCALER = 256
PRESCALER_INDEX = 6 -> PRESCALER = 1024

La valeur de TIMER_PERIOD devra être chargée dans un registre 8 bits et prendra donc une valeur ENTIERE entre 0 et 255.

Cette base de temps une fois programmée, déclenchera l’exécution de la fonction (gestionnaire d'interruption) qui se charge de piloter le DAC.

ISR(TIMER2_COMPA_vect)

Cette fonction communique avec votre programme à l'aide de deux FIFOs qui permettent de stocker les valeurs pour piloter les canaux I et Q.


Exercice 1: Génération d'un signal carré sur la voie I et contrôle de la base de temps

Calculer les valeurs de PRESCALER_INDEX et TIMER_PERIOD pour générer une base de temps à 2kHz.

Dans cette exercice vous coderez dans la boucle principale du programme Arduino, une fonction qui génère un signal périodique 0→1→0→1 sur la voie I et un signal à 0 sur la voie Q. Afin de palier au problème de synchronisation entre l'écriture sur l'ADC et le calcul du signal, nous utiliserons des FIFOs. La génération des signaux se fera alors par écriture sur les FIFOs, la lecture des FIFOs et la génération des ordres de commande du DAC étant déjà implémentées dans la fonction périodique. Vous utiliserez la fonction bloquante void write_fifo_I_Q(const char * data_I, const char * data_Q, int data_size, int enable_i, int enable_q) pour écrire deux valeurs simultanément dans les fifos pilotant I et Q.

La génération d'un signal dans une fifo doit donc se faire de la manière suivante :

appeler write_fifo_I_Q en lui passant  :
    - Le pointeur sur les données I (tableau contenant les échantillons)
    - Le pointeur sur les données Q (tableau contenant les échantillons) ou NULL si pas de données
    - La valeur data_size qui correspond au nombre d'échantillons dans dans les données I et Q
    - Les valeurs enable_i et enable_q (0 ou 1). Un enable à 0 génère des zero dans la fifo correspondante.

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Après avoir écrit votre code, vérifiez à l'oscilloscope le signal généré en expliquant la fréquence du signal carré généré.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'timer'
gitk & 
echo fini

Exercice 1bis: Pour Debugguer

Arduino ne permet pas facilement l'utilisation d'un débuggueur matériel. Il est donc pénible de détecter les erreurs dans un programme. Pour vous aider, la fonction void displayBuffer(const char * name, char * tab, char tab_size) est fournie. Cette fonction permet l'affichage d'un tableau de valeur dont le nom est donné en chaine de caractères name, dont l'adresse de départ en mémoire est donné par tab et dont le nombre de case est de tab_size. Le code de la fonction d'affichage, à copier dans votre programme est donné ci dessous:

debug.cpp
//#define DEBUG
void displayBuffer(const char * name, char * tab, char tab_size)
{
#ifdef DEBUG
Serial.print("Etat du buffer ");
Serial.print(name);
Serial.print(" contenant ");
Serial.print(tab_size,DEC);
Serial.println(" case(s) : ");
for (int i=0;i<tab_size ;i++)
{
  Serial.print(i,DEC);
  Serial.print("  : ");
  Serial.print(tab[i],DEC);
  Serial.println("");
}
#endif
}

Par exemple pour afficher le buffer_i contenant 8 cases remplies, il faudra exécuter:

displayBuffer("buffer_i", buffer_i,8);

L'affichage se faisant sur la liaison série, il ralentie l'exécution du programme, vous veillerez à ne l'activer que lorsque cela sera nécessaire en utilisant:

#define DEBUG

Vous veillerez à désactivez l'affichage en commentant la ligne définissant le symbole DEBUG pour le test en temps réel dans lequel vous observez les signaux à l'oscilloscope.

Pour visualiser le contenu des tableaux dans la console série Arduino, vous veillerez à la configurer à 115200Bauds.

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Appeler la fonction d'affichage pour visualiser les données du tableau utilisé pour stocker les échantillons du signal carré généré à l'exercice 1. Dans les exercices suivants, vous pourrez utiliser cette fonction pour visualiser le contenu des tableaux remplis par les différentes fonctions que vous implémenterez.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'debugger'
gitk & 
echo fini

Exercice 2: Génération du signal NRZ/BPSK sur la voie I

Dans cet exercice, vous allez générer un signal NRZ à partir de données stockées en mémoire ou calculées au fil du temps. Dans un premier temps, vous compléterez la fonction suivante, qui remplit le tableau ptr_i avec des valeurs 0 ou 1 dépendant de la donnée à coder src qui est sur size_src bits en commençant par le bit de poids faible. Cette fonction retourne le nombre de symboles générés dans les tableaux I et Q;

int encode_bpsk(char src, char * ptr_i, unsigned char size_src)

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Implémentez la fonction encode_bpsk en vous aidant des commentaires de celle-ci. Dans un deuxième temps, vous compléterez la fonction loop (en vous aidant du code de l'exercice précédent) pour :

  1. générer une donnée à transmettre sur 8-bits (0x5A)
  2. appeler la fonction encode_bpsk et affecter la valeur retournée par cette fonction à la variable data_size. La fonction attend en argument un tableau pour stocker les symboles produits. Vous utiliserez donc le tableau déjà défini i_buffer
  3. écrire le résultat du traitement (les data_size cases du tableaux i_buffer) dans la FIFO pour I uniquement (désactiver la fifo Q) en utilisant la fonction write_fifo_I_Q

Exécuter le même programme mais pour une donnée valant 0xB5. Comparer les signaux observés à l'oscilloscope avec les signaux prévus et conclure.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'bpsk'
gitk & 
echo fini



  

Exercice 3: Codage Manchester de la voie I

Dans cet exercice, nous allons ajouter une étape au codage NRZ afin de coder les bits de données au format Manchester.

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Complétez dans un premier temps la fonction manchester_as_xor (l'opérateur XOR est défini au début du fichier). Attention, dans le tableau de symboles généré par encode_bpsk, les symboles sont stockés en partant du bit de poids faible.

Vous rajouterez ensuite l'appel de cette fonction dans la fonction loop à la suite de la fonction encode_bpsk pour traiter la valeur 0x5A (8-bits). La fonction manchester_as_xor devra encoder le tableau issu de encode_bpsk vers un nouveau tableau (manchester_buffer) dont le contenu sera écrit dans la FIFO I comme dans l'exercice précédent.

Une fois le programme compilé et chargé, vérifiez à l'oscilloscope le signal généré.

Exécuter le même programme mais pour une donnée valant 0xB5. Comparer les signaux observés à l'oscilloscope avec les signaux prévus et conclure.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'manchester'
gitk & 
echo fini

Exercice 4: Codage DSSS de la voie I

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Complétez la fonction dsss_as_table en utilisant une clé de codage sur 8 bits définie dans le tableau const char dsss_key2[8] = {0,0,0,0,0,0,0,0};. La fonction dsss_as_table devra, pour chacun des bits qu'elle doit traiter, générer la séquence correspondant à la clef si le bit est à 0 et la séquence complémentaire si le bit est à 1 (utilisation du XOR).

Testez votre programme de la même manière que pour les exercices précédents. Avec la clef fournie, vous devez obtenir le même signal que pour l'encodage BPSK mais avec une durée de bit huit fois plus longue.

Déclarer ensuite une autre clef que vous devez composer vous même dans un autre tableau à 1 dimension en vous assurant qu'elle comporte le même nombre de 0 et de 1. Appelez la fonction dsss_as_table en utilisant cette seconde clef et en stockant le résultat de l'encodage dans un nouveau tableau. Modifiez l'appel à la fonction write_fifo_I_Q pour observer sur la voie I le signal BPSK ralenti et sur la voie Q le signal encodé avec votre clef. Vérifier le bon fonctionnement de votre programme et retrouver la valeur des bits composant la clef à l'oscilloscope.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'DSSS'
gitk & 
echo fini

Exercice 5: Codage QPSK

Pour le codage sur deux voies I/Q de la donnée à envoyer, il est nécessaire de découper cette donnée en groupe disjoints de deux bits (duplet de bits). Pour cette fonction, il est conseillé de déclarer un tableau faisant l'association des duplets avec la valeur à envoyer sur les voies I et Q. Cette méthode permettra d'avancer plus rapidement dans les exercices suivants.

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Afin de construire ce tableau, complétez le diagramme de constellation fourni avec :

  • les positions des combinaisons I/Q sur la constellation
  • le tableau associant pour chaque position les tensions (+V/-V) à générer sur les voies I et Q

A partir de ce tableau, construisez deux tableaux associatifs dans votre programme arduino (tableaux qpsk_i_chan_binary et qpsk_q_chan_binary. Chaque tableau (un pour la voie I et un pour la voie Q) encode la valeur 1 (+V) ou 0 (-V) pour une combinaison IQ.

Testez la fonction encode_qpsk comme dans les exercices précédents (attention pour cette exercice il faut penser à mettre le enable de la fifo Q à '1' lors de l'appel de la fonction write_fifo_I_Q).

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'QPSK'
gitk & 
echo fini

Exercice 6: Codage QPSK avec code de Gray

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Complétez la fonction encode_qpsk_gray. Cette fonction est presque identique à la fonction encode_qpsk mais définit une association différente entre les duplets et les symboles I et Q. Complétez le diagramme de constellation fourni puis construisez la table associative. Enfing, codez vos tableaux associatifs dans les variables qpsk_i_chan_gray et qpsk_q_chan_gray.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'QPSK gray'
gitk & 
echo fini

Exercice 7: 16QAM

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg Sauvez le sketch arduino sous un nouveau nom pour garder une version du code écrit précédemment dans un fichier.

Il vous faut maintenant adapter le programme pour piloter le DAC avec des valeurs autres que 0x000 et 0x3FF. En 16 QAM, les données sont découpées en mots de 4 bits. 2 bits sont envoyés sur le canal I et 2 bits sont envoyés sur le canal Q simultanément. Les voies du DAC doivent donc être pilotées avec des valeurs permettant de représenter 4 niveaux distincts.

Dans le fichier telecom_lib, dé-commentez la ligne :

//#ENABLE_QAM 

Ceci permet de piloter chaque voie du DAC avec quatre valeurs différentes, dépendant de la valeur sur 2 bits stockée dans la fifo.

Le remplissage des fifos sera réalisé par la fonction int codage16QAM(char src, unsigned int size_src, char * pf_i, char * pf_q) que vous devez coder. Les données stockées dans chacune des 2 fifos seront des valeurs 0,1,2 ou 3.

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'16QAM'
gitk & 
echo fini

Exercice 8:Envoi d'un message

bvdp.inetdoc.net_files_iut_tp_gps_todo.jpg

Ajoutez à votre code la déclaration du message suivant.

#define MSG_SIZE 16
char msg[] = {0, 0, 0, 0, 0, 1,  3,  2, 0, 0, 0, 0, 0, 1, 2, 3} ;

Et modifiez la fonction loop pour qu'elle contienne le code suivant.

for(int i = 0 ; i < MSG_SIZE ; i ++){
       int data_size = encode_qpsk_bin(msg[i], i_buffer,q_buffer, 2);
       write_fifo_I_Q(i_buffer, q_buffer, data_size, 1, 1);
}

Si vous aviez décommenté la ligne dans le fichier telecom_lib, re-commentez la pour obtenir:

//#ENABLE_QAM 

Une fois les réponses validées, mettre à jour le suivi de version en saisissant dans une console:

echo commence
cd ~/Arduino/telecom_num_a_trou_2
git commit -a -m'Message 16QAM'
gitk & 
echo fini  
tptelecomnum.txt · Dernière modification : 2021/02/19 20:20 de 127.0.0.1