Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
Localisation de LoRa par DToA
Implémentation sur FPGA
Thèse de Bachelor présentée par
Monsieur Sebastien CHASSOT
pour l’obtention du titre Bachelor of Science HES-SO en
Ingénierie des technologies de l’information avec orientation en
Informatique matérielle
septembre 2017
Professeur responsable
Andrès UPEGUI
printemps 2017 Session de bachelor
INGÉNIERIE DES TECHNOLOGIES DE L’INFORMATION
ORIENTATION – INFORMATIQUE MATERIELLE
ETUDE DE FAISABILITE DE L'IMPLEMENTATION D'UN GATEWAY LORA AVEC DES CAPACITES DE LOCALISATION PAR DTOA
Descriptif :
Dans la norme LoRa il est prévu de supporter un système de localisation basé sur le principe de «Difference Time of Arrival». Ce type de localisation à différence d'une méthode « Time of Flight » tel que présent sur les systèmes GPS, n'a pas besoin de gérer un timestamp précis du côté du dispositif à localiser, car le temps d'envoi du message n'est pas pris en compte par l'algorithme. C'est seulement du côté du gateway récepteur que ces timestamps doivent être gérés avec une haute précision afin de faire une trilatération basée sur la différence de temps de réception d'un message émis par un dispositif. Même si prévu dans la norme, les gateways actuels ne permettent pas de faire cette localisation car pour chaque message reçu, le timestamp attribué a une résolution de 1ms. Ce qui est largement insuffisante pour faire la localisation. Le but de ce projet est d'explorer la faisabilité d’implémenter un tel système basé sur une carte USRP B200, basé principalement sur un circuit RF, un ADC, une FPGA Spartan-6, et une interface USB-3. Deux principaux défis sont identifiés :
- Gestion du timestamp : à l'aide d'un signal de référence PPS fournie par un GPS, un système de compteurs devra gérer des timestamps avec une précision connue sur plusieurs cartes (2 cartes dans ce projet). Dans un premier temps ce timestamp sera validé avec la détection d'un événement simple.
- Traitement du signal LoRa: le but sera d'identifier plusieurs techniques pour identifier l'arrivée d'un signal LoRa basé sur l'entête du chirp. Cette détection servira à déclencher la capture du timestamp pour remplacer l’événement simple de l'item précédant. Le décodage de toute la trame reste hors de la porte de ce travail.
Travail demandé :
Pendant ce travail de diplôme l'étudiant devra :
- Analyser et comprendre l'architecture FPGA et le code C++ fournis avec la carte USRP B200.
- Proposer une solution matériel pour la gestion des timestamps. La valider sur la FPGA en utilisant deux USRP B200.
- Proposer aux moins deux méthodes pour détecter l'arrivé d'un signal LoRa : (1) Une méthode « naïve » qui permettra de valider la gestion de timestamps et qui nous permettra d'obtenir de résultats préliminaires. Cette méthode « naïve » aura certainement des limitations importantes para rapport à la distance ou à la fiabilité. (2) Un méthode qui pourra se baser soit sur un analyse fréquentielle ou sur une corrélation temporelle.
- Implémentation de la méthode naïve sur la FPGA.
- Validation et analyse de la deuxième méthode à l'aide de Matlab. Si la complexité de l'algorithme et le temps à disposition le permettent, implémentation sur FPGA.
- Tester le système afin d'obtenir de résultats.
Candidat : Professeur(s) responsable(s) :
M. Chassot Sébastien UPEGUI ANDRES
Filière d’études : ITI En collaboration avec :
Travail de bachelor soumis à une convention
de stage en entreprise : non
Travail de bachelor soumis à un contrat de
confidentialité : non
Printemps 2017Session de bachelor
Résumé :
L’internet des objets (IoT) est en pleine expansion. Les applications se multiplient. Une société suisse Semtech a innové en sortant sur le marché une solution sans-fil permettant de communiquer sur de grandes distances tout en consommant très peu d’énergie. Ces transcievers connus sous le nom de LoRa (contraction de long et range), permettent de transmettre de petits messages de quelques octets sur plusieurs dizaines de kilomètres.
Un besoin récurrent dans les applications IoT est la localisation des objets. Généralement on utilise un GPS et l’objet communique sa position. Avec LoRa il y a des inconvénients à faire cela. Un GPS met plusieurs dizaines de secondes à acquérir sa position et consomme beaucoup pour y arriver. On perdrait tous les avantages de LoRa en utilisant un GPS.
Il serait dès lors très intéressant de pouvoir localiser ces objets (LoRaMote) autrement. Ce travail a pour but d’étudier la faisabilité d’une localisation par « Difference Time of Arrival ». Une onde radio se propage aux environs de 2/3 de la vitesse de la lumière et parcourt 5m en environ 20 ns (20 milliardièmes de seconde). Ce temps tout en étant très petit devrait être mesurable, c’est du moins ce que ce travail tente d’évaluer. Si les résultats sont concluants, ce projet pourrait évoluer en utilisant plusieurs récepteurs synchronisés (gw0, gw1, gw2). Il serait dès lors possible de déterminer la position de la source d’émission (LoRaMote) en fonction des différents temps de réception.
Les récepteursdétectent un signal au tempst1, t2 et t3
Par trilatération de 3 temps et en connaissantla position desrécepteurs,on retrouve les coordonnées de l’émetteur dans le plan à l’intersection des 3 cercles
La difficulté est de synchroniser les récepteurs afin qu’ils partagent la même heure. Une montre à quartz retardant d’une s/an perd 31ns/s. Même synchronisées deux horloges, vont très vite dériver. La solution est d’utiliser le réseau GPS dont on peut extraire un signal périodique (PPS – pulse per second) avec une précision inférieure à la ns où que l’on se trouve sur terre.
La dernière difficulté est de détecter et reconnaître un instant précis dans la modulation LoRa afin d’y apposer un timestamp. L’algorithme est implémenté dans un FPGA afin de garantir les contraintes de temps, indispensables pour obtenir une bonne précision.
Candidat : Professeur(s) responsable(s) :
M. CHASSOT SEBASTIEN Upegui AndrèsFilière d’études : ITI
En collaboration avec : Travail de bachelor soumis à une convention
de stage en entreprise : nonTravail de bachelor soumis à un contrat de
confidentialité : non
Remerciements
Je tiens tout d’abord à remercier l’ensemble des professeurs de la filière ITI.Par leur enthousiasme et leur savoir, ils auront participé à rendre ces étudespassionnantes et particulièrement enrichissantes.
Un grand merci également à tous ceux qui m’ont aidé et soutenu durant laréalisation de ce travail de Bachelor. Notamment :
Andrès Upegui, professeur à l’hepia, pour avoir suivi mon travail ainsi que poursa grande disponibilité et ses conseils avisés.
Mickaël Hoerdt, professeur à l’hepia, qui a suivi mon travail de semestre auCERN et qui a soufflé l’idée de ce travail.
Tous les assistants et plus particulièrement Adrien Lescourt pour ses précieuxconseils.
Christian Bessat, ingénieur de recherche à l’hepia, toujours très serviable etd’une très grande efficacité.
Table des matières
1 Introduction 91.1 Le besoin de localisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.2 Principe Difference Time of Arrival (DToA) . . . . . . . . . . . . . . . . . . . 10
2 Architecture 112.1 SDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.2 Mesure du temps (compteurs) . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Description du matériel 153.1 Carte SDR USRP B200 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.1.1 Cypress FX3 (USB) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.1.2 Le FPGA Xilinx Spartan6 . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Les cartes Basys3 (FPGA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.3 Le récepteur GPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4 Environnement de développement 194.1 Les outils USRP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.1.1 Le SDK de Cypress . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.1.2 Les SDK de Xilinx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.2 Chipscope Pro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.3 GNURadio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5 le FPGA de l’USRP B200 235.1 Architecture de l’IP core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235.2 Les registres internes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245.3 Le compteur VITA time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265.4 Les échantillons IQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.5 Les GPIOs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.6 Les modifications apportées au FPGA . . . . . . . . . . . . . . . . . . . . . . 285.7 Chipscope Pro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.7.1 Alimentation du chipscope . . . . . . . . . . . . . . . . . . . . . . . . . 305.7.2 Mesures avec chipscope . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6 Compteur et simulateur sur Basys3 336.1 Envoi des timestamps en UART . . . . . . . . . . . . . . . . . . . . . . . . . 336.2 L’émulateur d’événements et de Pulse-Per-Second (PPS) . . . . . . . . . . . . 34
7 Agrégation des timestamp et trilatération 357.1 Calcul de la distance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
8 Synchronisation de systèmes distants 398.1 Principe de l’algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398.2 Mesures d’erreurs des sources de synchronisation . . . . . . . . . . . . . . . . 408.3 Méthodologie de tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418.4 Dérive temporelle entre deux compteurs synchronisés par simulateur . . . . . 418.5 Avec ou sans synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . 438.6 Dérive temporelle entre deux synchronisations par GPSDO . . . . . . . . . . 44
9 LoRa modulation 479.1 Canal de communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509.2 Quelques chiffres significatifs . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Chassot Sebastien, , septembre 2017 5/90
10 Recherche d’un algorithme 5310.1 Implémentation logiciel d’un simulateur . . . . . . . . . . . . . . . . . . . . . 5310.2 La fréquence d’exécution de l’algorithme . . . . . . . . . . . . . . . . . . . . . 5410.3 Première approche naïve (domaine temporel) . . . . . . . . . . . . . . . . . . 5610.4 Utiliser la phase (domaine temporel) . . . . . . . . . . . . . . . . . . . . . . . 5710.5 Produit de convolution (domaine temporel) . . . . . . . . . . . . . . . . . . . 5810.6 Inversion de chirp (domaine fréquentiel) . . . . . . . . . . . . . . . . . . . . . 5910.7 En détectant une transition (domaine fréquentiel) . . . . . . . . . . . . . . . . 59
11 Conclusions 61
12 Annexes 6312.1 Vue RTL compteur Basys3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6312.2 Vue RTL simulateur Basys3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6412.3 Vue RTL USRP B200 (vue partielle) . . . . . . . . . . . . . . . . . . . . . . . 6512.4 Script lançant la compilation du FPGA . . . . . . . . . . . . . . . . . . . . . 6612.5 LoRa détection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6712.6 Utilisation de deux USRP en parallèle . . . . . . . . . . . . . . . . . . . . . . 7112.7 Affichage et plot des timestamps . . . . . . . . . . . . . . . . . . . . . . . . . 7412.8 Envoi des timestamps (MQTT) . . . . . . . . . . . . . . . . . . . . . . . . . . 7812.9 Analyse des timestamps (MQTT) . . . . . . . . . . . . . . . . . . . . . . . . . 8312.10Capture Wireshark (USB) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8712.11Table des acronymes et sigles utilisés . . . . . . . . . . . . . . . . . . . . . . . 88
Table des figures
2.1 Architecture du système . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Système composé de deux récepteurs et d’un simulateur . . . . . . . . . . . . 13
3.1 Architecture générale de la carte USRP B200 . . . . . . . . . . . . . . . . . . 153.2 Bloc diagramme du tranciever . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.3 Connexion GPSDO sur USRP B200 . . . . . . . . . . . . . . . . . . . . . . . 18
4.1 Platform cable USB de Xilinx . . . . . . . . . . . . . . . . . . . . . . . . . . 214.2 Exemple d’utilisation de GNURadio . . . . . . . . . . . . . . . . . . . . . . . 21
5.1 Architecture des bus USRP B200 . . . . . . . . . . . . . . . . . . . . . . . . . 245.2 Architecture du readback des registres . . . . . . . . . . . . . . . . . . . . . . 245.3 Architecture compteur, PPS et LoRa . . . . . . . . . . . . . . . . . . . . . . . 265.4 Schéma du bloc timekeeper . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.5 Schéma GPIO USRP B200 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285.6 Schéma du bloc lora_detect initial . . . . . . . . . . . . . . . . . . . . . . . . 295.7 Schéma du bloc lora_detect final . . . . . . . . . . . . . . . . . . . . . . . . . 295.8 Schéma régulateur de tension secondaire . . . . . . . . . . . . . . . . . . . . . 305.9 Schéma régulateur de tension principal . . . . . . . . . . . . . . . . . . . . . . 305.10 Exemple d’utilisation du chipscope (vue d’un spectrogramme en parallèle) . . 31
6.1 Interface compteur Basys3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.2 Interface simulateur Basys3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
7.1 Schéma temps de propagation d’une onde . . . . . . . . . . . . . . . . . . . . 37
8.1 Déphasage de deux signaux PPS générés par deux GPSDO . . . . . . . . . . 408.2 Déphasage de deux signaux PPS générés simultanément depuis le simulateur 418.3 Dérive temporelle avec synchronisation par simulateur . . . . . . . . . . . . . 428.4 Dérive temporelle avec synchronisation par simulateur (avec un autre couple
de cartes) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438.5 Comparaison de la dérive avec ou sans synchronisation . . . . . . . . . . . . . 44
8.6 Perte de synchronisation et reprise . . . . . . . . . . . . . . . . . . . . . . . . 448.7 Dérive temporelle avec synchronisation par GPSDO (positive) . . . . . . . . . 458.8 Dérive temporelle avec synchronisation par GPSDO (négative) . . . . . . . . 458.9 Dérive temporelle avec synchronisation par simulateur et compensation logicielle 468.10 Dérive temporelle avec synchronisation par GPSDO et compensation logicielle 46
9.1 Exemple de chirp (fréquence) . . . . . . . . . . . . . . . . . . . . . . . . . . . 479.2 Evolution de la fréquence en fonction du temps . . . . . . . . . . . . . . . . . 479.3 Exemple de mixage du chirp et d’une fréquence fixe . . . . . . . . . . . . . . 489.4 Exemple de modulation de symboles . . . . . . . . . . . . . . . . . . . . . . . 489.5 Exemple de signal très bruité . . . . . . . . . . . . . . . . . . . . . . . . . . . 499.6 Exemple de mixage du down-chirp et d’un symbole . . . . . . . . . . . . . . . 499.7 Exemple de transmission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.1 Exemple de préambule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5310.2 Spectrogramme du préambule (6+2) . . . . . . . . . . . . . . . . . . . . . . . 5310.3 Exemples générés par le simulateur . . . . . . . . . . . . . . . . . . . . . . . . 5410.4 Juxtaposition des fenêtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5510.5 transition up-chirp/downchirp . . . . . . . . . . . . . . . . . . . . . . . . . . . 5510.6 Exemple d’un signal échantillonné (un paquet LoRa) . . . . . . . . . . . . . . 5610.7 Exemples générés par le simulateur . . . . . . . . . . . . . . . . . . . . . . . . 5710.8 Inversion de chirp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5810.9 Changement de phase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5810.10Exemple de point remarquable . . . . . . . . . . . . . . . . . . . . . . . . . . 5810.11FFT glissante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Liste des tableaux
8.1 LUT facteurs de correction pour un dtmax = 300ns . . . . . . . . . . . . . . . 42
Table des listings
5.1 Exemple d’utilisation de l’API . . . . . . . . . . . . . . . . . . . . . . . . . . 235.2 Adresses des registres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255.3 Exemple d’utilisation d’un registre . . . . . . . . . . . . . . . . . . . . . . . . 255.4 Exemple d’utilisation depuis l’API . . . . . . . . . . . . . . . . . . . . . . . . 255.5 Commentaire sur les GPIOs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285.6 Modification du firmware Cypress FX3 . . . . . . . . . . . . . . . . . . . . . . 305.7 Exemple de signaux internes à tester . . . . . . . . . . . . . . . . . . . . . . . 31
7.1 Script au broker MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357.2 Exemple de message transmis au broker MQTT . . . . . . . . . . . . . . . . . 357.3 Script analysant les timestamp avec MQTT . . . . . . . . . . . . . . . . . . . 36
12.1 ./included_src/wireshark_output1.txt . . . . . . . . . . . . . . . . . . . 8712.2 Exemple de paquet transféré sur l’USB. . . . . . . . . . . . . . . . . . . . . . 87
1 Introduction
L’extension d’Internet aux objets physiques, connue sous le nom de l’Internet des objets(IoT 1) va grandissant. On rencontre dans notre quotidien de plus en plus d’objets connectéstels que des capteurs, les smartphones, des montres, la domotique (ampoules, interrupteurs,stores, électroménagers...). On parle pour la prochaine décennie de 150 milliards d’objetsconnectés[24].
Pour qu’un objet soit dit connecté, il doit avoir une connexion avec Internet. Certains objetsutilisent un lien filaire mais une grande partie utilise des liens sans fil.
La société suisse Semtech a innové en matière de solutions sans-fil (radio fréquence (RF)) ensortant sur le marché des transcievers permettant de communiquer sur de grandes distancestout en consommant très peu d’énergie. Ils sont connus sous le nom de LoRa (contractionde long et range) et permettent de transmettre de petits messages de quelques octets surplusieurs kilomètres voir dizaines de kilomètres (même en milieu urbain) et ceci pendantplusieurs années tout en n’étant alimentés que par une simple batterie.
Ces performances ouvrent de nouveaux horizons. Là où un lien était inenvisageable il y apeu, il est aujourd’hui possible de déployer des objets connectés.
La possibilité d’émettre sur de grandes distances avec une faible consommation 2 ouvre denouvelles perspectives. En contre-partie, un duty-cycle limité à 1% 3 et une modulation stablemais lente font que LoRa permet uniquement un lien pour de brefs messages espacés dans letemps 4.
Historique
Le 29 décembre 2016, Matt Knight présente au Chaos Communication Congress (33C3 )le premier reverse engineering de la couche physique de LoRa[8]. Jusque là, n’existait quela documentation incomplète de Semtech. Depuis, les blogs décrivant la modulation LoRafleurissent sur Internet (comme une page très détaillée sur revspace.nl)[21]. On trouveégalement plusieurs projets d’implémentations logiciel (applications Software Defined Radio)de LoRa et de la couche LoRaWAN.
Cet événement m’a grandement influencé dans le choix de ce sujet et évidemment beaucoupaidé dans mes recherches.
1.1 Le besoin de localisation
Beaucoup d’applications ont besoin de localiser les objets (pour les réseaux LoRa, on appelleles objets Mote ou LoRaMote). Généralement, l’objet dispose d’un GPS 5 et transmet saposition en même temps que ses data. Avec un LoRaMote ce n’est pas intéressant. Si le choixd’une application s’est porté sur LoRa, c’est pour répondre à une contrainte de distanceou d’économie d’énergie. Le réseau GPS utilise le principe du Time of flight (TOF). Lessatellites émettent des messages et c’est le récepteur qui calcule activement sa position. Ces
1. Internet of Things (IoT)2. Au détriment du temps de transmission3. Partage de l’utilisation de la bande passante avec les autres usagers. Le temps d’émission total ne doit
pas dépasser 1% soit 36 secondesheure.4. Limité à quelques octets.5. Global Positioning System (GPS).
Chassot Sebastien, , septembre 2017 9/90
calculs nécessitent beaucoup de ressources et de temps. En résumé, le GPS n’est pas du toutadapté aux applications basse consommation.
Quand on souhaite économiser temps et énergie, on restreint la communication au strictminimum et on évite les data inutiles en émettant des messages courts.
Il serait dès lors très intéressant de pouvoir localiser ces LoRaMotes en utilisant une autretechnologie.
Ce travail a pour but d’étudier la faisabilité d’une localisation par «Difference Time ofArrival».
1.2 Principe DToA
Une onde radio se propage à environ 2/3 de la vitesse de la lumière. En simplifiant légèrement,on peut estimer que cette vitesse de propagation est constante dans l’air. Une onde parcourt1 mètre en 4 − 5ns 6.
Si la vitesse de propagation est constante 7, un temps peut être associé à une distance. Orretrouver la position d’un objet en partant de 3 (ou plus) positions connues et trois distancesest utilisé depuis longtemps. Cette branche de la géométrie s’appelle la trilatération[26] etles équations ne posent pas de problème particulier.
Le GPS repose sur ce principe ; en connaissant la position des satellites et le temps qu’unsignal met à atteindre le récepteur à localiser (TOF).
Ce besoin de localisation a bien été compris par l’industrie. Semtech développerait actuel-lement un service de localisation. On trouve d’ailleurs une mention intéressante dans ladocumentation de Semtech :
Ranging / Localization
An inherent property of LoRa is the ability to line arly discriminate betweenfrequency and time errors. LoRa is the ideal modulation for radar applications andis thus ideally suited for ranging and localization applications such as real-timelocation services[20].
Ce travail étudie la faisabilité d’un tel système. Dans un premier temps il s’agit d’explorer unsystème comprenant deux récepteurs et détectant les différences de temps de réception d’unpaquet LoRa. Il pourrait être étendu à un plus grand nombre de récepteurs et permettraitde localiser un LoRaMote dans l’espace.
6. 4 à 5 milliardièmes de secondes7. Ce que nous supposons dans ce travail.
2 Architecture
Dans un système DToA, nous travaillons avec des temps. Ces temps ne correspondent pasexactement à des distances puisque nous ne connaissons pas le temps qu’a mis l’onde àparcourir la distance entre le LoRaMote et les récepteurs et il n’est pas nécessaire de leconnaître. Une différence de temps suffit à déduire une distance. Pour ça, il faut que lesrécepteurs soient synchronisés entre-eux.
Deux horloges distantes ne peuvent avoir exactement la même heure et c’est là que se trouvela première difficulté : synchroniser les récepteurs malgré leur éloignement. Une montre àquartz retardant d’une s/an perd 31ns par seconde 1. Donc, même en mettant les récepteursà l’heure, ils vont très vite dériver les uns par rapport aux autres. La solution choisit pourpallier ce problème est d’utiliser le réseau GPS dont on peut extraire un signal périodique à1[Hertz] (PPS) avec une précision inférieure à la ns 2. Les récepteurs sont resynchroniséstoutes les secondes sur l’heure «Universal Time Coordinated (UTC)» quel que soit leuremplacement sur terre.
La deuxième difficulté est de détecter le signal émit par un émetteur LoRa et de timestamper 3
cet événement aussi précisément que possible. Un paquet LoRa de 32 octets peut prendreplus d’une seconde pour être transmis 4. Il ne suffit pas de le détecter, il faut définir un pointprécis (infinitésimal) dans cette modulation afin de conserver une résolution de l’ordre de la[ns].
Le système se compose d’un compteur synchronisé par GPSDO 5, d’un déclencheur d’évé-nements (détection d’un paquet LoRa) et de l’envoi du timestamp vers un cloud pour êtrecomparé avec d’autres timestamp et d’effectuer la localisation de la source par trilatéra-tion. Un des avantages est que le système n’implique aucune modification du côté desLoRaMotes 6.
Figure 2.1 – Architecture du système
1. Une erreur de +7m par seconde2. La plage de précision théorique va de 12 ps ou plus suivant la précision du device générant le signal.3. Associer l’événement à une heure précise.4. Avec un Spreading Factor de 12 et une Bande passante de 125KHz, Tt = 212125·10−3·42symb = 1.376[s]5. Global Positioning System Disciplined Oscillator (GPSDO)6. On peut localiser un LoRaMote sans qu’il le sache. Il y a donc des considérations éthiques à prendre en
compte en mettant en place un tel système.
Chassot Sebastien, , septembre 2017 11/90
2.1 SDR
Ce travail implique des contraintes particulières et nous avons utilisé des récepteurs SoftwareDefined Radio (SDR). Ce type de device sert à échantillonner un signal RF à haute vitesseet à fournir un stream traité au niveau logiciel.
Si l’on prend l’exemple d’un LoRaMote que l’on peut considérer comme une boîte noire,un message est reçu via son antenne et on a accès à un buffer contenant le payload de cemessage. Le passage d’une onde RF à une suite d’octets a été effectué dans un ASIC 7. Toutela complexité de la démodulation, du contrôle des parités, de la redondance d’informationest cachée.
En SDR, nous avons accès au signal lui-même et il est donc possible de ré-implémenter auniveau logiciel ce qui se passe dans un ASIC. C’est donc un outil parfaitement adapté à destests ou du prototypage.
Le SDR utilisé a de plus l’avantage d’embarquer un FPGA 8. Ce composant contient unsystème logique qui numérise et transporte le signal vers un host. Il a de plus l’avantaged’être re-programmable et il est donc possible d’en changer le comportement et faire du«traitement de signal». Le signal peut donc être traité de façon logiciel par un host maiségalement en temps réel par le FPGA. C’est ce choix qui a été retenu pour garantir lescontraintes de temps critiques de ce projet. Le SDR est connecté à un host en USB3.0, orl’USB partage le temps de transfert entre tous les périphériques 9. Ces data passent de pluspar les buffers du kernel avant d’être accessibles dans le user space et de pouvoir être traités.Il n’était dès lors par sûr qu’il soit possible de garantir les contraintes de temps en traitant leflux au niveau du host. Sans compter qu’un OS non realtime peine à garantir des contraintesde temps inférieures à quelques centaines de micro-secondes. Le FPGA par contre transportele flux d’acquisition vers le host, on peut y placer un compteur à la fréquence de son horlogeet implémenter un algorithme qui trigge sur un événement du flux d’acquisition avec unefaible latence.
2.2 Mesure du temps (compteurs)
Sur un OS ordonnancé de type POSIX, la résolution est de 10−6 seconde 10. Aucunechance de réaliser un système DToA sur un PC. C’est pourquoi, le compteur est im-plémenté sur un FPGA et est re-synchronisé toutes les secondes en utilisant le réseauGPS 11.
7. Application-specific integrated circuit (ASIC)8. Field-programmable gate array (FPGA)9. Pour du SDR on utilise le mode Bulk Streams
10. On peut espérer au mieux un tick de 700 à 900ns.11. Le problème de consommation du GPS ne concerne que les émetteurs pas le système DToA.
Figure 2.2 – Système composé de deux récepteurs et d’un simulateur
— 1 carte de développement simulant un signal GPS (Basys3[1], Xilinx Artix-7).— 2 cartes GPS (shield LoRa/GPS pour RaspberryPi[3]).— 2 cartes de développement servant de compteurs (Basys3[1], Xilinx Artix-7).— 2 cartes d’acquisition SDR (USRP B200[16]).— 1 émetteur LoRa pour tester et valider le système (waspmote[9]).
3 Description du matériel
3.1 Carte SDR USRP B200
Cette carte permet de traiter tous types de signaux RF entre 70MHz et 6GHz avecune bande passante de 56MHz. Elle est connectée au host en USB3.0 et une API 1 per-met de récupérer et traiter le signal en temps réel ou de le sauvegarder pour un post-traitement.
L’USRP peut également émettre un signal pré-enregistré ou généré en temps réel. Dansce travail il n’est pas nécessaire d’émettre ; c’est pourquoi le transmitter n’est pas détailléici.
Son architecture est principalement composée d’un transciever (AD9364 pour l’acquisi-tion/transmission du signal), un FPGA (Spartan 6, contrôlé par l’API) et d’un Cypress FX3(pour le transport en USB3.0).
Figure 3.1 – Architecture générale de la carte USRP B200
Les sources de l’API[17], du FPGA[19] et le firmware du Cypress FX3 [18] sont disponiblessur github et les manuels utilisateurs ainsi que la documentation de l’API sont sur le site dufabricant[16].
1. Application Programming Interface (API)
Chassot Sebastien, , septembre 2017 15/90
Le tranciever AD9364
Le composant AD9364 a été développé par Analog Devices en collaboration avec EttusResearch 2.
Il s’agit d’un ASIC, comprenant un tranciever et un Analog-to-Digital Converter (ADC)haute vitesse d’une profondeur de 12bits, faisant le lien entre le monde de la RF et celui dunumérique.
Figure 3.2 – Bloc diagramme du tranciever
Le signal provenant de l’antenne est d’abord amplifié puis mixé avec la fréquence de la PLL 3
afin d’être ramené en bande de base. Après un filtre passe-bande 4 le signal est échantillonné 5.L’acquisition peut monter à 60Msample/s et sort deux échantillons signés, I (réel) et Q(imaginaire) d’une profondeur de 12bits chacun.
L’AD9364 sort les échantillons sur 24 pins et peut transmettre de trois façons différentes.Soit comme un lien simple de 12bits parallèles (12 pins utilisées), soit en double lienascendant/descendant (2x12bits parallèles) ou en Low Volt Differencial Signal (LVDS) (12paires différentielles). La communication peut être half-duplex ou full-duplex en utilisant6 paires ascendantes et 6 paires descendantes. L’horloge peut être utilisée sur le flancmontant en Single Data Rate (sdr) ou en Double Data Rate (ddr) sur les flancs montants etdescendants.
L’AD9364 a une machine d’état interne (Wait, Sleep, Tx, Rx, FDD 6 et Alert). Elleest pilotée via un bus SPI tout comme le sont la fréquence de la PLL 7, le gain et lefiltre.
3.1.1 Cypress FX3 (USB)
Le cypress FX3 est un périphérique qui fait le lien entre l’USB3.0 d’un host et un SoC 8
(CPU, ASIC, DSP ou FPGA). Il intègre la couche physique de l’USB3.0 ainsi qu’un micro-contrôleur ARM 32bits 9 permettant de développer un traitement spécifique à une application(RTOS). Cypress met à disposition un environnement de développement. C’est cet environ-nement qu’Ettus a utilisé pour produire le firmware RTOS prenant en charge le protocolecommun à tous ses produits, l’«USRP Hardware Driver (uhd)» afin d’uniformiser sonAPI.
2. Producteur de l’USRP B200.3. Phase-Locked Loop (PLL).4. Utilisé généralement comme un filtre passe-bas5. Le signal numérisé peut être traité par un filtre FIR (128 taps) non représenté6. état rx+tx7. PLL.8. System on Chip (SoC)9. ARM926EJ-S
Le microcontrôleur est principalement utilisé pour configurer un DMA 10 qui s’occupe desmouvements mémoires entre les différentes FIFO. Un bus bidirectionnel GPIF II 11 relie leFX3 au FPGA.
Avec ce type d’architecture il est possible d’atteindre des capacités de transfert supérieures à400Mb/s.
3.1.2 Le FPGA Xilinx Spartan6
Le cœur du système est implémenté sur un Spartan6 XC6SLX75 12, l’un des plus gros de lagamme Spartan6 de Xilinx. Contrairement à ce qu’on pourrait imaginer il n’embarque pasde Softcore mais uniquement des blocs logiques.
Au début de ce travail, il était prévu de faire toute l’implémentation des algorithmes à ceniveau. Une grosse partie de mon travail a donc consisté à faire du reverse-engineering surl’IP core embarqué. Devant la complexité de l’environnement et le manque de temps, il afallu explorer d’autres solutions et se résoudre à utiliser plusieurs FPGA 13 et ré-écrire unepartie de la logique en repartant de zéro.
3.2 Les cartes Basys3 (FPGA)
Pendant la phase de développement et face à la complexité il a fallu diviser le problème enplus petites tâches, les résoudre, les valider et ensuite les assembler.
Pour commencer les essais, nous n’avions pas de GPS ; une alternative provisoire a donc étéde générer un signal PPS depuis une carte de développement. Par la suite, il a fallu simulerla réception d’un paquet LoRa. Plutôt que d’attendre d’avoir fini l’algorithme de détection, ilétait plus simple de le simuler avec un bouton et de le visualiser avec une LED. Sur l’USRP,il n’y a pas de bouton et chaque compilation prend 15 minutes.
Les cartes de développement Basys3 comprennent toute une série d’interfaces. Des boutons,des switchs, des LEDs, des 7-segments, des GPIOs, l’UART,...Elles sont rapidement devenuesindispensables pour valider une idée ou afficher un résultat (en faisant clignoter une LEDpar exemple). Petit à petit, elles ont été intégrées au projet et une partie des algorithmes afinalement été implémenté dessus.
Le FPGA embarqué est un Artix-7 de Xilinx. L’outil de développement est Vivado 14. LeFPGA fonctionne d’origine à 100Mhz (On peut le faire tourner plus vite) alors que leSpartan-6 lui fonctionne à 50MHz. Les cartes Basys3 offrent donc une meilleure résolutiontemporelle pour ce projet.
10. Direct Memory Access (DMA)11. General Programmable Interface v2 utilisé par Cypress12. 74637 Logic Cells, 11662 Slices et 3096Kb de BRAM.13. Les cartes Basys314. Vivado remplace ISE pour les FPGA sortis après les Spartan
3.3 Le récepteur GPS
Ce projet nécessite de synchroniser plusieurs USRP B200 (une pratique courante en SDRet l’USRP est prévu à cet effet). L’horloge interne est générée par un quartz mais on peututiliser un oscillateur externe de meilleure qualité 15.
Il est aussi possible d’ajouter sur l’USRP un GPSDO[15]. Cette option a l’avantage d’êtreparfaitement supportée par API mais elle coûte aussi chère que la carte. Pour ce travailexploratoire nous avons utilisé un GPS basic sortant un signal PPS tout en gardant à l’espritque les résultats pourraient être améliorés par l’utilisation de matériel plus précis. Le GPSDOd’Ettus n’est pas documenté et nous avions espoir qu’il serait possible de faire fonctionner lacarte avec un autre GPS. Sur le schéma de la carte, on voit qu’il y a deux interfaces série.L’un pour les trames NMEA 16 (gps_txd_nema) et un deuxième (gps_rxd, gps_rxd). Cedeuxième interface, non conventionnel, est utilisé pendant l’initialisation de l’USRP pourcommuniquer avec le GPS.
Figure 3.3 – Connexion GPSDO sur USRP B200
N’ayant ni documentation ni module, il aurait fallu se baser sur les sources de l’API pourcontourner ce mécanisme et tromper la carte. L’API est commune à tous les produits USRPet comprendre sont fonctionnement aurait nécessité beaucoup de temps sans garantie derésultats.
La shield Dragino LoRa/GPS Hat est faite pour être montée sur Rasberry Pi. Elle comprendun GPS basé sur un MTK MT3339[7] et un transciever LoRa 17. Il n’y a pas besoin deRaspberry Pi pour l’utiliser ; l’alimenter suffit pour récupérer un signal PPS. Il y a égalementun interface UART pour les trames NMEA[25]. Comme le travail est fait en intérieur, desantennes externes placées sur le rebord de la fenêtre ont été utilisées 18. Malgré cela, les joursde pluie, le GPS n’arrivait pas à acquérir de signal.
15. Il y a une entrée 10MHz prévue pour (connecteur SMA).16. Les GPS utilisent un protocole standardisé (NMEA) pour afficher les coordonnées calculées.17. SX1276 transceiver non utilisé dans ce travail.18. Avec 5m de câble
4 Environnement de développement
Les principaux outils utilisés sont ; Les librairies uhd d’Ettus (pour l’utilisation de l’USRP),les outils Xilinx ISE et Vivado pour les FPGA, GNURadio[6] et Matlab. Les scripts sontécris en python ou en bash.
4.1 Les outils USRP
L’un des points forts de l’USRP est que l’on a accès à tout le code source sur github.
Le dépôt principal contient le code des librairies (uhd), le firmware du Cypress FX3, celui duFPGA et des outils (Benchmark, tests, tests unitaires).
La plupart des distributions GNU/Linux récentes ont dans leurs dépôts les librairies uhd et uneversion précompilée du firmware FX3 et du bitstream pour le FPGA.
À chaque première utilisation de l’USRP, les firmwares sont reflashé sur la carte 1. Cetteméthode est très pratique quand on travaille sur le firmware. J’ai utilisé des liens symboliquesvers la dernière version compilée. Avec cette méthode, il y a moins de risque de confusionentre la version embarquée et celle de développement.
Comme les sources sont disponibles, le travail de développement a été fait sur un fork desdépôts git et en conservant git comme système de versioning. Pour éviter que de nouveauxcommits changent le comportement des outils, j’ai travaillé dans une nouvelle branche enn’utilisant plus la mainline. Pour le développement et les modifications apportées au projet,j’ai modifié les Makefile (cmake) de façon à toujours pouvoir compiler l’ensemble du projetoriginal et les modifications apportées.
Compiler le projet ne pose pas de problème particulier, il suffit d’avoir un environnement dedéveloppement correctement configuré (GCC et binutils).
Modification côté host
L’utilisation de l’USRP peut demander beaucoup de ressources au host en fonction dutype d’acquisition. Quand le taux d’échantillonnage dépasse les 20Ms, l’OS n’arrive plusà consommer le stream entrainant des pertes de données. Pour pallier ce problème, il fautdonner une priorité plus haute aux outils d’acquisitions. En modifiant les priorités du kernel,les acquisitions jusqu’à 50Ms n’ont plus de pertes de données 2.
echo "@wheel - rtprio 99" >> /etc/security/limits.conf
À cette vitesse, l’écriture du flux sur un disque dur n’est possible que pendant quelquesdizaines de secondes 3. Dans notre cas, le flux est redirigé vers /dev/null puisqu’il n’y a pasde traitement logiciel.
1. Ils ne sont pas stockés dans une mémoire de la carte.2. Avec 32 bits par échantillon, le flux est de 200Mb/s sans compter l’overhead du protocole de transport.3. Le temps de saturer les buffers du kernel.
Chassot Sebastien, , septembre 2017 19/90
Pour ce travail, le signal est sur-échantillonné 4 afin de garder un maximum de précisionpour l’algorithme de détection. Il est donc nécessaire de pouvoir exploiter pleinement lacarte.
4.1.1 Le SDK de Cypress
Le firmware du FX3 a été écrit par Ettus et il est dans le dépôt mais il faut le SDK 5 deCypress pour le compiler. Il suffit de le télécharger et copier les dossiers ; common, lpp_sourceet u3p_firmware dans le dépôt github du projet puis de le patcher.
cd uhd.git/firmware/fx3/common/
$ patch -p2 < ../b200/fx3_mem_map.patch
$ make
Le firmware est compilé et il suffit de débrancher/rebrancher l’USRP pour qu’il soit mis-à-jourà l’initialisation de la carte.
4.1.2 Les SDK de Xilinx
ISE
Pour ce qui est du FPGA, il faut installer ISE WebPACK[28] de Xilinx pour pouvoirle recompiler. Le code est entièrement écrit en verilog alors que nous avons étudié leVHDL et il m’a fallu une période d’adaptation avant d’être à l’aise avec ce nouveau lan-guage.
Le projet utilise des Makefile et des scripts Tcl pour générer le bitstream. La compilationprend une quinzaine de minutes ce qui implique d’être méticuleux dans son travail et de bienvérifier avant de lancer la compilation. Les outils d’ISE sont utiles pour visualiser le projetmais les modifications dans ISE sont écrasées lors de la compilation.
Pour avoir plus de souplesse pendant le développement, j’ai écris un script qui lance lacompilation et sauvegarde les logs ainsi que le résultat de la compilation dans un dossier dont lenom comprend la date, l’heure, l’id du comit, ainsi qu’un commentaire (ex. ./2017.07.12-11 :15-agde4e_commentaire/ ). En ayant l’historique de tous les builds, il est possible de vérifier uneancienne version ou faire rapidement un roll-back en cas de problème.
Vivado
L’outils ISE n’est plus développé depuis octobre 2013. Xilinx l’a remplacé par Vivado pourtoutes les nouvelles générations de FPGA. Il est nettement plus convivial et support la familleArtix mais pas la famille Spartan qui nécessite toujours ISE.
Ce projet utilisant deux familles de FPGA il a fallu jongler entre ces deux SDK.
4. D’après Shannon, le taux d’échantillonnage doit être le double de la bande passante du signal soit 1Mspour LoRa.
5. Software Development Kit (SDK)
4.2 Chipscope Pro
Chipscope Pro est un outils de debug proposé par Xilinx. Il s’agit d’une IP que l’on peutajouter dans le code du FPGA et sur laquelle on peut se connecter en JTAG 6 afin devisualiser l’état de signaux internes.
L’utilisation de Chipscope Pro nécessite une licence il a donc fallut utiliser le serveur delicence de l’hepia. Sous Vivado, il y a moyen de debugger via l’USB 7 et l’IP n’est plusChipscope mais ILA (Integrated Logic Analyzer).
Figure 4.1 – Platform cable USB de Xilinx
Il faut également un driver, une application pour la connexion (iMPACT) et un client(analyzer) pour gérer les conditions de trigger et visualiser les signaux. Le driver n’estdisponible que sous RedHat et Windows 8. J’ai finalement réussi à l’installer sous arch linuxau prix de lourds efforts.
4.3 GNURadio
GNURadio[6] a été initié en 2001, dans le cadre du projet GNU 9. C’est une suite d’outils et unframwork de traitement de signal et plus particulièrement de signaux radio 10.
GNURadio supporte très bien les cartes USRP d’Ettus et permet de prototyper rapidementune application SDR. Il travaille en connectant des blocs comme des filtres (FIR), des sourcesde bruits gaussien, des Fast Fourier Transform (FFT), des mixers ou des opérateurs (addition,soustraction, produit). Les résultats peuvent être affichés sous diverses formes (waterfall,diagramme de phase, terminal,fichiers,...). Les blocs sont écris en C,C++ avec des wrappersen python.
Figure 4.2 – Exemple d’utilisation de GNURadio
GNURadio ne rentre pas dans le cadre de ce travail mais c’est cet outil qui a permis de faireles acquisitions vers un fichier pour analyse avec Matlab.
On trouve maintenant des implémentations de LoRa et de LoRaWAN et des exemplesd’émissions/réceptions[14] avec des cartes SDR.
6. Joint Test Action Group (JTAG).7. Si la carte est prévue pour.8. Il y a une dépendance à la librairie windrv qui comme son nom le laisse supposer, n’est pas très bien
supportée sous GNULinux.9. Les outils GNU de la Free Software Foundation à l’origine de GNU/linux.
10. Il y a également un fork, Pothos.
5 le FPGA de l’USRP B200
Comme mentionné plus haut, la carte USRP B200 fait partie d’une famille de produits.Ettus a uniformisé sa gamme par l’utilisation de couches d’abstractions. On trouve uneAPI commune aux différents matériels puis une implémentation spécifique à chaque de-vice.
Pour utiliser un périphérique SDR :
/* instantiate board */
uhd::usrp::multi_usrp::sptr b200_lora = uhd::usrp::multi_usrp::make();
/* get a stream */
uhd::rx_streamer::sptr rx_stream0 = b200_lora->get_rx_stream();
/* set RX sample rate */
b200_lora->set_rx_rate(rate);
Listing 5.1 – Exemple d’utilisation de l’API
Ce code serait le même quel que soit le type de matériel ; instancier une carte, acquérir unflux et définir le taux d’échantillonnage.
Quand une carte B200 est instanciée, l’API va uploader le bitstream 1 sur le FPGA, maistoutes les cartes n’ont pas de FPGA. L’API propose des méthodes génériques mais cache lesspécificités du matériel.
On trouve également ce genre d’abstractions plus profondément dans l’API. Par exemple il ya des méthodes liées au transport mais ces méthodes font abstraction de la couche physiqueutilisée (USB ou ethernet).
L’API est très bien documentée 2 mais l’architecture matérielle ne l’est pas (hormis le schémade la carte). Une grande partie de mon travail a consisté à comprendre les liens entre lematériel, le code du FPGA et l’API. Il aurait sans doute fallu bien plus de temps pour maîtrisercet environnement et exploiter pleinement les fonctionnalités de l’API.
Il était prévu au départ d’implémenter tout le système sur l’USRP. Tous les éléments sont là ;le compteur, le signal RF et le support pour un GPS. Il ne reste plus qu’à trouver un moyende communiquer entre le FPGA et le host pour faire remonter l’information de détectiond’un paquet LoRa.
5.1 Architecture de l’IP core
Le FPGA comprend trois principaux blocs :
— Un bloc communiquant avec l’ADC (b200_io).— Un bloc central (b200_core) sur lequel s’est concentré mon travail.— Un bloc gérant l’interface GPIF II qui relie le FPGA au contrôleur USB (contrôle +
FIFO).
Ces blocs sont reliés par différents bus.
1. Le code du FPGA2. La documentation est basée sur doxygen et est compilée. Elle correspond donc exactement à la version
utilisée.
Chassot Sebastien, , septembre 2017 23/90
— un bus GPIF II 3 32 bits transférant toutes les trames entre l’USB et le FPGA.— 6 bus AXI-stream[27] 64 bits (3 pairs) 4.— 1 bus wishbone[12] 32 bits utilisé pour communiquer entre les différents blocs internes 5.
Figure 5.1 – Architecture des bus USRP B200
5.2 Les registres internes
On trouve dans le FPGA plusieurs blocs radio_ctrl à différents niveaux. Ces blocs reçoivent leflux AXI-stream dédié au contrôle et les relayent sur un bus wishbone. Ils possèdent égalementun deuxième bus AXI-stream pour la lecture des registres (readback). Chaque bloc radio_ctrlcontrôle un certain nombre de registres.
Chaque registre a un bus d’adresses (8bits) et un bus de data (32bits). Si son adressecorrespond, il met à jour sa valeur, les autres registres ne font rien.
La relecture est un peu plus complexe puisqu’un registre est utilisé comme sélecteur d’unmultiplexeur. On sélectionne le registre à lire depuis l’API. Le bus AXI-stream 6 a unemachine d’état qui revoit une trame vers le host.
Figure 5.2 – Architecture du readback des registres
3. Bus utilisé par Cypress pour ses contrôleurs USB.4. Bus de Xilinx.5. Bus open source.6. Qui arbitre les différents bus AXI-stream.
On trouve au niveau de l’API et du code verilog les adresses des différents registres 7.
localparam SR_CORE_SPI = 8;
localparam SR_CORE_MISC = 16;
localparam SR_CORE_COMPAT = 24;
localparam SR_CORE_GPSDO_ST = 40;
localparam SR_CORE_SYNC = 48;
localparam SR_LORA_TEST = 56; // usage attempt
localparam RB32_CORE_SPI = 8;
localparam RB32_CORE_MISC = 16;
localparam RB32_CORE_STATUS = 20;
localparam RB32_CORE_PLL = 24;
Listing 5.2 – Adresses des registres
Le code verilog comprend des exemples commentés d’usages des user_register.
// Set this register to put a test value on the readback mux.
setting_reg #(.my_addr(SR_LORA_TEST), .width(32)) sr_lora_test (
.clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
.out(test_readback), .changed());
always @(*) begin
case (rb_addr)
RB_VITA_TIME : {rb_stb, rb_data} <= {db_rb_stb, vita_time};
RB_VITA_LASTPPS : {rb_stb, rb_data} <= {db_rb_stb, vita_time_lastpps};
RB_TEST : {rb_stb, rb_data} <= {db_rb_stb, {rx, test_readback}};
RB_TXRX : {rb_stb, rb_data} <= {db_rb_stb, {tx, rx}};
RB_RADIO_NUM : {rb_stb, rb_data} <= {db_rb_stb, {32'd0,
RADIO_NUM[31:0]}};→֒
// All others default to daughter board control readback data
default : {rb_stb, rb_data} <= {db_rb_stb, db_rb_data};
endcase
end
Listing 5.3 – Exemple d’utilisation d’un registre
Au niveau de l’API on devrait pouvoir lire et écrire le registre.
_local_ctrl->poke32(TOREG(56), test_value); // write to
uint32_t reg_result = _local_ctrl->peek32(TOREG(56)); // readback
Listing 5.4 – Exemple d’utilisation depuis l’API
7. L’adresse est écrite en dure à la compilation.
Après plusieurs tentatives infructueuses, il s’avère que ces registres ont été récemment retiréde l’API 8.
Source trouvée sur le forum Ettus[4].
Apr 28, 2017 ; 11 :04pm Re : [USRP-users] writing to user settings registerOliver-I just went through all this myself. Unlike the N210 and older etti the userregisters are no longer exposed in the API so while you can "turn" stuff on in theFPGA image there are no implementations exposed in the B200 api.
Jeffrey Long, auteur de ce message, m’a très gentillement envoyé des exemples d’utilisationdes users_register. Malheureusement, nous avions abandonné cette voie et le travail étaittrop avancé pour re-tenter l’utilisation de ces registres.
5.3 Le compteur VITA time
L’USRP propose une gestion de l’heure accessible depuis l’API. L’heure est encodée sur 64bits. Les 32 bits de poids fort représentent la seconde et les 32 bits de poids faible la fractionde seconde. Cette représentation de l’heure a pour origine la spécification du protocole detransport VITA 9 et sa gestion est faite dans b200_core.
B200 Vita time (timekeeper)
radio_legacy contient un bloc dont la fonction est de synchroniser vita_time avec un signalPPS. La source de ce signal est soit un signal externe 10, soit un signal généré en interne 11
ou le signal venant du GPS.
Figure 5.3 – Architecture compteur, PPS et LoRa
8. L’API ne propose pas d’accès direct aux registres. Ce sont des méthodes privées qui ont été retirées.9. Un protocole de transport spécifique aux applications SDR (VITA Radio Transport Protocol for SDR
Architectures).10. connecteur sma de la carte B200.11. Basé sur la clock interne avec la dérive y liée.
Figure 5.4 – Schéma du bloc timekeeper
La source du PPS est sélectionnée via un registre. L’écriture dans ce registre est faite par l’APIquand le GPS est détecté. Il n’y a pas de méthode pour gérer le GPS 12, il est géré automati-quement par l’API. N’ayant pas le GPS d’origine, une autre solution a été de contourner lemultiplexeur en connectant directement le signal PPS au timekeeper.
À l’origine, le signal vita_time n’est utilisé que dans radio_legacy, il a fallu modifierles entrées/sorties du bloc afin de le rendre accessible au niveau supérieur ou se trouvelora_detect.
5.4 Les échantillons IQ
L’ADC a une profondeur de 12 bits mais le bloc b200_io ajoute 4 bits et concatène la partieréelle (I ) et imaginaire (Q) dans un signal 32 bits. Ces data restent sous cette forme et sontmis à disposition du host tel quel. Cette uniformité a facilité le test des algorithmes dansMatlab sans avoir à faire de conversions.
Ce signal étant disponible dans le bloc b200_core, il était facile de le connecter au bloclora_detect. C’est ce flux qui est utilisé par l’algorithme implémenté. Pour obtenir ce flux, ilfaut en parallèle, «démarrer» la carte, c’est-à-dire instancier la carte depuis l’API, régler lafréquence et le sample rate.
5.5 Les GPIOs
Une autre façon d’interagir avec l’extérieur sans passer par l’API est d’utiliser des General-Purpose Input/Output (GPIO)s.
12. Il y a une méthode mais elle échoue si le GPS ne répond pas.
Figure 5.5 – Schéma GPIO USRP B200
Après avoir tenté d’utiliser les GPIOs décrites sur le schéma de la carte sans succès 13, il s’avèreque la raison est que la version des cartes B200 (Rev 4 ) n’ont pas de GPIO.
// GPIO Header J504 - 10 pin 0.1" 3.3V.
// Only present on Rev6 and later boards...these pins unused on Rev5
// and earlier.
// NOTE: These pins are allocated from complimentry pairs and could
// potentially be used
// as differential style I/O.
`ifdef TARGET_B210
inout [7:0] fp_gpio,
`endif
Listing 5.5 – Commentaire sur les GPIOs
Finalement, il y a un interface UART disponible dont les pins sont routées sur la carte. Cetinterface a permis d’avoir un signal entrant (utilisé pour déclencher des évènements depuisl’extérieur à des fins de debug) et un signal sortant une pulse, signalant la détection d’unpaquet LoRa.
5.6 Les modifications apportées au FPGA
Après analyse du code verilog, il fallait trouver le bon endroit pour intégrer un algo-rithme. Le bloc b200_core est le plus adapté. Une partie des signaux nécessaires sontà ce niveau et ceux manquants sont accessibles en modifiant les entrées/sorties de quelquesblocs.
Il a tout d’abord fallu écrire un bloc en VHDL et l’instancier dans b200_core en verilog puismodifier les Makefile pour qu’il soit compilé et accessible au projet.
Au début, l’idée était de récupérer le compteur et de stocker sa valeur dans un registreaccessible depuis l’API quand une détection à lieu. L’USB n’ayant pas d’interruption, il étaitprévu pour vérifier le principe de faire du polling sur le registre.
13. Il n’y a qu’un schéma pour toutes les cartes de la famille B2x0.
Figure 5.6 – Schéma du bloc lora_detect initial
Modifications finales du FPGA B200
Aux vues des difficultés rencontrées avec les registres et le GPS et du manque de temps nousavons décidé de transférer une partie du système sur un deuxième FPGA. L’API est toujoursutilisée pour configurer le SDR, démarrer une acquisition avec un sample rate de 50MHz.Le FPGA a un nouveau bloc lora_detect dans lequel on peut implémenter n’importe quelalgorithme et un signal est sorti sur une pin (anciennement UART) de la carte quand unpaquet est détecté.
Figure 5.7 – Schéma du bloc lora_detect final
Le compteur et la lecture des timestamp est déporté sur un deuxième système, une carteFPGA (Basys3 ).
5.7 Chipscope Pro
Le seul moyen de vérifier et debugger l’état des signaux dans le FPGA est d’utiliser une probe.Heureusement, dans le bloc b200_core il y a un exemple commenté d’utilisation de chipscope.Je n’ai pas réussi à instancier le chipscope en VHDL c’est pourquoi j’ai sorti un bus 128bitsdu bloc lora_detect et l’ai utilisé au niveau du b200_core 14.
14. Certain signaux sont nommés in et out (dans le code verilog) alors que ce sont des mots réservés enVHDL.
5.7.1 Alimentation du chipscope
La carte USRP B200 a un footprint pour un connecteur JTAG mais il n’est pas soudé. Nousen avons ajouté un mais se connecter dessus était impossible 15.
En faisant quelques mesures sur la carte, il s’avère qu’il n’y pas d’alimentation 3.3V et doncpas d’alimentation sur le JTAG.
Figure 5.8 – Schéma régulateur de tension secondaire
En remontant le circuit, il s’avère qu’il n’y a pas non plus de 3.7V . La raison est que lerégulateur principal a une pin (SHDN_SW ) pilotée par une GPIO du contrôleur CypressFX3.
Figure 5.9 – Schéma régulateur de tension principal
Pour alimenter le circuit il a fallu recompiler le firmware du FX3 avec la modificationsuivante.
@@ -1079,7 +1079,7 @@ void b200_slfifo_mode_gpio_config(void) {
/* Initialize GPIO output values. */
CyU3PGpioSetValue(GPIO_FPGA_RESET, 0);
- CyU3PGpioSetValue(GPIO_SHDN_SW, 1);
+ CyU3PGpioSetValue(GPIO_SHDN_SW, 0);
Listing 5.6 – Modification du firmware Cypress FX3
On n’imagine pas au premier abord qu’il faille patcher un firmware pour pouvoir debugger leFPGA sans que ce ne soit documenté. La raison est sans doute une économie d’énergie enutilisation normale. L’utilisation du FPGA est un usage avancé de l’USRP B200 et n’estdonc pas documenté.
15. Avec un Platform Cable USB II de Xilinx.
5.7.2 Mesures avec chipscope
Arriver à se connecter au JTAG 16 a grandement facilité la suite du travail. En probant les si-gnaux du bloc lora_detect on peut vérifier le comportement interne du FPGA.
// signals to probe (size 128 bits)
chipscope_o <= ( rx_q & rx_i & "000000000" & strobe & rst &
save_time_int & gen_lora_trigger_int & gen_soft_trigger_int &
gen_uart_trigger_int & trigger_i);
Listing 5.7 – Exemple de signaux internes à tester
Il est ainsi possible de vérifier l’algorithme sur une acquisition réelle en visualisant l’état dessignaux (ici en triggant sur un flanc montant de detection LoRa).
Figure 5.10 – Exemple d’utilisation du chipscope (vue d’un spectrogramme en parallèle)
La détection se fait quand le seuil de 25000000 est dépassé. On peut contrôler que c’est bience qui s’est passé dans le FPGA.
16. JTAG
6 Compteur et simulateur sur Basys3
La gestion des timestamps est implémentée sur une Basys3. Le format du compteur est64bits (32bits secondes et 32bits fraction de seconde 1). Les secondes sont affichées sur des7-segments 2 et permettent de contrôler visuellement la synchronisation des compteurs entreeux.
Lorsqu’un événement se produit sur une entrée (une pulse) la valeur du compteur est placéedans un registre et ce timestamp est envoyé sur l’UART.
Il y a deux sources d’événements possibles ; depuis la carte USRP B200 ou depuis unémulateur.
Pour la synchronisation des compteurs il y a également deux sources ; le PPS du GPS ou celuid’un générateur émulant un signal PPS 3. Là encore, des switchs permettent de sélectionnerune source ou l’autre.
Figure 6.1 – Interface compteur Basys3
6.1 Envoi des timestamps en UART
Le plus simple à mettre en œuvre pour accéder aux timestamps était l’UART. Il est facileavec un script de les logger dans un fichier ou de les traiter.
L’UART, utilisé est celui du projet OpenCores, l’«UART 16550 core»[13]. Son utilisation n’apas posé de problèmes particuliers.
Les valeurs de timestamp sur l’UART comprennent 20 octets ; 16 octets pour la valeur duregistre, un délimiteur sec,frac et 2 caractères de fin de ligne CR/LF). À 115200bauds, lenombre maximal de timestamp que l’on peut transmettre est de 720s−1 ce qui est suffisantdans un premier temps.
1. Le compteur va de 0 à 10e8 et 27bits auraient suffit.2. La valeur est affichée en hexadécimal.3. Un signal PPS est une pulse d’une période de 1Hz et d’une durée de 40ms (en général).
Chassot Sebastien, , septembre 2017 33/90
6.2 L’émulateur d’événements et de PPS
L’émulateur n’a d’autres fonctions que de tester le système. Il a 8 sorties PPS simulées et 8sorties d’évènements synchrones.
Les évènements sont activés manuellement par un bouton ou avec un switch en modeautomatique générant 100 pulses par seconde.
Figure 6.2 – Interface simulateur Basys3
7 Agrégation des timestamp ettrilatération
La trilatération ne rentre pas dans le cadre de ce travail, néanmoins les timestamps ontbesoin d’être comparés. En l’état actuel, les détecteurs sont proches mais un système réelimpliquerait qu’ils soient éloignés de plusieurs centaines de mètres ; il faudra d’une manièreou d’une autre regrouper les données pour les comparer.
Un moyen rapide d’y arriver est d’envoyer depuis chaque système les mesures sur Internet.MQTT [11] est un protocole léger et facile à mettre en œuvre, il est basé sur l’envoi de petitsmessages en mode publisher/subscriber. Les détecteurs publient leurs mesures qui peuvent êtrerécupérées depuis n’importe où. MQTT a une forte latence mais jusqu’à quelques dizainesde messages par seconde ; il convient très bien.
Un script est lancé sur chaque système de détection.
./lora_detect_mqtt_pub.py -p -c /dev/ttyUSB0 -n liotard \\
--lat 46.209205 --long 6.134255
usage: mqtt_pps.py [-h] [-p] -c device -n CARD_NAME --lat LATITUDE --long
LONGITUDE→֒
optional arguments:
-h, --help show this help message and exit
-p pretty print timestamp
-c device device 0 (/dev/ttyUSB?)
-n CARD_NAME name of the gateway
--lat LATITUDE latitude of gateway
--long LONGITUDE longitude of gateway
Listing 7.1 – Script au broker MQTT
Le script python lit les timestamp depuis l’UART, les empaquète au format JSON et lesenvoie à un broker MQTT.
>>> sample_msg
{'name': 'gw_liotard', 'timestamp': 123.43254352, 'latitude': 46.209205,
'longitude': 6.134255}→֒
Listing 7.2 – Exemple de message transmis au broker MQTT
L’avantage de cette méthode est que l’architecture n’est pas prédéfinie. Un nombre quelconquede détecteurs peut être utilisé. Plus tard, un sens sera donné à ces données. Actuellement,le JSON ne contient que le timestamp. Idéalement, la détection devrait être couplée à unedémodulation de la trame complète. L’émetteur pourrait être identifié en lisant le payloaddes messages. La couche de transport (LoRaWAN) a un header identifiant l’émetteur et uncompteur de frame 1. Avec ces informations, on peut déterminer quels sont les messages à
1. La partie utilisée pour le routage de LoRaWAN n’est pas chiffrée.
Chassot Sebastien, , septembre 2017 35/90
comparer. Un service pourrait récupérer les mesures de tous les messages au header identiqueset les localiserait en fonction des coordonnées géo-temporelles de réceptions. Plus le nombrede récepteurs serait grand plus la trilatération serait précise.
Trois coordonnées géo-temporelles permettent de localiser un point dans un plan 2. Avecune quatrième, on peut également déterminer l’élévation. Toutes les coordonnées supplé-mentaires peuvent permettre d’affiner la localisation. On peut faire une trilatération pourchaque combinaison de 3 ou 4 mesures et prendre le centre de gravité de tous ces résul-tats.
En ne définissant pas d’architecture dès le début, le système pourra facilement évoluer dansle futur.
Actuellement, le système est composé de deux détecteurs. Un script s’abonne au brokerMQTT et récupère les messages à traiter.
./lora_timestamp_analyser.py -p -s test.mosquitto.org -t lora_dtoa_topic
usage: pps_analyzer.py [-h] [-p] -s MQTT_SRV -t MQTT_TOPIC
optional arguments:
-h, --help show this help message and exit
-p pretty print timestamp
-s MQTT_SRV mqtt server
-t MQTT_TOPIC mqtt topic
Listing 7.3 – Script analysant les timestamp avec MQTT
Quand deux timestamps sont reçus, ils sont comparés et le résultat affiché. La librairie geopypermet de faire des opérations sur les coordonnées comme mesurer les distances entre lesrécepteurs (ici un exemple hypothétique).
=======================================
Server started
=======================================
Listen to MQTT topic : lora_dtoa_topic
=======================================
=============================================
Location : prairie (46.209828, 6.135596)
Timestamp : 16.137763760 s
Location : liotard (46.209205, 6.134255)
Timestamp : 16.137763780 s
Distance entre les gateway : 124m
---------------------------------------------
Différence : 20 [ns] (env. 5m d´erreur)
=============================================
=============================================
Location : prairie (46.209828, 6.135596)
Timestamp : 16.198758160 s
Location : liotard (46.209205, 6.134255)
Timestamp : 16.198758180 s
Distance entre les gateway : 124m
---------------------------------------------
Différence : 20 [ns] (env. 5m d´erreur)
=============================================
2. L’intersection de trois sphères non alignées est un point.
7.1 Calcul de la distance
La transformation d’une différence de temps en distance est relativement triviale.
Figure 7.1 – Schéma temps de propagation d’une onde
Ce que nous savons, c’est qu’au temps tx, quand le récepteur 1 a détecté l’onde, elle a encoreparcouru dt · vonde avant d’atteindre le récepteur 2. Comme nous connaissons la position desrécepteurs dans l’espace, nous déduisons que :
s = 2x + (t2 − t1)vonde = 2x + dt · vonde
et que la position du LoRaMote est :
x =s − (dt · vonde)
2
À noter que quand dt · vonde = s ⇐⇒ x = 0, on ne peut déterminer la position duLoRaMote. L’émetteur doit nécessairement être entre les deux récepteurs (sinon impossiblede déterminer tx). Si x = 0 c’est que l’onde a pu parcourir une distance quelconque avantd’être détectée 3.
La précision des distances dépend directement de la précision des mesures de temps et del’erreur ξ.
dtm = (t2 ± ξ) − (t1 ± ξ) = (t2 − t1) ± 2ξ = dt ± 2ξ
Le taux d’erreur est :
T =2ξ
dt
Quand dt est petit, l’erreur est prépondérante alors que s’il est grand, l’erreur devientnégligeable.
En l’état actuel, localiser un émetteur n’a de sens que pour des distances de l’ordre de 100m(à moins d’utiliser du matériel plus précis). En dessous, la précision ne sera sans doutes pasassez fine et au-delà de quelques kilomètres on sera confronté à un signal très dégradé qu’ilsera difficile de détecter.
3. Il faudrait plus de récepteurs pour lever le doute.
8 Synchronisation de systèmes distants
8.1 Principe de l’algorithme
Le flanc montant du signal PPS est considéré comme fiable pour resynchroniser les systèmes.Or le GPS ne peut fournir ce signal que s’il reçoit les satellites, ce qui n’est pas toujours lecas. Pendant ce travail, les jours de pluie et malgré les antennes placées à l’extérieur 1, lesGPS n’arrivaient pas à locker le signal des satellites 2.
La synchronisation des compteurs repose sur un principe simple et s’inspire de celui del’USRP. Il y a deux compteurs ; l’un comptant les secondes et un second les fractions deseconde. Comme le DToA n’a besoin que de différence de temps, il n’y a pas besoin de tempsabsolu mais juste que les compteurs soient dans la «même seconde».
Le compteur fracsec est incrémenté à chaque coup d’horloge et prend des valeurs de [0 à108 − 1]. Quand sa valeur atteint 5 · 107, on place dans un registre la valeurs de la prochaineseconde. Si un signal PPS arrive le compteur est écrasé par la valeur registresec +0fracsec (lafracsec vaut zéro à cet instant). Si ce signal n’arrive pas, le compteur fonctionne normalement(avec sa dérive). Tant que la dérive ne dépasse pas ±0.5[s], le compteur est resynchronisé dansla «même seconde». Ce cas pourrait arriver si le signal PPS était perdu pendant plusieursjours, ce qui est peu probable.
L’USRP fonctionne de la même manière ; une méthode écrit la valeur que prendra lecompteur dans un registre et cette valeur sera effective lorsqu’un événement se produit.Il n’est pas possible de régler correctement l’heure depuis le host puisque la commandepasse par l’USB et qu’on ne peut savoir le temps qu’elle mettra à arriver dans le FPGA.La librairie uhd/host/lib/usrp/gpsd_iface.cpp traite les trames NMEA depuis l’OS. Quandle GPS est activé et qu’un temps valide est reçu, ce temps incrémenté d’une seconde estécrit dans un registre 3 et le compteur interne prend cette valeur au flanc montant du PPSsuivant.
Basé sur ce principe le compteur s’est révélé parfaitement fiable. Il reste que le compteur faitdes sauts à chaque synchronisation. Si un paquet LoRa arrive en même temps que le PPSil y a un risque qu’un compteur soit resynchronisé alors qu’un autre ne le soit pas encore.Cette erreur est inévitable avec une telle architecture mais n’est pas pire que les erreurs liéesaux dérives de l’oscillateur (comme nous le verrons plus bas).
La meilleure solution serait d’utiliser un oscillateur asservit. Le décalage entre la valeur ducompteur et le PPS serait utilisé comme rétroaction sur le quartz. En jouant sur sa températureavec un corps de chauffe 4 et une isolation thermique 5, on peut augmenter ou diminuer safréquence plutôt que d’avoir ces sauts de synchronisation[23].
1. Les antennes sont placées sur un rebord de fenêtre.2. Les GPS ont généralement un signal externe appelé lock signifiant que les trames UART sont valides
ou ne le sont pas.3. Le temps d’écriture est bien inférieur à la seconde.4. Une résistance ou un transistor.5. Oven controlled crystal oscillator (OCXO).
Chassot Sebastien, , septembre 2017 39/90
8.2 Mesures d’erreurs des sources de synchronisation
Précision des signaux PPS des shield Draguino LoRa/GPS
Le module choisi embarque un MTK MT3339[7]. D’après la datasheet le signal PPS à latolérance suivante.
— Typical accuracy : ±10ns
Le GPSDO proposé par Ettus n’a pas pu être testé mais annonce un jitter de ±50ns.Vu son prix et une compensation en température 6 cette valeur est certainement plus réa-liste.
Mesures du GPSDO et du simulateur
Afin de quantifier les sources d’imprécisions, il est important de vérifier les hypothèses. Lesmesures effectuées sur deux shield, donnent un déphasage allant de 0ns à ±70ns 7. En général,une carte est en avance sur l’autre mais parfois le déphasage s’inverse. Ces valeurs dépassentlargement les ±10ns annoncés par le fabricant.
Figure 8.1 – Déphasage de deux signaux PPS générés par deux GPSDO
Pour évaluer la précision théorique et s’affranchir des problèmes d’acquisition GPS enintérieur on utilise aussi le signal du simulateur. En théorie, le signal devrait être bienplus précis. La fréquence de 1Hertz ne l’est pas mais le signal devrait arriver «en mêmetemps».
On trouve néanmoins un petit déphasage.
6. Temperature compensated crystal oscillator (TCXO)7. Peut-être même plus.
Figure 8.2 – Déphasage de deux signaux PPS générés simultanément depuis le simulateur
Le déphasage est d’environ de 4ns par contre le taux de montée est relativement médiocre(15ns 8). Ce taux de montée est en partie dû à la qualité des câbles utilisés. L’origine auraitégalement pu être imputé au FPGA mais passer le slew rate 9 des pins à FAST n’y a rienchangé.
8.3 Méthodologie de tests
Le simulateur peut envoyer des évènements en continu à une fréquence de 100Hz. Avec100 mesures par seconde on peut mettre en évidence les variations entre les deux comp-teurs.
8.4 Dérive temporelle entre deux compteurs synchroniséspar simulateur
Les résultats montrent que les différences sont nulles juste après la synchronisation puis lescompteurs divergent. La dérive n’est pas stochastique mais linéaire. Son origine est forcémentliée aux fréquences d’horloges.
8. Mesuré à 10%-90%.9. Il est possible d’imposer des contraintes aux pins du FPGA comme par exemple un taux de montée
plus rapide.
Figure 8.3 – Dérive temporelle avec synchronisation par simulateur
On peut remarquer que la progression n’est pas complètement linéaire mais en forme d’escalier.Cela est dû à la résolution de l’horloge. La différence est stable pendant quelques mesuresavant d’atteindre 10ns et se stabiliser à un nouveau seuil. On remarque également quelquespics. Ces variations sont normales dans un système mais il est intéressant de noter qu’ils nedépassent pas les 10ns.
Une dérive stable est une bonne chose puisque des solutions pour la réduire sont envisageables.Comme par exemple un étalonnage avec une compensation.
s.00 s.01 s.02 s.03 (...) s.99dt - 0 ns - 3 ns - 6 ns - 9 ns ... -297 ns
Table 8.1 – LUT facteurs de correction pour un dtmax = 300ns
ou une fonction :
dtcompensated = dtmeasured(1 −dtmax
rate)
Tolérance des quartz
Le premier couple de carte utilisé pour les mesures donnait des dérives d’environ 1700ns s−1.En testant d’autres cartes les résultats sont identiques pour ce qui est de la linéarité maisl’écart au bout d’une seconde varie significativement.
Figure 8.4 – Dérive temporelle avec synchronisation par simulateur (avec un autre couplede cartes)
Les écarts de plusieurs cartes prises au hasard sont de {250, 600, 800, 1200, 1700}ns s−1.
On voit la disparité due aux composants. Ce taux d’erreur est bien inférieur à ce qu’il pourraitêtre. Le quartz DSC1033[10] utilisé sur la carte Basys3[2] a une tolérance de ±50ppm 10.À une fréquence de 100MHz l’erreur pourrait être de ±5000clk s−1 par carte soit jusqu’à10000 cycles d’horloge de décalage entre deux cartes.
Il est donc possible d’obtenir de meilleurs résultats et réduire cette dérive par l’utilisationd’un oscillateur de bonne qualité compensé en température[23].
À noter que les mesures ont été faites après avoir laissé chauffer les composants quelquesdizaines de minutes.
8.5 Avec ou sans synchronisation
Perte de synchronisation
Voici ce qui se passe quand la synchronisation ne s’effectue plus.
10. Température comprise entre -20°C et + 70°C.
Figure 8.5 – Comparaison de la dérive avec ou sans synchronisation
La synchronisation a eu lieu 3 fois. La dérive a été ramenée à zéro puis la synchronisation estinterrompue et les systèmes divergent.
Resynchronisation
Dans cet exemple, on voit très bien ce qui se passe quand le signal de synchronisation dusimulateur est interrompu. Les systèmes divergent, puis quand le signal arrive à nouveau, leshorloges se resynchronisent.
Figure 8.6 – Perte de synchronisation et reprise
8.6 Dérive temporelle entre deux synchronisations parGPSDO
Maintenant que les mécanismes sont plus clairs, vérifions ce qui se passe quand la sourcede synchronisation n’est plus unique (simulateur) mais vient de deux GPSDO utilisant leréseau GPS.
Figure 8.7 – Dérive temporelle avec synchronisation par GPSDO (positive)
Nous retrouvons cette forme en dents de scie mais cette fois il y a une composante continueliée au déphasage des signaux PPS.
Figure 8.8 – Dérive temporelle avec synchronisation par GPSDO (négative)
Cette composante continue peut être positive ou négative ce qui n’est pas étonnant pour dessystèmes indépendants.
Compensation logicielle
La dérive peut être réduite en soustrayant une compensation. Juste après la synchronisationla compensation est faible puis elle augmente. On arrive à supprimer presque complètement lacomposante linéaire. L’erreur est de l’ordre de ±5m avec une synchronisation par simulateur.Pour obtenir ce résultat, il faut faire une calibration des cartes.
Figure 8.9 – Dérive temporelle avec synchronisation par simulateur et compensation logi-cielle
L’erreur est de l’ordre de ±10m en situation réelle (GPS).
Figure 8.10 – Dérive temporelle avec synchronisation par GPSDO et compensation logicielle
Conclusion sur les compteurs
Ces résultats sont très encourageants. Il faut encore tenir compte de l’erreur dans la précisionde la détection mais quelques dizaines de mètres d’erreur sur un kilomètre offrent déjà uneinformation significative.
Voyons comment associer ces résultats avec la détection d’un paquet LoRa en traitant unsignal RF.
9 LoRa modulation
LoRa utilise une modulation par étalement de spectre (Spread Spectrum (SS)). Le principeest de répartir l’information sur toute la bande passante ce qui minimise les effets du bruit.Souvent les modulations basées sur SS utilisent des séquences prédéfinies (pseudo-random)comme par exemple le Bluetooth 1.
Dans le cas de LoRa on utilise une porteuse qui se déplace en permanence. La séquencepseudo-random est remplacée par une simple suite de fréquences 2. Cette technique appeléeCompressed High Intensity Radar Pulse (chirp), est inspirée des radars 3 militaires et civils.La porteuse est un signal qui augmente en fréquence en allant de fmin à fmax à une vitessedfdt
déterminée 4.
Figure 9.1 – Exemple de chirp (fréquence)
Si l’on observe comment la fréquence de la porteuse évolue dans le temps on voit quele signal f(t) est en forme de dents de scie. Quand la fmax est atteinte, elle reprend àfmin.
Figure 9.2 – Evolution de la fréquence en fonction du temps
1. Saut de fréquence dans la bande 2.4GHz.2. C’est une forme de séquence prédéfinie et c’est pourquoi LoRa est dans la bande 867-870MHz dédiée
aux modulations par SS.3. Le signal émit est du même type.4. fmin et fmax représente les bornes de l’occupation en fréquence du signal
Chassot Sebastien, , septembre 2017 47/90
Un mélange de FSK et de chirp
La modulation FSK 5 est relativement commune ; chaque symbole est représenté par unefréquence différente. En faisant une FFT 6 on obtient des pics correspondant aux symbolesencodés.
f(symb) ∈{
fs0, fs1, ..., fsn−1
}
LoRa fait exactement la même chose mais mixe une modulation FSK avec le chirp. On obtientune modulation par «saut de chirp». En pratique le chirp va sauter du chirp représentant lesymbole actuel vers celui du prochain symbole.
En mixant un chirp et une fréquence représentant le symbole, on obtient la modulationLoRa.
Figure 9.3 – Exemple de mixage du chirp et d’une fréquence fixe
Le nouveau signal sort de la bande d’émission (aliasing), il est donc replié et filtré etprend cette forme caractéristique que l’on retrouve dans le spectrogramme d’un signalLoRa.
Si le nombre de symbole est de 256 (2SF ) chacun est représenté par un chirp propre. Pour lesymbole n, le chirpn va de :
fdébut =(
fmin +n
bp
)
à ffin =(
fmax +n
bp
)
%bp
Figure 9.4 – Exemple de modulation de symboles
5. Frequency-Shift Keying (FSK)6. FFT
Effet du bruit
Même avec un rapport signal sur bruit (SNR) très faible il est possible de reconstruire lesignal. En théorie il suffit d’une coordonnée (f, t) pour déterminer quel chirpn unique passepar ce point.
Figure 9.5 – Exemple de signal très bruité
En sachant qu’un symbole peut s’étendre sur plusieurs millisecondes, on comprend mieuxpourquoi cette modulation est extrêmement résistante au bruit.
Démodulation
Que se passe-t-il quand un up-chirp ou un symbole est mixé avec un down-chirp ?
Figure 9.6 – Exemple de mixage du down-chirp et d’un symbole
On retrouve précisément une modulation FSK. Il suffit donc de faire une FFT sur le signalmixé pour reconnaître le symbole.
Voici à quoi ressemble le spectrogramme d’un court message.
Figure 9.7 – Exemple de transmission
9.1 Canal de communication
En pratique le canal de communication va être défini par plusieurs constantes sur lesquellesl’émetteur et le récepteur se sont préalablement entendus.
Ces constantes sont :
— l’occupation en fréquence (Bande Passante (BP)).— la fréquence du channel.— le Spreading Factor (SF 7).
L’occupation en fréquence
LoRa occupe une bande de 125, 250 ou 500KHz. Une plus grande bande passante améliore latransmission (meilleur étalement du spectre). En contre-partie, la vitesse df
dtétant fixe, les sym-
boles vont durer plus longtemps avec un «temps de vol» qui va s’allonger 8.
Le channel
LoRa peut exploiter 8 channels dans la bande UHF 9. En Europe aux alentours de 868MHzet aux États-Unis 915MHz. Le duty cycle doit rester inférieur à 1%.
Le spreading factor
Le SF est une valeur comprise entre 7 et 12 déterminant le nombre de symboles enco-dés :
Nbsymboles = 2SF (de 128 à 4096)
La BP est donc divisée en Nbfréquences et à chaque fin de période de symbole (Ts), un sautde chirpsn est opéré vers le chirpsn+1 du nouveau symbole.
La vitesse du chirp ( dfdt
) est également déterminé par la valeur du SF.
rate =BP
2SF=
df
dt
La période Ts est également fonction du SF et de la BP :
7. Sreading Factor (SF)8. Donc il y a également un impact sur le duty cycle9. Dans la bande Industrial Scientific and Medical radio bands (ISM)
Ts =2SF
BP[s]
Plus le SF est élevé, plus le symbole est maintenu longtemps. Le temps de transmission aug-mente mais en contrepartie la communication est plus résistante au bruit.
Sur-encodage, whitening et parité
Si le saut vers un nouveau symbole est proche du précédent, il y a un risque de ne pasarriver à les distinguer 10. Pour éviter cela LoRa utilise la technique du code de Gray[22]. Lemessage original est considéré comme un code de Gray. Dans un code de Gray, deux valeursconsécutives n’ont qu’un bit de différence. En appliquant l’opération inverse, on s’assureque deux symboles n’ayant qu’un bit de différence ne seront pas envoyés l’un à la suite del’autre.
Le message est également randomisé en faisant un XOR avec une séquence pseudo randompartagée par l’émetteur et le récepteur (Whitening) 11. On réduit ainsi l’envoi de suite desymboles identiques.
Pour la correction d’erreur, une parité est également ajoutée tous les nbits.
Toutes ces opérations sont réversibles. Le récepteur les ré-applique et retrouve le messageoriginal.
9.2 Quelques chiffres significatifs
Le bit rate d’un paquet LoRa
Avec un SF de 7 (125KHz), on obtient un bitrate de 27343 bits/s alors qu’un SF de 12 et unebande passante de 500KHz ne permet de transmettre que Rb = 366 bits/s 12.
Rb = SF ·BP
2SF[bits/s]
La période symboles
Avec un SF de 12 (125KHz), le temps d’un symbole est de Ts = 32.768[ms] alors qu’avec unSF de 7 (500KHz) le temps n’est plus que de Ts = 0.256[ms].
Ts =2SF
BW[s]
10. Le seuil de détection d’un changement dans la machine d’états du récepteur risque de ne pas êtreatteint.
11. Cette séquence a été découverte par reverse engineering et présenté par Matt Knight[8]12. Bite rate sans tenir compte des symboles de parité.
Le «temps en vol» d’un message
Si l’on tient compte du préambule et de la parité, pour un message de 32 symboles il faut50 symboles transmis 13.
Tvol = 50 ·2SF
BP[s]
Le même message peut être transmis en 1.63[s] avec un SF de 12 (125KHz) ou en 0.0128[s]avec un SF de 7 (500KHz).
Rapport temps/distance d’une onde électromagnétique
Une onde RF à une vélocité à peu près égale au 2/3 de la vitesse de la lumière, soit environ200000000[ms−1] d’où on peut déduire les ordres de grandeurs suivants :
1 m ⇐⇒ 5 ns
1 ns ⇐⇒ 0.2 m
10 ns ⇐⇒ 2 m
20 ns ⇐⇒ 4 m
En comparaison, le temps entre deux échantillons de l’ADC est de 20ns et l’horloge ducompteur à une période de 10ns. On comprend ainsi mieux la relation entre les erreurs demesures et les erreurs de localisation. Une distance de 50m est parcourue en 250ns et il faut50000ns pour parcourir 10Km. Arriver à une résolution de 100 − 200ns en ferait un systèmefonctionnel.
Ce sont ces grandeurs, très approximatives, qui ont été utilisées dans ce travail explora-toire. Il faudrait évidemment prendre des valeurs plus précises pour une application enproduction.
Voyons maintenant comment utiliser ces informations pour rechercher un bon algorithme dedétection.
13. Ce nombre peut changer en fonction du type de parité et de la longueur du préambule.
10 Recherche d’un algorithme
Pour qu’un système soit fonctionnel, il faudrait prendre en compte la détection de tousles SF, toutes les BP et détecter plusieurs LoRaMotes en même temps. Dans un premiertemps je me suis concentré sur un channel sur lequel on reçoit un signal de SF et BPdéterminés.
Lors de la réception d’un paquet une phase de synchronisation a lieu. Elle permet dereconnaître le début d’une transmission et de rentrer dans la machine d’états mais passeulement ; elle sert à synchroniser le récepteur sur le chirp de l’émetteur et à mettre en phasele downchirp qui va permettre de démoduler la suite du message. Les sauts de fréquences(fmax =⇒ fmin) vont également permettre de synchroniser la période Ts avec le début destemps symboles.
On retrouve une suite de nup−chirp suivit de 2down−chirp. Le nombre de upchirp peut variermais est communément de 8. La synchronisation, elle, est toujours composée de 2 downchirppuis suivent les symboles proprement dit.
Figure 10.1 – Exemple de préambule
Figure 10.2 – Spectrogramme du préambule (6+2)
Ce travail a pour but de timestamper un instant précis dans la réception d’un paquet LoRa.La phase de préambule est commune à tous les messages et sert à synchroniser l’émetteuret le récepteur. C’est donc dans cette zone qu’on cherchera à identifier un point précisreconnaissable.
10.1 Implémentation logiciel d’un simulateur
Pour vérifier les hypothèses et inspiré par un exemple d’algorithme en Matlab (blog SakshamaGhoslya)[5], j’ai ré-implémenté un modulateur/démodulateur en Python 1. Ce modèle permetde générer un signal modulé, un down-chirp, de les mixer et de comparer ce résultat avec lesacquisitions.
1. En utilisant Scipy, Numpy et matplotlib.
Chassot Sebastien, , septembre 2017 53/90
Figure 10.3 – Exemples générés par le simulateur
On retrouve bien les seuils correspondant aux symboles démodulés.
10.2 La fréquence d’exécution de l’algorithme
Un algorithme peut opérer dans le domaine temporel mais également dans le domainefréquentiel. Ce que nous cherchons est d’identifier une position dans le flux et déclencher lamémorisation du timestamp. Il n’est pas nécessaire de le faire instantanément mais s’il y aune latence elle doit impérativement être la même sur tous les systèmes. Un FPGA permetde garantir qu’un algorithme prend toujours le même nombre de coups d’horloge et sa latenceest donc stable.
L’algorithme peut être fait en comparant un échantillon au suivant mais généralement ontravaille sur un certain nombre d’échantillons (une fenêtre).
On peut utiliser des fenêtres juxtaposées mais généralement on superposera plus ou moinsles fenêtres.
Figure 10.4 – Juxtaposition des fenêtres
La fréquence à laquelle est exécuté l’algorithme dépend de la taille de la fenêtre et del’offset.
frequencedetection =samplerate · (offset)
windowsize
Quand l’offset = windowsize, la fréquence est de :
frequencedetection =samplerate
windowsize
et quand l’offset → 1, la fréquence tend vers :
frequencedetection = samplerate
Exécuter l’algorithme pour chaque nouvel échantillon (50millions/sec) demanderait trop deressources. Il va donc certainement falloir trouver un compromis entre la taille de la fenêtreet l’offset.
Figure 10.5 – transition up-chirp/downchirp
Ici la 1ère et la 4ème figures sont respectivement un up-chirp et un down-chirp alors que lesautres sont des transitions. Cet exemple montre un cas idéal où la fenêtre ne comprendqu’une fréquence (la fenêtre est parfaitement superposée avec la période Ts) mais ce ne serajamais le cas en pratique.
10.3 Première approche naïve (domaine temporel)
Nous savons qu’un signal à 868MHz n’est pas forcément un paquet LoRa mais c’est unévénement qu’on peut facilement détecter.
Vu que la modulation ne varie pas en amplitude, le module de chaque échantillon devraitêtre relativement constant.
‖amplitude‖ =√
I2 + Q2
Il suffit de fixer un seuil et de trigger dès que ce seuil est dépassé par n échantillonssuccessifs 2. Les samples sont sur 32bits (16bits I et 16bits Q) donc il suffit de faire attentionaux overflows.
Cet algorithme a été implémenté sur le FPGA avec succès. Comme attendu, les performancesne sont pas très bonnes. En regardant une acquisition de signal dans le domaine temporel,on peut remarquer que l’amplitude du signal suit une certaine pente.
Figure 10.6 – Exemple d’un signal échantillonné (un paquet LoRa)
Le seuil doit être au dessus du bruit et en dessousde l’amplitude supposée. Le seuil est donc atteintpendant cette phase de montée. Avec l’atténuationdu signal dû à la distance, l’amplitude ne sera pas lamême sur deux récepteurs éloignés. La détection sefait en des temps légèrement différents ; ce qui induitune erreur de mesure.
En jouant sur les gains au niveau des récepteurs onpeut améliorer la détection mais ça reste du brico-lage. Par contre cet algorithme est fait dans le do-maine temporel directement sur le signal. Il offre ledouble avantage d’être léger et facile à implémen-ter.
Cette algorithme reste relativement stable. En simulation, ajouter du bruit gaussien à lacapture ne fait varier la détection que de quelques échantillons 3. On obtiendrait égale-ment de bon résultat en normalisant le signal mais c’est compliqué de le faire en tempsréel 4.
2. Une fenêtre de taille n et d’offset = 1.3. ±50[sample] avec un bruit de 80dB.4. Il faut une fenêtre suffisamment grande.
Mesures
Les mesures effectuées tendent à prouver qu’un système DToA est possible.
Un émetteur a été placé à 5m des deux détecteurs et émet un paquet LoRa toutes les 3s.Voici ce que donne l’histogramme de 40 mesures.
Figure 10.7 – Exemples générés par le simulateur
On semble retrouver une distribution gaussienne centrée en zéro même si elle n’est pas trèsnette. Le système est en outre très vite perturbé. Il suffit de bouger un détecteur pour queles résultats varient beaucoup plus. Les tests ont été effectués en intérieur et les mesures sontsensibles aux obstacles. Il suffit de toucher une antenne pour que dt dépasse 3µs. Les deuxUSRP ont le même gain 5, mais le moindre changement donne des écarts de plusieurs µs. Lapreuve de principe est faite mais ne fonctionnerait pas aussi bien si les détecteurs étaientéloignés. Il faut donc chercher d’autres algorithmes plus fiables.
10.4 Utiliser la phase (domaine temporel)
Sur le diagramme de constellation on voit les échantillons tourner autour d’un cercle de rayonégal à l’amplitude. On remarque également la spirale (montée en amplitude).
5. Le gain du Low Noise Amplifier (LNA) interne.
Figure 10.8 – Inversion de chirp
Sur une acquisition on peut remarquer un changement de phase offrant une caractéristiquequi pourrait être identifiable.
Figure 10.9 – Changement de phase Figure 10.10 – Exemple de point remar-quable
On peut imaginer un algorithme basé sur une mesure angulaire.
θ1 < θ2 < (...) < θn−1 < θn > θn+1 > θn+2
Les angles croissent puis le phénomène s’inverse. En combinant cette caractéristique avec uneamplitude (inversion & amplitude>trigger ) on peut déclencher un évènement.
J’ai essayé de mettre en place un algorithme basé sur ce principe sans résultat. Cette partiedu signal ressemble à un passage par une fréquence de 0Hz ; or je n’ai pas retrouvé ce paternsur le modèle. La fonction utilisée dans le modèle théorique est scipy.signal.chirp() et diffèreapparemment de celui produit par un émetteur.
10.5 Produit de convolution (domaine temporel)
Une idée serait de faire un produit de convolution dans le domaine temporel avec commeréférence une partie du signal facile à reconnaître. Une difficulté est de faire une convolutionavec un signal non normalisé (en raison des différences de gains). Nous ne sommes pas sûrsnon plus que la corrélation fonctionnera sur différent modèles d’émetteurs. Mais il y a aussiune contrainte liée au matériel.
On peut placer les échantillons dans un buffer circulaire et le comparer à un signal stockédans un Block RAM. La difficulté va être de faire le produit de convolution en parallèle. Onpeut accéder à la mémoire de façon séquentielle mais pas massivement en parallèle ; il faudraitpipliner le produit de convolution. Réaliser ce type d’algorithme nécessiterait d’utiliserplusieurs cycles d’horloge et donc d’augmenter l’offset de la fenêtre.
10.6 Inversion de chirp (domaine fréquentiel)
En faisant une FFT sur le signal, on remarque que la fréquence va de gauche à droite pendantle up-chirp puis s’inverse pendant le down-chirp. Cet événement pourrait aussi servir derepère temporel. L’idée serait de rentrer dans une machine d’états (up-chirp) puis, dès qu’ily a n échantillons inversés successifs, le trigger est déclenché.
Par contre, la fréquence de détection serait au mieux égale à celle des FFT.
10.7 En détectant une transition (domaine fréquentiel)
Une dernière approche plus prometteuse serait d’utiliser une FFT et d’y chercher unetransition.
Figure 10.11 – FFT glissante
Faire une FFT revient à observer le signal pendant un laps de temps. Comme le chirpvarie pendant ce laps de temps, on retrouve une forme carrée. Faire la somme de cesfréquences revient à calculer l’énergie du spectre. Quand la fenêtre est à cheval entre deuxchirps! (chirps!), on voit un deuxième carré apparaître. En faisant la somme de chacun deces carrés, on obtient leur énergie respective. Le ratio des deux devrait correspondre à laposition dans la fenêtre.
x =∑
freq1∑
freq0
=a
b
La position serait x · windowsize. En augmentant le nombre de FFT on trouve un ensemblede position (x0, x1, ..., xn−1).
Un algorithme pourrait accumuler n mesures et en faire une moyenne
x =1n
n−1∑
i=0
xi · windowsize − i · offset
La valeur x est un décalage par rapport à la valeur du compteur (ref).
Cet algorithme n’a pas été testé pour des questions de temps mais il offrirait un boncompromis. La fenêtre devrait être plutôt grande (pour englober la transition) et l’offsetdéterminerait le nombre de mesures n. Le rapport ne dépend pas du gain mais uniquementdes fréquences.
11 Conclusions
Ce travail exploratoire s’articule autours de deux volets ; La synchronisation de systèmesdistants et l’identification d’un point précis dans un flux d’acquisition en temps réel.
Pour ce qui est de synchroniser des systèmes distants, l’objectif est pleinement atteint. Laqualité de l’horloge est très importante puisque les erreurs viennent principalement là. Avecun bon oscillateur l’erreur viendrait du GPS mais là encore on peut trouver du matériel plusprécis. La limite vient donc des moyens qu’on se donne et non d’une limitation de l’approcheelle-même. À noter que les compteurs ont été placés côte-à-côte parce qu’il est très difficilede les tester autrement. On suppose donc que le système garde sa précision grâce au réseauGPS.
Du côté de la détection le résultat est plus mitigé ; coupler un transciever et un FPGA estclairement une bonne approche. La partie SDR n’est pas indispensable. Il suffirait d’un ADCet d’un circuit ramenant le signal en bande de base. Il peut dès lors être intéressant de prendrele temps de développer un algorithme sur un FPGA puisque la tâche est très répétitive etdemande de bien maîtriser la latence. Néanmoins, la question de l’algorithme n’est pas réglée.Par manque de temps je n’ai fait que des propositions qu’il reste à explorer. Nous savions dèsle début qu’il n’y aurait pas le temps d’implémenter un algorithme robuste. L’algorithme naïffonctionne mais n’est pas suffisant. Il faut continuer les recherches.
On trouve sur Internet une multitude d’informations sur la trilatération. Une fois les co-ordonnées et distances connues, le calcul est trivial. La position des récepteurs peut êtreconnue à quelques mètres près et notre système DToA permet d’avoir les distances. Enaccumulant suffisamment d’informations on peut affiner la localisation. Avec un émetteurenvoyant plusieurs messages par minute, on obtient rapidement beaucoup de mesures et onpeut faire un traitement sur ces «big data». Il reste à voir comment déployer le système.Centraliser les data avec MQTT est une piste mais dans tous les cas, c’est une questiond’architecture logiciel qui ne remet pas en cause le principe du DToA.
Chassot Sebastien, , septembre 2017 61/90
12 Annexes
12.1 Vue RTL compteur Basys3
12.2 Vue RTL simulateur Basys3
b200_io
b200_io_i0
rx_data(11:0)
tx_i0(11:0)
tx_i1(11:0)
tx_q0(11:0)
tx_q1(11:0)
mimo
reset
rx_clk
rx_frame
rx_i0(11:0)
rx_i1(11:0)
rx_q0(11:0)
rx_q1(11:0)
tx_data(11:0)
radio_clk
tx_clk
tx_frame
timekeeper
timekeeper
set_addr(7:0)
set_data(31:0)
clk
pps
reset
set_stb
strobe
sync_in
vita_time(63:0)
vita_time_lastpps(63:0)
sync_out
radio_ctrl_proc
radio_ctrl_proc
ctrl_tdata(63:0)
readback(63:0)
vita_time(63:0)
clear
clk
ctrl_tlast
ctrl_tvalid
ready
reset
resp_tready
debug(31:0)
resp_tdata(63:0)
set_addr(7:0)
set_data(31:0)
ctrl_tready
resp_tlast
resp_tvalid
set_stb
radio_legacy:1
radio_0
ctrl_tdata(63:0)
fe_gpio_in(31:0)
fp_gpio_in(9:0)
rx(31:0)
tx_tdata(63:0)
bus_clk
bus_rst
ctrl_tlast
ctrl_tvalid
lora_trig_i
pps
radio_clk
radio_rst
resp_tready
rx_tready
time_sync
tx_tlast
tx_tvalid
debug(63:0)
fe_gpio_ddr(31:0)
fe_gpio_out(31:0)
fp_gpio_ddr(9:0)
fp_gpio_out(9:0)
resp_tdata(63:0)
rx_tdata(63:0)
tx(31:0)
vita_time_b(63:0)
vita_time_lora(63:0)
ctrl_tready
resp_tlast
resp_tvalid
rx_tlast
rx_tvalid
tx_tready
radio_ctrl_proc
radio_ctrl_proc
ctrl_tdata(63:0)
readback(63:0)
vita_time(63:0)
clear
clk
ctrl_tlast
ctrl_tvalid
ready
reset
resp_tready
debug(31:0)
resp_tdata(63:0)
set_addr(7:0)
set_data(31:0)
ctrl_tready
resp_tlast
resp_tvalid
set_stb
lora_detect
lora0
addr(7:0)
data(31:0)
rx_i(15:0)
rx_q(15:0)
vita_time(63:0)
bus_clk
radio_clk
rst
strobe
trigger_i
chipscope_bus_o(64:0)
lora_time_measured_o(63:0)
lora_trig_o
b200_core:1
b200_core
ctrl_tdata(63:0)
fp_gpio_in(9:0)
lock_signals(1:0)
rb_misc(31:0)
rx0(31:0)
rx1(31:0)
tx_tdata(63:0)
bus_clk
bus_rst
ctrl_tlast
ctrl_tvalid
debug_rxd
debug_scl
debug_sda
miso
pps_ext
pps_int
radio_clk
radio_rst
resp_tready
rxd
rx_tready
tx_tlast
tx_tvalid
debug(63:0)
fe0_gpio_out(7:0)
fe1_gpio_out(7:0)
fp_gpio_ddr(9:0)
fp_gpio_out(9:0)
lora_deadend(31:0)
misc_outs(31:0)
resp_tdata(63:0)
rx_tdata(63:0)
sen(7:0)
tx0(31:0)
tx1(31:0)
ctrl_tready
debug_txd
led_lora
mosi
resp_tlast
resp_tvalid
rx_tlast
rx_tvalid
sclk
txd
tx_tready
gpif2_slave_fifo32
slave_fifo32
gpif_ctl(3:0)
resp_tdata(63:0)
rx_tdata(63:0)
ctrl_tready
fifo_clk
fifo_rst
gpif_clk
gpif_enb
gpif_rst
resp_tlast
resp_tvalid
rx_tlast
rx_tvalid
tx_tready
ctrl_tdata(63:0)
debug(31:0)
fifoadr(1:0)
tx_tdata(63:0)
ctrl_tlast
ctrl_tvalid
pktend
resp_tready
rx_tready
slcs
sloe
slrd
slwr
tx_tlast
tx_tvalid
gpif_d(31:0)
b200:1
b200
codec_ctrl_out(7:0)
rx_codec_d(11:0)
AUX_PWR_ON
cat_clkout_fpga
cat_miso
codec_data_clk_p
codec_main_clk_n
codec_main_clk_p
FPGA_CFG_CS
fx3_ce
FX3_EXTINT
fx3_mosi
fx3_sclk
GPIF_CTL4
GPIF_CTL5
GPIF_CTL6
GPIF_CTL8
GPIF_CTL9
gps_lock
gps_txd
gps_txd_nmea
pll_lock
PPS_IN_EXT
PPS_IN_INT
rx_frame_p
codec_ctrl_in(3:0)
debug(31:0)
debug_clk(1:0)
tx_codec_d(11:0)
cat_ce
cat_mosi
cat_sclk
codec_enable
codec_en_agc
codec_fb_clk_p
codec_reset
codec_sync
codec_txrx
FPGA_TXD0
fx3_miso
GPIF_CTL0
GPIF_CTL1
GPIF_CTL2
GPIF_CTL3
GPIF_CTL7
GPIF_CTL11
GPIF_CTL12
gps_rxd
IFCLK
LED_RX1
LED_RX2
LED_TXRX1_RX
LED_TXRX1_TX
LED_TXRX2_RX
LED_TXRX2_TX
pll_ce
pll_mosi
pll_sclk
ref_sel
rx_bandsel_a
rx_bandsel_b
rx_bandsel_c
SFDX1_RX
SFDX1_TX
SFDX2_RX
SFDX2_TX
SRX1_RX
SRX1_TX
SRX2_RX
SRX2_TX
tx_bandsel_a
tx_bandsel_b
tx_enable1
tx_enable2
tx_frame_p
GPIF_D(31:0)
FPGA_RXD0
12.3
Vue
RT
LU
SR
PB
200
(vue
partie
lle)
12.4 Script lançant la compilation du FPGA
#!/bin/zsh
COMMIT=`git rev-parse HEAD`
if [[ $1 ]] ; then
BUILDDIR=`date +%Y.%m.%d-%H:%M`-${COMMIT:0:6}_$1
else
BUILDDIR=`date +%Y.%m.%d-%H:%M`-${COMMIT:0:6}
fi
OUTPUTDIR="/home/seba/documents/hepia/lora/lora_host_work/outputs/${BUILDDIR}"
mkdir -p $OUTPUTDIR
WORKDIR="${BASEDIR}/lora/uhd/fpga-src/usrp3/top/b200"
alias cd_lora.logs="cd ${OUTPUTDIR}"
cd $WORKDIR
# make sure using python2
source temp-python/bin/activate
[[ -d build-B200 ]] && mv build-B200 tmp-build-B200
make clean && mv tmp-build-B200 build-B200.last
make B200 DEBUG_UART=1
if [[ $? -eq 0 ]] ; then
echo -e "\n\n\nCompilation successfull...\n\n"
else
echo -e "\n\n\nCompilation failed...\n\n"
fi
[[ -e build-B200/b200.bin ]] && cp build-B200/b200.bin $OUTPUTDIR/usrp_b200_fpga.bin &&
\→֒
echo "Exporting bitstream files..." ; \
echo -e "Moved build-B200/b200.bin to $OUTPUTDIR/usrp_b200_fpga.bin"
[[ -e build-B200/b200.bit ]] && cp build-B200/b200.bit $OUTPUTDIR/usrp_b200_fpga.bit &&
\→֒
echo -e "Moved build-B200/b200.bit to $OUTPUTDIR/usrp_b200_fpga.bit"
[[ -e build-B200/b200.syr ]] && cp build-B200/b200.syr $OUTPUTDIR/usrp_b200_fpga.syr &&
\→֒
echo -e "Moved build-B200/b200.syr to $OUTPUTDIR/usrp_b200_fpga.syr"
[[ -e build-B200/b200.twr ]] && cp build-B200/b200.twr $OUTPUTDIR/usrp_b200_fpga.twr &&
\→֒
echo -e "Moved build-B200/b200.twr to $OUTPUTDIR/usrp_b200_fpga.twr"
echo "\nBuild DONE ... B200\n"
[[ -e build-B200/b200.cmd_log ]] && cp build-B200/b200.cmd_log ${OUTPUTDIR}/ && \
echo "Exporting logs..." ; \
[[ -e build-B200/build.log ]] && cp build-B200/build.log ${OUTPUTDIR}/
[[ -e build/par_usage_statistics.html ]] && cp build-B200/par_usage_statistics.html
${OUTPUTDIR}/ && \→֒
echo "Exporting html repports..." ; \
[[ -e build/usage_statistics_webtalk.html ]] && cp
build-B200/usage_statistics_webtalk.html ${OUTPUTDIR}/→֒
echo -e "Logs and files moved to ${OUTPUTDIR}...\n\n"
echo -e "Done...\n\n"
12.5 LoRa détection
-------------------------------------------------------------------------------
-- Title : LoRa core
-- Project : Travail de bachelor
-------------------------------------------------------------------------------
-- File : lora_detect.vhd
-- Author : <seba@t440p>
-- Company : HESSO - hepia - ITI
-- Created : 2017-06-18
-- Last update: 2017-07-14
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description: This module detect a LoRa packet in a stream of data from an
-- ADC and timestamp it.
-------------------------------------------------------------------------------
-- Copyright (c) 2017
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2017-05-17 1.0 seba Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lora_detect is
generic (
PULSE_LEN : integer := 1000000;
DISABLE_LEN : integer := 5000000;
COMP_VAL0 : signed(31 downto 0) := To_signed(9000000, 32); -- comparator value 0
COMP_VAL1 : signed(31 downto 0) := To_signed(9000000, 32); -- comparator value 1
COMP_VAL2 : signed(31 downto 0) := To_signed(16000000, 32); -- comparator value 2
COMP_VAL3 : signed(31 downto 0) := To_signed(25000000, 32); -- comparator value 3
COMP_VAL4 : signed(31 downto 0) := To_signed(36000000, 32); -- comparator value 4
COMP_VAL5 : signed(31 downto 0) := To_signed(49000000, 32); -- comparator value 5
COMP_VAL6 : signed(31 downto 0) := To_signed(64000000, 32); -- comparator value 6
COMP_VAL7 : signed(31 downto 0) := To_signed(100000000, 32));
-- comparator value 7→֒
port (
radio_clk : in std_logic; -- radio clock
bus_clk : in std_logic; -- bus clock
rst : in std_logic; -- reset SR registers
rx_i : in std_logic_vector(15 downto 0); -- rx I signal
rx_q : in std_logic_vector(15 downto 0); -- rx Q signal
vita_time : in std_logic_vector(63 downto 0); -- vita time
trigger_i : in std_logic; -- external trigger
-- wishbone
addr : in std_logic_vector(7 downto 0); -- setting reg
data : in std_logic_vector(31 downto 0); -- data
strobe : in std_logic;
lora_trig_o : out std_logic; -- lora counter trigger
-- debug chipscope
chipscope_bus_o : out std_logic_vector(64 downto 0); -- probe chipscope
lora_time_measured_o : out std_logic_vector(63 downto 0));
-- detected packet's trigger→֒
end entity lora_detect;
architecture lora_detect_behav of lora_detect is
------------------------------------
-- Components
------------------------------------
component gen_event_trigger is
port (
clk : in std_logic;
rst : in std_logic;
trigger_i : in std_logic);
end component gen_event_trigger;
component setting_reg_vhdl_wrapper is
port (
clk : in std_logic;
rst : in std_logic;
strobe : in std_logic;
addr : in std_logic_vector(7 downto 0);
data_in : in std_logic_vector(31 downto 0);
data_out : out std_logic_vector(31 downto 0));
end component setting_reg_vhdl_wrapper;
-------------------------------------------------------
-- signals
-------------------------------------------------------
signal sr0_value_int : std_logic_vector(31 downto 0); -- setting register value
signal sr0_value_nxt_int : std_logic_vector(31 downto 0); -- setting register value
signal save_time_int : std_logic := '0'; -- enable measure
signal gen_uart_trigger_int : std_logic; -- trigger rising edge
signal gen_lora_trigger_int : std_logic := '0'; -- trigger rising edge
signal lora_detected : std_logic; -- lora detect
signal iq_module : signed(31 downto 0); -- IQ module
signal comparator_int : std_logic_vector(7 downto 0); -- Comparator
signal trigger_disabled_counter : unsigned(31 downto 0);
-- disable detection after lora detection→֒
signal lora_trig_int : std_logic := '0'; -- trigger out
begin -- architecture lora_detect_behav
--------------------------
-- setting register 0
-- cpp API trigger
--------------------------
sr_lora_0 : setting_reg_vhdl_wrapper port map (
clk => bus_clk,
rst => rst,
strobe => strobe,
addr => addr,
data_in => data,
data_out => sr0_value_int);
--------------------------------------
-- LoRa detection
--------------------------------------
lora_detected <= '1' when comparator_int(4) = '1' else '0';
comparator_int(0) <= '1' when iq_module > COMP_VAL0 else '0';
comparator_int(1) <= '1' when iq_module > COMP_VAL1 else '0';
comparator_int(2) <= '1' when iq_module > COMP_VAL2 else '0';
comparator_int(3) <= '1' when iq_module > COMP_VAL3 else '0';
comparator_int(4) <= '1' when iq_module > COMP_VAL4 else '0';
comparator_int(5) <= '1' when iq_module > COMP_VAL5 else '0';
comparator_int(6) <= '1' when iq_module > COMP_VAL6 else '0';
comparator_int(7) <= '1' when iq_module > COMP_VAL7 else '0';
-- purpose: Detect Lora from I Q samples
-- type : sequential
-- inputs : radio_clk, rst, rx_i, rx_q
-- outputs: iq_module
lora_detection : process (radio_clk, rst) is
begin -- process lora_detection
if rst = '1' then -- asynchronous reset (active low)
iq_module <= (others => '0');
elsif rising_edge(radio_clk) then -- rising clock edge
iq_module <= abs(signed(rx_i))*abs(signed(rx_i)) +
abs(signed(rx_q))*abs(signed(rx_q));→֒
end if;
end process lora_detection;
-- /* debug purpose only
-- -- purpose: avoid simplification
-- mux_detections : process (comparator_int) is
-- begin -- process mux_detections
-- -- MUX for chipscope
-- case sr0_value_int(2 downto 0) is
-- when "000" => lora_detected <= comparator_int(0);
-- when "001" => lora_detected <= comparator_int(1);
-- when "010" => lora_detected <= comparator_int(2);
-- when "011" => lora_detected <= comparator_int(3);
-- when "100" => lora_detected <= comparator_int(4);
-- when "101" => lora_detected <= comparator_int(5);
-- when "110" => lora_detected <= comparator_int(6);
-- when others => lora_detected <= comparator_int(7);
-- end case;
-- end process mux_detections;
-- */
----------------------------------------
-- purpose: trigger out register
-- type : sequential
-- inputs : radio_clk, rst, save_time_int
-- outputs: lora_trig_o
----------------------------------------
trig : process (radio_clk, rst) is
begin -- process measure
if rst = '1' then -- asynchronous reset (active low)
lora_trig_int <= '0';
trigger_disabled_counter <= (others => '0');
elsif rising_edge(radio_clk) then -- rising clock edge
lora_trig_int <= lora_trig_int;
-- only start if disabled_counter is zero
if comparator_int(4) = '1' and trigger_disabled_counter = 0 then
trigger_disabled_counter <= to_unsigned(DISABLE_LEN, 32);
end if;
if trigger_disabled_counter > 0 then
-- count down
trigger_disabled_counter <= trigger_disabled_counter - 1;
-- pulse out for PULSE_LEN
if trigger_disabled_counter > to_unsigned(DISABLE_LEN - PULSE_LEN, 32) then
lora_trig_int <= '1';
else
lora_trig_int <= '0';
end if;
else
lora_trig_int <='0';
end if;
end if;
end process trig;
lora_trig_o <= lora_trig_int;
--------------------------------------
-- Debug with chipscope
--------------------------------------
chipscope_bus_o <= (std_logic_vector(trigger_disabled_counter) & lora_trig_int &
std_logic_vector(iq_module));→֒
end architecture lora_detect_behav;
12.6 Utilisation de deux USRP en parallèle
/*
* =====================================================================================
*
* Filename: print_rw_register.cpp
*
* Description: test read/write access to user setting register (LoRa)
*
* Version: 1.0
* Created: 28.05.2017 18:55:41
* Revision: none
* Compiler: gcc
*
* Author: Sebastien Chassot (sinux), [email protected]
* Company: HES-SO hepia section ITI (soir)
*
* =====================================================================================
*/
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <complex>
#include <chrono>
#include "../lib/usrp/cores/user_settings_core_3000.hpp"
#define NB_TESTS 60
namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
std::string args;
std::string args_board0 = "name=hepiaB200";
std::string args_board1 = "name=sinuxB200";
std::string wire;
int test_time = 0;
std::string time_source;
double seconds_in_future;
size_t total_num_samps;
double rate;
std::string channel_list;
//setup the program options
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""),
"single uhd device address args")→֒
("wire", po::value<std::string>(&wire)->default_value(""),
"the over the wire type, sc16, sc8, etc")→֒
("secs", po::value<double>(&seconds_in_future)->default_value(1.5),
"number of seconds in the future to receive")→֒
("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000),
"total number of samples to receive")→֒
("rate", po::value<double>(&rate)->default_value(50e6), "rate of incoming samples")
("dilv", "specify to disable inner-loop verbose")
("channels", po::value<std::string>(&channel_list)->default_value("0"),
"which channel(s) to use (specify \"0\", \"1\", \"0,1\", etc)")→֒
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << boost::format("UHD RX Timed Samples %s") % desc << std::endl;
return ~0;
}
// bool verbose = vm.count("dilv") == 0;
//create first usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args_board0 <<
std::endl;→֒
uhd::usrp::multi_usrp::sptr usrp0 = uhd::usrp::multi_usrp::make(args_board0);
std::cout << boost::format("Using Device: %s") % usrp0->get_pp_string() <<
std::endl;→֒
//create second usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args_board1 <<
std::endl;→֒
uhd::usrp::multi_usrp::sptr usrp1 = uhd::usrp::multi_usrp::make(args_board1);
std::cout << boost::format("Using Device: %s") % usrp1->get_pp_string() <<
std::endl;→֒
//detect which channels to use
std::vector<size_t> channel_nums;
channel_nums.push_back(boost::lexical_cast<int>(0));
//create a receive streamer
uhd::stream_args_t stream_args("fc32", wire); //complex floats
stream_args.channels = channel_nums;
uhd::rx_streamer::sptr rx_stream0 = usrp0->get_rx_stream(stream_args);
uhd::rx_streamer::sptr rx_stream1 = usrp1->get_rx_stream(stream_args);
//setup streaming
std::cout << std::endl;
std::cout << boost::format(
"Begin streaming %u samples, %f seconds in the future..."
) % total_num_samps % seconds_in_future << std::endl;
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = total_num_samps;
stream_cmd.stream_now = true;
// stream_cmd.time_spec = uhd::time_spec_t(seconds_in_future);
rx_stream0->issue_stream_cmd(stream_cmd);
rx_stream1->issue_stream_cmd(stream_cmd);
//allocate buffer to receive with samples
std::vector<std::complex<float> > buff0(rx_stream0->get_max_num_samps());
// sample are overwritten anyway→֒
std::vector<std::complex<float> > buff1(rx_stream1->get_max_num_samps());
// sample are overwritten anyway→֒
std::vector<void *> buffs;
buffs.push_back(&buff0.front()); //same buffer for each channel
buffs.push_back(&buff1.front()); //same buffer for each channel
//meta-data will be filled in by recv()
uhd::rx_metadata_t md0;
uhd::rx_metadata_t md1;
//set the rx sample rate
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
usrp0->set_rx_rate(rate);
usrp1->set_rx_rate(rate);
usrp0->set_rx_freq(868e6);
usrp1->set_rx_freq(868e6);
std::cout << boost::format("Actual hepiaB200 RX Rate: %f Msps...") %
(usrp0->get_rx_rate()/1e6) << std::endl << std::endl;→֒
std::cout << boost::format("Actual sinuxB200 RX Rate: %f Msps...") %
(usrp1->get_rx_rate()/1e6) << std::endl << std::endl;→֒
std::cout << boost::format("Actual hepiaB200 RX freq: %f MHz...") %
(usrp0->get_rx_freq()/1e6) << std::endl << std::endl;→֒
std::cout << boost::format("Actual sinuxB200 RX freq: %f MHz...") %
(usrp1->get_rx_freq()/1e6) << std::endl << std::endl;→֒
usrp0->set_time_source("external");
usrp1->set_time_source("external");
std::cout << boost::format("Setting device timestamp to 100.000...") << std::endl;
usrp0->set_time_now(uhd::time_spec_t(time(0)));
usrp1->set_time_now(uhd::time_spec_t(time(0)));
size_t num_acc_samps = 0; //number of accumulated samples
std::chrono::high_resolution_clock::time_point t0 =
std::chrono::high_resolution_clock::now();→֒
std::chrono::high_resolution_clock::time_point t1;
std::chrono::duration<double, std::milli> time_span;
while(true) {
//receive a single packet
size_t num_rx_samps0 = rx_stream0->recv(
buffs, buff0.size(), md0, 0.1, true);
size_t num_rx_samps1 = rx_stream1->recv(
buffs, buff1.size(), md1, 0.1, true);
uhd::time_spec_t now0 = usrp0->get_time_now();
uhd::time_spec_t now1 = usrp1->get_time_now();
time_span = t1-t0;
t1 = std::chrono::high_resolution_clock::now();
if (time_span.count() > 500.0) {
std::cout << boost::format( "Actual hepiaB200 time : %f s")
% (now0.get_real_secs()*1e0) << std::endl;
std::cout << boost::format( "Actual sinuxB200 time : %f s")
% (now1.get_real_secs()*1e0) << std::endl;
std::cout << boost::format( "Difference : %f us" ) % ((now1.get_real_secs()
- now0.get_real_secs())*1e6) << std::endl;→֒
std::cout << boost::format("Next PPS is %f s") % double(time(0)) <<
std::endl;→֒
usrp0->set_time_next_pps(double(time(0)));
usrp1->set_time_next_pps(double(time(0)));
t0 = std::chrono::high_resolution_clock::now();
}
}
std::cout << boost::format("Last PPS: %f ") %
(usrp1->get_time_last_pps().get_real_secs()*1e6) << std::endl << std::endl;→֒
//finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
//test write to register
usrp0->set_lora_trig(1);
//set the time at an unknown pps (will throw if no pps)
std::cout << std::endl << "Attempt to detect the PPS and set the time..." <<
std::endl << std::endl;→֒
usrp1->set_time_unknown_pps(uhd::time_spec_t(0.0));
std::cout << std::endl << "Success!" << std::endl << std::endl;
return EXIT_SUCCESS;
}
12.7 Affichage et plot des timestamps
#! /usr/bin/python3
# -*- coding: utf-8 -*-
#
# Description : Parse, log and pretty print DToA timestamp
#
__author__ = 'Sebastien Chassot (sinux)'
__author_email__ = '[email protected]'
__version__ = "1.0.1"
__copyright__ = ""
__licence__ = "GPL"
__status__ = "Travail de bachelor"
import serial
import argparse as ap
import sys
from os.path import splitext
import logging
import numpy as np
import matplotlib.pyplot as plt
NB_OF_POINTS = 10000
LOG_FILE = splitext(sys.argv[0])[0]+".log"
DT_DETECTION = 10000 # rise error when dt greater than...
CORRECTION_DT_MAX = 470
CORRECTION_DT_MIN = 10
compensated = True
log = logging.getLogger('spam_application.auxiliary')
logf = logging.FileHandler(LOG_FILE)
log.setLevel(logging.INFO)
logf.setLevel(logging.DEBUG)
def __exitprog__(e):
"""
Properly exit prog
:return:
"""
sys.exit(e)
def __read_val__(card):
"""
Read hex string from serial and convert it to secondes
:param card: card to read
:return: Value in secondes
"""
try:
val = card.read(20)
ns = int(val[12:20].decode('ascii').lower().lstrip("0"), 16)
sec = int(val[3:11].decode('ascii').lower().lstrip("0"), 16)+ns/10e8
except ValueError:
log.debug("Timeout\n")
return sec
def diff_timestamp(t0, t1):
"""
Delta time from two timestamp
:param t0: timestamp0 [s]
:param t1: timestamp1 [s]
:return: delta t in [s]
"""
return round((t1-t0)*10e9)# if t0 > t1 else round((t1-t0)*10e9)
def time_to_dist(dt):
"""
Convert time [s] to distance [m] based on rf speed (in air)
:param dt: time in [ns]
:return: distance
"""
return float(dt)/4
def time_compensation(t):
"""
Compensate error
:param t: time measured
:return: time compensated
"""
s = t - int(t)
comp = int(s*10 * (CORRECTION_DT_MAX-CORRECTION_DT_MIN))
return t - (comp + CORRECTION_DT_MIN)/10e9
def print_timestamp(t0, t1):
"""
Pretty print timestamp
:param t0: first timestamp
:param t1: second timestamp
"""
dt = diff_timestamp(t0, t1)
ds = time_to_dist(dt)
print("-------------\ntimestamp :\n-------------")
print("card0 : "+str(t0)+"0 s")
print("card1 : "+str(t1)+"0 s\n-----------------------")
print("difference : "+str(dt)+" ns, (env. "+str(ds)+" m)
\n-----------------------")
def log_timestamp(file, t0, t1):
"""
Log timestamp to a file
:param file: file handle
:param t0: timstamp 0
:param t1: timestamp 1
:return:
"""
s = str(t0)+","+str(t1)+","+str(diff_timestamp(t0, t1))+"\n"
try:
file.write(s)
except IOError:
logf.critical("Unable to write timestamp to log file")
if __name__ == "__main__":
"""
Parse args and help
"""
parser = ap.ArgumentParser(description="Process USRP timestamp :")
parser.add_argument('-p', dest='pr', action="store_true",
default=False, required=False,
help="pretty print timestamp")
parser.add_argument('-o', dest="file", action="store",
help="CSV output's filename")
parser.add_argument('-c0', dest="c0", action="store",
help="device 0 (/dev/ttyUSB?)")
parser.add_argument('-c1', dest="c1", action="store",
help="device 1 (/dev/ttyUSB?)")
args = parser.parse_args()
""" open first card
"""
try:
card0 = serial.Serial(args.c0, 115200, timeout=5,parity=serial.PARITY_NONE,
rtscts=1)→֒
except serial.SerialException:
logging.error("\n\nUnable to open serial ports : "+args.c0+"\n\n")
parser.print_help()
sys.exit(1)
""" open second card
"""
try:
card1 = serial.Serial(args.c1, 115200, timeout=5,parity=serial.PARITY_NONE,
rtscts=1)→֒
except serial.SerialException:
logging.error("\n\nUnable to open serial ports : "+args.c1+"\n\n")
parser.print_help()
sys.exit(1)
with open(args.file, 'w') as f:
f.write("timestamp0,timestamp1,dt\n")
n = 1
dtimes = []
timestamps = []
while True:
try:
keep_event = True
try:
t0 = __read_val__(card0)
except ValueError as e:
keep_event = False
except UnboundLocalError:
keep_event = False
sec = 0
try:
if compensated:
tm = __read_val__(card1)
t1 = time_compensation(tm)
else:
t1 = __read_val__(card1)
except ValueError as e:
keep_event = False
except UnboundLocalError:
keep_event = False
sec = 0
if keep_event:
dtimes.append(diff_timestamp(t0, t1))
timestamps.append((t0+t1/2))
n += 1
log.debug("keept values")
if diff_timestamp(t0, t1) > DT_DETECTION:
print("\n\n---------------\n"
"Warning : weird dt value\n"
"---------------\n\n")
if args.pr:
print_timestamp(t0, t1)
s = str(t0)+","+str(t1)+","+str(diff_timestamp(t0, t1))+"\n"
try:
f.write(s)
except IOError:
logf.critical("Unable to write timestamp to log file")
if n%NB_OF_POINTS is 0:
plt.scatter(timestamps, dtimes)
plt.show()
log.info(n)
print("Plot timestamp")
except KeyboardInterrupt:
f.close()
plt.scatter(timestamps, dtimes)
plt.show()
__exitprog__(0)
f.close()
12.8 Envoi des timestamps (MQTT)
#! /usr/bin/python3
# -*- coding: utf-8 -*-
#
# Description : Parse, log and pretty print DTOA timestamp
#
#
#
#
#
#
__author__ = 'Sebastien Chassot (sinux)'
__author_email__ = '[email protected]'
__version__ = "1.0.1"
__copyright__ = ""
__licence__ = "GPL"
__status__ = "Travail de bachelor"
import serial
import argparse as ap
import sys
from os.path import splitext
import time
import logging
import paho.mqtt.client as mqtt
import json
NB_OF_POINTS = 10000
LOG_FILE = splitext(sys.argv[0])[0]+".log"
MQTT_SRV="test.mosquitto.org"
MQTT_TOPIC="khw4Wsa6"
message = 'ON'
log = logging.getLogger('spam_application.auxiliary')
logf = logging.FileHandler(LOG_FILE)
log.setLevel(logging.INFO)
logf.setLevel(logging.DEBUG)
def on_connect(mosq, obj, rc):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print("rc: " + str(rc))
def on_message(mosq, obj, msg):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
global message
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
message = msg.payload
def on_publish(mosq, obj, mid):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print("mid: " + str(mid))
def on_subscribe(mosq, obj, mid, granted_qos):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_log(mosq, obj, level, string):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print(string)
def __exitprog__(e):
"""
Properly exit prog
:return:
"""
sys.exit(e)
def __read_val__(card):
"""
Read hex string from serial and convert it to secondes
:param card: card to read
:return: Value in secondes
"""
try:
val = card.read(20)
ns = int(val[12:20].decode('ascii').lower().lstrip("0"), 16)
sec = int(val[3:11].decode('ascii').lower().lstrip("0"), 16)+ns/10e7
except ValueError:
log.debug("Timeout\n")
return sec
def diff_timestamp(t0, t1):
"""
Delta time from two timestamp
:param t0: timestamp0 [s]
:param t1: timestamp1 [s]
:return: delta t in [s]
"""
return round((t1-t0)*10e9)# if t0 > t1 else round((t1-t0)*10e9)
def time_to_dist(dt):
"""
Convert time [s] to distance [m] based on rf speed (in air)
:param dt: time in [ns]
:return: distance
"""
return float(dt)/4
def time_compensation(t):
"""
Compensate error
:param t: time measured
:return: time compensated
"""
s = t - int(t)
comp = int(s*10 * (CORRECTION_DT_MAX-CORRECTION_DT_MIN))
return t - (comp + CORRECTION_DT_MIN)/10e9
def print_timestamp(t0, t1):
"""
Pretty print timestamp
:param t0: first timestamp
:param t1: second timestamp
"""
dt = diff_timestamp(t0, t1)
ds = time_to_dist(dt)
print("-------------\ntimestamp :\n-------------")
print("card0 : "+str(t0)+"0 s")
print("card1 : "+str(t1)+"0 s\n-----------------------")
print("difference : "+str(dt)+" ns, (env. "+str(ds)+" m)\n-----------------------")
def log_timestamp(file, t0, t1):
"""
Log timestamp to a file
:param file: file handle
:param t0: timstamp 0
:param t1: timestamp 1
:return:
"""
s = str(t0)+","+str(t1)+","+str(diff_timestamp(t0, t1))+"\n"
try:
file.write(s)
except IOError:
logf.critical("Unable to write timestamp to log file")
if __name__ == "__main__":
"""
Parse args and help
"""
parser = ap.ArgumentParser(description="Process USRP timestamp :")
parser.add_argument('-p', dest='pr', action="store_true",
default=False, required=False,
help="pretty print timestamp")
parser.add_argument('-c', dest="c", action="store", type=str,
help="device 0 (/dev/ttyUSB?)", required=True)
parser.add_argument('-n', dest="card_name", action="store",
help="name of the gateway", required=True)
parser.add_argument('--lat', dest="latitude", action="store",
help="latitude of gateway", required=True)
parser.add_argument('--long', dest="longitude", action="store",
help="longitude of gateway", required=True)
args = parser.parse_args()
mqttc = mqtt.Client()
# Assign event callbacks
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe
# Connect
mqttc.connect(MQTT_SRV, 1883, 30000)
""" open first card
"""
try:
card = serial.Serial(args.c, 115200, timeout=30000, parity=serial.PARITY_NONE,
rtscts=1)→֒
except serial.SerialException:
logging.error("\n\nUnable to open serial ports : "+args.c+"\n\n")
parser.print_help()
sys.exit(1)
if type(args.card_name) is not str:
logf.critical("Error gateway name")
exit(1)
while True:
try:
t = __read_val__(card)
log.debug("found values")
mqttc.publish(MQTT_TOPIC, json.dumps({"name": args.card_name,
"timestamp": t,
"lat": args.latitude,
"long": args.longitude}))
if args.pr:
print(str(t))
except ValueError:
pass
time.sleep(1)
sys.exit(1)
12.9 Analyse des timestamps (MQTT)
#! /usr/bin/python3
# -*- coding: utf-8 -*-
#
# Description : Parse, log and pretty print DTOA timestamp
#
#
#
#
#
#
__author__ = 'Sebastien Chassot (sinux)'
__author_email__ = '[email protected]'
__version__ = "1.0.1"
__copyright__ = ""
__licence__ = "GPL"
__status__ = "Travail de bachelor"
import serial
import argparse as ap
import sys
from os.path import splitext
import time
import logging
import paho.mqtt.client as mqtt
import json
import numpy as np
import matplotlib.pyplot as plt
from geopy.distance import vincenty
NB_OF_POINTS = 10000
LOG_FILE = splitext(sys.argv[0])[0]+".log"
MQTT_SRV="test.mosquitto.org"
MQTT_TOPIC="khw4Wsa6"
message = 'ON'
log = logging.getLogger('spam_application.auxiliary')
logf = logging.FileHandler(LOG_FILE)
log.setLevel(logging.INFO)
logf.setLevel(logging.DEBUG)
# CORRECTION_DT_MAX = 470
# CORRECTION_DT_MIN = 0
# compensated = True
last_msg = None
ref_card = None
NB_OF_MEASURES = 40
measures = []
HISTOGRAM_FILENAME = splitext(sys.argv[0])[0]+'-'+time.strftime("%Hh%M-%d.%m.%Y")+'.png'
def on_connect(mosq, obj, rc):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
log.info("rc: " + str(rc))
def on_message(mosq, obj, msg):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
global message
global last_msg
global ref_card
s = json.loads(msg.payload, encoding='utf-8')
if not ref_card:
ref_card = s['name']
if last_msg:
if abs(last_msg['timestamp'] - s['timestamp']) < 0.05:
print("=============================================\n"+
"Location : "+last_msg['name']+
" ("+last_msg['lat']+", "+last_msg['long']+")\n"+
"Timestamp : "+str(last_msg['timestamp'])+"0 s")
dist =
vincenty((last_msg['lat'],last_msg['long']),(s['lat'],s['long'])).meters→֒
print("Location : "+s['name']+
" ("+s['lat']+", "+s['long']+")\n"+
"Timestamp : "+str(s['timestamp'])+"0 s")
print("Distance entre les gateway : "+str(int(dist))+"m")
t0 = last_msg['timestamp']*10e9
t1 = s['timestamp']*10e9
diff = t0 - t1 if s['name'] == ref_card else t1 - t0
print("---------------------------------------------\n"+
"Difference : "+str(int(diff/10))+" [ns]"+" (env. "+str(abs(int(diff/40)))+"m d'erreur)"+→֒
"\n=============================================\n")
if abs(diff) < 100000:
measures.append(int(diff/10))
last_msg = None # clear couple value
else:
last_msg = s
last_msg = s
message = msg.payload
def on_publish(mosq, obj, mid):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print("mid: " + str(mid))
def on_subscribe(mosq, obj, mid, granted_qos):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
log.info("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_log(mosq, obj, level, string):
"""
mosquitto callback
:param mosq:
:param obj:
:param rc:
"""
print(string)
def time_compensation(t):
"""
Compensate error
:param t: time measured
:return: time compensated
"""
s = t - int(t)
comp = int(s*10 * (CORRECTION_DT_MAX-CORRECTION_DT_MIN))
return t - (comp + CORRECTION_DT_MIN)/10e9
if __name__ == "__main__":
"""
Parse args and help
"""
parser = ap.ArgumentParser(description="Process USRP timestamp :")
parser.add_argument('-p', dest='pr', action="store_true",
default=False, required=False,
help="pretty print timestamp")
parser.add_argument('-s', dest="mqtt_srv", action="store",
help="mqtt server", required=True)
parser.add_argument('-t', dest="mqtt_topic", action="store",
help="mqtt topic", required=True)
args = parser.parse_args()
if type(args.mqtt_srv) is not str:
logf.critical("Error server name must be a string")
exit(1)
if type(args.mqtt_topic) is not str:
logf.critical("Error topic must be a string")
exit(1)
mqttc = mqtt.Client()
# Assign event callbacks
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe
# Connect
try:
mqttc.connect(MQTT_SRV, 1883, 60)
mqttc.subscribe(args.mqtt_topic, 0)
print("\n===================================\nServer started"+
"\n===================================")
print("Listen to MQTT topic "+args.mqtt_topic+
"\n===================================\n\n")
except mqtt.MQTT_ERR_ERRNO:
logf.critical("Error subscribing topic")
exit(1)
while len(measures) < NB_OF_MEASURES:
mqttc.loop_start()
mqttc.loop_stop()
""" histogram
"""
hist, bins = np.histogram(measures, bins=50)
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
plt.bar(center, hist, align='center', width=width)
plt.savefig(HISTOGRAM_FILENAME)
plt.show()
sys.exit(0)
12.10 Capture Wireshark (USB)
Exemple de capture d’un paquet CHDR
No. Time Source Destination Protocol Length Info
228 10.439754 1.4.2 host USB/CHDR 77
URB_BULK in, CHDR→֒
Frame 228: 77 bytes on wire (616 bits), 77 bytes captured (616 bits)
USB URB
UHD CHDR
0101 .... = Header bits: 0x5, Packet type: 0005
Packet Type:
. = Has time: False
.... 0011 0100 0010 = Sequence ID: 834
Packet size: 21333
Stream ID: 0.0.4.163 (A3:04>00:00)
Source device: 0
Source endpoint: 0
Destination device: 4
Destination endpoint: 163
.... 0000 = Source block port: 0
Payload: 0000000001
Listing 12.1 – ./included_src/wireshark_output1.txt
Listing 12.2 – Exemple de paquet transféré sur l’USB.
Exemple de capture d’un échange de paquets USRP - host
No. Time Source DestinationProtocol Length Info
35 1.903407 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
38 1.903735 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
39 1.903744 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
42 1.904109 1.4.2 host USB/CHDR 82 URB_BULK in, CHDR
44 1.904241 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
45 1.904301 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
48 1.904572 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
49 1.904587 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
52 1.904949 1.4.2 host USB/CHDR 82 URB_BULK in, CHDR
54 1.905096 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
55 1.905158 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
58 1.905447 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
59 1.905452 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
62 1.905823 1.4.2 host USB/CHDR 82 URB_BULK in, CHDR
64 1.905973 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
65 1.906033 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
68 1.906325 1.4.2 host USB/CHDR 77 URB_BULK in, CHDR
69 1.906371 host 1.4.1 USB/CHDR 95 URB_BULK out, CHDR
12.11 Table des acronymes et sigles utilisés
IoT Internet of Things
SDR Software Defined Radio
API Application Programming Interface
GPS Global Positioning System
GPSDO Global Positioning System Disciplined Oscillator
DToA Difference Time of Arrival
RF radio fréquence
SF Sreading Factor
SS Spread Spectrum
BP Bande Passante
ADC Analog-to-Digital Converter
DAC Digital-to-Analog Converter
FPGA Field-programmable gate array
PPS Pulse-Per-Second
PLL Phase-Locked Loop
GPIO General-Purpose Input/Output
chirp Compressed High Intensity Radar Pulse
USB Universal Serial Bus
ddr Double Data Rate
sdr Single Data Rate
OS Operating system
LVDS Low Volt Differencial Signal
UTC Universal Time Coordinated
ASIC Application-specific integrated circuit
SoC System on Chip
DMA Direct Memory Access
uhd USRP Hardware Driver
SDK Software Development Kit
TOF Time of flight
ISM Industrial Scientific and Medical radio bands
FSK Frequency-Shift Keying
FFT Fast Fourier Transform
JTAG Joint Test Action Group
LNA Low Noise Amplifier
Bibliographie
[4] Ettus Forum.[USRP-users] writing to user settings register.[Online ; accessed Juillet-2017].2017.url : http://ettus.80997.x6.nabble.com/USRP-
users - writing - to - user - settings - register -
td5539.html#a5545.
[5] Sakshama Ghoslya.LoRa Decoding. Blog.[Online ; accessed Juillet-2017].2017.url : http://sakshamaghoslya.blogspot.ch/p/
lora_9.html.
[6] GNURadio.Official website. Open-Source Toolkit for SoftwareRadio.[Online ; accessed Juillet-2017].2017.url : https://www.gnuradio.org/.
[11] MQTT.org.Official website.[Online ; accessed Juillet-2017].2017.url : http://mqtt.org/.
[15] Ettus Research.Board Mounted GPSDO (TCXO) Recommended forUSRP B200/B210. USRP Products.[Online ; accessed Juillet-2017].2017.url : https://www.ettus.com/product/details/
GPSDO-TCXO-MODULE.
[16] Ettus Research.Page produit USRP B200.[Online ; accessed Juillet-2017].2017.url : https://www.ettus.com/product/details/
UB200-KIT.
[21] Bertrik Sikken.DecodingLora. Wiki.[Online ; accessed Juillet-2017].2017.url : https://revspace.nl/DecodingLora.
[22] Wikipedia.Code de Gray.[Online ; accessed Juillet-2017].2017.url : https://fr.wikipedia.org/wiki/Code_de_
Gray.
[23] Wikipedia.Crystal oven.[Online ; accessed Juillet-2017].2017.url : https://en.wikipedia.org/wiki/Crystal_
oven.
[24] Wikipedia.Internet des objets — Wikipedia, The Free Encyclo-pedia.[Online ; accessed Juillet-2017].2017.url : https : / / fr . wikipedia . org / wiki /
Internet_des_objets.
[25] Wikipedia.NMEA 0183.[Online ; accessed Juillet-2017].2017.url : https://fr.wikipedia.org/wiki/NMEA_
0183.
[26] Wikipedia.Trilateration.[Online ; accessed Juillet-2017].2017.url : https : / / en . wikipedia . org / wiki /
Trilateration.
[28] Xilinx.Xilinx Download product. Multi-File Download :ISE.[Online ; accessed Juillet-2017].2013.url : ttps : / / www . xilinx . com / support /
download / index . html / content / xilinx / en /
downloadNav/design-tools.html.
Datasheet
[1] Diligent.Basys3 reference.[Online ; accessed Juillet-2017].2017.url : https : / / reference . digilentinc . com /
basys3/refmanual.
[2] Diligent.Basys3 reference. schematics.[Online ; accessed Juillet-2017].2017.url : https : / / reference . digilentinc . com /
_media/basys3:basys3_sch.pdf.
[3] Dragino.Lora/GPS reference. wiki.[Online ; accessed Juillet-2017].2017.url : http : / / wiki . dragino . com / index . php ?
title=Lora/GPS_HAT.
[7] GlobalTop Technology Inc.
GPMMOPA6C Data Sheet. MTK MT3339.Version V0A. [Online ; accessed Juillet-2017].2011.url : https : / / cdn - shop . adafruit . com /
datasheets/GlobalTop- FGPMMOPA6C- Datasheet-
V0A-Preliminary.pdf.
[9] Libelium.Waspmote reference. Open Source Sensor Node forthe Internet of Things.[Online ; accessed Juillet-2017].2017.url : http : / / www . libelium . com / products /
waspmote/.
[10] Micrel.Quartz DSC1033 datasheet.[Online ; accessed Juillet-2017].2017.url : http : / / ww1 . microchip . com /
downloads/en/DeviceDoc/DSC1033%20Datasheet%
20MKQBPD0318091-7.pdf.
[12] OpenCores.SoC Interconnection : Wishbone.[Online ; accessed Juillet-2017].2010.url : https : / / opencores . org / opencores ,
wishbone.
[13] OpenCores.UART 16550 core : : Overview. project page.[Online ; accessed Juillet-2017].2001.url : https : / / opencores . org / project ,
uart16550.
[20] Semtch.LoRa modulation Basics. AN1200.22.[Online ; accessed Juillet-2017].2017.Chap. 4.1.8, p. 12.url : http : / / www . semtech . com / images /
datasheet/an1200.22.pdf.
[27] Xilinx.AXI Reference Guide. manuel.[Online ; accessed Juillet-2017].
2011.url : https : / / www . xilinx . com / support /
documentation / ip . . . /ug761 _ axi _ reference _
guide.pdf.
Conférences
[8] Matt Knight.« Decoding the LoRa PHY. conférence 33C3 (ChaosCommunication Congress 2016) ».In :[Online ; accessed Juillet-2017].2016.url : https : / / media . ccc . de / v / 33c3 - 7945 -
decoding_the_lora_phy.
[14] Pothos.« LoRa modem demo with LimeSDR. youtube ».In :[Online ; accessed Juillet-2017].2016.url : https://youtu.be/VZBr21xnFIQ.