14. Synchronisation¶
Ce chapitre traite de la synchronisation des signaux sans fil en temps et en frĂ©quence, afin de corriger les dĂ©calages de la frĂ©quence porteuse et dâeffectuer un alignement temporel au niveau des symboles et des trames. Nous utiliserons la technique de rĂ©cupĂ©ration dâhorloge de Mueller et Muller, ainsi que la boucle de Costas, en Python.
Introduction¶
Nous avons vu comment transmettre numĂ©riquement par voie hertzienne, en utilisant un schĂ©ma de modulation numĂ©rique comme la QPSK et en appliquant une mise en forme des impulsions pour limiter la largeur de bande du signal. Le codage de canal peut ĂȘtre utilisĂ© pour traiter les canaux bruyants, par exemple lorsque le rapport signal/bruit est faible au niveau du rĂ©cepteur. Il est toujours utile de filtrer autant que possible le signal avant de le traiter numĂ©riquement. Dans ce chapitre, nous allons Ă©tudier la maniĂšre dont la synchronisation est effectuĂ©e du cĂŽtĂ© de la rĂ©ception. La synchronisation est un ensemble de traitements qui se produisent avant la dĂ©modulation et le dĂ©codage du canal. La chaĂźne globale tx-canal-rx est reprĂ©sentĂ©e ci-dessous, avec les blocs abordĂ©s dans ce chapitre surlignĂ©s en jaune. (Ce diagramme nâest pas exhaustif : la plupart des systĂšmes incluent Ă©galement lâĂ©galisation et le multiplexage).
Simulation dâun canal sans fil¶
Avant dâapprendre Ă mettre en Ćuvre la synchronisation temporelle et frĂ©quentielle, nous devons rendre nos signaux simulĂ©s plus rĂ©alistes. Sans lâajout dâun retard alĂ©atoire, la synchronisation dans le temps est triviale. En fait, il suffit de prendre en compte le retard dâĂ©chantillonnage de tous les filtres que vous utilisez. Nous voulons Ă©galement simuler un dĂ©calage de frĂ©quence car, comme nous le verrons, les oscillateurs ne sont pas parfaits; il y aura toujours un certain dĂ©calage entre la frĂ©quence centrale de lâĂ©metteur et celle du rĂ©cepteur.
Examinons maintenant le code Python permettant de simuler un retard non entier et un dĂ©calage de frĂ©quence. Le code Python de ce chapitre part du code que nous avons Ă©crit lors de lâexercice Python de mise en forme des impulsions (cliquez ci-dessous si vous en avez besoin); vous pouvez le considĂ©rer comme le point de dĂ©part du code de ce chapitre, et le nouveau code viendra ensuite.
Code Python de la mise en forme des impulsions
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
import math
# cette partie provient de l'exercice des impulsions de mise en forme
num_symbols = 100
sps = 8
bits = np.random.randint(0, 2, num_symbols) # Nos données à transmettre: des 1 et des 0.
pulse_train = np.array([])
for bit in bits:
pulse = np.zeros(sps)
pulse[0] = bit*2-1 # définir la premiÚre valeur à 1 ou -1
pulse_train = np.concatenate((pulse_train, pulse)) # ajouter les 8 Ă©chantillons au signal
# Créer notre filtre à base de cosinus surélevé
num_taps = 101
beta = 0.35
Ts = sps # Supposons que la fréquence d'échantillonnage est de 1Hz, donc la période d'échantillonnage est de 1, donc la période du *symbole* est de 8.
t = np.arange(-51, 52) # n'oubliez pas que le nombre final n'est pas inclus
h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2)
# Filtrer notre signal, afin d'appliquer l'impulsion de mise en forme
samples = np.convolve(pulse_train, h)
Nous laisserons de cĂŽtĂ© le code relatif au tracĂ© car vous avez probablement dĂ©jĂ appris Ă tracer nâimporte quel signal. Pour que les tracĂ©s soient jolis, comme câest souvent le cas dans ce manuel, il faut beaucoup de code supplĂ©mentaire quâil nâest pas nĂ©cessaire de comprendre.
Ajouter un délai¶
Nous pouvons facilement simuler un retard en dĂ©calant les Ă©chantillons, mais cela ne simule quâun retard qui est un multiple entier de notre pĂ©riode dâĂ©chantillonnage. Dans le monde rĂ©el, le retard sera une fraction de la pĂ©riode dâĂ©chantillonnage. Nous pouvons simuler le retard dâune fraction dâĂ©chantillon en crĂ©ant un filtre Ă âretard fractionnelâ, qui laisse passer toutes les frĂ©quences mais retarde les Ă©chantillons dâune certaine quantitĂ© qui nâest pas limitĂ©e Ă lâintervalle dâĂ©chantillonnage. Vous pouvez lâimaginer comme un filtre passe-tout qui applique le mĂȘme dĂ©phasage Ă toutes les frĂ©quences. (Rappelez-vous quâun retard temporel et un dĂ©phasage sont Ă©quivalents.) Le code Python permettant de crĂ©er ce filtre est prĂ©sentĂ© ci-dessous:
# Créer et appliquer un filtre à retard fractionnel
delay = 0.4 # délai fractionné, en échantillons
N = 21 # nombre de taps
n = np.arange(-N//2, N//2) # ...-3,-2,-1,0,1,2,3...
h = np.sinc(n - delay) # calcul des taps du filtre
h *= np.hamming(N) # fenĂȘtre du filtre pour s'assurer qu'il dĂ©croit vers 0 des deux cĂŽtĂ©s
h /= np.sum(h) # normaliser pour obtenir un gain unitaire, nous ne voulons pas changer l'amplitude/puissance
samples = np.convolve(samples, h) # appliquer le filtre
Comme vous pouvez le voir, nous calculons les prises du filtre Ă lâaide dâune fonction sinc(). Une fonction sinc dans le domaine temporel est un rectangle dans le domaine frĂ©quentiel, et notre rectangle pour ce filtre couvre toute la gamme de frĂ©quences de notre signal. Ce filtre ne remodĂšle pas le signal, il le retarde simplement dans le temps. Dans notre exemple, nous retardons de 0.4 Ă©chantillon. Nâoubliez pas que lâapplication de nâimporte quel filtre retarde un signal de la moitiĂ© des taps du filtre moins un, en raison de la convolution du signal Ă travers le filtre.
Si nous traçons le graphique âavantâ et âaprĂšsâ le filtrage dâun signal, nous pouvons observer le retard fractionnel. Dans notre graphique, nous ne zoomons que sur quelques symboles. Sinon, le retard fractionnel nâest pas visible.
Ajout dâun dĂ©calage de frĂ©quence¶
Pour rendre notre signal simulĂ© plus rĂ©aliste, nous allons appliquer un dĂ©calage de frĂ©quence. Disons que notre frĂ©quence dâĂ©chantillonnage dans cette simulation est de 1 MHz (la valeur nâa pas vraiment dâimportance, mais vous verrez pourquoi il est plus facile de choisir un nombre). Si nous voulons simuler un dĂ©calage de frĂ©quence de 13 kHz (un nombre arbitraire), nous pouvons le faire via le code suivant:
# appliquer un décalage de fréquence
fs = 1e6 # supposons que notre fréquence d'échantillonnage est de 1 MHz
fo = 13000 # simuler le décalage de la fréquence
Ts = 1/fs # période d'échantillonnage
t = np.arange(0, Ts*len(samples), Ts) # créer un vecteur temps
samples = samples * np.exp(1j*2*np.pi*fo*t) # effectuer un décalage de fréquence
La figure ci-dessous montre le signal avant et aprĂšs lâapplication du dĂ©calage de frĂ©quence.
Nous nâavons pas reprĂ©sentĂ© graphiquement la partie Q puisque nous transmettions en BPSK, ce qui fait que la partie Q est toujours nulle. Maintenant que nous ajoutons un dĂ©calage de frĂ©quence pour simuler les canaux sans fil, lâĂ©nergie sâĂ©tend sur I et Q. Ă partir de maintenant, nous devrions tracer Ă la fois I et Q. NâhĂ©sitez pas Ă substituer un dĂ©calage de frĂ©quence diffĂ©rent pour votre code. Si vous abaissez le dĂ©calage Ă environ 1 kHz, vous serez en mesure de voir la sinusoĂŻde dans lâenveloppe du signal car elle oscille suffisamment lentement pour couvrir plusieurs symboles.
En ce qui concerne le choix dâune frĂ©quence dâĂ©chantillonnage arbitraire, si vous examinez le code, vous remarquerez que ce qui importe est le rapport entre fo
et fs
.
Vous pouvez prétendre que les deux blocs de code présentés précédemment simulent un canal sans fil. Le code devrait venir aprÚs le code cÎté émission (ce que nous avons fait dans le chapitre sur les impulsions de mise en forme) et avant le code cÎté réception, qui est ce que nous allons explorer dans le reste de ce chapitre.
Synchronisation du temps¶
Lorsque nous transmettons un signal sans fil, il arrive au rĂ©cepteur avec un dĂ©phasage alĂ©atoire dĂ» au temps parcouru. Nous ne pouvons pas simplement commencer Ă Ă©chantillonner les symboles Ă notre dĂ©bit de symboles car il est peu probable que nous lâĂ©chantillonnions au bon endroit dans lâimpulsion, comme nous lâavons vu Ă la fin du chapitre Mise en Forme. Revoyez les trois figures Ă la fin de ce chapitre si vous ne suivez pas.
La plupart des techniques de synchronisation prennent la forme dâune boucle Ă verrouillage de phase (ou PLL en anglais pour phase locked loop). Nous nâĂ©tudierons pas les PLL ici, mais il est important de connaĂźtre ce terme et vous pouvez vous documenter sur le sujet si vous ĂȘtes intĂ©ressĂ©. Les PLL sont des systĂšmes en boucle fermĂ©e qui utilisent la rĂ©troaction pour ajuster continuellement un paramĂštre; dans notre cas, un dĂ©calage temporel nous permet dâĂ©chantillonner au pic des symboles numĂ©riques.
Vous pouvez vous reprĂ©senter la rĂ©cupĂ©ration du temps comme un bloc dans le rĂ©cepteur, qui accepte un flux dâĂ©chantillons et sort un autre flux dâĂ©chantillons (similaire Ă un filtre). Nous programmons ce bloc de rĂ©cupĂ©ration du temps avec des informations sur notre signal, la plus importante Ă©tant le nombre dâĂ©chantillons par symbole (ou notre meilleure estimation de celui-ci, si nous ne sommes pas sĂ»rs Ă 100 % de ce qui a Ă©tĂ© transmis). Ce bloc agit comme un âdĂ©cimateurâ, câest-Ă -dire que notre Ă©chantillon de sortie sera une fraction du nombre dâĂ©chantillons dâentrĂ©e. Nous voulons un Ă©chantillon par symbole numĂ©rique, donc le taux de dĂ©cimation est simplement les Ă©chantillons par symbole. Si lâĂ©metteur transmet Ă 1M symboles par seconde et que nous Ă©chantillonnons Ă 16 Msps, nous recevrons 16 Ă©chantillons par symbole. Ce sera le taux dâĂ©chantillonnage entrant dans le bloc de synchronisation. Le taux dâĂ©chantillonnage sortant du bloc sera de 1 Msps car nous voulons un Ă©chantillon par symbole numĂ©rique.
La plupart des mĂ©thodes de rĂ©cupĂ©ration du temps reposent sur le fait que nos symboles numĂ©riques montent puis descendent, et que la crĂȘte est le point auquel nous voulons Ă©chantillonner le symbole. En dâautres termes, nous Ă©chantillonnons le point maximum aprĂšs avoir pris la valeur absolue :
Il existe de nombreuses mĂ©thodes de rĂ©cupĂ©ration du temps, la plupart ressemblant Ă une PLL. La diffĂ©rence entre elles rĂ©side gĂ©nĂ©ralement dans lâĂ©quation utilisĂ©e pour effectuer la âcorrectionâ du dĂ©calage temporel, que nous dĂ©signons par ou mu
dans le code. La valeur de mu
est mise Ă jour Ă chaque itĂ©ration de la boucle. Elle est exprimĂ©e en unitĂ©s dâĂ©chantillons, et vous pouvez lâimaginer comme le dĂ©calage que nous devons faire pour pouvoir Ă©chantillonner au moment âparfaitâ. Ainsi, si mu = 3.61
, cela signifie que nous devons dĂ©caler lâentrĂ©e de 3.61 Ă©chantillons pour Ă©chantillonner au bon endroit. Comme nous avons 8 Ă©chantillons par symbole, si mu
dépasse 8, il revient simplement à zéro.
Le code Python suivant implĂ©mente la technique de rĂ©cupĂ©ration dâhorloge de Mueller et Muller.
mu = 0 # estimation initiale de la phase de l'Ă©chantillon
out = np.zeros(len(samples) + 10, dtype=np.complex)
out_rail = np.zeros(len(samples) + 10, dtype=np.complex) # stocke les valeurs, à chaque itération nous avons besoin des 2 valeurs précédentes plus la valeur actuelle.
i_in = 0 # index des échantillons d'entrée
i_out = 2 # indice de sortie (les deux premiĂšres sorties sont 0)
while i_out < len(samples) and i_in+16 < len(samples):
out[i_out] = samples[i_in + int(mu)] # prendre ce que nous pensons ĂȘtre le "meilleur" Ă©chantillon.
out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0)
x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1])
y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1])
mm_val = np.real(y - x)
mu += sps + 0.3*mm_val
i_in += int(np.floor(mu)) # arrondir Ă l'entier le plus proche puisque nous l'utilisons comme un index
mu = mu - np.floor(mu) # supprimer la partie entiĂšre de mu
i_out += 1 # incrémenter l'indice de sortie
out = out[2:i_out] # supprimer les deux premiers, et tout ce qui suit i_out (qui n'a jamais été rempli)
samples = out # n'incluez cette ligne que si vous voulez connecter cet extrait de code avec la boucle Costas plus tard
Le bloc de rĂ©cupĂ©ration du timing reçoit les Ă©chantillons âreçusâ et produit un Ă©chantillon de sortie un par un (notez que i_out
est incrĂ©mentĂ© de 1 Ă chaque itĂ©ration de la boucle). Le bloc de rĂ©cupĂ©ration nâutilise pas seulement les Ă©chantillons âreçusâ lâun aprĂšs lâautre Ă cause de la façon dont la boucle ajuste i_in
. Elle sautera quelques Ă©chantillons pour essayer de tirer le âbonâ Ă©chantillon, qui serait celui au pic de lâimpulsion. Au fur et Ă mesure que la boucle traite les Ă©chantillons, elle se synchronise lentement sur le symbole, ou du moins elle tente de le faire en ajustant mu
. Ătant donnĂ© la structure du code, la partie entiĂšre de mu
est ajoutée à i_in
, puis retirée de mu
(gardez Ă lâesprit que mm_val
peut ĂȘtre nĂ©gatif ou positif Ă chaque boucle). Une fois quâelle est complĂštement synchronisĂ©e, la boucle ne devrait tirer que lâĂ©chantillon central de chaque symbole/impulsion. Vous pouvez ajuster la constante 0.3, qui modifiera la vitesse de rĂ©action de la boucle de rĂ©troaction; une valeur plus Ă©levĂ©e la fera rĂ©agir plus rapidement, mais avec un risque plus Ă©levĂ© de problĂšmes de stabilitĂ©.
Le graphique suivant montre un exemple de sortie oĂč nous avons dĂ©sactivĂ© le dĂ©lai fractionnel ainsi que le dĂ©calage de frĂ©quence. Nous montrons seulement I parce que Q est tout Ă fait nul avec le dĂ©calage de frĂ©quence dĂ©sactivĂ©. Les trois graphiques sont empilĂ©s les uns sur les autres pour montrer comment les bits sont alignĂ©s verticalement.
- Graphique du haut
- Symboles BPSK originaux, câest-Ă -dire des 1 et des -1. Rappelez-vous quâil y a des zĂ©ros entre les deux car nous voulons 8 Ă©chantillons par symbole.
- Graphique du milieu
- Echantillons aprĂšs lâimpulsion de mise en forme mais avant le synchronisation.
- Graphique du bas
- Sortie de la synchronisation de symboles, qui fournit seulement 1 Ă©chantillon par symbole. Cela signifie que ces Ă©chantillons peuvent ĂȘtre introduits directement dans un dĂ©modulateur, qui, pour la BPSK, vĂ©rifie si la valeur est supĂ©rieure ou infĂ©rieure Ă 0.
Concentrons-nous sur le graphique du bas, qui est la sortie de la synchronisation. Il a fallu prĂšs de 30 symboles pour que la synchronisation se verrouille sur le bon dĂ©lai. En raison inĂ©vitablement du temps nĂ©cessaire aux synchroniseurs pour se verrouiller, de nombreux protocoles de communication utilisent un prĂ©ambule contenant une sĂ©quence de synchronisation: il sert Ă annoncer lâarrivĂ©e dâun nouveau paquet et donne au rĂ©cepteur le temps de se synchroniser sur celui-ci. Mais aprĂšs ces ~30 Ă©chantillons, la synchronisation fonctionne parfaitement. Nous nous retrouvons avec des 1 et des -1 parfaits qui correspondent aux donnĂ©es dâentrĂ©e. Il est utile que cet exemple nâait pas eu de bruit ajoutĂ©. NâhĂ©sitez pas Ă ajouter du bruit ou des dĂ©calages temporels et voyez comment la synchronisation se comporte. Si nous utilisions la QPSK, nous aurions affaire Ă des nombres complexes, mais lâapproche serait la mĂȘme.
Synchronisation du temps avec interpolation¶
Les synchroniseurs de symboles ont tendance Ă interpoler les Ă©chantillons dâentrĂ©e par un certain nombre, par exemple 16, afin de pouvoir se dĂ©caler dâune fraction dâĂ©chantillon. Le retard alĂ©atoire causĂ© par le canal sans fil ne sera probablement pas un multiple exact dâun Ă©chantillon, de sorte que le pic du symbole peut ne pas se produire rĂ©ellement sur un Ă©chantillon. Câest particuliĂšrement vrai dans le cas oĂč il nây aurait que 2 ou 4 Ă©chantillons par symbole reçu. Lâinterpolation des Ă©chantillons nous permet dâĂ©chantillonner âentreâ les Ă©chantillons rĂ©els, afin dâatteindre le pic de chaque symbole. La sortie du synchroniseur nâest toujours quâun Ă©chantillon par symbole. Les Ă©chantillons dâentrĂ©e sont eux-mĂȘmes interpolĂ©s.
Le code Python de synchronisation temporelle que nous avons implĂ©mentĂ© ci-dessus nâincluait pas dâinterpolation. Pour Ă©tendre notre code, activez le retard temporel fractionnaire que nous avons implĂ©mentĂ© au dĂ©but de ce chapitre afin que notre signal reçu ait un retard plus rĂ©aliste. Laissez le dĂ©calage de frĂ©quence dĂ©sactivĂ© pour le moment. Si vous relancez la simulation, vous constaterez que la synchronisation ne parvient pas Ă se synchroniser complĂštement sur le signal. Câest parce que nous nâinterpolons pas, et que le code nâa aucun moyen âdâĂ©chantillonner entre les Ă©chantillonsâ pour compenser le retard fractionnel. Ajoutons lâinterpolation.
Un moyen rapide dâinterpoler un signal en Python est dâutiliser signal.resample
ou signal.resample_poly
de scipy. Ces deux fonctions font la mĂȘme chose mais fonctionnent diffĂ©remment. Nous utiliserons la derniĂšre fonction car elle a tendance Ă ĂȘtre plus rapide. Interpolons par 16, câest-Ă -dire que nous allons insĂ©rer 15 Ă©chantillons supplĂ©mentaires entre chaque Ă©chantillon. Cela peut ĂȘtre fait en une ligne de code, et cela devrait se faire avant dâeffectuer la synchronisation temporelle (avant le gros extrait de code ci-dessus). Nous allons Ă©galement tracer le graphique avant et aprĂšs pour voir la diffĂ©rence:
samples_interpolated = signal.resample_poly(samples, 16, 1)
# Tracez l'ancien et le nouveau
plt.figure('avant interp')
plt.plot(samples,'.-')
plt.figure('aprĂšs interp')
plt.plot(samples_interpolated,'.-')
plt.show()
Si on zoome beaucoup, on voit que câest le mĂȘme signal, mais avec 16x plus de points :
JâespĂšre que la raison pour laquelle nous devons interpoler Ă lâintĂ©rieur du bloc de synchronisation temporelle devient claire. Ces Ă©chantillons supplĂ©mentaires nous permettront de prendre en compte une fraction dâun Ă©chantillon de retard. En plus de calculer samples_interpolated
, nous devons Ă©galement modifier une ligne de code dans notre synchronisation temporelle. Nous allons changer la premiĂšre ligne Ă lâintĂ©rieur de la boucle while pour devenir:
out[i_out] = samples_interpolated[i_in*16 + int(mu*16)]
Nous avons fait plusieurs choses ici. Dâabord, nous ne pouvons plus utiliser i_in
comme index de lâĂ©chantillon dâentrĂ©e. Nous devons le multiplier par 16 car nous avons interpolĂ© nos Ă©chantillons dâentrĂ©e par 16. Rappelez-vous que la boucle de rĂ©troaction ajuste la variable mu
. Elle reprĂ©sente le dĂ©lai qui nous permet dâĂ©chantillonner au bon moment. Rappelez-vous Ă©galement quâaprĂšs avoir calculĂ© la nouvelle valeur de mu
, nous avons ajouté la partie entiÚre à i_in
. Maintenant, nous allons utiliser la partie restante, qui est un flottant de 0 Ă 1, et qui reprĂ©sente la fraction dâĂ©chantillon que nous devons retarder. Avant, nous nâĂ©tions pas capables de retarder dâune fraction dâĂ©chantillon, mais maintenant nous le pouvons, au moins par incrĂ©ments de 16Ăšme dâĂ©chantillon. Il faut donc multiplier mu
par 16 pour savoir de combien dâĂ©chantillons de notre signal interpolĂ© nous devons retarder. Ensuite, nous devons arrondir ce nombre, car la valeur entre parenthĂšses est finalement un index et doit ĂȘtre un nombre entier. Si ce paragraphe nâa pas eu de sens, essayez de revenir au code initial de rĂ©cupĂ©ration dâhorloge de Mueller et Muller, et lisez Ă©galement les commentaires Ă cĂŽtĂ© de chaque ligne de code.
Le rĂ©sultat du tracĂ© de ce nouveau code devrait ĂȘtre Ă peu prĂšs le mĂȘme que prĂ©cĂ©demment. Tout ce que nous avons fait, câest rendre notre simulation plus rĂ©aliste en ajoutant un retard dâĂ©chantillon fractionnaire, puis nous avons ajoutĂ© lâinterpolateur Ă la synchronisation afin de compenser ce retard dâĂ©chantillon fractionnaire.
NâhĂ©sitez pas Ă jouer avec diffĂ©rents facteurs dâinterpolation, câest-Ă -dire Ă remplacer tous les 16 par une autre valeur. Vous pouvez Ă©galement essayer dâactiver le dĂ©calage de frĂ©quence, ou dâajouter un bruit blanc gaussien au signal avant quâil ne soit reçu, pour voir comment cela affecte les performances de synchronisation (indice : vous devrez peut-ĂȘtre ajuster le multiplicateur de 0.3).
Si nous activons uniquement le décalage de fréquence en utilisant une fréquence de 1kHz, nous obtenons les performances de synchronisation suivantes. Nous devons montrer à la fois I et Q maintenant que nous avons ajouté un décalage de fréquence :
Câest peut-ĂȘtre difficile Ă voir, mais la synchronisation du temps fonctionne toujours trĂšs bien. Il faut environ 20 Ă 30 symboles avant quâelle ne soit verrouillĂ©e. Cependant, il y a un motif sinusoĂŻdal parce que nous avons encore un dĂ©calage de frĂ©quence, et nous allons apprendre Ă le gĂ©rer dans la section suivante.
La figure ci-dessous montre le graphique IQ (aussi appelé constellation) du signal avant et aprÚs la synchronisation. Rappelez-vous que vous pouvez tracer des échantillons sur un graphique IQ en utilisant un nuage de points : plt.plot(np.real(samples), np.imag(samples), '.')
. Dans lâanimation ci-dessous, nous avons spĂ©cifiquement laissĂ© de cĂŽtĂ© les 30 premiers symboles. Ils sont apparus avant la fin de la synchronisation temporelle. Les symboles restants sont tous approximativement sur le cercle des unitĂ©s en raison du dĂ©calage de frĂ©quence.
Pour en savoir encore plus, nous pouvons observer la constellation dans le temps afin de discerner ce qui arrive rĂ©ellement aux symboles. Au tout dĂ©but, pendant une courte pĂ©riode de temps, les symboles ne sont pas Ă 0 ou sur le cercle unitaire. Câest la pĂ©riode pendant laquelle la synchronisation temporelle trouve le bon dĂ©lai. Câest trĂšs rapide, regardez bien! La rotation est juste le dĂ©calage de frĂ©quence. La frĂ©quence est un changement constant de la phase, donc un dĂ©calage de frĂ©quence provoque une rotation de la BPSK (crĂ©ant un cercle dans le tracĂ© statique/persistant ci-dessus).
Nous espĂ©rons quâen voyant un exemple de synchronisation temporelle, vous avez une idĂ©e de ce quâelle fait et une idĂ©e gĂ©nĂ©rale de son fonctionnement. En pratique, la boucle while que nous avons crĂ©Ă©e ne fonctionnerait que sur un petit nombre dâĂ©chantillons Ă la fois (par exemple, 1000). Vous devez vous souvenir de la valeur de mu
entre les appels Ă la fonction sync, ainsi que des deux derniĂšres valeurs de out
et out_rail
.
Ensuite, nous allons étudier la synchronisation de la fréquence, que nous divisons en synchro de fréquence grossiÚre et fine. La synchronisation grossiÚre vient généralement avant la synchronisation temporelle, tandis que la synchronisation fine vient aprÚs.
Synchronisation grossiÚre des fréquences¶
MĂȘme si nous demandons Ă lâĂ©metteur et au rĂ©cepteur de fonctionner sur la mĂȘme frĂ©quence centrale, il y aura un lĂ©ger dĂ©calage de frĂ©quence entre les deux en raison dâimperfections matĂ©rielles (par exemple, lâoscillateur) ou dâun dĂ©calage Doppler dĂ» au mouvement. Ce dĂ©calage de frĂ©quence sera minuscule par rapport Ă la frĂ©quence porteuse, mais mĂȘme un petit dĂ©calage peut perturber un signal numĂ©rique. Le dĂ©calage Ă©voluera probablement dans le temps, ce qui nĂ©cessite une boucle de rĂ©troaction permanente pour corriger le dĂ©calage. Par exemple, lâoscillateur Ă lâintĂ©rieur du Pluto a une spĂ©cification de dĂ©calage maximale de 25 PPM. Câest-Ă -dire 25 parties par million par rapport Ă la frĂ©quence centrale. Si vous ĂȘtes rĂ©glĂ© sur 2.4 GHz, le dĂ©calage maximal serait de +/- 60 kHz. Les Ă©chantillons que notre SDR nous fournit sont en bande de base, ce qui fait que tout dĂ©calage de frĂ©quence se manifeste dans ce signal en bande de base. Un signal BPSK avec un petit dĂ©calage de la porteuse ressemblera au tracĂ© temporel ci-dessous, ce qui nâest Ă©videmment pas idĂ©al pour dĂ©moduler des bits. Nous devons supprimer tout dĂ©calage de frĂ©quence avant la dĂ©modulation.
La synchronisation de frĂ©quence est gĂ©nĂ©ralement dĂ©composĂ©e en synchronisation grossiĂšre et synchronisation fine, oĂč la synchronisation grossiĂšre corrige les grands dĂ©calages de lâordre du kHz ou plus, tandis que la synchronisation fine corrige ce qui reste. La synchronisation grossiĂšre intervient avant la synchronisation temporelle, tandis que la synchronisation fine intervient aprĂšs.
MathĂ©matiquement, si nous disposons dâun signal en bande de base et quâil subit un dĂ©calage de frĂ©quence (aussi appelĂ© porteuse) de Hz, nous pouvons reprĂ©senter ce qui est reçu comme suit:
oĂč est le bruit.
La premiĂšre astuce que nous allons apprendre, afin dâeffectuer une estimation grossiĂšre du dĂ©calage de frĂ©quence (si nous pouvons estimer la frĂ©quence de dĂ©calage, alors nous pouvons la compenser), est de prendre le carrĂ© de notre signal. Ignorons le bruit pour lâinstant, afin de garder les mathĂ©matiques plus simples :
Voyons ce qui se passe lorsque nous prenons le carrĂ© de notre signal en considĂ©rant ce que ferait la QPSK. LâĂ©lĂ©vation au carrĂ© de nombres complexes donne lieu Ă un comportement intĂ©ressant, surtout lorsquâil sâagit de constellations comme la BPSK et la QPSK. Lâanimation suivante montre ce qui se passe lorsquâon Ă©lĂšve au carrĂ© une QPSK, puis si on lâĂ©lĂšve encore une deuxiĂšme fois. Jâai utilisĂ© spĂ©cifiquement la QPSK au lieu de la BPSK parce que vous pouvez voir que lorsque vous Ă©rigez la QPSK une fois, vous obtenez essentiellement la BPSK. Et aprĂšs un autre carrĂ©, on obtient un cluster. (Merci Ă http://ventrella.com/ComplexSquaring/ qui a crĂ©Ă© cette belle application web).
Voyons ce qui se passe lorsquâon applique Ă notre signal QPSK une petite rotation de phase et une mise Ă lâĂ©chelle de lâamplitude, ce qui est plus rĂ©aliste :
Il sâagit toujours dâun seul groupe, mais avec un dĂ©phasage. Ce quâil faut retenir, câest que si vous mettez la QPSK au carrĂ© deux fois (et la BPSK une fois), les quatre groupes de points seront fusionnĂ©s en un seul groupe. Pourquoi cela est-il utile? En fusionnant les groupes, nous supprimons essentiellement la modulation! Si tous les points sont maintenant dans le mĂȘme groupe, câest comme si on avait un tas de constantes dans une rangĂ©e. Câest comme sâil nây avait plus de modulation, et que la seule chose qui restait Ă©tait la sinusoĂŻde causĂ©e par le dĂ©calage de frĂ©quence (nous avons aussi du bruit, mais ignorons-le pour lâinstant). Il sâavĂšre que vous devez Ă©lever le signal au carrĂ© N fois, oĂč N est lâordre du schĂ©ma de modulation utilisĂ©, ce qui signifie que cette astuce ne fonctionne que si vous connaissez le schĂ©ma de modulation Ă lâavance. LâĂ©quation est en fait la suivante :
Pour notre cas de BPSK, nous avons un schĂ©ma de modulation dâordre 2, nous utiliserons donc lâĂ©quation suivante pour notre synchronisation grossiĂšre de la frĂ©quence:
Nous avons dĂ©couvert ce qui arrive Ă la partie de lâĂ©quation, mais quâen est-il de la partie sinusoĂŻde (alias exponentielle complexe)? Comme on peut le voir, on ajoute le terme , ce qui la rend Ă©quivalente Ă une sinusoĂŻde Ă une frĂ©quence de au lieu de . Une mĂ©thode simple pour dĂ©terminer est de prendre la FFT du signal aprĂšs lâavoir Ă©levĂ© au carrĂ© N fois et de voir oĂč le pic se produit. Faisons une simulation en Python. Nous allons retourner Ă la gĂ©nĂ©ration de notre signal BPSK, et au lieu de lui appliquer un retard fractionnel, nous allons appliquer un dĂ©calage de frĂ©quence en multipliant le signal par comme nous lâavons fait dans le chapitre Filtres pour convertir un filtre passe-bas en un filtre passe-haut.
En utilisant le code du dĂ©but de ce chapitre, appliquez un dĂ©calage de frĂ©quence de +13 kHz Ă votre signal numĂ©rique. Cela peut se produire juste avant ou juste aprĂšs lâajout du retard fractionnĂ©; cela nâa pas dâimportance. Quoi quâil en soit, cela doit se faire aprĂšs lâimpulsion de mise en forme, mais avant dâeffectuer toute fonction cĂŽtĂ© rĂ©ception, comme la synchronisation temporelle.
Maintenant que nous avons un signal avec un dĂ©calage de frĂ©quence de 13kHz, traçons la FFT avant et aprĂšs la mise au carrĂ©, pour voir ce qui se passe. Vous devriez maintenant savoir comment effectuer une FFT, y compris les opĂ©rations abs() et fftshift(). Pour cet exercice, peu importe que vous preniez ou non le logarithme ou que vous Ă©leviez au carrĂ© le signal aprĂšs avoir effectuĂ© lâopĂ©ration abs().
Regardez dâabord le signal avant de lâĂ©lever au carrĂ© (juste une FFT normale):
psd = np.fft.fftshift(np.abs(np.fft.fft(samples)))
f = np.linspace(-fs/2.0, fs/2.0, len(psd))
plt.plot(f, psd)
plt.show()
On ne voit pas vraiment de pic associé au décalage de la porteuse. Il est couvert par notre signal.
Maintenant avec lâĂ©lĂ©vation au carrĂ© ajoutĂ©e (juste une puissance de 2 parce que câest une BPSK) :
# Ajoutez ceci avant la ligne FFT
samples = samples**2
Il faut zoomer pour voir sur quelle fréquence se trouve le pic :
Vous pouvez essayer dâaugmenter le nombre de symboles simulĂ©s (par exemple, 1000 symboles) afin dâavoir suffisamment dâĂ©chantillons pour travailler. Plus il y a dâĂ©chantillons dans notre FFT, plus notre estimation du dĂ©calage de frĂ©quence sera prĂ©cise. Pour rappel, le code ci-dessus doit venir avant la synchornisation de temps.
Le pic de frĂ©quence apparaĂźt Ă . Nous devons diviser cette valeur (26.6kHz) par 2 pour trouver notre rĂ©ponse finale, qui est trĂšs proche du dĂ©calage de frĂ©quence de 13kHz que nous avons appliquĂ© au dĂ©but du chapitre! Si vous avez jouĂ© avec ce nombre et quâil nâest plus de 13kHz, ce nâest pas grave. Assurez-vous simplement que vous ĂȘtes conscient de ce que vous avez rĂ©glĂ©.
Comme notre frĂ©quence dâĂ©chantillonnage est de 1 MHz, les frĂ©quences maximales que nous pouvons voir sont de -500kHz Ă 500kHz. Si nous portons notre signal Ă la puissance N, cela signifie que nous ne pouvons âvoirâ les dĂ©calages de frĂ©quence que jusquâĂ , ou dans le cas de la BPSK +/- 250kHz. Si nous recevions un signal QPSK, il ne serait que de +/- 125kHz, et un dĂ©calage de la porteuse supĂ©rieur ou infĂ©rieur Ă cette valeur serait hors de notre portĂ©e avec cette technique. Pour vous donner une idĂ©e du dĂ©calage Doppler, si vous transmettez dans la bande des 2.4GHz et que lâĂ©metteur ou le rĂ©cepteur se dĂ©place Ă 96km/h (câest la vitesse relative qui compte), cela entraĂźnera un dĂ©calage de frĂ©quence de 214Hz. Le dĂ©calage dĂ» Ă un oscillateur de mauvaise qualitĂ© sera probablement le principal coupable dans cette situation.
En fait, la correction de ce décalage de fréquence se fait exactement comme nous avons simulé le décalage en premier lieu: en multipliant par une exponentielle complexe, mais avec un signe négatif puisque nous voulons supprimer le décalage.
max_freq = f[np.argmax(psd)]
Ts = 1/fs # période d'échantillonnage
t = np.arange(0, Ts*len(samples), Ts) # vecteur de temps
samples = samples * np.exp(-1j*2*np.pi*max_freq*t/2.0)
Câest Ă vous de dĂ©cider si vous voulez le corriger ou modifier le dĂ©calage de frĂ©quence initial que nous avons appliquĂ© au dĂ©but Ă un nombre plus petit (comme 500Hz) pour tester la synchronisation de frĂ©quence fine que nous allons maintenant apprendre Ă faire.
Synchronisation fine de la fréquence¶
Ensuite, nous allons passer Ă la synchronisation fine de la frĂ©quence. Lâastuce prĂ©cĂ©dente est plutĂŽt destinĂ©e Ă lâĂ©vanouissement grossier, et ce nâest pas une opĂ©ration en boucle fermĂ©e (de type feedback). Mais pour la synchronisation fine de la frĂ©quence, nous aurons besoin dâune boucle de rĂ©troaction par laquelle nous ferons passer des Ă©chantillons, ce qui sera une fois de plus une forme de PLL. Notre objectif est de ramener le dĂ©calage de frĂ©quence Ă zĂ©ro et de lây maintenir, mĂȘme si le dĂ©calage change au fil du temps. Nous devons continuellement suivre le dĂ©calage. Les techniques de synchronisation fine de la frĂ©quence fonctionnent mieux avec un signal qui a dĂ©jĂ Ă©tĂ© synchronisĂ© dans le temps au niveau du symbole, donc le code dont nous parlons dans cette section viendra aprĂšs la synchronisation temporelle.
Nous allons utiliser une technique appelĂ©e boucle de Costas. Il sâagit dâune forme de PLL spĂ©cialement conçue pour la correction du dĂ©calage de la frĂ©quence de la porteuse pour les signaux numĂ©riques tels que BPSK et QPSK. Elle a Ă©tĂ© inventĂ©e par John P. Costas chez General Electric dans les annĂ©es 1950 et a eu un impact majeur sur les communications numĂ©riques modernes. La boucle de Costas supprime le dĂ©calage de frĂ©quence tout en fixant le dĂ©calage de phase. LâĂ©nergie est alignĂ©e avec lâaxe I. La frĂ©quence nâest quâun changement de phase, ils peuvent donc ĂȘtre suivis comme un tout. La boucle de Costas est rĂ©sumĂ©e Ă lâaide du diagramme suivant (notez que les 1/2 ont Ă©tĂ© laissĂ©s de cĂŽtĂ© dans les Ă©quations car ils nâont pas dâimportance fonctionnelle).
Lâoscillateur commandĂ© en tension (ou VCO en anglais pour voltage controlled oscillator) est simplement un gĂ©nĂ©rateur dâondes sin/cos qui utilise une frĂ©quence basĂ©e sur lâentrĂ©e. Dans notre cas, puisque nous simulons un canal sans fil, il ne sâagit pas dâune tension, mais plutĂŽt dâun niveau reprĂ©sentĂ© par une variable. Elle dĂ©termine la frĂ©quence et la phase des ondes sinus et cosinus gĂ©nĂ©rĂ©es. Ce quâil fait, câest multiplier le signal reçu par une sinusoĂŻde gĂ©nĂ©rĂ©e en interne, afin de tenter dâannuler le dĂ©calage de frĂ©quence et de phase. Ce comportement est similaire Ă celui dâune SDR qui effectue une conversion de frĂ©quence et crĂ©e les branches I et Q.
Voici le code Python qui constitue notre boucle Costas:
N = len(samples)
phase = 0
freq = 0
# Ces deux paramÚtres suivants sont ce qu'il faut ajuster, pour rendre la boucle de rétroaction plus rapide ou plus lente (ce qui a un impact sur la stabilité).
alpha = 0.132
beta = 0.00932
out = np.zeros(N, dtype=np.complex)
freq_log = []
for i in range(N):
out[i] = samples[i] * np.exp(-1j*phase) # ajuster l'échantillon d'entrée par l'inverse du décalage de phase estimé
error = np.real(out[i]) * np.imag(out[i]) # Voici la formule d'erreur pour une boucle de Costas de 2Ăšme ordre (par exemple pour BPSK)
# Avancer la boucle (recalculer la phase et le décalage de fréquence)
freq += (beta * error)
freq_log.append(freq * fs / (2*np.pi)) # convertir de la vitesse angulaire en Hz pour la journalisation
phase += freq + (alpha * error)
# Facultatif: Ajustez la phase de façon à ce qu'elle soit toujours entre 0 et 2pi, rappelez-vous que la phase s'enroule autour de chaque 2pi
while phase >= 2*np.pi:
phase -= 2*np.pi
while phase < 0:
phase += 2*np.pi
# Tracez la fréquence en fonction du temps pour voir combien de temps il faut pour atteindre le bon décalage.
plt.plot(freq_log,'.-')
plt.show()
Il y a beaucoup de choses ici, alors passons-les en revue. Certaines lignes sont simples et dâautres sont super compliquĂ©es. samples
est notre entrée, et out
les Ă©chantillons de sortie. phase
et frequency
sont comme le mu
du code de synchronisation temporelle. Ils contiennent les estimations du dĂ©calage actuel, et Ă chaque itĂ©ration de la boucle, nous crĂ©ons les Ă©chantillons de sortie en multipliant les Ă©chantillons dâentrĂ©e par np.exp(-1j*phase)
. La variable error
contient la mĂ©trique dâerreur, et pour une boucle de Costas dâordre 2, câest une Ă©quation trĂšs simple. Nous multiplions la partie rĂ©elle de lâĂ©chantillon (I) par la partie imaginaire (Q), et parce que Q devrait ĂȘtre Ă©gal Ă zĂ©ro pour la BPSK, la fonction dâerreur est minimisĂ©e lorsquâil nây a pas de dĂ©calage de phase ou de frĂ©quence qui fait passer lâĂ©nergie de I Ă Q. Pour une boucle de Costas dâordre 4, câest encore relativement simple mais pas tout Ă fait une ligne, car I et Q auront de lâĂ©nergie mĂȘme lorsquâil nây a pas de dĂ©calage de phase ou de frĂ©quence, pour la QPSK. Si vous ĂȘtes curieux de voir Ă quoi cela ressemble, cliquez ci-dessous, mais nous ne lâutiliserons pas dans notre code pour le moment. La raison pour laquelle cela fonctionne pour la QPSK est que lorsque vous prenez la valeur absolue de I et Q, vous obtenez +1+1j, et sâil nây a pas de dĂ©calage de phase ou de frĂ©quence, la diffĂ©rence entre la valeur absolue de I et Q devrait ĂȘtre proche de zĂ©ro.
Ăquation d'erreur de la boucle de Costas de l'ordre 4 (pour les curieux)
# For QPSK
def phase_detector_4(sample):
if sample.real > 0:
a = 1.0
else:
a = -1.0
if sample.imag > 0:
b = 1.0
else:
b = -1.0
return a * sample.imag - b * sample.real
Les variables alpha
et beta
dĂ©finissent la vitesse de mise Ă jour de la phase et de la frĂ©quence, respectivement. Il y a une certaine thĂ©orie derriĂšre le choix de ces deux valeurs, mais nous ne lâaborderons pas ici. Si vous ĂȘtes curieux, vous pouvez essayer de modifier alpha
et/ou beta
pour voir ce qui se passe.
Nous enregistrons la valeur de freq
à chaque itération afin de pouvoir la tracer à la fin, pour voir comment la boucle de Costas converge vers le décalage de fréquence correct. Nous devons multiplier freq
par la frĂ©quence dâĂ©chantillonnage et convertir la frĂ©quence angulaire en Hz, en la divisant par . Notez que si vous avez effectuĂ© une synchronisation temporelle avant la boucle Costas, vous devrez Ă©galement diviser par votre facteur de surĂ©chantillonnage sps
(par exemple, 8), car les Ă©chantillons provenant de la synchronisation temporelle sont Ă un taux Ă©gal Ă votre taux dâĂ©chantillonnage original divisĂ© par sps
.
Enfin, aprĂšs avoir recalculĂ© la phase, nous ajoutons ou supprimons suffisamment de âs pour maintenir la phase entre 0 et âs, ce qui enroule la phase autour.
Notre signal avant et aprĂšs la boucle de Costas ressemble Ă ceci:
Et lâestimation du dĂ©calage de frĂ©quence au fil du temps, se stabilisant sur le dĂ©calage correct (un dĂ©calage de -300Hz a Ă©tĂ© utilisĂ© dans cet exemple de signal) :
Il faut prĂšs de 70 Ă©chantillons pour que lâalgorithme se verrouille complĂštement sur le dĂ©calage de frĂ©quence. Vous pouvez voir que dans mon exemple simulĂ©, il restait environ -300 Hz aprĂšs la synchronisation grossiĂšre de la frĂ©quence. Les vĂŽtres peuvent varier. Comme je lâai dĂ©jĂ mentionnĂ©, vous pouvez dĂ©sactiver la synchronisation grossiĂšre de la frĂ©quence et dĂ©finir le dĂ©calage initial de la frĂ©quence Ă la valeur de votre choix et voir si la boucle de Costas sâen rend compte.
La boucle de Costas, en plus de supprimer le dĂ©calage de frĂ©quence, a alignĂ© notre signal BPSK pour quâil soit sur la partie I, ce qui rend Q Ă nouveau nul. Il sâagit dâun effet secondaire pratique de la boucle de Costas, et il permet Ă la boucle de Costas dâagir essentiellement comme notre dĂ©modulateur. Maintenant, tout ce que nous avons Ă faire est de prendre I et de voir sâil est supĂ©rieur ou infĂ©rieur Ă zĂ©ro. Nous ne saurons pas vraiment comment transformer un nĂ©gatif et un positif en 0 et 1 parce quâil peut y avoir ou non une inversion; il nây a aucun moyen pour la boucle de Costas (ou notre synchronisation temporelle) de le savoir. Câest lĂ que le codage diffĂ©rentiel entre en jeu. Il lĂšve lâambiguĂŻtĂ© car les 1 et les 0 sont basĂ©s sur le fait que le symbole a changĂ© ou non, et non sur le fait quâil Ă©tait +1 ou -1. Si on ajoute le codage diffĂ©rentiel, on utilise toujours la BPSK. Nous ajouterions un bloc de codage diffĂ©rentiel juste avant la modulation du cĂŽtĂ© Tx et juste aprĂšs la dĂ©modulation du cĂŽtĂ© Rx.
Vous trouverez ci-dessous une animation de la synchronisation temporelle et de la synchronisation de frĂ©quence. La synchronisation temporelle se produit presque immĂ©diatement, mais la synchronisation de frĂ©quence prend presque toute lâanimation pour sâinstaller complĂštement, et ce parce que alpha
et beta
ont Ă©tĂ© rĂ©glĂ©s trop bas, Ă 0.005 et 0.001 respectivement. Le code utilisĂ© pour gĂ©nĂ©rer cette animation peut ĂȘtre trouvĂ© ici.
Synchronisation des trames¶
Nous avons vu comment corriger les dĂ©calages de temps, de frĂ©quence et de phase dans notre signal reçu. Mais la plupart des protocoles de communication modernes ne se contentent pas de transmettre des bits en continu Ă un taux dâutilisation de 100%. Ils utilisent plutĂŽt des paquets/trames. Au niveau du rĂ©cepteur, nous devons ĂȘtre en mesure dâidentifier le dĂ©but dâune nouvelle trame. Habituellement, lâen-tĂȘte de trame (au niveau de la couche MAC) indique le nombre dâoctets contenus dans la trame. Nous pouvons utiliser cette information pour connaĂźtre la longueur de la trame, par exemple, en unitĂ©s dâĂ©chantillons ou de symboles. NĂ©anmoins, la dĂ©tection du dĂ©but de la trame est une tĂąche totalement distincte. Vous trouverez ci-dessous un exemple de structure de trame WiFi. Notez que la toute premiĂšre chose transmise est un en-tĂȘte de la couche PHY, et que la premiĂšre moitiĂ© de cet en-tĂȘte est un âprĂ©ambuleâ. Ce prĂ©ambule contient une sĂ©quence de synchronisation que le rĂ©cepteur utilise pour dĂ©tecter le dĂ©but des trames, et câest une sĂ©quence connue dâavance par le rĂ©cepteur.
Une mĂ©thode courante et simple de dĂ©tection de ces sĂ©quences au niveau du rĂ©cepteur consiste Ă effectuer une corrĂ©lation croisĂ©e entre les Ă©chantillons reçus et la sĂ©quence connue. Lorsque la sĂ©quence se produit, cette intercorrĂ©lation ressemble Ă une autocorrĂ©lation (avec du bruit ajoutĂ©). Typiquement, les sĂ©quences choisies pour les prĂ©ambules auront de belles propriĂ©tĂ©s dâautocorrĂ©lation, telles que lâautocorrĂ©lation de la sĂ©quence crĂ©e un seul pic fort Ă 0 et aucun autre pic. Les codes de Barker en sont un exemple. Dans la norme 802.11/WiFi, une sĂ©quence de Barker de longueur 11 est utilisĂ©e pour les dĂ©bits de 1 et 2Mbit/sec :
+1 +1 +1 â1 â1 â1 +1 â1 â1 +1 â1
On peut lâassimiler Ă 11 symboles BPSK. Nous pouvons regarder lâautocorrĂ©lation de cette sĂ©quence trĂšs facilement en Python :
import numpy as np
import matplotlib.pyplot as plt
x = [1,1,1,-1,-1,-1,1,-1,-1,1,-1]
plt.plot(np.correlate(x,x,'same'),'.-')
plt.grid()
plt.show()
Vous pouvez voir quâil y a 11 (longueur de la sĂ©quence) au centre, et -1 ou 0 pour tous les autres dĂ©lais. Il fonctionne bien pour trouver le dĂ©but dâune trame car il intĂšgre essentiellement 11 symboles dâĂ©nergie dans une tentative de crĂ©er un pic de 1 bit dans la sortie de la corrĂ©lation croisĂ©e. En fait, la partie la plus difficile de la dĂ©tection du dĂ©but dâune trame est de trouver un bon seuil. Vous ne voulez pas que des trames qui ne font pas rĂ©ellement partie de votre protocole le dĂ©clenchent. Cela signifie quâen plus de la corrĂ©lation croisĂ©e, vous devez Ă©galement effectuer une sorte de normalisation de la puissance, que nous nâexaminerons pas ici. En dĂ©cidant dâun seuil, vous devez faire un compromis entre la probabilitĂ© de dĂ©tection et la probabilitĂ© de fausses alarmes. Rappelez-vous que lâen-tĂȘte de trame lui-mĂȘme contiendra des informations, donc certaines fausses alarmes sont acceptables; vous dĂ©couvrirez rapidement quâil ne sâagit pas dâune trame lorsque vous dĂ©coderez lâen-tĂȘte et que le CRC Ă©chouera inĂ©vitablement (parce quâil ne sâagissait pas dâune trame). Cependant, si certaines fausses alarmes sont acceptables, manquer complĂštement la dĂ©tection dâune trame est une mauvaise chose.
Les sĂ©quences de Zadoff-Chu, utilisĂ©es en LTE, sont une autre sĂ©quence prĂ©sentant dâexcellentes propriĂ©tĂ©s dâautocorrĂ©lation. Elles ont lâavantage de se prĂ©senter sous forme dâensembles; vous pouvez avoir plusieurs sĂ©quences diffĂ©rentes qui ont toutes de bonnes propriĂ©tĂ©s dâautocorrĂ©lation, mais elles ne se dĂ©clencheront pas les unes les autres (câest-Ă -dire quâelles ont Ă©galement de bonnes propriĂ©tĂ©s de corrĂ©lation croisĂ©e, lorsque vous corrĂšlez diffĂ©rentes sĂ©quences de lâensemble). GrĂące Ă cette fonctionnalitĂ©, des sĂ©quences diffĂ©rentes seront attribuĂ©es Ă diffĂ©rentes stations de bases, de sorte quâun tĂ©lĂ©phone puisse non seulement trouver le dĂ©but de la trame mais aussi savoir de quelle station il reçoit.