Unidad 6 · Los códigos BCH · lo recibido evaluado en las raíces, la mitad que sale gratis, el cambio de incógnitas que lineariza el sistema y la lectura de Newton: los síndromes son la salida de un registro
Un código BCH se define por raíces: su generador se anula en potencias consecutivas de un elemento . Decodificarlo empieza por preguntarle a lo recibido cuánto vale en esas raíces. Lo que contesta son los síndromes, y lo que hay que sacar de ellos son las posiciones de los errores: un sistema no lineal que se vuelve lineal al cambiar de incógnita, y que resulta ser la descripción de un registro de desplazamiento.
Sea un BCH binario que corrige errores, con , donde es el polinomio mínimo de y tiene orden en . Llega . El componente del síndrome es
Cada es un elemento de , no un bit: el síndrome entero son elementos del cuerpo, bits escritos. Los índices empiezan en 1 porque las raíces pedidas empiezan en ; con otro primer exponente se corren igual. Dos pasos lo llevan del canal al error.
Paso 1: lo transmitido no aporta. Toda palabra es múltiplo de , que se anula en . Entonces y : el síndrome depende sólo del patrón de error, como en todo código lineal.
Paso 2: el error, posición por posición. Si hubo errores, en las posiciones , entonces , y evaluado en :
Siendo binario, no hay magnitudes de error que averiguar: conocida una posición errada, se invierte el bit. Todo el problema es encontrar las posiciones.
Es el mismo síndrome de la Unidad 5, leído en otro cuerpo. Allá el síndrome era el resto , que calcula el registro divisor de el síndrome cíclico. Como y se anula en las raíces,
y la segunda igualdad sale igual, con en el lugar de : alcanza un divisor de etapas por síndrome. En el (15,7), con : el resto por es , y da , y , porque , y comparten polinomio mínimo; el resto por es , y . La igualdad se comprobó sobre los 32 768 vectores de quince bits, en el (15,7) y en el (15,5).
En un cuerpo de característica dos, , porque el término cruzado es cero. Aplicado a la suma del paso 2:
con , que en la sección 03 recibe nombre. El paso descansa en que los coeficientes de son 0 o 1, que al cuadrado no cambian: es propio del caso binario. Vale para cualquier patrón, con cualquier cantidad de errores, y por eso también para entero: . La consecuencia práctica: sólo hay que evaluar los síndromes de índice impar, y los otros salen de elevar al cuadrado, que en hardware es lógica fija. Con tres errores en las posiciones 3, 5 y 12 del (15,5):
Y la cuenta de información cierra con lo que ya se sabía. Los elementos ocupan bits, 24 en el (15,5), pero el síndrome cíclico tenía , y los son evaluaciones suyas: no pueden decir más. Recorridos los 32 768 vectores de quince bits, salen exactamente 1024 vectores de síndromes distintos en el (15,5) y 256 en el (15,7), en los dos. En el (15,5) los diez bits se reparten así: y toman los 16 valores del cuerpo, cuatro bits cada uno, y toma sólo cuatro: 0, 1, y . La razón es la misma propiedad, aplicada dos veces: , porque , y los únicos elementos de con son esos cuatro. Es la clase conjugada , de dos elementos: tiene grado 2 y su síndrome, dos bits. .
Conviene abreviar. El número localizador del error es
Como tiene orden , sus potencias son todas distintas: conocer es conocer la posición. En el ejemplo, los localizadores son , y . Con esta notación, lo que hay que resolver es
Tiene tres dificultades a la vez. Es no lineal: las incógnitas aparecen elevadas hasta la . La cantidad de incógnitas, , no se conoce. Y es simétrico: intercambiar dos localizadores no cambia ninguna ecuación, así que no hay forma de despejarlos de a uno, porque nada distingue al primero del segundo.
Además tiene muchas soluciones. Todos los patrones de un mismo coset dan los mismos síndromes: patrones por vector de síndromes, 32 en el (15,5). La que se busca es la de menos errores, y si es única: dos patrones de peso con los mismos síndromes sumarían una palabra no nula de peso , por debajo de la distancia diseñada. Probar los patrones uno por uno son intentos: 576 en el (15,5), 32 641 en el (255,239). Hace falta otra cosa.
La salida es no buscar los , sino un polinomio que los tenga a todos adentro. El polinomio localizador de errores es
Tres cosas salen de la definición. Sus raíces son los inversos de los localizadores, : el factor vale en . Su grado es la cantidad de errores, porque es un producto de elementos no nulos. Y sus coeficientes son las funciones simétricas elementales de los localizadores:
Ahí está la ganancia del cambio de incógnitas. Los no tienen orden; los sí están determinados, porque son simétricos: el mismo conjunto de posiciones da el mismo en cualquier orden. Y en la sección siguiente se relacionan con los síndromes por ecuaciones lineales.
En el ejemplo, con , y :
El término en falta: , y sin embargo son tres errores. Lo que cuenta los errores es el grado, no la cantidad de términos. De los 455 patrones de tres errores del largo 15, 35 tienen . Encontrar las raíces de probando las potencias de es la búsqueda de Chien.
Las sumas de potencias y las funciones simétricas están ligadas por las identidades de Newton, que son clásicas. Sobre un cuerpo de característica dos tienen dos tramos. Para :
donde el entero que multiplica al último término se reduce módulo 2: en las de índice par desaparece, en las de índice impar queda . Y para :
Las incógnitas aparecen a la primera potencia, multiplicadas por síndromes, que se conocen. El sistema no lineal en los se volvió lineal en los , y resolverlo así es el método de Peterson. El segundo tramo se prueba en tres pasos, con un polinomio auxiliar: el recíproco de ,
que tiene por raíces a los localizadores mismos.
Paso 1: cada localizador anula al recíproco. , para cada .
Paso 2: correrla en potencias. Multiplicada por , con , queda .
Paso 3: sumar sobre los errores. Sumando las igualdades, cada columna es una suma de potencias, , y queda la identidad.
El primer tramo pide más cuenta, la de la fórmula clásica entre sumas de potencias y funciones simétricas, y está en el apunte y en el libro. En el ejemplo se comprueba a mano. Con , y : ; ; y , porque y .
El segundo tramo, despejado, dice otra cosa:
Cada síndrome es una combinación fija de los anteriores. Es una recurrencia lineal de orden , y eso es un LFSR: etapas que guardan cada una un elemento de , cargadas con , y una realimentación que multiplica la etapa por la constante . Cada ciclo sale el síndrome que sigue. En el ejemplo, cargado con :
exactamente los de la sección 02. El registro no es nuevo. El LFSR de la Unidad 5 dividía por un polinomio y su salida cumplía la recurrencia del recíproco. Acá la recurrencia es la de , así que el registro divide por , el polinomio cuyas raíces son los localizadores. Y se entiende por qué: es una progresión geométrica de razón , que la genera un registro de una etapa; los síndromes son la suma de de esas progresiones.
El registro no se detiene en . La recurrencia vale para todo , y tiene sentido para cualquier . Como , la sucesión es periódica de período . En el ejemplo, de a el registro da 0, 1, , , 0, , 0, 0, 1, lo mismo que evaluar directamente, y . El decodificador ve sólo los primeros .
Con eso el problema cambia de forma. Lo que hay que hacer es encontrar el registro más corto que genera , y eso es lo que hace Berlekamp-Massey. Que el más corto sea no es obvio, y vale si . Sea otro registro, de etapas con , que también genera los .
Paso 1: si coinciden en , coinciden siempre. La diferencia entre lo que sale de los dos registros cumple la recurrencia del producto de sus dos polinomios, que tiene orden . Sus primeros términos son cero, así que la recurrencia sólo puede seguir produciendo ceros: el otro registro genera la sucesión entera , no sólo los que se ven.
Paso 2: la sucesión entera pide los localizadores. Si un registro con coeficientes la genera, el mismo cálculo de la sección 05 al revés da para todo , con . Tomando valores seguidos de queda un sistema de Vandermonde en los , que son distintos y no nulos: la única solución es para cada . Un polinomio mónico de grado con raíces distintas pide , y si , es .
Con un Berlekamp-Massey general, que no usa la simplificación binaria, sobre todos los patrones de hasta errores: el registro más corto es el de en los 575 patrones no nulos del (15,5) y en los 120 del (15,7).
Arranca sin errores, y no hay nada que ver: seis ceros y . Poné un error y mirá qué valen los seis. Después el patrón de las secciones de arriba, en 3, 5 y 12, y corré el registro hasta . Pasá al registro más corto: con tres errores no cambia nada. Ahora cuatro, en 0, 1, 2 y 4, y compará los dos registros más allá de .
Las identidades de Newton valen para cualquier . Con cuatro errores en el (15,5), el registro de cuatro etapas de genera los seis síndromes en los 1365 patrones. Lo que deja de valer es la unicidad: el paso 1 pedía , y un registro de tres etapas contra el verdadero de cuatro suma 7, uno más que los seis síndromes que hay. Recorridos los 1365 patrones con Berlekamp-Massey:
| registro más corto | patrones | lo que pasa |
|---|---|---|
| 3 etapas, 3 raíces | 525 | corrige tres: otra palabra |
| 3 etapas, sin raíces | 750 | falla declarada |
| 4 etapas | 90 | falla: grado mayor que t |
En 1275 de los 1365 hay un registro más corto que el verdadero que genera los mismos seis síndromes, y el decodificador se queda con él porque es el más corto: es lo único que puede saber. En los 750 del medio, el registro corto no tiene ni una raíz en el cuerpo. Las fallas suman 840 y las palabras equivocadas 525: el mismo reparto que da el decodificador de Meggitt con cuatro errores, ahora visto desde el registro.
Un caso: errores en 0, 1, 2 y 4. Los síndromes son , , , , , , y hay dos registros que los generan:
Las raíces de señalan las posiciones 5, 8 y 10. El decodificador las invierte y entrega una palabra de código que difiere de la transmitida en las siete posiciones 0, 1, 2, 4, 5, 8 y 10: es mismo, de peso 7. Los dos registros coinciden hasta y se separan en el primer síndrome que el decodificador no calcula: en el verdadero da y el corto . Con síndromes, un registro de etapas queda determinado si ; con uno más, los síndromes que se ven ya no alcanzan para distinguirlo. Cuántas veces termina en una palabra equivocada depende del código, y está en pasado t, la cuenta la hacen las palabras livianas.
El decodificador de un BCH binario queda partido en tres etapas independientes, y esta nota cubre la primera y el planteo de la segunda.
Síndromes. Evaluar en las raíces de índice impar, por Horner, con un multiplicador por constante en cada celda, y elevar al cuadrado para los pares. El costo es fijo y lineal en . Entra binario, sale en .
Polinomio localizador. Sacar de los síndromes: resolviendo el sistema lineal de Newton, que es el método de Peterson, o sintetizando el registro más corto, que es Berlekamp-Massey. Es la etapa difícil.
Raíces. Encontrar los ceros de entre las potencias de , invertirlos para tener los localizadores, y corregir: la búsqueda de Chien. Si el grado de pasa de , o no tiene tantas raíces distintas como su grado, el decodificador declara falla. Las tres etapas, sobre un mismo ejemplo de punta a punta, están en el (15,5) de punta a punta.
El ejemplo de las secciones 02 a 06, sin librerías: por tablas de potencias, los síndromes como sumas de potencias de los localizadores, multiplicando los factores de a uno, y el registro de Newton cargado con los tres primeros. Lo de los comentarios es la salida de correrlo.
EXP = [1] # GF(2⁴) con 1 + X + X⁴: EXP[i] = α^i
for _ in range(14):
x = EXP[-1] << 1
EXP.append(x ^ 0b10011 if x & 0b10000 else x)
LOG = {v: i for i, v in enumerate(EXP)}
def mul(a, b):
return 0 if a == 0 or b == 0 else EXP[(LOG[a] + LOG[b]) % 15]
def sum_gf(xs):
s = 0
for x in xs:
s ^= x
return s
def pot(x): # un elemento como potencia de α
return '0' if x == 0 else '1' if x == 1 else f'α^{LOG[x]}'
def sindromes(errores, cuantos):
"""S_i = e(α^i) = Σ X_l^i, con X_l = α^(j_l)."""
return [sum_gf(EXP[i * j % 15] for j in errores) for i in range(1, cuantos + 1)]
def localizador(errores):
"""σ(X) = Π (1 + X_l X), coeficientes de menor a mayor grado."""
sigma = [1]
for j in errores:
Xl = EXP[j]
sigma = [a ^ mul(Xl, b) for a, b in zip(sigma + [0], [0] + sigma)]
return sigma
def registro(sigma, iniciales, hasta):
"""El registro de Newton: S_i = σ1 S_(i-1) + ... + σν S_(i-ν)."""
S = list(iniciales)
nu = len(sigma) - 1
while len(S) < hasta:
S.append(sum_gf(mul(sigma[k], S[-k]) for k in range(1, nu + 1)))
return S
errores = [3, 5, 12] # el ejemplo, en el (15,5)
S = sindromes(errores, 6)
sigma = localizador(errores)
print([pot(s) for s in S])
# ['1', '1', 'α^10', '1', 'α^10', 'α^5']
print([pot(c) for c in sigma])
# ['1', '1', '0', 'α^5']
print([pot(s) for s in registro(sigma, S[:3], 6)])
# ['1', '1', 'α^10', '1', 'α^10', 'α^5']
print(all(S[2 * i + 1] == mul(S[i], S[i]) for i in range(3)))
# True
print([pot(s) for s in registro(sigma, S[:3], 16)[6:]])
# ['0', '1', 'α^5', 'α^5', '0', 'α^10', '0', '0', '1', '1']
La segunda línea es , con el cero de a la vista. La tercera es el registro cargado con : devuelve los seis. La última sigue de a , y el 1 final es otra vez. La línea de localizador que hace el zip es multiplicar por : el coeficiente nuevo de es el viejo más por el viejo de .