Bitácora · FEC · Concepto

La captura de errores

Unidad 5 · Los códigos cíclicos · cuando los errores caben en la ventana de paridad, el síndrome es el error: el test de peso, el anillo, y lo que el Golay pide de más

El decodificador de Meggitt gira la palabra recibida y en cada ciclo pregunta si el síndrome está en un conjunto: en el (15,5), uno de 106 síndromes. Hay un caso en que esa pregunta se reemplaza por otra mucho más barata, ¿pesa el síndrome t o menos?, y la respuesta trae además el error entero, bit por bit. Es la captura de errores. Funciona siempre que los errores estén juntos, y cuánto es «juntos» depende de qué fracción del anillo de posiciones cubre la paridad.

01 · El síndrome que es el error

Se transmite v(X), una palabra de un código cíclico (n,k) de polinomio generador g(X), y llega r(X)=v(X)+e(X), con e(X) el patrón de error. El síndrome es el resto de dividir lo recibido por el generador, y como v(X) es múltiplo de g(X) no deja resto:

s(X)=Rg(X){r(X)}=Rg(X){e(X)}

Tiene n−k coeficientes, de s0 a sn−k−1. Ahora, el caso particular: todos los errores caen en las primeras n−k posiciones, de X0 a Xn−k−1, o sea, e(X) tiene grado menor que n−k. Dividir un polinomio por otro de grado mayor da cociente nulo, y el resto es el propio dividendo:

s(X)=e(X)

El síndrome no es una pista sobre el error: es el error. En la forma sistemática cíclica la paridad va primero y el mensaje al final, así que esas n−k posiciones son las de paridad, y se las llama la ventana de paridad. Con el (15,5) de g(X)=1+X+X2+X4+X5+X8+X10 y errores en X2 y X7, el registro de síndrome termina en 0010000100, con la posición 0 a la izquierda: un uno en la 2 y otro en la 7. Corregir es sumar el registro a las primeras diez posiciones de lo recibido. No hay tabla ni lógica de reconocimiento.

02 · Girar hasta capturar

Si los errores no están en la ventana pero están juntos, algún desplazamiento cíclico puede llevarlos ahí. El desplazamiento de orden i de lo recibido, r(i)(X)=RXn+1{Xir(X)}, es otra palabra del código más el patrón girado e(i)(X), porque el código es cíclico. Y su síndrome no hay que calcularlo de nuevo:

s(i)(X)=Rg(X){Xis(X)}

Cada giro de la palabra es un ciclo más del registro de desplazamiento que calculó el síndrome, sin entrada. La captura de errores es este procedimiento, para un código que corrige t errores:

Paso 1: el síndrome y su peso. Se calcula s(X) y se mira su peso w(s), la cantidad de unos.

Paso 2: si pesa t o menos, los errores están capturados. Si w(s(i))≤t, entonces e(i)(X)=s(i)(X), y deshaciendo el giro,

e(X)=RXn+1{Xn−is(i)(X)}

Paso 3: si no, un giro más. Se avanza el registro un ciclo y se vuelve al paso 2, hasta n giros. Si en los n el peso nunca bajó a t, se declara un fallo de decodificación.

En el (15,5), con t=3 y errores en X11 y X13, fuera de la ventana: el síndrome pesa 5, y en los giros siguientes 5, 8 y 5. En el giro 4 el registro tiene 1010000000, que pesa 2, o sea s(4)(X)=1+X2. Deshacer el giro es multiplicar por X15−4=X11: sale X11+X13, el patrón que entró.

El circuito es el registro de síndrome de n−k etapas, un buffer con lo recibido que gira junto con él, y una sola compuerta de umbral de n−k entradas, que vale 1 cuando a lo sumo t están en uno. Donde Meggitt reconoce 106 síndromes, la captura cuenta unos. Lo que se paga es lo mismo, n ciclos por palabra, y algo más: sólo funciona con errores que algún giro meta en la ventana.

03 · Por qué alcanza con mirar el peso

No es evidente que un síndrome liviano sea el error. Podría ser un síndrome cualquiera que, por casualidad, tenga pocos unos. No puede, y la razón es la distancia.

Proposición. Sea un código de distancia mínima dmin≥2t+1 y un patrón con a lo sumo t errores. Entonces w(s(i))≤t si y sólo si s(i)(X)=e(i)(X), es decir, si y sólo si en el giro i todos los errores están en la ventana.

