Correção de Erros I: Simulador de Códigos Reed-Solomon
Embora sejam famosos por sua eficácia na correção de erros de símbolos, com aplicações em diversas áreas
da engenharia, os códigos de Reed-Solomon são pouco conhecidos em profundidade, o que dificulta a sua
implementação prática. Visando a esclarecer sua lógica e os mecanismos internos de codificação e
decodificação, esta série de tutoriais tem como objetivo apresentar o desenvolvimento de um simulador
genérico para códigos de Reed-Solomon.
Os tutoriais foram preparados a partir do trabalho de conclusão de curso “Desenvolvimento de um
Simulador de Codificação-Decodificação Reed-Solomon”, elaborado pelos autores, e apresentado à
Coordenação de Pós-graduação Lato Sensu do Inatel como requisito parcial para a obtenção do Certificado
de Conclusão do Curso de Engenharia de Sistemas de TV Digital e IPTV. Foi orientador do trabalho o Prof.
Dr. Geraldo Gil R. Gomes.
Este tutorial parte I apresenta os fundamentos teóricos dos códigos Reed-Solomon, detalhando suas
características, aspectos teóricos dos campos finitos e a codificação e decodificação desses códigos.
Daniel Cursi Junior
Engenheiro Eletroeletrônico pela Fundação Educacional de Barretos (SP, 1987), também é graduado em
Administração de Empresas com ênfase mercadológica pelo IMESB-VC de Bebedouro (SP, 1998),
pós-graduado em Administração de Empresas (MBA) pela Fundace/USP de Ribeirão Preto e pós-graduado
em Televisão Digital pelo Inatel de Santa Rita do Sapucai (MG).
Desde 1993 é sócio de uma empresa do Setor de Telecomunicações, prestando serviços de consultoria e
manutenção de sistemas de retransmissão de televisão aberta.
Email: [email protected]
1
Júlio Tanomaru
Engenheiro Eletrônico pelo Instituto Tecnológico de Aeronáutica (ITA, 1986), completou o mestrado como
bolsista do governo japonês na Universidade de Tokushima (Japão, 1992). Com pesquisas centradas em
aplicações de Inteligência Computacional em Engenharia, obteve o título de Doutor em Engenharia na
mesma universidade em 1996.
Atuou como Professor Auxiliar na Universidade de Tokushima (Japão). Após deixar a universidade, atuou
como Gerente de Projetos de software na Fujitsu Tokushima Systems Engineering.
Atualmente é Professor no Centro Universitário Unilins, onde leciona diversas disciplinas relacionadas à
Engenharia de Computação e Eletrônica.
Email: [email protected]
Categorias: Telefonia Celular, TV e Rádio
Nível: Introdutório
Enfoque: Técnico
Duração: 15 minutos
Publicado em: 22/08/2010
2
Correção de Erros I: Introdução
Motivação
Isoladamente ou em conjunto com outras formas de codificação, os códigos de Reed-Solomon estão
certamente entre os códigos corretores de erros com maior número de aplicações práticas. Embora muito
conhecidos pelo nome e por suas principais características, poucos são os que compreendem seu
funcionamento interno a ponto de poder implementá-los desde o início. Isso se deve a vários fatores,
incluindo: o entendimento de sua lógica demanda conhecimentos de álgebra de conjuntos finitos; há falta de
material de referência que explique como implementar decodificadores práticos; a maior parte dos livros
mostra somente exemplos simples, que podem ser resolvidos à mão com uso de álgebra, e não entra em
detalhes sobre como fazer implementações práticas em software ou hardware.
O desejo de entender a fundo o funcionamento dos códigos de Reed-Solomon constitui a principal
motivação deste trabalho. Além de permitir sua real utilização prática, esse entendimento profundo
possibilita a otimização e melhoria dos códigos, comparação de algoritmos de decodificação, e até mesmo a
implementação em hardware utilizando tecnologias de hardware reconfigurável como os FPGA (Field
Programmable Gate Arrays).
Objetivo
Este trabalho tem o objetivo prático de implementar um simulador em software de códigos de
Reed-Solomon, facilitando o entendimento dessa importante categoria de códigos. Para isso, os
procedimentos de codificação e decodificação são estudados em detalhe e é desenvolvida uma biblioteca de
classes na linguagem de programação Java. O simulador consiste numa aplicação Java com interface gráfica
rica e intuitiva, permitindo simulações de códigos Reed-Solomon com grande variedade de parâmetros.
A biblioteca de classes é totalmente original, desenvolvida a partir do zero, e é disponibilizada gratuitamente
a interessados. As classes e seus métodos foram escritos de modo a facilitar sua compreensão e utilização,
sem grande ênfase à eficiência de execução.
Tutoriais
Este tutorial parte I apresenta os fundamentos teóricos dos códigos Reed-Solomon, detalhando suas
características, aspectos teóricos dos campos finitos e a codificação e decodificação desses códigos.
O tutorial parte II apresentará inicialmente a biblioteca desenvolvida em linguagem de programação Java
contendo as classes para realização de álgebra de Campos de Galois, e a seguir apresentará o simulador
propriamente dito e as conclusões do trabalho realizado.
3
Correção de Erros I: Fundamentos
Fundamentos dos Códigos Reed-Solomon
Num trabalho publicado em 1960, Irving Reed e Gus Solomon [9] propuseram uma classe de códigos
corretores de erros que hoje encontram aplicações das mais variadas, tais como tocadores de CDs e
codificadores de televisão digital. Esses códigos, largamente conhecidos como Códigos de Reed- Solomon
(códigos R-S), são códigos cíclicos e não binários, onde cada símbolo é formado por uma sequência de m
bits, onde m > 2.
Os códigos R-S são normalmente denotados como R-S (n, k), onde n indica o número total de símbolos num
bloco codificado e k é o número de símbolos de dados (mensagem original) do bloco. Dado o número de bits
por símbolo, m, existem códigos R-S para todos os valores n e k que obedeçam à relação:
0 < k < n < 2m + 2
(1)
Nos códigos R-S mais comuns:
(n, k) = (2m – 1,2m – 1 – 2t)
(2)
Onde t dá a capacidade de correção de erros de símbolo do código.
Nota: O padrão brasileiro de televisão digital emprega símbolos de m = 8 bits, n = 204 e k = 188 e, portanto,
tem capacidade para correção de t = 8 símbolos.
Características
Apresentam-se a seguir as características dos código Reed-Solomon.
Distância Mínima
Para um dado número de símbolos de entrada e saída do decodificador, os códigos R-S resultam na maior
distância mínima possível para qualquer código linear [10]. Esses códigos são capazes de corrigir t ou menos
erros de símbolo, onde:
t = [(n – k) / 2]
(3)
O operador [x] indica o maior inteiro que não excede x, ou seja, o número de símbolos que o decodificador é
capaz de corrigir é metade do número de símbolos de paridade que o codificador insere.
Conforme já exposto, os códigos R-S são não-binários e utilizam símbolos de m bits cada.
Num código binário (n, k), de um total de 2n n-tuples possíveis, 2k n-tuples são palavras-código válidas.
Essa fração é reduzida significativamente no caso de códigos R-S, o que possibilita maiores distâncias
mínimas. Por exemplo, considerando (n, k) = (255, 235), no caso binário a fração das n-tuplas que são
palavras-código válidas é de 2-20; no caso não-binário, considerando m = 8 bits por símbolo, essa fração cai
para 2km / 2nm = 21880 / 22040 = 2-160.
4
Robustez a Erros em Rajada
Os códigos R-S são particularmente eficientes para correção de erros em rajada. Consideremos um ruído em
rajada de duração de l bits afetando a transmissão de um bloco de um código R-S (n, k) com m bits por
símbolo. Se l = 1, é óbvio que somente um símbolo será afetado; se l = 2, então 1 ou 2 símbolos serão
afetados pelo ruído, dependendo da localização da rajada em relação aos bits de início ou fim de um
símbolo. Essa situação é ilustrada com um exemplo na figura 1, onde ns indica o número de símbolos
afetados pelo ruído em rajada.
Estendendo esse raciocínio, é possível determinar o menor comprimento de rajada em bits necessário para
afetar um dado número de símbolos. Por exemplo, o menor comprimento de rajada para o qual 3 símbolos
poderão ser afetados é l = m + 2 (neste caso, a rajada afeta um símbolo por inteiro e um bit em cada símbolo
vizinho). Para rajadas de comprimento até 4m bits, o número de símbolos afetados é mostrado na tabela 1.
Por exemplo, para o exemplo da figura 1, l = 14 = 3m+2 e, portanto, da tabela segue que o número de
símbolos afetados, ns, fica entre 4 e 5.
Figura 1: Efeito de uma rajada de l = 14 bits num fluxo de símbolos com m = 4 bits cada.
O número de símbolos corrompidos, ns, será de 4 ou, no pior caso, 5.
Tabela 1: Símbolos afetados por erros em rajada
Comprimento da rajada Número de símbolos afetados
1
1
2...m
1...2
m+1
2
(m + 2)...2m
2...3
2m + 1
3
2m + 2...3m
3...4
3m + 1
4
3m + 2...4m
4...5
A partir da tabela 1, pode-se concluir que o menor e o maior comprimento de rajada capaz de afetar ns >= 2
símbolos de m bits podem ser determinados, respectivamente, por:
lmin = (ns – 2) m + 2
(4)
lmax = (ns – 1) m + 1
(5)
Um código R-S (n, k) é capaz de corrigir até t = (n–k) / 2 símbolos errados, independentemente das
5
localizações desses símbolos dentro da palavra-código. Se t símbolos incorretos aparecerem em sequência,
como resultado de uma rajada, teremos que garantidamente o código suporta rajadas de até lmax bits, ou
seja:
lmax = (((n–k) / 2) – 1) m + 1 = (t – 1) m + 1
(6)
Por exemplo, considerando o código R-S (204, 188) utilizado no Sistema Brasileiro de Televisão Digital, com
m = 8 bits por símbolo, teremos uma imunidade a rajadas de até (8–1) x 8+1 = 57 bits, o que é notavelmente
superior ao desempenho de códigos binários. Obviamente, no caso de um canal sem memória, em que os
erros não ocorram em rajadas, mas se distribuam aleatoriamente, a robustez do código R-S cai
significativamente.
Probabilidade de Erro e Desempenho
Para modulações específicas, é possível relacionar a probabilidade de erro de bit, PB, com a probabilidade
de erro de símbolo, PE. Por exemplo, para modulação MFSK como M = 2m, essa relação é [10]:
PB / PE = 2m–1 / 2m – 1
(7)
Para os códigos R-S, a probabilidade de erro é uma função que decresce exponencialmente com o
comprimento do bloco n, enquanto que a complexidade de decodificação é proporcional a uma baixa
potência de n. O aumento da redundância de um código R-S implica o aumento da complexidade da
implementação, particularmente para dispositivos de alta velocidade, mas traz o benefício de melhor taxa de
erro de bits.
Em sistemas de telecomunicações digitais, é errado imaginar que o desempenho do código R-S melhora
monotonicamente com o aumento da redundância (ou redução da taxa de código). Na realidade, para cada
tipo de modulação e canal de comunicação há uma taxa de código ótimo; isso se explica porque, para altas
taxas de código, há pouca redundância e, consequentemente, altas taxas de erros; já quando a taxa de
código é muito baixa, num sistema de comunicação em tempo real, menor será a energia por símbolo, o que
acaba degradando o desempenho. Para um canal Gaussiano, a taxa de código ótima fica entre 0,6 e 0,7 [10].
6
Correção de Erros I: Campos Finitos
Campos Finitos ou Campos de Galois
Para entender os princípios de codificação e decodificação de códigos não-binários, é necessária uma
introdução aos campos finitos conhecidos como Campos de Galois (Galois Fields, GF). Um campo de
GF(n) é um conjunto com n elementos, fechado com relação às operações de adição e multiplicação, e para
qual todo elemento tem seu inverso aditivo e multiplicativo (com exceção para o 0, que não tem inverso
multiplicativo).
Dado um número primo p, existe um campo de Galois GF(p) com exatamente p elementos. Por exemplo, o
campo GF(2) = {0, 1} é um campo de Galois, pois tem dois elementos e, realizando a adição e multiplicação
módulo 2, ou seja, tomando o resto da divisão do resultado por 2, o conjunto é fechado. De modo similar,
para p primo, GF(p) pode ser representado pelo conjunto {0, 1, 2,..., p – 1}, e as operações aritméticas são
realizadas em módulo p. Esse campo pode ser estendido para pm elementos, onde m é um inteiro
estritamente positivo, resultando no campo estendido GF(pm). Os códigos R-S utilizam símbolos do campo
de extensão GF(2m).
Nota: Na prática, basta definir a adição como uma operação de OU-exclusivo lógico e a multiplicação como
um E-lógico.
À exceção do elemento nulo, todos os elementos em GF(2m) podem ser representados por uma potência de
um símbolo básico, a. Como GF(2m) deve ter exatamente 2m elementos, resulta que:
(8)
Já a propriedade de fechamento implica que:
(9)
Os códigos R-S utilizam os símbolos do campo de extensão da Equação 8.
Representação Polinomial
A representação de cada elemento não nulo como uma potência de a é conhecida como representação
exponencial. A equivalência de cada elemento com uma palavra binária resulta em sua representação
polinomial. Nessa representação, os elementos de GF(2m) são inteiros de 0 a 2m–1.
Um elemento não nulo de GF(2m) pode ser representado por um polinômio de grau menor ou igual a m – 1.
Ou seja, para i = 0, 1, 2,...,2m – 2, resulta:
(10)
Onde cada um dos coeficientes pertence a GF(2) (ou seja, é binário). Assim sendo, cada elemento de
GF(2m) tem um número binário equivalente da forma:
7
(11)
Adição e Multiplicação no Campo de Extensão
O campo de extensão GF(2m) é fechado em relação à adição e multiplicação, ou seja, a soma ou produto de
dois elementos de GF(2m) resulta sempre num elemento do mesmo campo. Essas operações são necessárias
para cálculo dos símbolos de paridade e das síndromes, utilizadas no processo de decodificação. A adição de
dois elementos quaisquer de um campo finito é definida como a soma módulo-2 (ou seja, uma operação de
ou-exclusivo) dos coeficientes de mesma potência dos polinômios correspondentes a cada elemento, ou seja,
na forma polinomial:
(12)
Se os elementos forem expressos na forma exponencial, é necessário primeiro convertê-los para forma
polinomial antes de proceder a adição. Já em relação à multiplicação, a condição de fechamento implica
que:
(13)
Portanto, a multiplicação de dois elementos resulta num elemento cujo expoente é obtido dividindo-se a
soma dos expoentes dos elementos por 2m – 1 e tomando o resto, ou seja, na forma exponencial:
(14)
Se os fatores forem expressos na forma polinomial, é necessário então convertê-los na forma exponencial e
então efetuar o produto conforme a Equação 14.
Polinômios Primitivos
Um campo de Galois GF(2m) é definido por um polinômio primitivo f(X) de ordem m. Para gerar os
elementos de GF(2m) a partir de f(X), começamos com os elementos 0, 1 e X, e seguimos multiplicando o
último elemento por X, tomando o resto da divisão do resultado por f(X), ou seja, resultado módulo f(X).
Esse procedimento continua até que o conjunto tenha exatamente 2m elementos.
Um polinômio irredutível (que não pode ser fatorado) f(X) de ordem m é primitivo se e somente se o menor
número inteiro positivo n para o qual f(X) é um divisor de Xn + 1 para n = 2m – 1.
A tabela 2 mostra alguns exemplos de polinômios primitivos. Um grande número de exemplos de polinômios
primitivos pode ser encontrado em [8].
m
2
3
3
4
Tabela 2: Exemplos de polinômios primitivos
f(X)
m
f(X)
1 + X + X2
5
1 + X + X3 + X4 +
X5
1 + X2 + X3
5
1 + X + X2 + X4 +
X5
1 + X + X3
6
1 + X5 + X6
1 + X3 + X4
6
1 + X + X6
8
4
1 + X + X4
6
5
1 + X3 + X5
6
5
1 + X2 + X5
6
5
1 + X + X2 + X3 +
X5
1 + X2 + X3 + X4 +
X5
6
5
1 + X + X4 + X5 +
X6
1 + X + X2 + X5 +
X6
1 + X + X3 + X4 +
X6
1 + X2 + X3 + X5 +
X6
Um polinômio primitivo f(X) de ordem m pode ser representado como:
f(X) = f0 + f1 X + f2 X2 + ... + fm-1 Xm-1 + fm Xm
(15)
Onde cada coeficiente fi é binário, além disso, sempre f0 = 1 (caso contrário, o polinômio seria fatorável por
X e, portanto, não seria irredutível, nem primitivo) e fm = 1 (caso contrário, não teria ordem m). Ou seja, a
Equação 16 pode ser reescrita como:
f(X) = 1 + f1 X + f2 X2 + ... + fm-1 Xm-1 + fm Xm
(16)
É também interessante notar que, se um polinômio f(X) for primitivo, seu recíproco também o será. Ou seja,
também é primitivo o polinômio:
f(X) = 1 + fm-1 X + fm-2 X2 + ... + f2 Xm-2 + f1 Xm-1 + Xm
(17)
Tomemos, como exemplo, o campo finito GF(24) definido pelo polinômio primitivo f(X) = 1 + X + X4,
extraído da tabela 2. Como m = 4, o campo terá um total de 24 = 16 elementos, cada qual com 4 bits; esses
elementos serão os símbolos usados pelo código R-S. Cada elemento pode ser expresso em função dos
elementos-base {X0, X1, X2, X3}. O elemento nulo e os 4 primeiros não-nulos ({a0, a1, a2, a3}) são expressos
segundo a Equação 11 de forma trivial:
0 = 0X0 + 0X1 + 0X2 + 0X3
(18)
a0 = 1X0 + 0X1 + 0X2 + 0X3
(19)
a1 = 0X0 + 1X1 + 0X2 + 0X3
(20)
a2 = 0X0 + 0X1 + 1X2 + 0X3
(21)
a3 = 0X0 + 0X1 + 0X2 + 1X3
(22)
Para obter as representações binárias dos demais elementos ({a4, a5, ... , a14}) é necessário utilizar o
polinômio primitivo. Primeiramente, definindo a como raiz do polinômio primitivo, tem-se que:
9
(23)
Onde se usou o fato de que, na aritmética binária, +1 = –1. Para obter a5, usa-se a Equação 23, resultando
em:
(23)
Os próximos elementos são obtidos de forma similar:
Só a título de confirmação, o que já se esperava da Equação 13:
(34)
Lembrando novamente que, segundo a Equação 11, cada elemento de GF(24) pode ser expresso como um
polinômio de ordem igual ou inferior a 3; os resultados obtidos nas Equações 18 - 33 podem ser sumarizados
na tabela 3.
Tabela 3: Mapeamento dos elementos do campo GF(16) gerado pelo polinômio f(X) = 1+X+X4
Representação Coeficiente
Representação
Exponencial
Polinomial
Hexadecimal
X0
0
1
X1
0
0
X2
0
0
X3
0
0
0
1
a1
0
1
0
0
2
a2
0
0
1
0
4
a3
0
0
0
1
8
a4
1
1
0
0
3
0
a
0
10
a5
0
1
1
0
6
a6
0
0
1
1
12
a7
1
1
0
1
11
a8
1
0
1
0
5
a9
0
1
0
1
10
a10
1
1
1
0
7
a11
0
1
1
1
14
a12
1
1
1
1
15
a13
1
0
1
1
13
a14
1
0
0
1
13
Para campos de pequena extensão, como o GF(24) analisado, é conveniente sumarizar os resultados das
somas e produtos de dois elementos quaisquer do campo em tabelas, como as ilustradas nas tabelas 4 e 5.
0
Tabela 4: Tabela de adição para o campo GF(16) gerado pelo polinômio f(X) = 1 + X + X4
0
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10 a11 a12 a13
0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10 a11 a12 a13
a0
a14
a14
a0
a0
0
a1
a1
a4
a4
0
a2
a2
a8
a3
a3
a4
+
a8
a14
a1
a10
a13
a9
a2
a7
a5
a12
a11
a6
a3
a9
a0
a2
a11
a14
a10
a3
a8
a6
a13
a12
a7
a5
a5
0
a10
a1
a3
a12
a0
a11
a4
a9
a7
a14
a13
a14
a9
a6
a6
0
a11
a2
a4
a13
a1
a12
a5
a10
a8
a0
a4
a1
a0
a10
a7
a7
0
a12
a3
a5
a14
a2
a13
a6
a11
a9
a5
a5
a10
a2
a1
a11
a8
a8
0
a13
a4
a6
a0
a3
a14
a7
a12
a6
a6
a13
a11
a3
a2
a12
a9
a9
0
a14
a5
a7
a1
a4
a0
a8
a7
a7
a9
a14
a12
a4
a3
a13
a10
a10
0
a0
a6
a8
a2
a5
a1
a8
a8
a2
a10
a0
a13
a5
a4
a14
a11
a11
0
a1
a7
a9
a3
a6
a9
a9
a7
a3
a11
a1
a14
a6
a5
a0
a12
a12
0
a2
a8
a10
a4
a10
a10
a5
a8
a4
a12
a2
a0
a7
a6
a1
a13
a13
0
a3
a9
a11
a11
a11
a12
a6
a9
a5
a13
a3
a1
a8
a7
a2
a14
a14
0
a4
a10
a12
a12
a11
a13
a7
a10
a6
a14
a4
a2
a9
a8
a3
a0
a0
0
a5
a13
a13
a6
a12
a14
a8
a11
a7
a0
a5
a3
a10
a9
a4
a1
a1
0
a14
a14
a3
a7
a13
a0
a9
a12
a8
a1
a6
a4
a11
a10
a5
a2
*
0
a0
Tabela 5: Tabela de multiplicação para o campo GF(16) gerado pelo polinômio f(X) = 1+X+X4
0 a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10 a11 a12 a13
0 0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
2
3
4
5
6
7
8
9
10
11
12
0 a
a
a
a
a
a
a
a
a
a
a
a
a
a13
a2
0
a14
0
a14
11
a1
0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a2
0
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a3
0
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a4
0
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a5
0
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a6
0
a6
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a7
0
a7
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a8
0
a8
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a9
0
a9
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a10
0
a10
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a11
0
a11
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a12
0
a12
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a13
0
a13
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a14
0
a14
a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
Circuito Gerador
Para campos de Galois de alta dimensão, a determinação da representação polinomial de cada elemento por
meios algébricos é inviável. No caso geral, o mapeamento dos elementos do campo GF(2m) da forma
exponencial para forma polinomial pode ser realizado de forma mais genérica utilizando a idéia de um
circuito com registradores de deslocamento com realimentação linear (Linear Feedback Shift Register,
LFSR). Esse circuito consiste em m flip-flops em cascata, com realimentação do bit mais significativo. A
realimentação ou não desse bit reflete exatamente os coeficientes do polinômio primitivo, conforme a
Equação 15. O estado dos registradores num dado instante dá a representação polinomial de um elemento do
campo de Galois.
Para o campo GF(16) analisado como exemplo nesta seção, o circuito LFSR é ilustrado na figura 2. Para
gerar os elementos do campo, à exceção do elemento nulo, basta iniciar os registradores com um elemento
qualquer e aplicar pulsos ao circuito; a cada pulso, um novo estado é gerado. Obviamente, o circuito tem
natureza periódica (cíclica), e o procedimento termina quando o estado inicial se repetir.
Figura 2: Circuito baseado em registrador de deslocamento com realimentação para geração
dos elementos do campo de Galois GF(16) gerado pelo polinômio f(X) = 1 + X + X4
As conexões de realimentação refletem os coeficientes do polinômio primitivo.
12
Correção de Erros I: Codificação e Decodificação
Codificação
Em sua forma mais comum, os códigos de Reed-Solomon podem ser expressos conforme a Equação (35):
(n, k) = (2m-1,2m – 1 – 2t)
(35)
Onde o número de símbolos de paridade é dado por n – k = 2t e t representa a capacidade de correção de
erros de símbolo do código. Os códigos R-S são um subconjunto dos códigos BCH (Bose, Chaudhuri e
Hocquenghem) e, portanto, podem ser gerados por um polinômio de grau igual ao número de símbolos de
paridade, ou seja:
g(X) = g0 + g1X + g2X2 + ... + g2t–1X2t–1 + X2t
(36)
Onde cada um dos coeficientes é um elemento do campo GF(2m). Como o grau desse polinômio é 2t, há
exatamente 2t sucessivas potências de a que são raízes de g(X). Portanto, o polinômio gerador pode ser
construído a partir do polinômio primitivo que define o campo através de:
g(X) = (X – a)(X – a2)(X – a3) ... (X – a2t)
(37)
Onde as operações aritméticas em a devem obedecer às tabelas para o campo de extensão.
Codificação na Forma Sistemática
O processo de codificação de códigos R-S é análogo ao dos códigos cíclicos binários. O polinômio da
mensagem a ser codificada, m(X), é deslocado para os k estágios mais à direita de um registrador da palavracódigo, e então o polinômio contendo os símbolos de paridade, p(X), é adicionado nos n – k estágios à
esquerda. Matematicamente, o polinômio correspondente à palavra-código pode ser escrito como
U(X) = p(X) + Xn–k m(x)
(38)
onde a multiplicação por Xn–k equivale a deslocar a mensagem para a direita de n–k posições. O polinômio
de paridade pode ser obtido dividindo-se a mensagem deslocada pelo polinômio gerador e tomando o resto,
ou seja,
p(X) = Xn–k m(X) modulo g(X)
(39)
Codificação Sistemática Usando Registradores de Deslocamento
O processo de codificação pode ser implementado de maneira direta utilizando-se a idéia de registradores de
deslocamento com realimentação. O processo é similar ao usado para gerar os elementos do campo de
extensão, mas agora cada estágio do registrador armazena um símbolo, e não um bit e, de maneira similar,
cada coeficiente do polinômio gerador é um símbolo também. O circuito é ilustrado na figura 3, tem um
registrador de deslocamento com n – k = 2t estágios e duas chaves, e seu funcionamento pode ser descrito
da seguinte maneira:
13
Inicialmente os registradores são todos zerados.
Durante os k primeiros ciclos do sinal de relógio, a chave S1 é fechada, de modo que os símbolos de
entrada vão sendo carregados nos registradores de deslocamento. À medida que os símbolos de
entrada vão sendo deslocados, os símbolos de paridade vão ser formando nos registradores.
Durante esses ciclos, a chave S2 fica na posição para baixo, de modo que os símbolos de entrada vão
também sendo direcionados à saída.
Após o k-ésimo símbolo da mensagem original ter sido transferido para a saída, a chave S1 é aberta e
a chave S2 movida para a posição para cima.
Durante os próximos n – k ciclos, os símbolos de paridade contidos nos registradores são movidos
para a saída e os registradores são zerados novamente.
O total de número de ciclos de relógio é de n e o conteúdo do registrador de saída será U(X) = p(X) +
Xn–k m(X), onde p(X) representa os símbolos de paridade e m(X) denota a mensagem original em
forma polinomial.
Figura 3: Codificador Reed-Solomon.
Durante os primeiros k ciclos, S1 fica fechada e S2 para baixo, e os símbolos de entrada passam para saída.
Então S1 é aberta e S2 passa para a posição para baixo, e durante os próximos n – k ciclos os símbolos de
paridade são movidos para saída.
Decodificação
Em Telecomunicações, a palavra-código produzida pelo codificador pode ser corrompida por erros durante
os processos de transmissão; alternativamente, no caso de sistemas de memória podem acontecer erros
durante o armazenamento e/ou recuperação de dados. O padrão de erros pode ser entendido como uma
palavra de n símbolos que é adicionada à palavra-código. Esse padrão de erros pode ser representado por:
(40)
Onde cada termo ei é um símbolo de GF(2m). A palavra corrompida (ou recebida) pode sr representada pela
soma da palavra-código com o padrão de erros, ou seja:
r(X) = U(X) + e(X)
(41)
Dada a palavra recebida, se o padrão de erro puder ser determinado, a palavra-código pode ser determinada
14
por
U(X) = r(X) + e(X)
(42)
E, portanto, o problema de decodificação é, a partir da palavra recebida, determinar o padrão de erro.
Observe que, para cada termo não nulo na Equação 40, há duas incógnitas: a localização do erro (o índice i
na equação) e sua magnitude (o termo ei). Contrastando com o caso de decodificação binária, o problema é
significativamente mais complexo, pois, no caso binário, conhecendo a localização de um erro, basta
inverter o bit na localização para corrigir a palavra recebida; já com codificação não binária, como é o caso
do código Reed-Solomon, é também necessário determinar a magnitude do erro para possibilitar a correção.
Portanto, para decodificar uma palavra corrompida com v <= t erros, são necessárias 2v equações.
Arquitetura do Processo de Decodificação
O processo de decodificação pode ser dividido em etapas que devem ser executadas em sequência. O
procedimento adotado neste trabalho é ilustrado na figura 4.
Figura 4: Fluxo do processo de decodificação utilizando o algoritmo de
Berlekamp-Massey, o procedimento de Chien e a fórmula de Forney.
Inicialmente, a partir da palavra recebida, as síndromes são calculadas. A partir das síndromes, conforme
explicado abaixo, são determinados o polinômio localizador de erros e o polinômio avaliador de erros,
utilizando o algoritmo de Berlekamp-Massey [6]. Em seguida, utilizando o procedimento de Chien, as
posições dos erros são determinadas. Finalmente, usando a fórmula de Forney, as magnitudes dos erros são
determinadas e a palavra-código original é restaurada. Obviamente, caso as síndromes sejam todas nulas,
considera-se que não houve erro e a palavra recebida é tida como a palavra-código original; além disso, caso
o número de erros exceda a capacidade de correção do código, a palavra-código obtida ao final do processo
não corresponderá à palavra-código original.
Cálculo das Síndromes
15
Uma síndrome é o resultado de um teste de paridade sobre a palavra recebida r, determinando se ela
pertence ou não ao conjunto de palavras-código válidas. Se r for uma palavra-código, então todas as
síndromes devem ter o valor 0. Há n – k síndromes, frequentemente representadas como um vetor S = {si}
para i = 1, ... , n–k. Como, para toda palavra-código válida, vale a relação:
U(X) = m(X) g(X)
(43)
Segue que todas as raízes do polinômio gerador do código, g(X), também são raízes de U(X).
Consequentemente, da Equação 41 temos que, se r for uma palavra-código válida (em outras palavras, não
houve erros), então o polinômio r(X) avaliado para cada uma das raízes de g(X) deve resultar em 0. As
síndromes são calculadas por:
(44)
É conveniente definir um polinômio de síndromes como:
(45)
Embora o polinômio s(X) tenha um número infinito de termos, a relação da Equação 44 somente é válida
para os primeiros n – k termos.
Localização e Magnitude dos Erros
Suponhamos que a palavra-código tenha sido corrompida por v <= t erros nas localizações Xj1, Xj2, ... , Xjv.
Assim sendo, a Equação 40 pode ser escrita somente com os termos não-nulos, como se segue:
(46)
O índice 1 <= j <= n dá a posição de cada erro, e os subíndices j1, j2, ... , jv são somente contadores.
Por conveniência, usamos a seguinte definição:
Definição 1: Um número localizador de erro é definido como:
Para simplificar a notação, define-se também:
Definição 2: A magnitude de um erro é definida como:
Usando as Definições 1 e 2, as n–k = 2t equações para determinação das síndromes podem ser escritas
como:
16
(47)
Embora as síndromes definam um conjunto de 2t equações com 2t incógnitas (t localizações de erros e t
magnitudes), o sistema não é trivial porque, com exceção da primeira, todas são não lineares. Qualquer
procedimento que resolva esse conjunto de equações pode ser chamado de um decodificador de
Reed-Solomon.
Algoritmo de Berlekamp-Massey
Vários algoritmos para implementação do decodificador têm sido propostos na literatura. Por exemplo,
Blahut concebeu configurações originais de decodificadores que não requerem o cálculo das síndromes [1].
Wei e Wei propuseram um algoritmo rápido que pode ser implementado num único chip em VLSI [11].
Clarke [2] constrói o polinômio localizador de erros utilizando o algoritmo Euclidiano e até propõe uma
implementação em hardware. Para os códigos cíclicos conhecidos como códigos BCH (Bose-ChaudhuriHocquenghem) em geral e Reed-Solomon em particular, Huffman e Pless apresentam, após longa e
detalhada exposição teórica, quatro algoritmos de decodificação [5]:
Algoritmo de Peterson-Gorenstein-Zierler [3], aplicado numa sequência de quatro passos, na qual o
segundo passo é notadamente o mais complexo e que requer mais tempo de processamento;
Algoritmo de Berlekamp-Massey [7], que fornece uma maneira mais eciente de executar o segundo
passo do algoritmo de Peterson-Gorenstein-Zierler;
Algoritmo de Sugiyama-Kasahara-Hirasawa-Namekawa [12], que através da aplicação do algoritmo
Euclidiano para polinômios, sugere uma outra maneira de executar o segundo passo de PetersonGorenstein-Zierler de forma mais eficiente;
Algoritmo de Sudan-Guruswami [4], que implementa a decodificação para além da distância mínima
do código e produz uma lista de todas as palavras-código a certa distância da palavra recebida.
Neste trabalho, optou-se por implementar o decodificador utilizando o algoritmo de Berlekamp-Massey, por
sua eficiência e relativa facilidade de implementação. Tomou-se o cuidado, porém, de deixar a estrutura das
bibliotecas de software flexível o suficiente para que outros algoritmos possam ser naturalmente adaptados
ao simulador.
Polinômios de Localização e Avaliação de Erros
A determinação das posições e magnitudes dos erros é realizada indiretamente. Primeiro, dois polinômios
são definidos conforme abaixo.
Definição 3: O polinômio localizador de erros é dado por:
(48)
17
Portanto, as raízes do polinômio são os inversos dos localizadores de erro, ou seja:
Definição 4: O polinômio avaliador de erros é definido por:
(49)
O polinômio localizador de erros está relacionado com o polinômio avaliador de acordo com uma expressão
conhecida como Equação-Chave. O algoritmo de Berlekamp-Massey dá um procedimento iterativo para
determinação dos polinômios definidos nas Equações 48 e 49. Para obtenção da equação-chave,
primeiramente, das definições acima, temos:
(50)
Usando a expansão em série:
(51)
A Equação 50 se torna:
(52)
Rearranjando os somatórios, teremos:
(53)
Substituindo a Equação 47 na expressão acima, teremos, finalmente, a equação-chave usando a definição da
Equação 45:
Sumarizando, temos a seguinte definição.
Definição 5: A equação-chave da decodificação de Reed-Solomon usando o algoritmo de BerlekampMassey é:
Onde s(X) tem, no máximo, 2t coeficientes não-nulos e os polinômios localizador e avaliador de erro devem
18
ter grau de, no máximo, t, para possibilitar a decodificação. Não há como computar esses polinômios
diretamente, e o algoritmo de Berlekamp-Massey dá um procedimento iterativo de 2t passos para
calculá-los. Na l-ésima etapa é determinado o par de polinômios de grau l, para l = 1, 2, ... , 2t. O último par
de polinômios, de grau 2t, é o par de polinômios que se desejava calcular originalmente. A cada etapa, a
equação-chave deve ser satisfeita, ou seja:
(54)
Idealmente, os polinômios encontrados numa etapa também deveriam satisfazer a equação chave da etapa
seguinte, ou seja:
(55)
Pois, caso isso acontecesse, teríamos o m do procedimento iterativo. Contudo, isso normalmente não ocorre
e temos a seguinte relação:
(56)
Onde D1(l) é o coeficiente não-nulo de Xl+1 do produto polinomial [1 + s(X)]s(l)(X).
Polinômios Auxiliares
Para permitir o cálculo de (s(l+1)(X), w(l+1)(X)) a partir de (s(l)(X), w(l)(X)), dois outros polinômios, (t(l)(X),
g(l)(X)), com grau menor ou igual a l, são introduzidos, de modo que respeitem a seguinte equação:
(57)
Usando os polinômios auxiliares, derivam-se as equações para obtenção de s(l+1)(X) e w(l+1)(X) a partir de
s(l)(X), w(l)(X), t(l)(X) e g(l)(X):
(58)
(59)
As equações acima garantem que o novo par (s(l+1)(X), w(l+1)(X)) satisfaça a equação-chave.
As Equações 58 e 59 são fáceis de implementar na prática, pois requerem somente uma multiplicação por
escalar (D1(l)), um deslocamento de coeficientes (multiplicação por X) e uma subtração de polinômios. Para
atualizar os polinômios auxiliares, há dois conjuntos de regras possíveis:
19
Tanto as regras A (Equações 60 e 61) quanto as B (Equações 62 e 63) são facilmente implementáveis em
hardware ou software; as regras A exigem somente um deslocamento de coeficientes, enquanto que as
regras B implicam uma divisão (ou multiplicação) dos coeficientes de um polinômio por um escalar. O
conjunto apropriado de regras é escolhido de modo a minimizar os graus dos polinômios t(l+1)(X) e g(l+1)(X).
Pode-se demonstrar que, qualquer que seja a escolha, teremos:
(64)
A escolha do conjunto apropriado de regras depende da análise dos graus dos polinômios s(l)(X), w(l)(X),
t(l)(X) e g(l)(X), o que não é trivial, pois devem ser considerados os casos em que termos são cancelados
acidentalmente. Para facilitar essa análise, Berlekamp e Massey introduziram um termo D(l) que determina
os limites superiores dos graus dos polinômios, de modo que:
(65)
(66)
As regras A são usadas quando D1(l) = 0 ou D(l) > (l+1) / 2. As regras B serão usadas quando D1(l) <> 0 ou
D(l) < (l+1) / 2. Quando as regras A forem empregadas, D(l) não muda, ou seja, D(l+1) = D(l); quando
forem usadas as regras B, fazemos D(l+1) = l + 1 – D(l). Essas escolhas garantem que 0 <= D(l+1) <= l+1,
que os graus de s(l+1)(X) e w(l+1)(X) sejam limitados por D(l+1), e que os graus de t(l+1)(X) e g(l+1)(X) sejam
limitados por 1 – D(l+1). Além disso, pode-se verificar que 0 <= D(l) <= l.
As condições acima não incluem o caso em que D1(l) <> 0 ou D(l) < (l+1) / 2. Neste caso, pode ser provado
que tanto as regras A como as regras B garantem que os limites impostos nas Equações 65 e 66 sejam
respeitadas. Berlekamp e Massey sugerem que, através da introdução de um novo parâmetro binário, B(l),
pode-se restringir ainda mais os limites sobre os graus dos polinômios t(l)(X) e g(l)(X). Com esse novo
parâmetro, as regras A são usadas quando D1(l) <> 0 ou D(l) < (l+1) / 2 e B(l) = 0 e, nesse caso, B(l+1) =
B(l); caso D1(l) <> 0 ou D(l) < (l+1) / 2 e B(l) = 1, as regras B são usadas e faz-se B(l+1) = 1 – B(l). Essas
regras garantem que:
(67)
(68)
O procedimento descrito acima limita os graus dos polinômios localizador e avaliador de erros conforme o
20
lema abaixo, apresentado sem demonstração.
Lema 1: A cada iteração, os graus dos polinômios localizador e avaliador de erros são limitados por:
(69)
(70)
Como o procedimento de Berlekamp-Massey tem n – k = 2t etapas, o lema acima garante que, no final,
s(2t)(X) = s(X) tenha, no máximo, grau t. O mesmo acontece com w(X). Para completar o algoritmo, as
seguintes condições iniciais são definidas:
(71)
O fluxograma completo do algoritmo é ilustrado na figura 5, onde a decisão entre as regras A e B pode ser
sumarizada em:
(72)
21
Figura 5: Fluxograma do algoritmo de Berlekamp-Massey
Procedimento de Busca de Chien
O algoritmo de Berlekamp-Massey permite determinar os polinômio localizador e avaliador de erros, ou seja,
s(X) e w(X). Da Equação 48, tem-se que os localizadores de erros são os recíprocos das raízes de s(X). Em
vez de determinar as raízes de s(X), Chien propôs uma maneira mais eficiente de determinar os localizadores
de erros através de um procedimento enumerativo descrito na figura 6.
1. Inicializar conjunto de localizadores como o conjunto vazio,
ou seja, {bl}¬ Ø
2. l¬0
3. Repetir
4. l¬l+1
5. Se s(al = 0), então incluir localizador al em {bl}
6. Até que o número de localizadores seja igual à ordem de s(X)
Figura 6: Procedimento de busca de Chien
22
Como o procedimento de Chien dá diretamente os índices em que os erros ocorreram, não há necessidade de
computar o logaritmo discreto. Além disso, o procedimento pode ser ainda otimizado se os coeficientes de
s(al+1) forem calculados a partir dos coeficientes de s(al). Lembrando que:
(73)
Temos que:
(74)
E, portanto:
(75)
Comparando as Equações 74 e 75, percebe-se que o i-ésimo coeficiente de s(al+1) pode ser obtido
rapidamente multiplicando-se o coeficiente correspondente de s(al) por ai.
Fórmula de Forney
Tendo calculado as posições dos erros, resta determinar suas magnitudes, Yl. Forney notou que a magnitude
de cada erro pode ser determinada computando o valor do polinômio avaliador de erros, w(X), para X =
bl–1, ou seja:
(76)
Finalmente, a magnitude de um erro pode ser calculada como
(77)
Com as posições e magnitudes dos erros determinadas, a palavra-código original pode ser restaurada pela
Equação 42, finalizando o processo de decodificação.
23
Correção de Erros I: Considerações finais
Este tutorial parte I procurou apresentar os fundamentos teóricos dos códigos Reed-Solomon, detalhando
suas características, aspectos teóricos dos campos finitos e a codificação e decodificação desses códigos.
O tutorial parte II apresentará inicialmente a biblioteca desenvolvida em linguagem de programação Java
contendo as classes para realização de álgebra de Campos de Galois, e a seguir apresentará o simulador
propriamente dito e as conclusões do trabalho realizado.
Referências
[1] Richard E. Blahut. A universal reed-solomon decoder. IBM Journal of Research and Development,
28(2):150-158, March 1984.
[2] C. K. P. Clarke. Reed-solomon error correction. Technical report, BBC Research & Development, 2002.
[3] D. C. Gorenstein and N. Zierler. A class of error-correcting codes in pm symbols. Journal of SIAM,
9:207-214, 1961.
[4] V. Guruswami and M. Sudan. Improved decoding of reed-solomon and algebraic-geometry codes. IEEE
Transactions on Information Theory, 45:1757 1767, 1999.
[5] W. Cary Huffman and Vera Pless. Fundamentals of Error Correcting Codes. Cambridge University Press,
2003.
[6] Bruce Maggs. Decoding reed-solomon codes. Lecture notes, October 2000.
[7] J. L. Massey. Shift-register synthesis and bch decoding. IEEE Transactions on Information Theory,
15:122-127, 1969.
[8] Todd K. Moon. Error Correction Coding: Mathematical Methods and Algorithms. Wiley- Interscience,
2005.
[9] I. S Reed and G. Solomon. Polynomial codes over certain finite fields. SIAM Journal of Applied Math.,
8:300-304, 1960.
[10] Bernard Sklar. Digital Communications: Fundamentals and Applications. Prentice-Hall, 2 edition, 2001.
[11] Shyue-Win Wei and Che-Ho Wei. High-speed decoder of reed-solomon codes. IEEE Transactions on
Communications, 11(41):1588-1593, November 1993.
[12] S. Hirasawa Y. Sugiyama, M. Kasahara and T. Namekawa. A method of solving a key equation for decoding goppa codes. Information
and Control, 27:87-99, 1975.
24
Correção de Erros I: Teste seu entendimento
1. Qual a finalidade dos códigos Reed-Solomon?
Implementar códigos de correção de erros em sistemas digitais de comunicação.
Implementar criptografia em sistemas de segurança.
Implementar geradores de códigos aleatórios.
Implementar reparadores de arquivos criptografados.
2. Qual é o conceito necessário para entender os princípios de codificação e decodificação de códigos
não-binários?
Conceito de aritmética não binária.
Conceito de transmissão analógica.
Conceito de campos finitos conhecidos como Campos de Galois (Galois Fields, GF).
Conceito de geometria espacial.
3. Como para os campos de Galois de alta dimensão, a determinação da representação polinomial de
cada elemento por meios algébricos é inviável, qual é a alternativa utilizada?
Um supercomputador com gerador de polinômios aleatórios.
Um circuito analógico com gerador de ruídos.
Um sistema de n equações com n-1 incógnitas.
Um circuito gerador de polinômios com registradores de deslocamento com realimentação linear
(Linear Feedback Shift Register, LFSR).
25
Download

Correção de Erros I: Simulador de Códigos Reed-Solomon