Unidad 6 · Ecualizadores adaptativos · taps a T/2 contra taps a T, el espectro plegado y la fase de muestreo, el FIR finito que ecualiza exacto, el leakage y el análisis en MATLAB
En la cadena canal → AGC → ecualizador → slicer, esta nota mira la entrada del ecualizador: a qué ritmo muestrea. Todos los scripts de la unidad ecualizan con taps separados , no , y la razón es una sola: muestrear a la tasa de símbolo pliega el espectro, y según el instante en que caiga el reloj las réplicas se suman o se cancelan en el borde de banda. Lo que se canceló ahí ya no se recupera. A no hay nada que plegar, y el instante deja de importar.
El ecualizador fraccionario (FSE, fractionally spaced equalizer en la filmina) es un FIR transversal cuyos retardos valen . En el diagrama de la cátedra la señal pasa por un filtro antialiasing genérico (AAF), se muestrea en , entra a , y recién a la salida se toma una muestra por símbolo, en :
con y la fase de muestreo: dónde cayó el reloj del receptor respecto del pico del pulso. El error existe una vez por símbolo, porque hay un solo símbolo por período con el cual comparar, y con él se corrigen los taps.
El contraste es el ecualizador a tasa de símbolo: muestrea primero, a , y filtra después con taps separados :
Los dos son el mismo FIR transversal con otro espaciado, y los dos entregan una salida por símbolo. Lo que cambia es qué ven: uno la señal ya muestreada a , el otro a . En todo lo que sigue el pulso es el de los scripts: raíz de coseno realzado en el transmisor, con rolloff (en B_FSE_equalizer.m se llama BETA).
Sea el pulso total que llega al muestreador —transmisor, canal y filtro del receptor— y su transformada. Lo que el ecualizador a tasa de símbolo recibe de cada símbolo es la secuencia .
Paso 1: el corrimiento es una fase. Muestrear en es muestrear en el pulso adelantado , cuyo espectro es .
Paso 2: muestrear a suma réplicas corridas . Es el espectro plegado de la nota de la ISI, ahora con la fase adentro:
Paso 3: cada réplica gira distinto. La réplica lleva un factor propio: con las réplicas ya no se suman en fase. Donde no se tocan no pasa nada, porque hay una sola. Con un pulso total coseno realzado y sin canal, eso es : el plegado vale 1 en módulo, sea cual sea . En el flanco se pisan dos réplicas, la propia con peso y la vecina con , que es justo lo que hace plano al coseno realzado. Con el giro relativo entre las dos:
con , que recorre de a desde el comienzo del flanco hasta el borde de banda.
Paso 4: el borde de banda. En las dos réplicas pesan lo mismo, , y queda
Con el reloj en el pico las réplicas se suman y el plegado es plano. Al correrlo, cavan un pozo en el borde de banda: −0,44 dB con , −3,01 dB con , −10,20 dB con , y con un cero exacto: las dos réplicas llegan iguales y en contrafase. Es la forma cerrada; integral sobre la suma de réplicas da lo mismo en MATLAB. El pozo no depende del rolloff, pero su ancho sí: el flanco mide en unidades de , y con no habría flanco que plegar.
Un zero forcing pondría : con es infinito en el borde, y cerca de ahí levanta el ruido tanto como la señal. El que minimiza el error cuadrático medio hace un trato frecuencia por frecuencia. Con símbolos de potencia 1, ruido blanco de varianza en cada muestra y taps infinitos, en cada frecuencia es un Wiener escalar, y el MSE es
Donde la señal le gana al ruido, el error es chico; donde el pozo baja la señal por debajo de , el integrando se acerca a 1 y esa frecuencia se pierde. El ruido sale blanco a la tasa de símbolo porque pasó por la raíz del receptor y el coseno realzado es de Nyquist; eso vale para cualquier . La integral se resuelve cerrada.
Paso 1: la parte plana. En un tramo de ancho el plegado vale 1 y aporta .
Paso 2: los flancos, en la variable . Cada uno mide y lo recorre de a , así que . Los dos flancos juntos aportan
Paso 3: una integral de tabla. Con , . Con y :
La fase de muestreo entra en un solo lugar: , el pozo contra el ruido. Con da , el piso que pone el ruido. Con el segundo término pasa a valer : proporcional a , no a . Por eso la pérdida en dB crece con la SNR: con son 4,49 dB a 20 dB de SNR y 8,53 dB a 30 dB; con , 7,42 y 12,13 dB. Más rolloff es más flanco donde las réplicas se pueden cancelar.
Con taps finitos es peor, porque invertir un pozo angosto pide una respuesta al impulso larga. MSE mínimo (Wiener, eligiendo el mejor retardo de decisión) con SNR de 20 dB, y la raíz del transmisor repetida en el receptor:
| τ / T | pozo en 1/2T | 21 taps a T | infinitos a T | 21 taps a T/2 |
|---|---|---|---|---|
| 0 | 0 dB | −20,04 dB | −20,04 dB | −20,04 dB |
| 0,1 | −0,44 dB | −20,00 dB | −20,00 dB | −20,04 dB |
| 0,25 | −3,01 dB | −19,70 dB | −19,70 dB | −20,04 dB |
| 0,4 | −10,20 dB | −18,14 dB | −18,52 dB | −20,04 dB |
| 0,5 | −∞ | −12,89 dB | −15,56 dB | −20,04 dB |
La columna de taps infinitos es la forma cerrada, y coincide con integral sobre la suma de réplicas al centésimo. Con el de tasa de símbolo da −9,40 dB con 5 taps, −11,22 con 11, −12,89 con 21, −14,46 con 41 y −15,34 con 81: se arrima al −15,56 de taps infinitos y no lo pasa. Hay dos pérdidas apiladas. La que se va con taps es la de no poder armar un inverso angosto; la otra, 4,49 dB, no se va con nada, porque lo que se canceló al plegar ya no está en las muestras.
A las réplicas quedan corridas , y la señal ocupa hasta , que con nunca pasa de . En la banda que ve el FSE, de a , hay una sola réplica:
El módulo es el del pulso, entero, para cualquier . La fase de muestreo quedó reducida a : un retardo, y un FIR que ya está ecualizando se lo come corriendo sus taps. Medido con las mismas condiciones de la tabla, el FSE de 21 taps da −20,04 dB en todas las fases; con 5 taps, también. Recién con 3 se le nota la fase: −19,55 dB en .
Ver la banda entera sin plegar le da una segunda cosa: absorbe el filtro adaptado. La filmina lo muestra en dos pasos: primero el receptor con muestreado a ; después, un AAF genérico, muestreo a y un solo . El filtro adaptado trabaja antes del muestreo, así que sólo lo puede reemplazar un filtro que vea la señal sin aliasing. Sin filtro receptor —un AAF ideal hasta y el mismo ruido—, el FSE de 21 taps vuelve a dar −20,04 dB en las tres fases medidas (0, y ), mientras que el de tasa de símbolo, aun en la fase óptima, se queda en −17,40 dB con 41 taps: el ruido de afuera de la banda ya se plegó adentro.
Hasta casi no pasa nada: el pozo es de pocos dB y el ecualizador a lo levanta sin pagar casi nada. Después el pozo se hunde, y aunque siga arriba del ruido levantarlo ya cuesta: con la pérdida es de 1,9 dB. Pasado , donde baja de , el pozo cruza la línea del ruido, aparece el rojo, y el MSE se dispara hasta . Del otro lado baja igual, porque es el pico del símbolo siguiente. El panel del medio no se mueve nunca. Con el eco el pozo arranca 4,44 dB más abajo, porque el eco a un símbolo multiplica el borde de banda por , y el de tasa de símbolo empieza a perder antes. Con 3 taps también el FSE se mueve un poco: le faltan taps para interpolar.
Un canal FIR a tasa de símbolo se invierte con , que tiene polos donde el canal tiene ceros: un IIR, que un FIR sólo aproxima. El FSE puede lograrlo exacto con un FIR finito. La razón está en el modelo multicanal del paper de Johnson y otros que acompaña a la última filmina: separando canal y ecualizador (ambos a ) en muestras pares e impares, la respuesta total a la tasa de símbolo es
Son dos subcanales a tasa —el reloj en y el reloj medio símbolo después— con dos subecualizadores cuyas salidas se suman. Ninguno tiene que invertir su subcanal: tienen que lograr, entre los dos, que la suma sea un retardo puro. El ejemplo más chico: a , o sea y . Con dos taps, :
La segunda componente pide , y la primera . En MATLAB, conv([0.625 0.5], [1 0.8 0.5 -0.4]) da 0.6250 1.0000 0.7125 0 -0.2000: las muestras que van al slicer, una sí y una no, son 1 0. Las otras son basura que nadie mira. Un ecualizador a tasa de símbolo que viera sólo necesitaría , infinitos taps.
Las dos condiciones del paper para que exista esa solución, sin ruido: que el ecualizador sea al menos tan largo como el canal (con un canal de muestras a y un FSE de taps, ), y que los dos subcanales no tengan ceros en común. Acá tiene su cero en y en . Si compartieran uno, la suma lo heredaría y ningún FIR lo sacaría. Es la misma idea de la sección anterior vista en el tiempo: dos miradas del mismo símbolo que no fallan en el mismo lugar.
La banda entera tiene su contracara. Entre y no hay señal: una fracción de lo que ve el FSE, el 40 % con el rolloff del script. Lo que el ecualizador haga ahí no cambia la salida, así que no cambia el MSE: el óptimo no está definido en esa banda. En la matriz de autocorrelación de la entrada eso son autovalores casi nulos, más o menos de ellos. Con 101 taps y el ruido también limitado por la raíz del receptor, la cuenta da 40,4, y medidos son 43 por debajo de una milésima del mayor, 39 por debajo de una diezmilésima: el número depende del umbral porque el flanco es gradual, pero se amontonan ahí. Con el ruido blanco hasta , en cambio, el menor autovalor es el piso del ruido, 0,02.
En esas direcciones los taps no tienen fuerza que los traiga de vuelta: quedan donde los dejó la inicialización, o derivan si algo los empuja siempre para el mismo lado —el redondeo de una aritmética finita, un desvío de continua—. La cura del script es el leakage, una pérdida en la actualización:
con el paso (step), la pérdida (leak) y el buffer entero a . Es el LMS de la nota del algoritmo aplicado a : un resorte débil hacia cero en cada tap. Donde hay señal el MSE tira mucho más fuerte y el resorte no se nota; donde no hay, es lo único que actúa, y la respuesta ahí se apaga como . Con los valores del script, y , la constante de tiempo es símbolos: casi diecisiete veces los 30 000 que simula el script. El leakage está para el receptor que corre meses.
Medido sobre el sistema de B_FSE_equalizer.m durante dos millones de símbolos, con el ruido entrando antes del filtro que limita la banda, así que afuera no queda nada. Por fila, la norma de los taps y la respuesta media del ecualizador fuera de :
| arranque | leak | 10⁵ símbolos | 10⁶ | 2·10⁶ | MSE |
|---|---|---|---|---|---|
| spike | 0 | 2,566 · 0,0 dB | 2,601 · 0,0 dB | 2,653 · 0,0 dB | −17,93 dB |
| spike | 10⁻³ | 2,515 · −1,7 dB | 2,463 · −17,4 dB | 2,468 · −33,8 dB | −17,90 dB |
| otro | 0 | 2,581 · 0,8 dB | 2,615 · 0,8 dB | 2,667 · 0,8 dB | −17,93 dB |
| otro | 10⁻³ | 2,526 · −0,9 dB | 2,463 · −16,5 dB | 2,468 · −33,1 dB | −17,90 dB |
«Spike» es el arranque del script, un 1 en el tap central, que tiene 0 dB en toda la banda. «Otro» le suma una alternancia de signos que sólo cambia la respuesta afuera: +0,8 dB. Sin leakage, la respuesta afuera no se mueve en dos millones de símbolos: cada arranque se queda con la suya, los dos llegan al mismo MSE, y sus taps finales difieren en 0,822 de norma. Ésa es la solución no única. Con leakage la respuesta afuera cae como predice : la predicción da −1,7, −17,4 y −34,7 dB en las tres marcas, y se midió −1,7, −17,4 y −33,8. Los dos arranques terminan a 0,015 de distancia, y la norma se queda en 2,46–2,47 desde el millón de símbolos, mientras la de sin leakage sigue subiendo despacio: 2,566, 2,601, 2,653. El costo: 0,03 dB de MSE.
Una precisión sobre el script tal cual: ahí el ruido se suma después del canal, blanco hasta , y llena la banda vacía. Ese ruido hace el mismo trabajo que el leakage —le da al MSE algo que cuidar afuera— y la diferencia desaparece: con y sin leakage la respuesta afuera termina en −24,6 y −24,4 dB, y el MSE en −13,30 dB los dos. El problema aparece en el receptor real, donde el AAF recorta el ruido junto con la señal.
Tomar es diezmar por 2 a la salida, y las salidas que se tiran no hace falta calcularlas. Por símbolo el FSE hace productos para la salida y para la actualización: lo mismo que un ecualizador a tasa de símbolo de taps. Con los mismos taps cubre la mitad del tiempo —los 101 del script abarcan — y aun así, con el reloj corrido, 21 taps a le ganan a 81 a : en , −20,04 contra −15,34 dB.
En el bucle del script eso es la condición mod(m,N)==0: todas las muestras entran al buffer, pero la salida que va al slicer, el error y la actualización ocurren sólo en una de cada dos. El script calcula yeq en todas las muestras porque guarda out_eq completo, que en una simulación no molesta; lo que va al slicer es out_eq_down. Dos cosas no se negocian. El error va sólo en los instantes de decisión: entre dos símbolos no hay nada con qué comparar. Y el gradiente usa el buffer entero a , no una muestra de cada dos: si no, el FSE vuelve a ser un ecualizador a tasa de símbolo con la mitad de los taps en cero. Cómo encaja este bloque con el AGC, el slicer y el arranque está en la nota del transceptor.
B_FSE_equalizer.m corre tal cual en R2026a (con slicer_qam.m en la misma carpeta), en unos 26 segundos que son casi todos del gráfico que redibuja mientras converge. Lo que sigue arma las tres mediciones de esta nota: el barrido de la fase con los dos ecualizadores, por la fórmula de Wiener y por LMS, y el leakage sobre el sistema del script. Lo que figura como comentario es la salida real de correrlo.
%% 1. MSE mínimo contra la fase de muestreo: 21 taps a T y 21 taps a T/2 % Frente fijo: la raíz de coseno realzado del transmisor, repetida en el % receptor. Pulso total RC, roll-off 0,2 (el del script de clase), SNR 20 dB. alfa = 0.2; s2 = 0.01; L = 21; taus = 0:1/8:1/2; JT = arrayfun(@(t) wiener(t, L, 1, alfa, s2), taus); JT2 = arrayfun(@(t) wiener(t, L, 1/2, alfa, s2), taus); Jinf = (1-alfa)*s2/(1+s2) + alfa*s2./sqrt((1+s2)*(cos(pi*taus).^2 + s2)); fprintf('tau/T %s\n', sprintf('%8.3f', taus)); fprintf('Wiener a T %s\n', sprintf('%8.2f', 10*log10(JT))); fprintf('Wiener a T/2 %s\n', sprintf('%8.2f', 10*log10(JT2))); fprintf('a T, infinitos %s\n', sprintf('%8.2f', 10*log10(Jinf))); % tau/T 0.000 0.125 0.250 0.375 0.500 % Wiener a T -20.04 -19.97 -19.70 -18.72 -12.89 % Wiener a T/2 -20.04 -20.04 -20.04 -20.04 -20.04 % a T, infinitos -20.04 -19.97 -19.70 -18.88 -15.56 %% 2. Lo mismo con LMS: el analógico emulado a 16 muestras por símbolo rng(3); OS = 16; Ns = 150000; mu = 2e-3; a = ((2*randi([0 1], Ns, 1) - 1) + 1j*(2*randi([0 1], Ns, 1) - 1))/sqrt(2); g = rcosdesign(alfa, 25, OS, 'sqrt'); g = g/norm(g); % g*g tiene pico 1 tx = filter(g, 1, upsample(a, OS)); w = sqrt(s2/2)*(randn(size(tx)) + 1j*randn(size(tx))); r = filter(g, 1, tx + w); % ruido blanco y filtro receptor for p = 0:2:8 % tau = p/16 T mse = zeros(1, 2); for e = 1:2 % e = 1: taps a T; e = 2: taps a T/2 y = r(401 + p : OS/e : end); % el pico del símbolo 1 cae en 401 X = zeros(L, 1); C = zeros(1, L); C((L+1)/2) = 1; err = zeros(Ns, 1); k = 0; for n = 1:length(y) X(2:end) = X(1:end-1); X(1) = y(n); m = n - 1 - (L-1)/2; % muestra que está en el tap central if m >= 0 && mod(m, e) == 0 % una salida por símbolo s = m/e + 1; if s > Ns, break; end k = k + 1; ek = C*X - a(s); % entrenamiento: el símbolo se conoce C = C - mu*ek*X'; err(k) = ek; end end mse(e) = mean(abs(err(k-50000+1:k)).^2); end fprintf('tau = %5.3f T LMS a T: %6.2f dB LMS a T/2: %6.2f dB\n', p/16, 10*log10(mse)); end % tau = 0.000 T LMS a T: -19.94 dB LMS a T/2: -19.95 dB % tau = 0.125 T LMS a T: -19.88 dB LMS a T/2: -19.94 dB % tau = 0.250 T LMS a T: -19.59 dB LMS a T/2: -19.93 dB % tau = 0.375 T LMS a T: -17.57 dB LMS a T/2: -19.90 dB % tau = 0.500 T LMS a T: -12.77 dB LMS a T/2: -19.89 dB %% 3. El leakage: el sistema de B_FSE_equalizer.m, dos millones de símbolos rng(5); N = 2; Ls = 2e6; EbNo = 15; kb = 2; x = (2*randi([0 1], Ls, 1) - 1) + 1j*(2*randi([0 1], Ls, 1) - 1); g2 = rcosdesign(0.2, 25, N, 'sqrt'); g2 = g2/sum(g2); yup = filter(g2, 1, upsample(x, N)); b = fir1(10, 0.4); SNR = 10^((EbNo - 10*log10(N) + 10*log10(kb))/10); sigma = sqrt(var(yup)/SNR/2); ruido = sigma*(randn(size(yup)) + 1j*randn(size(yup))); rxA = filter(b, 1, yup + ruido); % ruido ANTES del filtro: afuera de la banda no hay nada rxD = filter(b, 1, yup) + ruido; % como en el script: ruido blanco DESPUÉS NTAPS = 101; step = 2e-3; W0 = zeros(1, NTAPS); W0(51) = 1; % el spike del script nn = 41:61; W1 = W0; W1(nn) = W1(nn) + 0.3*(-1).^nn.*hann(21)'; % igual en banda, otro afuera marcas = [1e4 1e5 3e5 1e6 2e6]; NF = 4096; ff = (-NF/2:NF/2-1)/NF*2; % f/BR, de -1 a 1 casos = {rxA, 0, W0, 'antes, sin leak, spike'; rxA, 1e-3, W0, 'antes, leak, spike'; ... rxA, 0, W1, 'antes, sin leak, otro'; rxA, 1e-3, W1, 'antes, leak, otro'; ... rxD, 0, W0, 'despues, sin leak'; rxD, 1e-3, W0, 'despues, leak'}; Wfin = cell(6, 1); for ic = 1:6 rx = casos{ic,1}; leak = casos{ic,2}; W = casos{ic,3}; X = zeros(NTAPS, 1); e2 = zeros(Ls, 1); fila = ''; for m = 1:length(rx) X(2:end) = X(1:end-1); X(1) = rx(m); if mod(m, N) == 0 yeq = W*X; ek = yeq - slicer_qam(yeq, 4); W = W*(1 - step*leak) - step*ek*X'; k = m/N; e2(k) = abs(ek)^2; if any(k == marcas) Hw = fftshift(fft(W, NF)); fila = [fila sprintf(' | %.3f %6.1f', norm(W), 10*log10(mean(abs(Hw(abs(ff) > 0.65)).^2)))]; end end end Wfin{ic} = W; fprintf('%-24s%s | MSE %.2f dB\n', casos{ic,4}, fila, 10*log10(mean(e2(end-1e5+1:end))/2)); end fprintf('distancia entre los dos arranques: sin leak %.3f, con leak %.3f\n', ... norm(Wfin{1} - Wfin{3}), norm(Wfin{2} - Wfin{4})); fprintf('(1 - step*leak)^k en dB: %s\n', sprintf('%7.1f', 20*log10((1 - step*1e-3).^marcas))); % antes, sin leak, spike | 2.153 -0.0 | 2.566 -0.0 | 2.568 -0.0 | 2.601 -0.0 | 2.653 -0.0 | MSE -17.93 dB % antes, leak, spike | 2.143 -0.2 | 2.515 -1.7 | 2.482 -5.2 | 2.463 -17.4 | 2.468 -33.8 | MSE -17.90 dB % antes, sin leak, otro | 2.080 0.9 | 2.581 0.8 | 2.583 0.8 | 2.615 0.8 | 2.667 0.8 | MSE -17.93 dB % antes, leak, otro | 2.048 0.7 | 2.526 -0.9 | 2.487 -4.4 | 2.463 -16.5 | 2.468 -33.1 | MSE -17.90 dB % despues, sin leak | 2.099 -1.4 | 2.265 -21.1 | 2.262 -22.3 | 2.251 -23.0 | 2.267 -24.4 | MSE -13.30 dB % despues, leak | 2.089 -1.6 | 2.252 -22.0 | 2.249 -22.5 | 2.239 -23.3 | 2.255 -24.6 | MSE -13.30 dB % distancia entre los dos arranques: sin leak 0.822, con leak 0.015 % (1 - step*leak)^k en dB: -0.2 -1.7 -5.2 -17.4 -34.7 %% Funciones function J = wiener(tau, L, dt, alfa, s2) % MSE mínimo de L taps espaciados dt (en T), muestreando en tau + k*dt. % Recorre el retardo de decisión y se queda con el mejor. t = tau + ((L-1)/2 - (0:L-1)')*dt; H = rc(t - (-80:80), alfa); % pulso de cada símbolo en cada tap Phi = H*H' + s2*rc(t - t', alfa) + 1e-9*eye(L); % el ruido pasó por la raíz: sale RC J = inf; for d = -8:8 al = rc(t - d, alfa); J = min(J, 1 - al'*(Phi\al)); end end function p = rc(t, a) % Coseno realzado con T = 1 y pico 1 p = sinc(t).*cos(pi*a*t)./(1 - (2*a*t).^2); p(abs(1 - (2*a*t).^2) < 1e-10) = pi/4*sinc(1/(2*a)); end
Cuatro detalles que muerden:
1e-9*eye(L) es un leakage diminuto que la deja resolver, y no mueve el resultado: el FSE da −20,04 dB, que es exacto.X' conjuga. C - mu*ek*X' es la actualización que corresponde a la salida C*X con símbolos complejos: el gradiente lleva el buffer conjugado. X.' transpone sin conjugar, y con señales reales las dos dan lo mismo, así que el error no aparece hasta que se pasa a QPSK.