Unidad 3 · Códigos de bloque lineales · la regla de máxima verosimilitud, los cosets y sus líderes, la tabla de síndromes, los empates y la decodificación incompleta
El síndrome dice algo exacto y algo insuficiente. Lo exacto: depende sólo del patrón de error, no de lo que se mandó. Lo insuficiente: en el (7,4) cada síndrome es compatible con patrones distintos, y el decodificador tiene que apostar por uno. El standard array es esa apuesta hecha de una vez para los vectores que pueden llegar. La decodificación por síndrome es la misma apuesta guardada en una tabla de renglones.
Sobre un canal binario simétrico que da vuelta cada bit con probabilidad , independiente de los demás, un patrón de peso en una palabra de bits tiene probabilidad
Pasar de peso a multiplica esa probabilidad por , que es menor que 1 mientras . Entre los patrones que comparten síndrome, entonces, el más probable es el de menor peso. Elegirlo es la regla de máxima verosimilitud.
Es también la regla de mínima distancia. Si llegó , la distancia de a la palabra de código es . Suponer el patrón más liviano es lo mismo que entregar la palabra más cercana a lo recibido.
Con palabras equiprobables, ninguna regla tiene menos probabilidad de entregar una palabra equivocada. Pero óptima no quiere decir infalible. Si el canal metió un patrón pesado y hay otro más liviano con el mismo síndrome, el decodificador elige el liviano y entrega otra palabra. La distancia mínima garantiza corregir cualquier patrón de hasta errores, la capacidad de corrección. Qué corrige la regla de verdad, patrón por patrón, lo dice el arreglo.
El standard array reparte los vectores de en una tabla de filas por columnas. Se arma fila por fila.
Paso 1: la primera fila es el código. Las palabras, empezando por la nula. Cada una encabeza una columna.
Paso 2: el líder es el más liviano que queda. Entre los vectores que todavía no aparecen en la tabla se elige uno de peso mínimo, , y va a la primera columna.
Paso 3: la fila es el líder más el código. Debajo de la palabra va . Debajo de la nula queda el propio .
Paso 4: repetir hasta agotar. Cuando todos los vectores de están en la tabla, se termina.
Cada fila es un coset del código, el conjunto , y el vector que la encabeza es su líder de coset. Cada fila agrega vectores nuevos, sin repetir ninguno (lo prueba la sección siguiente), así que las filas son . En el (7,4), 8 filas de 16.
Cada vector aparece una sola vez. Dentro de una fila, obliga a . Entre filas: si un vector estuviera en la fila de y en la de un líder posterior , sería , o sea . La suma de dos palabras es palabra, así que ya estaba en la fila de . Pero se lo eligió entre los que no estaban.
Dos vectores de una fila difieren en una palabra. : el líder se cancela.
Una fila, un síndrome, y al revés. Con la matriz de paridad, toda palabra cumple , y entonces : la fila entera comparte el síndrome de su líder. Dos filas no lo comparten: si , entonces es palabra y estaba en la fila de , el mismo absurdo de antes.
La tercera es la que hace práctico al arreglo. Hay exactamente tantas filas como síndromes posibles, , y el síndrome de lo recibido dice en qué fila cayó sin tener que buscarlo.
Llega y se lo ubica en el arreglo. El líder de su fila es el patrón que se supone, , y el encabezado de su columna es lo que se entrega:
Como el líder es el vector más liviano de la fila, es exactamente la regla de la sección 01.
De ahí sale lo más útil del arreglo: un patrón se corrige si y sólo si es un líder. Si se mandó y el canal metió , lo recibido cae en la misma fila que , porque difieren en una palabra. Si es el líder, se entrega . Si no lo es, el líder es otro vector y se entrega . Hay patrones corregibles, uno por fila, y ni uno más.
En el (7,4) son 8 de 128: la palabra nula y los siete errores simples. Ese es lo que hace perfecto al (7,4). En el (8,4), el mismo código con un bit de paridad global y , son 16 de 256: la nula, los 8 errores simples y 7 de los 28 dobles. Ahí y sin embargo se corrigen siete patrones de peso 2. es lo que se garantiza para todo patrón de ese peso, no lo único que se corrige.
Contando los líderes por peso, de peso , la probabilidad de que el decodificador entregue una palabra equivocada sale directa:
En el (7,4), y , y con da . Cuánto vale esto medido en —la ganancia de codificación, y el cruce del (7,4) con no codificar en 5,85 dB— está en «El código que todos inventan primero no paga nunca».
En el (7,4), cualquier vector que toques cae en una fila cuyo líder pesa 0 o 1, y el aviso dice lo mismo cada vez: se acierta sólo si el canal metió justo ese líder. Con 16 vectores por fila, quedan quince maneras de haber llegado ahí. En el (8,4) aparecen filas con un líder de peso 2, y con ellas cuatro candidatos en rojo. Ahí el botón «Otro líder» se habilita, y vale la pena apretarlo con un vector elegido para ver qué pasa con su columna.
En el (7,4) no hay nada que elegir: cada fila tiene un solo vector de peso mínimo. En el (8,4), las siete filas cuyo líder pesa 2 tienen cuatro vectores de peso 2 cada una —los 28 dobles se reparten así, siete por cuatro—, y los cuatro son igual de probables. Cuál encabeza la fila es una elección arbitraria, y no es inocente. Dos candidatos y de la misma fila difieren en una palabra, , que en el (8,4) pesa 4. Cambiar de líder le suma esa palabra a todo lo que la fila entrega. Medido en las siete filas y con cada candidato alternativo: cambia la palabra entregada en las 16 celdas de la fila. Mismo vector recibido, mismo síndrome, otra palabra.
Un empate sólo puede pasar por encima de . Dos vectores de peso a lo sumo en la misma fila diferirían en una palabra de peso a lo sumo , y esa palabra no existe. Por eso un líder de peso es único, y es el que se corrige con garantía.
Al revés no vale: que el líder pese más que no obliga a empatar. El (7,1) cuya única palabra no nula es 1100001 tiene y . De sus 64 filas, 56 tienen un líder de peso entre 2 y 5, y ninguna tiene empate. Cada fila son dos vectores, y , y como esa palabra pesa 3, sus pesos tienen distinta paridad: nunca coinciden. El coset de 0110000, por ejemplo, es {0110000, 1010001}, con un único vector de peso 2.
Y con decodificación completa, el bit de más del (8,4) no compra nada. Sus líderes son , y , y sacando factor común los dos códigos dan lo mismo:
A la izquierda, lo que queda del (8,4); a la derecha, lo que queda del (7,4). Las dos tienen , para todo : los siete dobles que el (8,4) corrige pagan exactamente lo que cuesta exponer un bit más al canal. Para que el octavo bit sirva hay que cambiar de decodificador.
La decodificación incompleta corrige sólo en las filas cuyo líder pesa . Para los demás síndromes declara falla y levanta una bandera, en vez de apostar. Renuncia justo a las apuestas más flojas, que es donde viven los empates, y en un sistema con retransmisión una bandera vale más que una corrección dudosa.
Lo que no trae es una promesa sobre los errores grandes. La bandera se levanta cuando está a distancia mayor que de todas las palabras, fuera de toda esfera de radio , y nada más. Un patrón pesado que deja a adentro de la esfera de otra palabra se corrige hacia esa otra palabra, en silencio, igual que con la decodificación completa. Medido sobre los 255 patrones no nulos del (8,4), mandando cualquier palabra:
| peso del error | patrones | bandera | bien corregidos | mal, en silencio |
|---|---|---|---|---|
| 1 | 8 | 0 | 8 | 0 |
| 2 | 28 | 28 | 0 | 0 |
| 3 | 56 | 0 | 0 | 56 |
| 4 | 70 | 56 | 0 | 14 |
| 5 | 56 | 0 | 0 | 56 |
| 6 | 28 | 28 | 0 | 0 |
| 7 | 8 | 0 | 0 | 8 |
| 8 | 1 | 0 | 0 | 1 |
| todos | 255 | 112 | 8 | 135 |
Los patrones de peso impar desde 3 dejan a a distancia 1 de alguna palabra y salen mal sin aviso. Los 14 de peso 4 que no avisan y el de peso 8 son palabras de código, que ningún síndrome ve. Con , la incompleta entrega en silencio una palabra equivocada con probabilidad y levanta la bandera con . La completa se equivoca, siempre en silencio, con .
En el (7,4) la incompleta no se distingue de la completa. Es perfecto: sus esferas de radio 1 cubren entero, ningún queda afuera y la bandera no se levanta nunca. Los 120 patrones de peso 2 o más salen mal, todos en silencio.
Del arreglo se puede tirar todo menos la primera columna. Como el síndrome identifica la fila, decodificar son tres pasos:
Paso 1: calcular el síndrome, .
Paso 2: buscar el líder que la tabla tiene para ese .
Paso 3: entregar . Con el código en forma sistemática, el mensaje son sus primeras posiciones.
La tabla tiene entradas en lugar de . La del (7,4), con la del apunte y los vectores escritos con la posición 0 a la izquierda:
| síndrome s | líder ê | qué supone |
|---|---|---|
| 000 | 0000 000 | sin errores |
| 110 | 1000 000 | error en la posición 0 |
| 011 | 0100 000 | error en la posición 1 |
| 111 | 0010 000 | error en la posición 2 |
| 101 | 0001 000 | error en la posición 3 |
| 100 | 0000 100 | error en la posición 4 |
| 010 | 0000 010 | error en la posición 5 |
| 001 | 0000 001 | error en la posición 6 |
Salvo el nulo, cada síndrome es una columna de . Que un error simple en la posición dé vale en cualquier código: el síndrome es la suma de las columnas de donde hubo error. Lo particular del (7,4) es lo otro, que los siete síndromes no nulos sean todos errores simples y no sobre ninguno para un patrón más pesado. Pasa porque sus siete columnas son los siete vectores no nulos de 3 bits: es el otra vez.
El costo sigue siendo exponencial, ahora en la redundancia. Un (255,239) necesita una tabla de líderes, y su arreglo tendría celdas: nadie lo construye, se lo estudia porque dice qué hace un decodificador óptimo. Por eso los códigos que vienen imponen estructura. Los cíclicos de la Unidad 5 y los BCH de la Unidad 6 calculan el patrón de error a partir del síndrome, en vez de buscarlo.
El decodificador del (7,4) del curso es la tabla de síndromes en hardware. Un bloque calcula los tres bits del síndrome con compuertas XOR, y el corrector traduce el síndrome a una posición, arma un patrón de un solo bit y lo suma a lo recibido:
always_comb begin
case (i_syndrome)
3'b011: error_position = 3'd0; //h0
3'b110: error_position = 3'd1; //h1
3'b111: error_position = 3'd2; //h2
3'b101: error_position = 3'd3; //h3
3'b001: error_position = 3'd4; //h4
3'b010: error_position = 3'd5; //h5
3'b100: error_position = 3'd6; //h6
default: error_position = 3'd0;
endcase
end
always_comb begin
estimated_error = 7'd0;
estimated_error[error_position] = 1'b1;
end
assign corrected_message = (i_zero_syndrome) ? i_message : (i_message ^ estimated_error);
El detalle que confunde está en los literales. El bus del síndrome se empaqueta como {s2, s1, s0}, con en el bit 0, y un literal de Verilog escribe el bit más alto a la izquierda. La tabla de arriba escribe al revés, con la posición 0 a la izquierda. Así la columna —, , — aparece en el case como 3'b011. Son los mismos tres bits leídos desde la otra punta, y los siete casos son las siete columnas de dadas vuelta. Los dos que no cambian, y , son palíndromos.
El síndrome nulo cae en el default, que apunta a la posición 0. No la invierte porque la última línea entrega i_message tal cual cuando i_zero_syndrome está en alto. Y es un decodificador completo: la salida o_is_corrected sólo dice que el síndrome no fue nulo, no que la corrección haya salido bien. Con dos errores también se levanta, y lo entregado está mal. Simulado sobre los 2048 casos —los 16 mensajes por los 128 patrones de error—, el mensaje que entrega coincide en todos con el de la tabla de síndromes.
1100001 ninguna. Cambiar de candidato cambia lo entregado en toda la fila.{s2, s1, s0}, la columna se escribe 3'b011.