CODIFICA A BLOCCHI E CODICI LINEARI
Abbiamo visto come nella codifica ciascuna delle 2k k-ple di informazione viene
trasformata in una delle 2n n-ple (nk), dove k=n corrisponde all’assenza di codifica.
Definiamo quindi in questo modo la codifica a blocchi:
Ad ogni blocco di k bit di informazione si associa una parola di codice di lunghezza n.
Gli M blocchi di informazione saranno M=2k. Le possibili parole di codice saranno 2n>2k.
Scegliere un codice significa selezionare 2k tra le 2n possibili parole codice. La scelta va
eseguita in modo che le parole codice siano quanto più differenti tra di lor,o cioè quanto
più i segnali si siano distanti tra di loro, utilizzando come misura la distanza di Hamming
dH.
All’aumentare di k il numero delle parole di codice M=2k cresce esponenzialmente, e
così di conseguenza anche la complessità del codificatore e del decodificatore.
E’ necessario allora imporre al codice a blocchi un’ulteriore proprietà al fine di ottenere
una complessità accettabile. Si vedrà che la proprietà di linearità porterà a diminuire la
complessità algoritmica della codecodifica.
Supponiamo infatti di avere un codice (n,k), con R=k/n.
Prendiamo come indice di complessità dell’algoritmo di decodifica il numero di binit da
memorizzare per implementare l’algoritmo: in generale è richiesta la memorizzazione della
tabella relativa alla corrispondenza biunivoca fra parole di sorgente e parole di codice :
2k righe per k+n colonne, ossia n(R+1)2nR celle di memoria binarie.
La capacità di memoria necessaria cresce quindi esponenzialmente con n, e diviene ben
presto impraticabile, anche per n intorno al centinaio.
D’altra parte, se si vuole arrivare vicini al limite indicato dal secondo teorema di Shannon è
necessario arrivare a valori elevati di n.
Occorre quindi trovare classi di codici che abbiano una struttura tale da permettere
operazioni
di
codecodifica
con
algoritmi
la
cui
complessità
che
non
cresca
esponenzialmente con n.
Sarebbe opportuno che la parola di codice c da associare alla parola di ingresso a,
anzichè riferirsi ad una tabella, fosse calcolabile come c=F(a), con F funzione vettoriale
ad n componenti della variabile a a k componenti.
Questoo richiede di definire un particolare tipo di algebra non ordinaria, in cui ci riferisce
ad un insieme finito A di valori che rappresentano le cifre dell’alfabeto impiegato.
Questa algebra viene definita su un Campo di Galois contenente A elementi, ed indicata
come GF(A).
In un campo GF(A) risultano definite due operazioni, somma e prodotto. Queste operano
su due operandi costituiti da elementi del campo, e forniscono un risultato che è ancora un
elemento del campo.
Consideriamo il campo GF(2), particolarmente semplice perché i due elementi che lo
compongono possono essere indicati con 0 e 1, e le operzioni di somma e prodotto si
identificano con somma modulo 2 (operazione logica XOR o OR esclusivo) e prodotto
algebrico ordinario.
L'operatore XOR, detto anche EX-OR, OR esclusivo o somma modulo 2, restituisce 1 se e
solo se la somma degli operandi uguali ad 1 è dispari, mentre restituisce 0 in tutti gli altri
casi.
A
B A XOR B
0
0
0
0
1
1
1
0
1
1
1
0
Definiamo ora la funzione F citata.
Il modo più semplice è quello di considerarla lineare, ottenendo così l’importante classe
dei codici lineari.
Ciascuno dei simboli della parola di codice c risulta una combinazione lineare dei simboli
della parola di ingresso a, con opportuni coefficienti che definiscono il codice. Anche i
coefficienti devono essere elementi del campo GF(2).
Una generica funzione vettoriale lineare c=F(a) può esprimersi utilizzando la notazione
matriciale
c= a G
dove c ed a sono vettori riga e G una matrice di k righe ed n colonne, costituita da elementi
appartenenti a GF(2). La matrice G è detta matrice generatrice del codice.
Il numero di elementi di memoria necessari nel codificatore si riduce in questo caso al
numero di elementi della matrice G , che ha il valore kn=n2R e quindi cresce con n2 .
Questa è una significativa riduzione di complessità: ad esempio, per n=100 e k=80, la
matrice G è costituita da 8000 elementi, mentre la tabella di corrispondenza biunivoca
avrebbe circa 1030 elementi.
La decodifica prevede l’impiego di una matrice analoga a G, ma richiede una crescita
esponenziale della complessità con esponente (1-R)n , anziché Rn, permettendo di
utilizzare codici con elevato valore di n purchè R abbia valori elevati, ossia prossimi
all’unità.
CODIFICA E DECODIFICA DI CODICI LINEARI BINARI
Prendiamo in considerazione codici binari (cioè definiti in GF(2)). Indichiamo con dm la
distanza del codice, e indichiamo con “peso” di una parola il numero di cifre “1” che vi
appaiono.
Si consideri un ccodice lineare binario (n,k) definito dalla matrice generatrice i cui elementi
gij sono elementi binari (0,1):
 g 00
