Chapitre 7 |
Codes représentatifs
L |
e chapitre 5 a en bonne partie couvert la matière portant sur les codes analytique. Le chapitre qui débute ici complète ces notions en les étendant aux codes dits représentatifs. Les codes représentatifs se distinguent des codes analytiques en cela qu’ils ne sont pas restreints aux objets numéraux. Les codes sont utilisés par les systèmes logiques pour véhiculer de l’information sous encodage binaire. Les codes représentatifs auxquels nous nous intéresserons dans ce chapitre sont principalement utilisés pour représenter des caractères alphanumériques.
Le Code ASCII (acronyme de Américan Standard Code for Information Interchange) est l’un des plus anciens et certainement le plus largement utilisé des codes représentatifs. Le tableau suivant énumère quelques caractères du code ASCII
Caractère |
Code |
Caractère |
Code |
Caractère |
Code |
Caractère |
Code |
0 1 2 3 4 5 6 7 8 9 A B C D E F G H |
0110000 0110001 0110010 0110011 0110100 0110101 0110110 0110111 0111000 0111001 1000001 1000010 1000011 1000100 1000101 1000110 1000111 1001000 |
I J K L M N O P Q R S T U V W X Y Z |
1001001 1001010 1001011 1001100 1001101 1001110 1001111 1010000 1010001 1010010 1010011 1010100 1010101 1010110 1010111 1011000 1011001 1011010 |
a b c d e f g h i j k l m n o p q r |
1100001 1100010 1100011 1100100 1100101 1100110 1100111 1101000 1101001 1101010 1101011 1101100 1101101 1101110 1101111 1110000 1110001 1110010 |
s t u v w x y z |
1110011 1110100 1110101 1110110 1110111 1111000 1111001 1111010 |
Le code ASCII présenté dans ce tableau a été initié par la compagnie américaine Bell pour représenter les caractères alphanumériques usuels de l’anglais. Cette version du code ASCII ne comportait que 7 bits par mot. Ce qui ne permettait de représenter que 27 = 128 mots possibles. Lorsque le code fut ouvert à d’autres langues, des versions standardisées et rendues internationales suivirent, aboutissant à une représentation sur 8 bits, permettant d’obtenir 28 = 256 mots possibles, permettant de représenter des caractères spéciaux tel que le ‘é’, ‘è’ du français. Néanmoins, avec le développement des technologies de l’information, des représentations plus évoluées ont vu le jour, dont le code Unicode, comportant 16 bits, pour un total de 65 536 mots possibles et permettent de représenter différents caractères des nombreux alphabets utilisés un peu partout dans le monde.
Le code ASCII s’est depuis plié au bonheur des artistes,
donnant naissance à ce qu’on appelle
le Art-ASCII. Ainsi, on dessine des choses simples du type :
(__) (oo) /-------\/ __ O / | || /o)\ /|\ * ||----|| \(o/ / \ ~~ ~~
Vache Yin/Yang Personne |
Le code BCD est un autre code représentatif très en usage. Il permet de représenter des nombres sous leur écriture décimale. L’acronyme BCD est pour Binary Coded Decimal, en français Décimal, Codé Binaire.
Il s’agit de coder les chiffres de 0 à 9 en binaire. Le code 8421 est le plus répandu. Le tableau suivant en résume la correspondance :
Chiffre Bits Chiffre Bits
0 0000 5 0101
1 0001 6 0110
2 0010 7 0111
3 0011 8 1000
4 0100 9 1001
Code BCD : 8421
On appelle ce code 8421 car les 4 bits pondèrent les nombres 8, 4, 2 et 1 respectivement. Ainsi, 0111 correspond à 7 puisque 7 = 0 x 8 + 1 x 4 + 1 x 2 + 1 x 1.
Cela permet d’écrire 123 : 0001 0010 0011.
D’autres codes BCD existent, certains fonctionnant selon le même principe de pondération, comme le code 2421 ou le code 5421, dont les tables suivent :
Chiffre Bits Chiffre Bits
0 0000 5 1011
1 0001 6 1100
2 0010 7 1101
3 0011 8 1110
4 0100 9 1111
Code BCD : 2421
Chiffre Bits Chiffre Bits
0 0000 5 1000
1 0001 6 1001
2 0010 7 1010
3 0011 8 1011
4 0100 9 1100
Code BCD : 5421
Il existe également des codes non basés sur la pondération, dont l’exemple le plus connu est certainement le code-barres. Pour l’instant, on retiendra du code BCD son but utilitaire, à savoir la représentation des chiffres 0 à 9 en code binaire. Le grand intérêt du système BCD pour l’électronicien est la possibilité de manipuler les chiffres en base dix pour différentes fins, notamment l’affichage, comme ce sera illustré dans les chapitres subséquents.
Comme nous aurons le temps de l’apprécier plus tard, un des problèmes importants des systèmes numériques tient dans la synchronisation des différents signaux numériques. Lorsque l’on conçoit un compteur, ce problème devient important car dans la représentation binaire des nombres entiers, il arrive souvent que plusieurs bits changent en même temps. Dans ce cas, il est possible que des nombres non désirés apparaissent dans le compte.
Considérons l’exemple suivant. Nous voulons concevoir un compteur trois bits, en faisant varier trois signaux, v0, v1, v2 :
Lorsque le compteur passe de 001 à 010, il doit modifier deux bits. Si il y a un problème de synchronisation entre les bits v1 et v0, le nombre 011 s’affiche pendant un court laps de temps, bien que ce ne soit pas le résultat recherché.
Pour remédier à ce problème il est possible d’utiliser le code de Gray, inventé aux Bell Labs par Frank Gray et breveté en 1953.
Le code de Gray encode les entiers de telle façon que le passage d’un nombre au suivant ne change qu’un seul bit à la fois, comme l’illustre le tableau suivant où les entiers ont été encodés sur 4 bits :
Décimal |
Binaire |
Gray |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
00000 00001 00010 00011 00100 00101 00110 00111 01000 01001 01010 01011 01100 01101 01110 01111 |
0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 0110 0111 0101 0100 |
Le code de gray règle le problème de compte que nous avons vu précédemment, comme l’illustre la figure suivante :
On construit le code de Gray en recopiant les bits de façon symétrique (effet miroir) et en procédant de façon itérative jusqu’au bit désiré.
0 1 |
|
|
||||||||
Itération 1 |
Itération 2 |
Itération 3 |
Le code de Gray est encore très utilisé, notamment dans les ordinateurs où le compteur de programme utilise le code de Gray pour minimiser sa consommation d’énergie. On le retrouve également dans certains systèmes de télécommunication pour la correction d’erreur. Mentionnons aussi que le code de Gray a été utilisé pour trouver une solution au problème des tours de Hanoi.
Les systèmes de communication numériques souffrent du bruit ambiant autant que leur pendant analogique. Le bruit est un signal parasitaire non désiré dont on ne peut pas prévoir le comportement. Très tôt, les ingénieurs ont été confrontés à ce problème et ont dû définir des outils leur permettant d’assurer l’intégrité des messages envoyés.
On part de la problématique générale suivante :
On dispose d’une source émettrice (l’émetteur) et d’un dispositif pour la réception (le récepteur). Pour transférer les données de l’émetteur au récepteur, on utilise un canal de communication. Ces trois éléments se retrouve très fréquemment dans les systèmes numériques modernes. Les exemples ne manquent pas. Citons à titre d’exemple (émetteur, canal, récepteur) : Souris d’ordinateur, fil, ordinateur ; télécommande, lien infrarouge, télévision ; modem, cable RJ45, ordinateur ; guichet automatique, ligne téléphonique, central de la banque ; etc….
Le bruit vient altérer l’information transmise. Cela signifie qu’il peut altérer les bits envoyés de telle sorte qu’un 0 devienne 1 et vice versa. Il est cependant possible, en utilisant un protocole approprié permettant de retrouver l’information même si elle a été modifiée par le bruit.
Pour bien comprendre la problématique, supposons que nous disposions d’un code utilisant deux bits d’information, et que ce code soit formé des mots : {00, 01, 10, 11}. Si l’émetteur envoie le mot 00, et que le récepteur obtient 01 (altération du bit le moins significatif), il est clair que le récepteur est incapable d’identifier l’information reçue après intervention du bruit car il serait dans l’incapacité de savoir si aucun bruit n’est venu altérer le message émis qui aurait été 01, ou que le bruit ait altéré un bit, auquel cas le message aurait tout autant pu être 00 que 11.
Dans l’exemple précédent, la difficulté rencontrée dans l’identification des mots reçus réside dans le fait que modifier un bit d’un mot du code revienne à générer un nouveau mot du même code. Supposons maintenant que nous disposions du code formé des mots : {0000, 0011, 1100, 1111}. Il est évident que dans ce cas, si l’émetteur envoie 0000, et que le bruit vient altérer un des bits de sorte que le récepteur reçoive 0100 par exemple, le récepteur est en mesure de constater que le mot reçu n’existe tout simplement pas dans le code, et pourrait demander une retransmission du message.
Afin de mieux manipuler la possibilité de corriger une erreur si elle survient, nous allons nous intéresser à une métrique qui va nous permettre de mesurer la capacité d’un système de communication numérique à s’immuniser au bruit : la distance de Hamming. La distance de Hamming, qui tient son nom d’un informaticien célèbre qui a participé au projet Manhattan, est la mesure entre deux mots dans un code. Pour cela, elle considère le nombre de bits qui ont changé de valeur entre le premier mot et le second. Reprenons l’exemple du paragraphe précédent. Les mots 0000 et 0011 ont une distance de Hamming de 2, car les deux derniers bits ont changé quand les mots passaient de 0000 à 0011. Le code de Gray par exemple offre une distance de Hamming de 1 entre deux mots consécutifs.
Dans un code, on parlera de distance minimale, que nous noterons M. La distance de Hamming minimale d’un code est la plus petite distance entre deux mots différents du code. Pour les deux exemples précédents, on aura :
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Distance minimale : 1 |
Distance minimale : 2 |
Grâce aux développements qui vont suivre, nous allons être en mesure d’évaluer la capacité d’un système de communication à détecter une erreur, et même de pouvoir la corriger. À cet effet, la théorie de la détection d’erreur stipule que :
M – 1 = D + C
où :
M est la distance minimale d’un code ;
D est le nombre de bits pouvant être détecté ;
C est le nombre de bits pouvant être corrigés, sachant que C ≤ D, c’est-à-dire que toute erreur corrigée doit nécessairement être détectée au préalable.
Considérons ici l’exemple du code formé des mots {0000, 0011, 1100, 1111}, dont la distance minimale M est 2. Sachant que M=2, on trouve M – 1 = 1, ce qui signifie que le mieux qu’on puisse faire est de poser D=1 et C = 0, puisque C ≤ D. Ce résultat signifie qu’il est possible de détecter une erreur sur un bit lorsqu’elle survient car D = 1 (si l’émetteur envoie 0000, et qu’à la réception, le mot apparaisse comme étant 0100, on sait qu’il y a erreur), mais qu’il est alors incapable de corriger l’erreur détecter car C = 0 (lorsque le récepteur reçoit 0100, il est en mesure de savoir que le mot n’appartient pas au code, mais il ne sait pas pour autant si le mot envoyé était 1100 ou 0000).
On comprend de ce qui précède qu’il est nécessaire de garantir M = 3 pour qu’un système de communication soit en mesure de détecter une erreur sur 1 bit, et de la corriger :
M = 3 => M – 1 = 2
=> C+D = 2
=> (D = 2 et C = 0 ) ou (D = 1 et C = 1)
Ce qui précède signifie : si il y a deux bits erronés, le système va détecter l’erreur, mais ne sera pas en mesure de corriger l’erreur. Cependant, si il y a un seul bit erroné, le système détectera l’erreur et sera en mesure de la corriger.
La difficulté réside dans le fait d’être en mesure de trouver un code qui permette d’obtenir une distance minimale M valant 3. Dans ce qui suit, nous allons montrer des méthodes systématiques permettant d’atteindre ce niveau de sécurité.
Nous allons nous outiller d’une autre métrique qui réfère au coût de l’information d’un code. Supposons que nous utilisions un code qui comporte n mots, et qu’il soit possible de représenter N mots différents en utilisant l’écriture utilisée par ce code, la quantité d’information[1], noté I, est égale à I = log2(N/n).
Plus cette valeur s’approche de 0, et plus le codage est optimal. Supposons que l’on veuille représenter de façon binaire les 26 lettres de l’alphabet. Pour ce faire, on utilise 5 bits :
00000 |
A |
01010 |
K |
10100 |
U |
Ici : n = 26, N = 25 = 32 :
I = log2(N/n)
= log2(32/26)
= log2(1,230) = 0,2988
I ≈ 0,3
Le premier type d’encodage est l’encodage avec redondance. Nous avions vu à la section 7.2.1 que répéter chaque bit deux fois permettait d’avoir M = 2. Il est possible de montrer que si l’on répète chaque bit n fois, on aura M = n. Ainsi, pour obtenir un code avec M = 3, il suffit de répéter chaque bit du code 3 fois. Par exemple, pour un code comportant {00, 01, 10, 11}, on peut le modifier de sorte à ce que les mots du codes correspondent respectivement à {000000, 000111, 111000, 111111}. Dans ce cas là, on trouve que la distance minimale M est 3.
|
|||||||||||||||||||||||||
Distance minimale : M = 3 |
Il est intéressant de connaître le coût d’un tel encodage. Dans notre cas, la quantité d’information I vaut : I = log2(26/22) = log2(24) = 4. Notons que cette valeur est égale au nombre de bits ajoutés. Cela est dû au fait que le code de départ possédait une quantité d’information nulle que nous avons alourdie de quatre bits supplémentaire.
Il est possible d’ajouter un bit de parité au mot d’un code avant de le transmettre. Supposons que nous disposions de n bits, bi, en ajoute un bit p pour la parité :
bn-1bn-2…b2b1b0 => bn-1bn-2…b2b1b0p
Le bit p est tel que :
· p=1 si le nombre de bits 1 est pair (le plus fréquemment utilisé)
· p=1 si le nombre de bits 0 est pair
· p=1 si le nombre de bits 1 est impair
· p=1 si le nombre de bits 0 est impair
Nous utiliserons dans la suite de l’ouvrage le premier de ceux-là. En ajoutant un bit de parité, on ajoute 1 à M, la distance de Hamming minimale du code. Prenons l’exemple du code {00, 01, 10, 11}, nous aurons le code {000, 011, 101, 111}. Et comme prévu, on trouve M :
|
|||||||||||||||||||||||||
Distance minimale : M = 2 |
Dans ce cas, un système de communication sera en mesure de détecter une erreur sur un bit, mais ne sera pas en mesure de la corriger. Si nous reprenons la mesure logarithmique établie plus tôt, nous aurons dans ce cas : log2(24/23) = log2(2) = 1. Cette valeur ne change pas quelle que soit le nombre de bits transmis.
La parité orthogonale est une technique permettant
d’obtenir une distance de Hamming minimal M = 3. Pour ce faire, on considère un
code de longueur n x m bits organisés en n groupes de m
bits. On ajoute aux
m x n bits, m+n+1 bits de parité. Pour ce faire, on
utilise une matrice de parité orthogonale.
Afin de bien comprendre la technique, considérons l’exemple suivant, où nous prenons n = 3 m = 4
0001 1101 0100 |
1 1 1 |
1000 |
1 |
Les bits à envoyer sont ici : 000111010100. Sur chaque ligne, on calcule le bit de parité. On calcule ensuite le bit de parité sur chaque colonne, et finalement, en ligne ou en colonne, le bit de parité des bits de parité obtenus (que ce soit en ligne ou en colonne, la valeur sera identique).
On trouve toujours I = m + n + 1 et M = 3. L’avantage de la méthode tient surtout dans la facilité avec laquelle le système est en mesure de corriger l’erreur sur un bit si jamais elle survient. Considérons à nouveau l’exemple précédent.
Nous voulons envoyer 000111010100 partagé sur les mots 0001, 1101 et 0100. Pour ce faire, on utilise la parité orthogonale et envoyons 4 (m+1) mots de 5 bits (n+1) : 00011, 11011, 01001 et 10001. Supposons maintenant qu’un des bits de cette séquence soit affecté par le bruit du canal de communication, et qu’à la réception, nous obtenions 00111, 11011, 01001 et 10001 au lieu de 00011, 11011, 01001 et 10001.
Le récepteur reconstruit la matrice avec les bits reçus :
0011 1101 0100 |
1 1 1 |
1000 |
1 |
Que ce soit sur la troisième colonne ou la première ligne, on constate que les bits de parité ne correspondent pas au résultat attendu. Il y a donc erreur (détection d’erreur). Pour corriger l’erreur, il faut retrouver le bit qui se trouve à l’intersection de la ligne et la colonne où la parité n’est pas respectée :
0011 1101 0100 |
1 1 1 |
1000 |
1 |
Il suffit alors d’inverser la valeur de ce bit :
0001 1101 0100 |
1 1 1 |
1000 |
1 |
Ce qui permet de retrouver le message transmis : 0001, 1101 et 0100 → 000111010100.
Hamming a proposé une méthode systématique permettant de créer un code où M = 3. Supposons un code de longueur fixe n, Hamming propose d’ajouter p bits de parité, de sorte à respecter l’inégalité suivante :
n + p + 1 ≤ 2p
Nous obtenons la table (incomplète) suivante :
n |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
… |
p |
2 |
3 |
3 |
3 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
5 |
5 |
5 |
5 |
5 |
… |
Les codes sont formés de la façon suivante :
1. Pour chaque mot du code de longueur n, on forme un nouveau mot de longueur n+p.
2. Chaque bit de parité porte un index i qui début par 1 (p1, p2, p3, p4…)
3. Les bits du nouveau mot (de longueur n+p) sont indexés selon j et on débute par 1 (b1, b2, b3, b4…)
4. Chaque
bit de parité (d’index i) prend la position de bit bj dont
l’index j est une puissance de 2
(1, 2, 4, 8…) de sorte que j = 2 i – 1
5. Les bits du mot de départ sont placés dans les espaces libres restant
6. Chaque bit de parité d’index i positionné au bit de position j ( j = 2 i – 1 ) mesure la parité d’une suite de bits qui débutent à l’index j, de telle sorte que l’on prend alternativement i bits, une fois sur deux.
Le cas particulier qui nous concerne ici est celui où n = 4. Les règles précédentes deviennent :
1. Pour chaque mot du code de longueur 4, on forme un nouveau mot de longueur 7.
2. Chaque bit de parité porte un index i qui début par 1 (p1, p2, p3)
3. Les bits du nouveau mot sont indexés selon j et on débute par j=1 (b1, b2, b3, b4, b5, b6, b7)
4. Chaque
bit de parité (d’index i) prend la position de bit dont l’index j
est une puissance de 2
(1, 2, 4) de sorte que j = 2 i – 1
5. Les bits du mot de départ sont placés dans les espaces libres restant d’index 3, 5, 6, 7
6. Chaque bit de parité d’index i positionné au bit de position j ( j = 2 i – 1 ) mesure la parité d’une suite de bits qui débutent à l’index j, de telle sorte que l’on prend i bits, puis saute i bits, puis prend i bits et ainsi de suite… Ce qui donne
p1 = parité(b1, b3, b5, b7) = parité(b3, b5, b7)
p2 = parité(b2, b3, b6, b7) = parité(b3, b6, b7)
p3 = parité(b4, b5, b6, b7) = parité(b5, b6, b7)
Regardons l’exemples suivant. On veut envoyer le mot 0110 :
1. On forme un nouveau mot de longueur 7 :
0 |
0 |
0 |
0 |
0 |
0 |
0 |
2. Chaque bit de parité porte un index i qui début par 1 (p1, p2, p3)
3. Les bits du nouveau mot sont indexés selon j et on débute par 1 (b1, b2, b3, b4, b5, b6, b7)
0 |
0 |
0 |
0 |
0 |
0 |
0 |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
4. Chaque
bit de parité (d’index i) prend la position de bit dont l’index j
est une puissance de 2
(1, 2, 4) de sorte que j = 2 i – 1
0 |
0 |
0 |
p3 |
0 |
p2 |
p1 |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
5. Les bits du mot de départ sont placés dans les espaces libres restant d’index 3, 5, 6, 7
0 |
1 |
1 |
p3 |
0 |
p2 |
p1 |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
6. Chaque bit de parité d’index i positionné au bit de position j ( j = 2 i – 1 ) mesure la parité d’une suite de bits qui débutent à l’index j, de telle sorte que l’on prend i bits, puis saute i bits, puis prend i bits et ainsi de suite… Ce qui donne :
p1 = parité(b1, b3, b5, b7) = parité(b3, b5, b7) = parité(0, 1, 0) = 1
p2 = parité(b2, b3, b6, b7) = parité(b3, b6, b7) = parité(0, 1, 0) = 1
p3 = parité(b4, b5, b6, b7) = parité(b5, b6, b7) = parité(1, 1, 0) = 0
0 |
1 |
1 |
0 |
0 |
1 |
1 |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
Le code de Hamming permet d’obtenir M = 3 de sorte à pouvoir détecter et corriger une erreur sur un bit. Pour ce faire, un nombre binaire C de longueur p est créé. Dans notre cas, ce nombre est formé des bits
c1 = parité(b1, b3, b5, b7)
c2 = parité(b2, b3, b6, b7)
c3 = parité(b4, b5, b6, b7)
Le nombre C = c3c2c1 donne l’index j du bit qui a été altéré. Si C = 0, on présume qu’aucun bit n’a été modifié. Si C est différent de 0, on inverse le bit d’index j = C.
Reprenons l’exemple précédant. Nous voulons envoyer le mot 0110. Pour cela, on forme le mot 0110011. Le récepteur reçoit 0100011. Le récepteur forme le nombre C en calculant la valeur des bits :
c1 = parité(b1, b3, b5, b7) = parité(1, 0, 0, 0) =1
c2 = parité(b2, b3, b6, b7) = parité(1, 0, 1, 0) =0
c3 = parité(b4, b5, b6, b7) = parité(0, 0, 1, 0) =1
C = 101(2) = 5(10). On inverse b5 et on trouve : 0110011 qui est le mot envoyé par l’émetteur.
[1] On appelle I quantité d’information car elle quantifie l’information supplémentaire (bits) utilisée pour porter l’information globale nécessaire. Dans l’exemple des 26 lettres de l’alphabet, la valeur est proche de 0 (mais non nulle) car des certains mots du code (6 au total) existent sans qu’il y ait de symbole qui leur soit associé.