Partie A - Encodeur Reed-Solomon.
Partie A.1 - Introduction et définitions.
Ces codes correcteurs d'erreurs (CCE) sont utilisés dans les technologies de transmission de l'information
ou dans l'aérospatiale. Les CCE peuvent être divisés en deux grandes familles : codes en blocs ou codes
récurrents. Dans la deuxième famille, qui sont des codes séquentiels ou convolutif, un effet de mémoire est
introduit, cela sera l'objet d'un autre article (codage Viterbi).
Figure 1 : Reed-solomon Encoder block diagramm.
www.opencores.org propose les sources d'un codeur RS, au format Verilog peu clair et sans aucune explication.
Quelques autres sources diffusent des informations soient pertinentes, soit erronées. Remédions à cet état de
fait et expliquons en "succinctement" le principe.
Partie A.2 - Polynôme générateur et polynôme primitif..
L'arithmétique des champs finis fut découverte par Evarsite Galois (1811 Bourg-la Reine,
1832). Un corps de Galois est un ensemble pour lequel le résultat de certaines opérations
arithmétiques (addition, multiplication...) entre deux éléments du corps est un autre
élément du corps.
p(x) = x^8 + x^4 + x^3 + x^2 + 1
Le polynome générateur g(x) permet quant à lui de générer les octets appropriés de parité pour chaque block de k symbole d'information. g(x) est de degré n-k et vaut dans le cas de la TnT ou tout autre système ajoutant 16 octets de parité :
g(x) = (x + α0).(x + α1). ... .(x + α15)
g(x) = Produit de i=b à b+n-k-1
(x - αi)
Partie A.3 - Corps finis de Galois et arithmétique. La clef de voûte pour la compréhension d'un codec Reed-Solomon, c'est le corps de Galois. L'analyse détaillée des corps finis sort largement du cadre de cet exposé, le lecteur intéressé par la théorie mathématique se reportera à un ouvrage spécialisé. Il est toutefois nécessaire d'appréhender quelques notions afin de comprendre le principe des codes cycliques. Quelques aspects vont être abordés : la génération des éléments de GF ainsi que certains opérations arithmétiques sur le Corps de Galois, puis le principe de génération des coefficients du polynôme générateur. Un corps finis est une structure algébrique mathématique très utile dans laquelle il est possible d'additionner, soustraire, multiplier ou diviser et ce sur des nombres réels ou complexes. Un champs à q éléments sera noté GF(p) ; par exemple GF(2) est composé de deux éléments {0,1}. Par extension, nous noterons GF(pm) un champs fini dans lequel le nombre d'élément est une puissance entière d'un nombre premier p. Pour p=2, dans le champs GF(2m) il existe toujours un élément primitif α qui permet d'exprimer tout élément de GF(2m) sauf zéro comme une puissance de α. Il est possible de générer n'importe quel corps GF(2m) en utilisant un polynôme primitif sur GF(2) ; l'arithmétique effectuée dans le champs GF(2m) est le modulo du polynôme primitif. Regardons le cas plus concret de GF(23) ; le polynôme primitif de degré 3 que l'on peut utiliser pour générer les éléments de GF(23) est donné par p(x) = x3 + x + 1. Prenons α un élément primitif de GF(23) ; comme α est une racine de p(x), α3 + α + 1 = 0 et selon certaines propriétés α3 = α + 1. Maintenant, appliquons ces résultats et propriétés afin de générer tous les éléments du champs GF(23) en terme de puissance de α.
Table 2 : Valeur des éléments du champs GF(23).
La représentation polynomiale des éléments du champs facilite les opérations mathématiques ; une addition de deux éléments du champs consistera à additionner les coefficients du polynome primitif : par exemple ajouter α2 à α3 consiste à ajouter modulo 2 les valeurs 100 et 011 soit 111 = α5. La multiplication de deux éléments du champs s'effectue en ajoutant les puissances de α modulo 2m-1 (soit 7 dans notre cas ou m vaut 3). Par exemple, α 4 par α6 vaudra α10mod(7) soit α3. Il est d'usage d'utiliser deux tables, l'une anti-log A(i) permet d'effectuer des additions. Cette table retourne la valeur binaire d'une puiisance de alpha. La seconde table appelée log ou L(i) permet de réaliser les multiplications, cette table retourne la puissance de alpha d'un vecteur. Avant de s'atteler au cas le plus traditionnel GF(28) regardons GF(24) = GF(16) et qui comprend donc 15 éléments notés de α0 à α14. Un polynome primitif valide est p(x) = x4 + x + 1 = 10011. α est racine de p(x) (Ceci n'est pas démontré ici mais est analogue au nombre imaginaire 'i' racine de l'équation x^2 + 1 = 0).
Table 3 : Valeur des éléments du champs GF(24).
Algorithme de génération de GF(2^8). p(x) = x^8 + x^4 + x^3 + x^2 + 1 coef : 8 7654 3210 p(x) = 1 0001 1101 a0 = 0 0000 0001 initialisation a1 = 0 0000 0010 ROL (ROtate Left) ... a6 = 0 0100 0000 ROL a7 = 0 1000 0000 ROL a8 = 1 0000 0000 ROL C=1 + 1 0001 1101 donc normalisation a8 = 0 0001 1101 a9 = 0 0011 1010 ROL a10 = 0 0111 0100 ROL a11 = 0 1110 1000 a12 = 1 1101 0000 ROL C=1 + 1 0001 1101 a12 = 0 1100 1101 a13 = 1 1001 1010 + 1 0001 1101 a13 = 0 1000 0111 poly_prim = 1 0001 1101; -- initialisation alpha_to[0] = 1; -- initialisation pour (i=1 i inférieur à 255 i++) -- boucle sur les éléments de CG alpha_to[i] ROL alpha_to[i-1]; -- décalage à gauche de n-1 if (MSB de alpha_to[i] = 1) -- test de x^8 alpha_to[i] = alpha_to[i] xor poly_prim; -- normalisation fin si fin pourIl est possible dès lors de vérifier la véracité de la table par le truchement de certaines propriétés mathématiques. En premier lieu, par exemple, α étant racine, la relation α8 + α4 + α3 + α2 + 1 = 0 doit être vérifiée. Par ailleurs, l'élément GF(2m-1) = GF(255) = 1 CG(2m) = {0,1,α,α2...α2^m-2} Table complète des éléments de GF(28).
Regardons de plus près la multiplication. C'est la somme des puissances de α modulo 2m-1
Cette formule bien pratique pour l'informaticien s'avère difficilement utilisable pour l'électronicien.
Cherchons donc les équations littérales de la multiplication simple pour commencer avec des symboles
de type quartet.
A = a3.α3 + a2.α2 + a1.α + a0
A.B = Ce résultat présente sept coefficients que nous devons convertir en 4-aires (quartet); pour cela nous substituerons α6, α5 et α4 par leur représentation polynomiale. (soit respectivement x^3+x^2, x^2+x et x+1).
A.B = Les performances d'un codeur/décodeur Reed Solomon dépendent en partie de l'arithmétique des corps finis (field). Si l'addition est simple et consiste uniquement en un ou exclusif des éléments des symboles, il en va tout autrement du multiplieur. Différentes structures ont été développées :
Les équations pour un symbole de taille 'm' pourront être obtenues par le logiciel rs_cal.c proposé en bas de ce fichier. (partie A.7 liens et documentation.)
Partie A.4 - Coefficients du polynôme générateur. Pour calculer les symboles de parité, il faut connaître les coefficients du polynôme générateur. Intéressons nous au code RS(7,3,5) dans GF(2^3) ou p(x) = x^3 + x + 1 est polynome primitif, donc p(α) = α3 +α + 1 = 0 et donc :
g(x) = produit de i=0 à n-k-1
(x + αi) x^4 : 1 x^3 : α3 + α2 + α + 1 x^2 : α5 + α4 + α2 + α x^1 : α6 + α5 + α4 + α3 x^0 : α6
Soit après addition des notations binaires associées de la table 2 : g(x) = x^4 + α2.x^3 + α5.x^2 + α5.x + α6 Regardons maintenant le cas du code RS(15,9,7) dans GF(2^4) dont le polynôme primitif est p(x) = x^4 + x^3 + 1 donc p(α) = α4 + α3; + 1 = 0 et g(x) = Produit de i=1 à 6 de (x + αi) [ici b=1]g(x) = x^6 + α12.x^5 + x^4 + α2.x^3 + α7.x^2 + α11.x + α6 Il est facile de vérifier le terme en x^0 qui vaut le produit des α soit :α6.α5.α4.α3.α2.α = = α(6+5+4+3+2+1)mod(2^m+1) = α(6+5+4+3+2+1)mod(15) = α6 Le calcul manuel des autres coefficients est fastidieux, il vaut mieux utiliser un algorithme en C par exemple. Rappelons tout d'abords le triangle de Pascal qui permet de calculer les coefficients du développement de (x+1)^n (x+1)^0 : 0 : 1 (x+1)^1 : 1 : 1 1 (x+1)^2 : 2 : 1 2 1 (x+1)^3 : 3 : 1 3 3 1 (x+1)^4 : 4 : 1 4 6 4 1 for (ligne = 1; ligne <= red; ligne++) { tab_coef[ligne] = 1; for (colonne = ligne-1; colonne > 0; colonne--) tab_coef[colonne] = tab_coef[colonne-1] + tab_coef[colonne]; fin pour; fin pour;Le calcul des coefficients du polynome générateur est largement inspiré de cet algorithme mais utilise en plus toutes les notions abordées précédemment, à savoir les valeurs du corps de Galois, l'addition et la multiplication dans ce même corps. Regardons le développement jusqu'à l'ordre 3 du produit des (x + αi)
0 : 1
tab_coef[c] = αligne-1.tab_coef[c-1] + tab_coef[c]; // colonne(i) = colonne(i-1).A^(ligne-1) xor colonne(i) // Note1 : index_of(vector) retourne la puissance de alpha. // exemple : index_of(6) retourne 4 // Note2 : pour effectuer la multiplication prendre la puissance de alpha // de colonne(i-1) puis appliquer la relation : // alpha^i.alpha^j = alpha(i+j)modulo(2^m) // Note3 : pour effectuer le xor : prendre index_of(valeur) afin de calculer // sur les valeurs décimales. // Le résultat obtenu sera sous forme décimale. (vector) // Nous trouvons par calcul et pour une valeur initiale b=0 puis b=1 : gin(0) = 59 pour b=0, 79 pour b=1 gin(1) = 36 pour b=0, 44 pour b=1 gin(2) = 50 pour b=0, 81 pour b=1 gin(3) = 98 pour b=0, 100 pour b=1 gin(4) = 229 pour b=0, 49 pour b=1 gin(5) = 41 pour b=0, 183 pour b=1 gin(6) = 65 pour b=0, 56 pour b=1 gin(7) = 163 pour b=0, 17 pour b=1 gin(8) = 8 pour b=0, 232 pour b=1 gin(9) = 30 pour b=0, 187 pour b=1 gin(10) = 209 pour b=0, 126 pour b=1 gin(11) = 68 pour b=0, 104 pour b=1 gin(12) = 189 pour b=0, 31 pour b=1 gin(13) = 104 pour b=0, 103 pour b=1 gin(14) = 13 pour b=0, 52 pour b=1 gin(15) = 59 pour b=0, 118 pour b=1
Partie A.5 - Encodeur Reed-Solomon. Le code RS utilisé pour la TNT permet de corriger 8 octets erronés par paquet de transport. Ce mécanisme ajoute donc 16 octets de redondance au paquet initial afin d'obtenir un mot de code (204,188,8) : (n,k,t). Ce mécanisme peut corriger jusqu'à 8 symboles, c'est un code adapté pour corriger les erreurs en rafale (burst) introduites par le canal de transmission (voies hertziennes terrestres). Le code (204,188,8) est une version raccourcie de (255,239,8) qu'il est possible d'utiliser en ajoutant 51 octets nuls avant les 188 d'information. En sortie de codeur, les octets nuls sont supprimés le code bloc étant ainsi ramené aux 204 symboles utiles.
Revenons à l'encodage Reed-solomon.
g(x) = (x - λb) + (x - λb+1) + ... + (x - λb+2t-1) p(x) = i(x) . x(n-k) + [i(x) . x(n-k)]. mod g(x) La partie gauche de l'équation signifie que l'on décale le symbole d'information vers les puissances de X les plus élevées de n-1 à n-k (203 à 16); ces k premiers coefficients sont donc les symboles d'information d'origine. Les n-k valeurs qui suivent constituent l'information de redondance. L'architecture d'un encodeur est représentée dans le diagramme suivant.
Figure 2 : Reed-Solomon Encoder block diagramm.
Code source vhdl de l'encodeur RS au format html.
Partie A.6 - Introduction au décodeur RS.. Le décodage, très demandeur en ressources, est basé sur l'algorithme Peterson-Gorenstein- Zierler qui utilise des calculs matriciels ; la procédure consiste à déterminer la localisation des erreurs (les puissances de X) dans le polynome reçu, ainsi que l'amplitude de l'erreur (le symbole qu'il faudrait ajouter au symbole reçu afin de retrouver le symbole encoder d'origine). Le polynome d'erreur e(x) s'écrit : e(x) = e_i1.x(i1) + e_i2.x(i2) + ... + e_iv.x(iv) où e_ik représente l'amplitude de la k ième erreur qui est à la position ik. Rappelons qu'un code BCH est un code à symboles binaire définis sur GF(2) dans ce cas l'erreur est toujours égale à 1, ce qui n'est pas le cas pour un code Reed-Solomon. La première étape consiste à évaluer le block reçu afin d'obtenir les valeurs de syndromes. La figure qui suit rappelle la formule du polynome générateur et introduit celle du syndrome ; la valeur entière b (qui vaut zéro dans le cas de la TnT ou de G709) doit être identique coté encodeur et décodeur. La partie droite présente le principe matériel de calcul des syndromes.
Figure 2 : Calcul du syndrome. Le syndrome consiste à l'évaluation de r(x), mot reçu, pour chaque zéro du code (α puissance i, racine du polynome générateur). le mot reçu r(x) correspond à la somme du mot transmis v(x) plus l'erreur e(x) apportée par le canal de transmission.
S1 = r(αb)
Partie A.7 - Liens & documentation.
Compiler un source avec gcc :
Programmes en C (new_rs_erasures.c)
Pour terminer cette première partie, les sources permettant de simuler l'encodeur ainsi que la vérification
par calcul du syndrome. Les heureux propriétaires de Core-generator (outil xilinx) pourront corréler les
résultats fournis par le core avec ceux du code proposé, les autres se contenteront du syndrome... Le fichier
(format zip) contient le testbench ainsi que les différents composants, une macro de commande ModelSim et
les signaux à visualiser ; pour l'utiliser, créer un projet avec les fichiers puis >Tools>Execute Macro/commande_tnt.do
Interprétation et analyse :
The art of error coding,
Pierre Csillag
Autres livres techniques sur les codes correcteurs d'erreurs.
BCH : Bose-Chaudhuri-Hockenghem.
Plan de la rubrique électronique.
Florent PORTELATINE mai 2005 Sceaux V1.0a
Révision --.
|