Paso 1: la suma es una palabra. s(i)(X) es el resto de dividir e(i)(X) por g(X), así que e(i)(X)+s(i)(X) es múltiplo de g(X) y tiene grado menor que n: es una palabra del código.

Paso 2: pesa demasiado poco para no ser la nula. Si w(s(i))≤t, esa palabra pesa a lo sumo w(e(i))+w(s(i))≤2t<dmin. Toda palabra no nula pesa al menos dmin: ésta es la nula, y s(i)=e(i).

Paso 3: la vuelta. Si los errores del giro i están en la ventana, la sección 01 da s(i)=e(i), que pesa lo mismo que e: a lo sumo t.

La consecuencia práctica es que, con hasta t errores, la captura nunca corrige mal: o los captura, o recorre los n giros sin que el umbral se dispare y declara el fallo. Medido sobre todos los patrones de peso ≤t del (15,7), el (15,5) y el Golay, ninguno sale mal corregido.

El Paso 2 necesita que el patrón tenga a lo sumo t errores, y sin eso el test se engaña. En el (15,5), cuatro errores en {0,1,2,4} están dentro de la ventana desde el principio, pero el registro pesa 4 y el decodificador sigue girando. En el giro 10 el registro pesa 3, y lo que se corrige es X5+X8+X10: con los cuatro del canal suman siete errores, que son una palabra del código. De los 1365 patrones de peso 4, contados uno por uno, 510 terminan corregidos así, mal, y 855 se declaran.

Simulación El anillo y la ventana de paridad — las n posiciones en círculo; la franja es la ventana, de X⁰ a Xⁿ⁻ᵏ⁻¹, y adentro de ella, una celda por etapa del registro de síndrome. Tocá posiciones para poner errores, apostá, y girá: cada giro mueve los errores un lugar y avanza el registro un ciclo.
Código
Antes de girar: ¿algún giro lo captura?
errores — giro — registro — peso —

Arranca en el (15,5) con un error adentro de la ventana y dos afuera, y el registro pesa 6. Los tres errores no se ven juntos, pero mirá los huecos entre ellos antes de apostar. Después pasá al Golay y poné dos errores a once lugares uno del otro.

04 · Qué patrones entran en la ventana

Por la proposición, un patrón de hasta t errores se captura si y sólo si algún giro lo deja en n−k posiciones consecutivas del anillo, contando la vuelta de Xn−1 a X0. Dicho al revés, que es como se cuenta mejor: hay k posiciones seguidas sin ningún error, porque lo que queda afuera de la ventana son k posiciones.

Con dos errores, el anillo queda partido en dos tramos sin error que suman n−2, y el más largo tiene al menos ⌈(n−2)/2⌉. En el (15,7) de g(X)=1+X4+X6+X7+X8, con dmin=5 y t=2, eso es ⌈13/2⌉=7=k: todo par de errores tiene siete posiciones libres seguidas, justo las que hacen falta. Ahí la captura no es una heurística: corrige todo lo que el código promete. Contados los patrones uno por uno, corriendo el registro, en tres códigos:

códigoventanat1 error2 errores3 errores
(15,7)8 de 15215 de 15105 de 105—
(15,5)10 de 15315 de 15105 de 105450 de 455
Golay (23,12)11 de 23323 de 23230 de 2531035 de 1771

Los que faltan no salen mal corregidos: se declaran. Contados también por la otra vía, buscando una ventana sobre el anillo sin pasar por el registro, salen exactamente los mismos patrones en los tres códigos: es la proposición, verificada patrón por patrón.

El (15,5) y el Golay tienen la misma distancia, 7, y la misma capacidad de corrección, 3. Lo que los separa es la fracción del anillo que cubre la ventana: dos tercios en el (15,5), menos de la mitad en el Golay. En el Golay ⌈21/2⌉=11<12=k, y ya hay dobles que no entran: los dos errores a once lugares por un lado y doce por el otro, como X11+X22. La captura simple corrige ahí 1288 de los 2047 patrones no nulos de peso ≤3, el 62,9 %. Los dos códigos, patrón por patrón, están resueltos en atrapar errores y ráfagas.

La regla de diseño sale de la tabla: la captura rinde cuando n−k es grande frente a n, o sea en códigos de tasa baja o moderada, y se vuelve ineficaz en los largos de tasa alta. Y rinde siempre que los errores vengan agrupados: una ráfaga de largo ≤n−k cabe en la ventana por definición. Por eso es el método de elección de los códigos correctores de ráfagas.