g
 10
G =  ...

g k -10
g 01
g 11
...
g k -11
g 0n -1 
... g 1n 1 
...
... 

... g k -1n -1 
...
Per un codice lineare generico valgono le seguenti proprietà:
Proprietà 1:
In un codice lineare esiste sempre la parola di codice nulla c=0
(0 è un vettore riga con componenti tutte nulle)
Dim.: Ponendo a=0 si ottiene c=aG=0 per ogni G.
Proprietà 2:
Le righe della matrice G sono parole di codice.
Dim.: Quando a sia formata da n-1 “0” e un solo “1” in posizione i-esima, il prodotto c=aG
risulta uguale alla i-esima riga di G.
Proprietà 3:
La somma di due parola di codice c’ e c’’ è ancora una parola dello stesso codice.
Proprietà 4:
La distanza dm di un codice lineare è uguale al peso pm della parola di codice che ha peso
minimo, escludendo quella di peso nullo.
CODICI SISTEMATICI
I codici sistematici sono un’important classe di codici lineari definiti dalla proprietà di avere
nella parola codificata i primi k binit identicamente uguali ai k binit della corrispondente
parola di ingresso:
[c0,c1,…,ck-1]=[ a0,a1,…,ak-1]=a
Quindi le prime k colonne della matrice G costituiscono una matrice identità Ik, e le ultime
n-k colonne, che formano una matrice P di dimensioni k(n-k), definiscono quindi
completamente il codice:
1
0
G = [Ik P] = 
...

0
g1k
g 2k
...
g1k-1
g 2k1
...
0 ... 1 g k -1k
g k -1k 1
0 ... 0
1 ... 0
... ... ...
g1n-1 
g 2 n 1 
... 

... g k -1n-1 
...
...
...
Questa classe di codici è importante perché si può dimostrare che dato un qualsiasi
codice (n,k) non sistematico, è possibile trovare un codice sistematico con uguali valori di
n e k che ha le stesse prestazioni del codice dato, rispetto alla capacità di correzione di
errori.
Consideriamo ora il problema della decodifica nel caso in cui si voglia effettuare una
correzione d’errore.
Supponiamo di voler realizzare la decodifica in accordo al criterio della massima
verosimiglianza (Maximum Likelihood Decision, MLD), ossia tale per cui ricevuta una
parola r si ipotizza come trasmessa la parola c* per la quale fra tutte le parole di codice è
massima la probabilità di transizione P(r|c*) .
Allora supponiamo che sia stata ricevuta una particolare parola r : la probabilità P(r|c) che
r sia stata ottenuta per effetto della trasmissione di una parola di codice c equivale alla
probabilità che, nella trasmissione di n simboli, si verifichino e errori, disposti nelle
posizioni in cui r differisce da c.
Poniamo come regola di decisione la seguente regola:
Ricevuta la parola r, ipotizzare come trasmessa quella parola di codice c* che ha la
distanza minima da r , dove indichiamo come distanza minima il parametro dm (0 dm n) .
La decodifica avviene in due passi successivi:
1. determinazione della parola di codice
ĉ che ha distanza minima dalla parola
ricevuta r
2. determinazione della parola di informazione
â associata a ĉ nella corrispondenza
biunivoca che definisce il codice.
3. In un codice lineare sistematico questo passo 2 è banale perché consiste nel
prelevare i primi k binit della parola
ĉ .
Per definire il primo passo occorre definire la matrice H (matrice di controllo o check
matrix) di dimensioni n(n-k) ed espressa come
 P 
