Unidad 4 · Las familias · canales con ráfagas, el intercalador de bloque y sus ⌈b/λ⌉ errores por palabra, lo que cuesta, el convolucional y la condición en la que cuesta la mitad, y la cadena del OIF-400ZR
Todos los códigos de la unidad se diseñan contra errores sueltos: cada símbolo se equivoca por su cuenta. Los canales reales se equivocan de a muchos seguidos. El intercalado no cambia el código ni le agrega redundancia: cambia el orden en que sus símbolos pasan por el canal, para que una ráfaga llegue a cada palabra como unos pocos errores sueltos.
El canal binario simétrico invierte cada bit con probabilidad , independiente de lo que pasó con el anterior. Describe bien un canal dominado por ruido térmico. No describe un desvanecimiento en un enlace de radio, una rayadura en un disco, un transitorio de conmutación o una no linealidad en la fibra: ahí, si un símbolo salió mal, es probable que el siguiente también. El canal tiene memoria, y los errores llegan agrupados.
Una ráfaga de longitud es un tramo de símbolos consecutivos del canal donde caen los errores. Contra un código con capacidad de corrección , lo que importa no es cuántos errores hay sino cómo se reparten. Con el Hamming (7,4), que corrige , una ráfaga de 3 que cae entera en una palabra la arruina; los mismos 3 errores, uno en cada una de tres palabras, se corrigen los tres. El problema es la concentración.
Hay códigos diseñados para corregir ráfagas. La solución que domina en la práctica es otra: no tocar el código y transformar el canal.
Un intercalador de bloque de profundidad junta palabras de código de largo en un arreglo de filas por columnas, una palabra por fila, y lo transmite leyéndolo por columnas: primero el símbolo 0 de las palabras, después el símbolo 1 de todas, y así. Con la palabra de la fila , su símbolo viaja en la ranura
El desintercalador hace la inversa: escribe por columnas los símbolos que llegan y entrega las filas al decodificador, en el orden original. Entre los dos, el decodificador ve las mismas palabras de siempre; sólo el canal vio otro orden.
El ejemplo del apunte es el (7,4) con : un arreglo de 4 × 7 que sale al canal como 28 símbolos. Una ráfaga de 7 que arranca en la ranura 2 toca las ranuras 2 a 8, que son de las palabras 2, 3, 0, 1, 2, 3, 0. Desintercalado, deja 2, 1, 2 y 2 errores en a . Sin intercalar, la misma ráfaga sobre las mismas 28 posiciones deja 5 en una palabra y 2 en la siguiente.
Paso 1: las ranuras recorren las filas en ciclo. La ranura es de la palabra . Dos ranuras consecutivas son de filas consecutivas, y la sucesión de filas se repite con período .
Paso 2: en ranuras seguidas hay una de cada palabra. Cualquier tramo de ranuras consecutivas recorre los restos módulo una vez cada uno, empiece donde empiece. Dentro del mismo arreglo eso es una ranura por palabra; si el tramo cruza al arreglo siguiente, las ranuras del final y las del principio son de palabras distintas, y la cuenta por palabra sólo puede bajar.
Paso 3: se cortan las ranuras en tramos de . Una ráfaga de ranuras se parte en tramos de a lo sumo . Cada tramo le aporta a una palabra a lo sumo un error:
Y de ahí el corolario: si , cada palabra recibe a lo sumo errores y el decodificador de siempre corrige la ráfaga entera. La cota es justa: una ráfaga de que arranca en la ranura 0 toca en las ranuras , que son . La profundidad se elige entonces por la ráfaga más larga que se espera del canal: .
El conjunto de los arreglos transmitidos es otro código lineal, de parámetros : la misma tasa y la misma distancia mínima que el original, porque cada arreglo son palabras del original, y el de menor peso no nulo es una sola de ellas con las demás en cero. El intercalado no agrega redundancia: reordena.
Con numpy, intercalar es transponer y aplanar. Desintercalar es la inversa, y ahí está la trampa: reshape llena por filas, así que el flujo hay que cortarlo en tramos de —uno por columna del arreglo— y recién después transponer:
import math
import numpy as np
def intercalar(palabras):
"""λ palabras, una por fila (λ × n) → el flujo leído por columnas."""
return palabras.T.flatten()
def desintercalar(flujo, lam, n):
"""La inversa: se escribe por columnas y se lee por filas."""
return flujo.reshape(n, lam).T
def errores_por_palabra(lam, n, b, inicio):
e = np.zeros(lam * n, dtype=np.uint8)
e[inicio:inicio + b] = 1 # la ráfaga, en el canal
return desintercalar(e, lam, n).sum(axis=1)
lam, n, b = 4, 7, 7
print(errores_por_palabra(lam, n, b, 2).tolist())
# [2, 1, 2, 2]
peor = max(errores_por_palabra(lam, n, b, i).max() for i in range(lam * n - b + 1))
print(int(peor), math.ceil(b / lam))
# 2 2
e = np.zeros(lam * n, dtype=np.uint8)
e[2:2 + b] = 1
print(e.reshape(lam, n).sum(axis=1).tolist()) # sin la transpuesta
# [5, 2, 0, 0]
La última línea es el error que da reshape(lam, n) sin transponer: vuelve a cortar el flujo en tramos consecutivos de , que es exactamente no haber intercalado, y la ráfaga queda amontonada en una palabra. El peor caso sobre las 22 posiciones de arranque posibles es 2, que es .
Las ventajas se pagan en memoria y en retardo. El apunte cuenta el arreglo entero, símbolos en cada extremo, y un retardo del orden de . El mínimo exacto sale de un modelo explícito: entra un símbolo por tiempo de símbolo, sale uno por tiempo de símbolo, y nada sale antes de haber llegado.
Paso 1: cuándo llega cada símbolo. Contando desde el principio del arreglo, el símbolo de llega en el instante .
Paso 2: cuándo puede salir. Si el canal arranca en , ese símbolo sale en . Tiene que ser después de haber llegado para todo y todo :
El peor es , : la primera columna necesita el primer símbolo de la última palabra.
Paso 3: el receptor, al revés. El desintercalador tiene que entregar en orden, y el que más se hace esperar es el último símbolo de la primera palabra, que viaja en la última columna. Por la misma cuenta agrega otros , y el retardo mínimo de punta a punta es
Paso 4: la memoria. En cada extremo entra un símbolo y sale uno por tiempo de símbolo, corridos : adentro hay siempre esa cantidad. Contado con un modelo de eventos —cada símbolo ocupa una celda desde que llega hasta que sale, arreglo tras arreglo— da eso mismo, en régimen y en los dos extremos. En el (7,4) con son 18 símbolos por extremo y 36 de retardo, contra los 28 y 56 de contar el arreglo entero. Implementado como un arreglo que se llena y se vacía, se reservan los ; los 18 son el piso.
El intercalador convolucional evita el arreglo y trabaja sobre un flujo continuo. Tiene ramas, que son líneas de retardo de celdas, y dos conmutadores sincronizados que las recorren en ciclo, una rama por símbolo. El símbolo de la entrada entra por la rama . Esa rama avanza una celda cada vez que el conmutador vuelve a ella, o sea cada símbolos, así que el símbolo sale al canal en
Con λ = 4 y J = 2: las dos mitades tienen las ramas en orden inverso, y cada símbolo pasa por (λ − 1)J = 6 celdas de su rama.
El retardo es el mismo para todos. El desintercalador tiene las mismas ramas en orden inverso: la rama retarda celdas. Un símbolo de la rama espera instantes de un lado y del otro, y en total
sea cual sea su rama. Por eso a la salida el flujo vuelve al orden original, entero, con un corrimiento fijo.
La memoria es la suma de las ramas. En cada extremo,
celdas, que están siempre llenas. Y emite un símbolo por cada símbolo que recibe desde el primer instante: no hay arreglo que llenar. Lo que sí hay que decidir es , y de eso depende todo lo que sigue. Probalo abajo: con el (7,4) y , mirá qué ráfaga aguanta con y con .
Con el canal lleva las palabras enteras, una detrás de otra, y la ráfaga de 3 cae en una sola. Subí a 4: cada renglón del canal pasa a alternar las cuatro palabras, y para dejar dos errores en una hace falta una ráfaga de 5. Arrastrala —o movela con las flechas— y buscá dónde duele. En el convolucional, con el mismo , el número de abajo es la ráfaga más larga que se corrige en cualquier lugar del flujo; con chico se derrumba. Con el (8,4) y , poné y prendé «palabras corridas».
El apunte y la filmina dicen que, a igual capacidad de dispersar ráfagas, el convolucional usa aproximadamente la mitad de memoria y la mitad de retardo que el de bloque equivalente. Para medirlo hay que fijar qué es «equivalente». Acá: la misma profundidad , y el más chico con el que el convolucional corrige, como el de bloque, toda ráfaga de hasta en cualquier lugar del flujo. El modelo: palabras de símbolos consecutivos de la entrada, el símbolo sale en , y se cuenta cuántos errores le deja a cada palabra una ráfaga en cada posición del canal, ya en régimen.
El J mínimo. Barriendo , y de 2 a 8, el mínimo es, en todos los casos,
si la primera palabra entra por la rama 0, y si no,
Con ese , los símbolos de una misma palabra quedan en el canal a ranuras o más unos de otros, como en el de bloque. Un menos y la garantía se derrumba: el (15,11) con y ya no aguanta ni una ráfaga de 2, y el Golay (24,12), con , y , corrige hasta 15, no hasta 21. Si no divide a , las palabras arrancan en todas las ramas por turno y las dos fórmulas dan lo mismo. Si lo divide, todas arrancan en la misma rama, y que sea la 0 vale una celda por rama: corrido un símbolo, el (15,11) con y vuelve a no aguantar una ráfaga de 2, y necesita .
La razón. Con el de bloque en su mínimo, memoria y retardo dan la misma razón, porque los dos lados escalan igual:
Como , la razón es por lo menos : siempre un poco más que la mitad, y tiende a la mitad cuando divide a , las palabras entran alineadas con la rama 0 y es largo. Medidas con el modelo de eventos —las ocupaciones y los retardos, no las fórmulas—:
| código | λ | J | ráfaga que corrige | memoria conv / bloque | retardo conv / bloque | razón | contra λn |
|---|---|---|---|---|---|---|---|
| (7,4) | 4 | 2 | 4 | 12 / 18 | 24 / 36 | 0,667 | 0,429 |
| (15,11) | 5 | 3 | 5 | 30 / 56 | 60 / 112 | 0,536 | 0,400 |
| (24,12) | 4 | 6 | 12 | 36 / 69 | 72 / 138 | 0,522 | 0,375 |
| (24,12) | 7 | 4 | 21 | 84 / 138 | 168 / 276 | 0,609 | 0,500 |
| (24,12) | 8 | 3 | 25 | 84 / 161 | 168 / 322 | 0,522 | 0,438 |
| (128,119) | 16 | 8 | 16 | 960 / 1905 | 1920 / 3810 | 0,504 | 0,469 |
La última columna compara contra la cuenta del apunte, el arreglo entero: por extremo y de retardo. Contra eso la razón es , y queda por debajo de la mitad cuando . La fila del Golay con corrige 25, uno más que los del de bloque: cada palabra tiene sólo 3 símbolos por rama.
Así que la afirmación vale en su versión aproximada, y con condiciones: que divida a , que las palabras entren alineadas con la rama 0, y palabras largas. El (128,119) con está en 0,504. Cuando no divide a , se redondea para arriba y la razón sube: el (7,4) con cuesta dos tercios. Y con las palabras corridas, el (15,11) con necesita y cuesta 20/28 = 0,714.
El de bloque tiene fronteras: el desintercalador tiene que saber dónde empieza cada arreglo, y desalineado un solo símbolo mezcla palabras y su salida no sirve. Hay alineaciones posibles y una sola es la buena. El convolucional no tiene arreglos: el desintercalador sólo necesita saber en qué rama está el conmutador, una referencia de fase entre posibles. Del lado del transmisor, la sección anterior agrega una condición barata, porque codificador e intercalador están en el mismo lugar: hacer que cada palabra arranque en la rama 0.
No corrige más errores sueltos. El código intercalado tiene la misma y la misma tasa que el original. Sobre un canal sin memoria, reordenar no cambia nada: un canal que se equivoca en cada símbolo por su cuenta lo sigue haciendo en cualquier orden.
La garantía es para una ráfaga. Dos ráfagas cortas en el mismo arreglo suman. En el (7,4) con , una ráfaga en las ranuras 0 y 1 y otra en la 4 y la 5 dejan dos errores en y dos en , aunque cada una por separado medía 2, la mitad de lo que el arreglo aguanta.
Y se paga en retardo. La profundidad sale de la ráfaga más larga del canal, , y el retardo crece con . En muchos sistemas es esa latencia, y no la capacidad de corrección, lo que fija el diseño. El convolucional la recorta, pero no la saca.
El código producto es el mismo mecanismo visto desde adentro: transmitido fila por fila, cada columna es una palabra intercalada con profundidad igual al largo de las filas, y la ráfaga que aguanta depende del orden en que salen los símbolos, no del código. Eso es la ráfaga la corrige el orden.
El esquema C-FEC del OIF-400ZR, el del trabajo práctico final, concatena tres piezas de esta unidad. En el transmisor: un código exterior tipo producto, el staircase sobre BCH (255,239); un intercalador convolucional; y un código interior, el Hamming extendido y acortado (128,119). Después, el mapeo a DP-16QAM y la fibra. En el receptor, el camino inverso: el Hamming decodifica con decisión blanda, el desintercalador reordena, y el código exterior decodifica con decisión dura.
La ráfaga que este intercalador desarma no es sólo la del canal: la produce también el decodificador interior. Cuando elige mal, la palabra que entrega difiere de la transmitida en una palabra no nula del (128,119), con porque acortar no la baja: por lo menos 4 bits mal, todos dentro de los mismos 128. Para el código exterior eso es una ráfaga, y el desintercalador la reparte entre muchas de sus palabras antes de que las vea. La tarea del Hamming no es entregar datos limpios: es bajar la tasa de error hasta donde el exterior, con su capacidad de corrección, la puede terminar.