05 · Kasami: unos pocos errores afuera

Para el Golay hacen falta patrones con casi todos los errores en la ventana y uno afuera. La idea de Kasami es adivinar la parte de afuera. Se parte el patrón en dos: eP(X), los errores en las posiciones de paridad, y eI(X), los de las posiciones de mensaje, de Xn−k en adelante.

Paso 1: la parte de mensaje deja un resto. Sea ρ(X)=Rg(X){eI(X)}. Como eP(X) tiene grado menor que n−k, es su propio resto, y el síndrome es la suma de los dos restos: s(X)=eP(X)+ρ(X).

Paso 2: conocida la parte de mensaje, la de paridad sale del síndrome. Despejando, eP(X)=s(X)+ρ(X). La captura simple es el caso eI=0.

Paso 3: una lista corta de candidatos. Se eligen polinomios de cobertura φj(X), de grado menor que k, tales que todo patrón corregible tenga, en algún giro, la parte de mensaje exactamente igual a Xn−kφj(X) para algún j. Sus restos ρj=Rg(X){Xn−kφj(X)} se calculan una vez, y en cada giro una compuerta por candidato prueba

w(s(i)+ρj)≤t−w(φj)

Si la compuerta j se dispara, e(i)=s(i)+ρj+Xn−kφj. El candidato pesa a lo sumo t y tiene el mismo síndrome que el patrón verdadero, así que el argumento de la sección 03 vale igual: con hasta t errores, ninguna compuerta se dispara en falso.

Para el Golay de g1(X)=1+X2+X4+X5+X6+X10+X11 alcanzan tres: φ1=0, φ2=X5 y φ3=X6, un error de mensaje en la posición 16 o en la 17, con umbrales 3, 2 y 2. Los restos son

ρ2=X+X2+X5+X6+X8+X9,ρ3=Xρ2

y el segundo sale del primero sin dividir: X17=X·X16, y Xρ2 tiene grado 10, menor que 11, así que ya es un resto. Medido sobre los 2047 patrones no nulos de peso ≤3, cada compuerta tiene su razón de estar:

compuertascorregidosdeclaradoslo que queda afuera
φ₁128875923 dobles y 736 triples
φ₁, φ₂202423los giros de X⁰ + X⁶ + X¹¹
φ₁, φ₂, φ₃20470nada

La primera fila es la captura simple. La segunda compuerta rescata los 23 dobles y casi todos los triples, y deja afuera un solo patrón con sus 23 giros. La tercera es para ése. Ninguno de los 2047 sale mal corregido. El precio es una compuerta de umbral por polinomio de cobertura, y encontrar el conjunto no es fácil. Con n y t grandes las compuertas se vuelven demasiadas: el método sirve en códigos cortos y de tasa baja.

06 · La búsqueda sistemática

La otra forma de llevar el Golay a sus tres errores usa una sola compuerta. Se apoya en un hecho del anillo de 23: en todo patrón de tres errores o menos hay al menos un error que, sacado, deja a los demás dentro de once posiciones consecutivas. Medido: vale en los 2047.

Paso 1: la captura simple. Se gira con umbral 3. Si se captura, listo.

Paso 2: invertir un dígito y volver a capturar. Si no, se invierte un dígito de lo recibido y se repite la captura con umbral 2. Si el umbral se dispara, ese dígito estaba mal y el registro tiene los otros dos errores. Si no, se lo vuelve a invertir y se prueba con el siguiente.

Invertir un dígito correcto no engaña al umbral. Deja un patrón de a lo sumo cuatro errores, y un registro de peso ≤2 sumaría con él una palabra de peso ≤6<7: la nula. Eso pasa sólo si el patrón invertido tiene a lo sumo dos errores, o sea si el original tenía a lo sumo uno, y a ése ya lo había capturado el Paso 1.

La condición dice «un error», no «un error de mensaje», y la diferencia importa. En X0+X11+X12, sacar X11 deja X0+X12, a once lugares por un lado y doce por el otro: no entra. Sacar X12 deja X0+X11, igual. El que hay que sacar es X0, que está en la paridad. Probando sólo los doce dígitos de mensaje de lo recibido quedan once patrones sin corregir, los {i,i+11,i+12} con i=0,…,10: corrige 2036 de 2047. La búsqueda tiene que hacer pasar cada una de las 23 posiciones por la inversión, girando la palabra para que todas atraviesen la zona de mensaje. Así corrige los 2047.