H= 

 I n k 
(9.0)
dove In-k è la matrice identità di dimensioni (n-k).
La matrice H viene impiegata nella decodifica ma permette anche di acquisire informazioni
sulla struttura del codice. Infatti si consideri il prodotto
s=xH
(9.1)
dove x è una sequenza arbitraria di n binit. Il risultato del prodotto è un vettore riga s con
n-k componenti binarie, detto sindrome.
Si vede subito che s=0 se e soltanto che x coincide con una parola di codice c, ossia
xH=0
(9.2)
costituisce condizione necessaria e sufficiente affinchè x sia parola di codice.
Questa condizione è utile per dedurre la forma della matrice H per costruire un codice di
assegnata distanza dm.
Vale infatti la
Proprietà 5:
La distanza dm di un codice lineare avente matrice di controllo H è uguale al numero
minimo di righe di H che, scelte in modo arbitrario e sommate simbolo a simbolo, diano
luogo ad una sequenza di n-k binit costituita da tutti 0.
La dimostrazione segue dalla (9.2) e dalla Proprietà 4.
In particolare, sempre dalla Proprietà 4 discende che se una generica riga di H è costituita
da tutti 0, si ha chiaramente dm=1: condizione quindi da evitare per evitare che il codice sia
inutile.
Se nessuna riga di H è nulla, ma due righe sono uguali fra loro, allora la somma delle due
righe è nulla, e quindi dm=2.
Se le righe di H sono tutte diverse e non nulle allora occorrono almeno tre righe affinchè la
loro somma sia nulla, e si ha dm  3.
Dunque per avere un codice con distanza minima fra parole non inferiore a 3 si riesce ad
avere una semplice scelta della matrice P : infatti poiché le ultime k righe della matrice H
sono tutte e sole le sequenze di k binit contenenti un solo 1, si potrà avere dm  3 soltanto
se le righe di P sono tutte diverse e ciascuna contiene almeno due 1.
Nel caso di questi codici lineari la decodifica si effettua osservando la parola r ricevuta
all’uscita dal canale e calcolando la sindrome s = r H.
Se non si sono verificati errori di trasmissione la sindrome è nulla, in quanto r coincide con
la parola di codice trasmessa. La rilevazione d’errore si effettua quindi verificando se la
sindrome è uguale o diversa da zero.
Tuttavia s = 0 non garantisce la certezza di trasmissione corretta, perché può verificarsi un
errore che trasformi una parola in un’altra di sindrome nulla.
Se chiamiamo e la configurazione d’errore, si ha
s=rH=(c+e)H=cH+eH=eH
ossia la sindrome è funzione solo della configurazione d’errore e contenente un numero e
di simboli errati.
Il decodificatore determinerà una stima ê della configurazione d’errore in base al valore di
s calcolato dalla (9.1).
Si calcolerà allora
ĉ come differenza (in GF(2)) fra la configurazione d’errore ê e la parola
ricevuta r:
ĉ = r + ê .
Ora, la parola
ĉ H=( r +
ĉ è una parola di codice, infatti
ê )H = rH + ê H = s + s = 0 .
Ma se scegliamo fra le 2k configurazioni d’errore possibili (cioè fra quelle che possono
aver dato luogo alla sindrome s) quella di peso minimo, ĉ risulta anche la parola di codice
che ha distanza minima da r. Questo realizza una decisione a massima verosimiglianza
come definito più sopra.
Per quanto riguarda la complessità della decodifica, il numero di elementi binari di H è n(nk)=n2(1-R) , quindi per R costante la complessità cresce come n2, come per G.
Ma nel decodificatore dobbiamo anche memorizzare la tabella che deinisce la
corrispondenza biunivoca fra le sindromi e le configurazioni di errore a peso minimo:
tabella che ha 2n-k righe (numero delle sindromi distinte) per 2n-k colonne (somma della
lunghezza della sindrome e della configurazione d’errore). Possiede quindi n(2-R)2n(1-R)
elementi binari. La tabella cresce quindi, come si era detto in modo esponenziale ma con
esponente (1-R)n.
I CODICI DI HAMMING: CLASSE DI CORRETTORI D’ERRORE SINGOLO.
I vincoli cui deve soddisfare la matrice H per garantire una distanza del codice dm3
permettono di definire una classe di codici sistematici con distanza dm=3 .
Assegnando infatti in modo arbitrario il valore della differenza
n-k
, è possibile
determinare dalla (9.0) una matrice H in modo che contenga tutte e sole le 2n-k-1
combinazioni distinte (esclusa quella formata da tutti 0) formate da n-k simboli, ordinate in
modo arbitrario salvo che quelle che contengono un solo 1 che devono far parte della
matrice In-k.
Una volta assegnata in questo modo H, risulta assegnata la matrice P e quindi il relativo
codice sistematico. Un codice di questo tipo ha distanza dm=3 per le ragioni già esposte e
soddisfa la relazione
n=2n-k-1.
Per ogni valore n-k>1 esisterà un insieme di codici (di prestazioni equivalenti) con dm=3,
ottenibili da tutte le permutazioni delle prime k righe di H, determinati come sopra. La
classe di codici così ottenuta è detta di codici di Hamming.
Essi hanno la proprietà, facilmente verificabile costruendo le tabelle di decodifica, di
correggere tutte e sole le configurazioni di un solo errore. Infatti queste sono in numero di
n e risultano biunivocamente associate alle 2n-k-1 sindromi non nulle.
I codici aventi distanza dm=2t+1 in grado di correggere tutte e sole le configurazioni di non
più di t errori (t1) vengono detti codici perfetti.
Infatti si può dimostrare che un codice avente distanza d m=2t+1 che corregga non solo
tutte le configurazioni con più di t errori ma anche quelle con più di t errori non contribuisce
significativamente alla riduzione della probabilità di decodifica errata rispetto ad un
codeice perfetto che corregga solo quelle con al più t errori.
PROPRIETA’ DEL CODICE DI HAMMING
Il codice di Hamming (1950) è un particolare codice a correzione d’errore che:
•
Consente di correggere 1 singolo errore
•
Ha un numero di bit di controllo pari al limite teorico inferiore (m+1≤2r-r)
•
Funziona con qualunque dimensione del messaggio m
•
I bit della parola di codice vengono numerati da sinistra verso destra cominciando
con l’indice 1
•
I bit di controllo sono quelli aventi come indice una potenza di due (1, 2, 4,8, 16, ... )
•
I bit del messaggio sono tutti gli altri bit della parola di codice, nell’ordine il bit di
controllo con indice 2k è il bit di parità dei bit del messaggio i cui indici hanno il
termine 2k nella loro scomposizione in somma di potenze di due
•
In ricezione, ciascun bit di controllo viene ricalcolato:
–
Se tutti i valori dei bit di controllo sono corretti, la parola di codice viene
accettata
–
Se alcuni bit di controllo hanno valori non corretti, l’indice del bit in cui si è
verificato l’errore è dato dalla somma degli indici dei bit di controllo con
valore sbagliato.