Unidad 6 · Ecualizadores adaptativos · el nivel recibido, el paso del LMS y la escala del slicer
El AGC va entre el filtro antialias y el ecualizador: canal → AGC → ecualizador → slicer, con el error volviendo al ecualizador. Su trabajo es uno solo, llevar la potencia de la señal recibida a un valor fijo . Hace falta porque el LMS no ve el paso solo: ve el producto . Sin AGC, el mismo es un paso distinto para cada nivel que llega.
La filmina lo define por lo que hace: amplifica las señales débiles y atenúa las fuertes, para que lo que sigue trabaje siempre en el mismo rango de amplitudes. La potencia que llega depende de la potencia transmitida, de la distancia, de la orientación de la antena y de los obstáculos, y cambia con el tiempo. La ganancia del AGC sigue el nivel medio, lento comparado con la tasa de símbolos: los cambios de largo plazo son suyos; los de uno o pocos símbolos son del ecualizador o de la corrección de errores.
En simulación el nivel no cambia durante la corrida, y el AGC se reduce a corregir la varianza de la señal recibida :
El target es un RMS. La filmina dice que se elige mirando la máxima excursión de la señal (la relación potencia pico a promedio) y que usualmente vale 0,3: tiene que dejar lugar a los picos debajo del fondo de escala del ADC, sin tirar resolución. Ese es el otro trabajo del AGC, el del conversor, y lo que cuesta poner mal el fondo de escala está en la nota del cuantizador. El AGC no mejora la SNR: multiplica señal y ruido por el mismo número.
El LMS de la cátedra actualiza los taps con el error y la entrada:
con los últimos valores de la entrada y el símbolo de referencia (el conocido, en entrenamiento, o la decisión del slicer). La pregunta es qué cambia si la entrada llega multiplicada por una ganancia .
Paso 1: escalar la entrada es escalar el paso. Sea la trayectoria del LMS con entrada y paso , y la del LMS con entrada y paso . Si en algún vale , la salida es la misma, , así que el error también, y la actualización queda
Por inducción vale para todo , siempre que arranque bien: con los taps en cero arranca, porque . Es una identidad, no una aproximación: el LMS con la señal veces más grande hace exactamente lo mismo que el LMS con la señal original y el paso veces más grande. Mismas salidas, mismos errores, taps divididos por .
Paso 2: leerlo con los resultados del LMS. Con entrada blanca de potencia y taps, el algoritmo LMS da el factor de convergencia, el paso óptimo, la cota de estabilidad y la constante de tiempo:
En las cuatro aparece multiplicado por . Conviene medir el paso en unidades del óptimo, , y entonces . Si el paso se eligió como para la señal nominal y la señal llega con ganancia , su potencia es y el LMS trabaja con
Con , que es un paso razonable, la señal diverge en cuanto : 6,02 dB más fuerte alcanzan. Esa cuenta es de entrada blanca: con un canal que dispersa los autovalores el margen es menor, y en la nota del LMS el MSE ya se dispara al 1,3 del paso óptimo. Hacia abajo no diverge nunca, pero se arrastra: 10 dB más débil es un paso diez veces más chico y, con paso chico, se multiplica por diez. Un rango de 40 dB en la potencia recibida es un rango de en el paso efectivo: no hay un que ande en todo el rango.
Paso 3: el AGC cancela la ganancia. Si la señal llega como , el AGC de la sección 01 la lleva a
La desaparece antes de llegar al ecualizador. El ecualizador ve siempre , y el que se eligió para esa potencia es el que efectivamente usa. Es lo que dice el comentario de la sección AGC del script de clase: «mantiene la potencia de entrada del FSE constante para evitar que se mueva el paso óptimo».
Medido en MATLAB con un ecualizador entrenado: símbolos , canal , ruido de desvío 0,05, taps, target 0,3 (así que ) y fijo en para la señal nominal. La curva de aprendizaje es el promedio de 200 corridas. Las dos primeras columnas son las cuentas del paso 2, con la fórmula de entrada blanca; las dos últimas, lo medido sin AGC:
| nivel | hasta −20 dB | MSE a las 2000 | ||
|---|---|---|---|---|
| −20 dB | 0,005 | 1102 | nunca | −6,39 dB |
| −10 dB | 0,05 | 112 | 750 | −25,49 dB |
| 0 dB | 0,5 | 14,2 | 84 | −24,19 dB |
| +3 dB | 1,00 | 10,5 | 62 | −22,07 dB |
| +5 dB | 1,58 | 16,1 | nunca | −15,30 dB |
| +6 dB | 1,99 | 583 | nunca | diverge |
| +10 dB | 5,0 | — | nunca | diverge |
«Hasta −20 dB» es la primera iteración en que la curva, suavizada con una media móvil de 21, baja de −20 dB; el MSE mínimo de este ecualizador (Wiener) es −25,6 dB. Con AGC las siete filas dan lo mismo: 84 iteraciones y −24,18 dB. Tres cosas se leen de la tabla:
Sin AGC, bajar el nivel estira la curva hacia la derecha, que es lo que hace un paso más chico. Subirlo la acelera hasta +3 dB, a costa de levantarle el piso; a +5 dB el piso ya queda arriba de −20 dB, y a +6 dB la dispara para arriba. Con AGC el deslizador no hace nada: cualquiera sea el nivel, la curva es la nominal. Y el efecto va con , no con : con este canal el margen hacia arriba es de 5 dB y hacia abajo no hay borde, sólo una espera que crece diez veces cada 10 dB.
El slicer también supone una escala. Los umbrales de una -PAM con niveles están en , y si la señal llega a la salida del ecualizador multiplicada por , el punto cae del lado equivocado de apenas baja de , y el punto cruza el umbral apenas pasa . Sin ruido, la ventana de escalas que decide todo bien es:
| por eje | constelación | entre | en dB |
|---|---|---|---|
| 2-PAM | QPSK | 0 y ∞ | cualquiera |
| 4-PAM | 16-QAM | 2/3 y 2 | −3,52 a +6,02 |
| 8-PAM | 64-QAM | 6/7 y 6/5 | −1,34 a +1,58 |
Con ruido la ventana se achica todavía más. En QPSK el slicer mira sólo el signo y la escala no le importa; en 64-QAM, 1,6 dB de más ya hace decidir mal todos los puntos que tienen un ±5 en alguno de sus ejes.
Pero esa escala no la pone el AGC: la pone la ganancia del ecualizador. En el script de clase el AGC deja la señal en 0,1 de RMS y la 64-QAM de qammod tiene RMS ; la diferencia la aporta el ecualizador, que por eso arranca con el tap central en 16 y no en 1. En modo entrenado da igual de dónde arranque, porque el error se calcula contra el símbolo conocido y el LMS aprende la ganancia que falte. En modo dirigido por decisiones no da igual, porque el error se calcula contra lo que decidió el slicer. Lo que el AGC garantiza es que el tap inicial signifique siempre lo mismo: con la entrada en 0,1 de RMS, un tap de 16 da siempre la misma escala de arranque, llegue la señal como llegue. Medida en el script, esa escala es 0,245 veces la de la 64-QAM, afuera de la ventana. Con 64-QAM el script no converge en modo DD (SER 0,938 con la semilla 1), y no es por esto: arrancando en la escala justa da 0,901. Por qué, es tema del modo dirigido por decisiones.
El AGC de basic_transceiver_DD_equalizer.m es la versión de simulación, un escalado del bloque entero, no un lazo: metric = std(y), agc_gain = target/metric, y_norm = y .* agc_gain. Lo mismo hace basic_transceiver_CMA_equalizer.m. Con los números del script DD:
target = 0.1, así que . Con 63 taps, , y step = 2e-3 es : un paso chiquito, con símbolos. El script cuenta errores desde T0 = L/2, 125 000 símbolos: cinco constantes de tiempo.y tal cual, con std(y) = 2,824 (semilla 1): 29,0 dB por encima del target. El mismo step pasa a valer , justo el más rápido y a 3 dB del borde.step es nueve veces más rápido. Cambiar el target sin cambiar el paso cambia el ecualizador.Con 64-QAM el script DD no converge ni con AGC, así que para ver el efecto del nivel sobre el transceptor de clase hay que bajar a M = 4. Así, con AGC, converge y decide todo bien. Sacando el AGC y metiendo la señal a varios niveles respecto del target, con el tap inicial en 16 como en el script:
Las dos pérdidas llegan bastante antes que el de la fórmula. La fórmula es para entrada blanca, y la del FSE está lejos de serlo: sobremuestreada y filtrada, su autovalor mayor es 2,65 veces . Y en modo DD el error sale de decisiones que pueden estar mal.
En un receptor de verdad el AGC es un lazo: mide el nivel después del ADC y corrige una ganancia variable antes, siguiendo el nivel medio. La filmina pide que sea lento respecto de la tasa de símbolos, y la razón es la misma que en el paso 1: una ganancia que se mueve rápido es un paso que se mueve rápido, y además aplastaría la información de amplitud de una QAM. El std del bloque entero, en cambio, mira toda la señal —también la que todavía no llegó—, y sirve porque en la simulación el nivel no cambia.
El barrido de la sección 03. Lo que figura como comentario es la salida real de correrlo en R2026a. Tarda 2,6 segundos.
%% 1. El sistema: 2-PAM, un canal con ISI y un ecualizador LMS entrenado rng(7) h = [1 0.3]; % canal sigma = 0.05; % desvío del ruido N = 11; % taps del ecualizador K = 2000; % iteraciones R = 200; % realizaciones que se promedian target = 0.3; % el objetivo del AGC, en RMS phi0 = target^2; % la potencia que el AGC deja a la entrada beta = 0.5 / (N*phi0); % 0,5 beta_opt para la señal nominal, y FIJO P = sum(h.^2) + sigma^2; A = sign(randn(K+N, R)); % símbolos, uno por columna X = filter(h, 1, A) + sigma*randn(K+N, R); X = X * target / sqrt(P); % nivel nominal: RMS = target %% 2. El barrido: el mismo beta con la señal a varios niveles niveles = [-20 -10 0 3 5 6 10]; fprintf(' nivel beta/beta_opt gamma tau | sin AGC: k(-20 dB) MSE(K) | con AGC: k(-20 dB) MSE(K)\n') for nivel = niveles g = 10^(nivel/20); f = 0.5 * g^2; % el paso que ve el LMS, en beta_opt gam = 1 - f*(2 - f)/N; % entrada blanca [m0, k0] = curva(g*X, A, beta, N, false); [m1, k1] = curva(g*X, A, beta, N, true); if gam < 1, tau = sprintf('%6.1f', -1/log(gam)); else, tau = ' inf'; end fprintf('%+4d dB %8.3f %6.4f %s | %6s %8s | %6s %8s\n', nivel, f, gam, tau, ... txt(k0), dB(m0), txt(k1), dB(m1)) end % nivel beta/beta_opt gamma tau | sin AGC: k(-20 dB) MSE(K) | con AGC: k(-20 dB) MSE(K) % -20 dB 0.005 0.9991 1102.3 | nunca -6.39 dB | 84 -24.18 dB % -10 dB 0.050 0.9911 112.3 | 750 -25.49 dB | 84 -24.18 dB % +0 dB 0.500 0.9318 14.2 | 84 -24.19 dB | 84 -24.18 dB % +3 dB 0.998 0.9091 10.5 | 62 -22.07 dB | 84 -24.18 dB % +5 dB 1.581 0.9398 16.1 | nunca -15.30 dB | 84 -24.18 dB % +6 dB 1.991 0.9983 583.4 | nunca diverge | 84 -24.18 dB % +10 dB 5.000 2.3636 inf | nunca diverge | 84 -24.18 dB %% 3. Con AGC el nivel desaparece [mA, ~] = curva(0.01*X, A, beta, N, true); [mB, ~] = curva(3.16*X, A, beta, N, true); fprintf('max |curva(-40 dB) - curva(+10 dB)| con AGC = %.1e\n', max(abs(mA - mB))) % max |curva(-40 dB) - curva(+10 dB)| con AGC = 2.2e-16 function [mse, kc] = curva(X, A, beta, N, agc) [K, R] = size(A); K = K - N; target = 0.3; mse = zeros(K, 1); for r = 1:R x = X(:, r); if agc, x = x * target / std(x); end % el AGC de los scripts de clase c = zeros(N, 1); for k = N:K+N-1 rk = x(k:-1:k-N+1); E = A(k, r) - c.'*rk; % modo entrenado, retardo 0 c = c + beta*E*rk; mse(k-N+1) = mse(k-N+1) + E^2/R; end end kc = find(10*log10(movmean(mse, 21)) < -20, 1); end function s = dB(m) v = mean(m(end-199:end)); if ~isfinite(v) || v > 1, s = 'diverge'; else, s = sprintf('%.2f dB', 10*log10(v)); end end function s = txt(k) if isempty(k), s = 'nunca'; else, s = sprintf('%d', k); end end
Tres detalles que muerden si no se los conoce:
std resta la media. Para una constelación simétrica da lo mismo que el RMS. Si la señal trae continua (un offset del ADC), queda más grande que . El RMS de verdad es sqrt(mean(abs(y).^2)).C.'*buffer transpone sin conjugar, como pide la salida , y la actualización lleva conj(buffer). Con ' en vez de .' la salida sale conjugada y el error no tiene sentido; el script lo avisa en un comentario. Acá todo es real y no hace falta.step = , símbolos. Cambiar el target de 0,1 a 0,3 hace el paso nueve veces más rápido.