Frente a Kasami, una compuerta en vez de tres, pagada en tiempo: cada dígito que se prueba es otra vuelta entera del registro, y la lógica de temporizado que ordena las inversiones es más compleja.

07 · La cuenta en Python

El decodificador entero, con listas de bits: el registro divisor, la compuerta de umbral y el giro que se deshace al final. Cuenta los patrones capturados de los tres códigos de la sección 04. Lo de los comentarios es la salida de correrlo.

from itertools import combinations

def reloj(s, g, entrada=0):
    """Un ciclo del registro divisor por g: s' = X s + entrada mod g."""
    f = s[-1]
    return [entrada ^ f] + [s[j - 1] ^ (g[j] & f) for j in range(1, len(s))]

def sindrome(r, g):
    s = [0] * (len(g) - 1)
    for bit in reversed(r):          # entra r_{n-1} primero
        s = reloj(s, g, bit)
    return s

def capturar(r, g, t):
    """El patrón de error y el giro que lo capturó, o (None, None)."""
    n, nk = len(r), len(g) - 1
    s = sindrome(r, g)
    for i in range(n):
        if sum(s) <= t:              # la compuerta de umbral
            e_i = s + [0] * (n - nk) # e^(i) = s^(i)
            return e_i[i:] + e_i[:i], i
        s = reloj(s, g)              # un giro sin entrada
    return None, None

def contar(n, g, t, w):
    ok = 0
    for pos in combinations(range(n), w):
        e = [int(j in pos) for j in range(n)]
        ok += capturar(e, g, t)[0] == e
    return ok

g157 = [1, 0, 0, 0, 1, 0, 1, 1, 1]          # 1 + X⁴ + X⁶ + X⁷ + X⁸
g155 = [1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1]    # 1 + X + X² + X⁴ + X⁵ + X⁸ + X¹⁰
gol = [1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1]  # 1 + X² + X⁴ + X⁵ + X⁶ + X¹⁰ + X¹¹
for nombre, n, g, t in [("(15,7)", 15, g157, 2), ("(15,5)", 15, g155, 3), ("Golay", 23, gol, 3)]:
    print(nombre, [contar(n, g, t, w) for w in range(1, t + 1)])
# (15,7) [15, 105]
# (15,5) [15, 105, 450]
# Golay [23, 230, 1035]

e = [int(j in (11, 13)) for j in range(15)]
print(capturar(e, g155, 3))
# ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0], 4)

El giro se deshace con e_i[i:] + e_i[:i]: rotar i lugares hacia la izquierda es multiplicar por Xn−i. En el circuito ese paso no existe, porque el buffer gira junto con el registro y la corrección se aplica a medida que los dígitos salen.

Para tener a mano

  1. Si e(X) tiene grado menor que n−k, entonces s(X)=e(X): con los errores en la ventana de paridad, el síndrome es el error.
  2. Captura: girar el registro, s(i)=Rg(X){Xis}, hasta que pese ≤t; entonces e=RXn+1{Xn−is(i)}. Si en n giros no baja, fallo declarado. Una compuerta de umbral en vez de una tabla.
  3. El test de peso es necesario y suficiente con hasta t errores: s+e sería una palabra de peso ≤2t<dmin. Nunca corrige mal: captura o declara. Con más de t sí puede corregir mal.
  4. Se captura si y sólo si hay k posiciones seguidas sin error en el anillo. (15,7): todo, porque ⌈13/2⌉=7. (15,5): todos los dobles y 450 de 455 triples. Golay: 230 de 253 dobles y 1035 de 1771 triples.
  5. Rinde con n−k grande frente a n y con ráfagas de largo ≤n−k.
  6. Kasami: eP=s+Rg{eI}, y una compuerta por polinomio de cobertura. En el Golay, 0,X5,X6 con umbrales 3, 2, 2: 1288, 2024 y 2047 corregidos al sumar cada una.
  7. Búsqueda sistemática: invertir un dígito y capturar con umbral 2. El error que hay que sacar puede estar en la paridad: todas las posiciones tienen que pasar por la inversión, o quedan los once {i,i+11,i+12}.
← Anterior Siguiente → Inicio
Relacionados El síndrome cíclico El decodificador de Meggitt El código de Golay Los CRC y los códigos cíclicos acortados Atrapar errores y ráfagas