Bitácora · DCSS · Concepto

El control automático de ganancia

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 φ0. Hace falta porque el LMS no ve el paso β solo: ve el producto βφ0. Sin AGC, el mismo β es un paso distinto para cada nivel que llega.

01 · La definición

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 R:

z=R·targetstd(R)⟹φ0=E|z|2=target2

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.

02 · Por qué el LMS lo necesita

El LMS de la cátedra actualiza los taps con el error y la entrada:

ck+1=ck+βEkrk*,Yk=ckTrk,Ek=Ak−Yk

con rk los últimos N valores de la entrada y Ak 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 g>0.

Paso 1: escalar la entrada es escalar el paso. Sea ck la trayectoria del LMS con entrada rk y paso βg2, y ck′ la del LMS con entrada grk y paso β. Si en algún k vale ck′=ck/g, la salida es la misma, Yk′=(ck/g)Tgrk=Yk, así que el error también, y la actualización queda

ck+1′=ckg+βEkgrk*=ck+βg2Ekrk*g=ck+1g

Por inducción vale para todo k, siempre que arranque bien: con los taps en cero arranca, porque 0/g=0. Es una identidad, no una aproximación: el LMS con la señal g veces más grande hace exactamente lo mismo que el LMS con la señal original y el paso g2 veces más grande. Mismas salidas, mismos errores, taps divididos por g.

Paso 2: leerlo con los resultados del LMS. Con entrada blanca de potencia φ0 y N taps, el algoritmo LMS da el factor de convergencia, el paso óptimo, la cota de estabilidad y la constante de tiempo:

γ=1−2βφ0+β2Nφ02,βopt=1Nφ0 0<β<2βopt,τ≈12βφ0

En las cuatro β aparece multiplicado por φ0. Conviene medir el paso en unidades del óptimo, f=β/βopt=Nβφ0, y entonces γ=1−f(2−f)/N. Si el paso se eligió como f0 para la señal nominal y la señal llega con ganancia g, su potencia es g2φ0 y el LMS trabaja con

f=g2f0

Con f0=0,5, que es un paso razonable, la señal diverge en cuanto g2>4: 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, τ≈1/(2βφ0) se multiplica por diez. Un rango de 40 dB en la potencia recibida es un rango de 104 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 gR, el AGC de la sección 01 la lleva a

z=gR·targetstd(gR)=gR·targetgstd(R)=R·targetstd(R)

La g desaparece antes de llegar al ecualizador. El ecualizador ve siempre φ0=target2, 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».

03 · Cómo cambia con el nivel

Medido en MATLAB con un ecualizador entrenado: símbolos ±1, canal 1+0,3z−1, ruido de desvío 0,05, N=11 taps, target 0,3 (así que φ0=0,09) y β fijo en 0,5βopt=0,505 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β/βoptτhasta −20 dBMSE a las 2000
−20 dB0,0051102nunca−6,39 dB
−10 dB0,05112750−25,49 dB
0 dB0,514,284−24,19 dB
+3 dB1,0010,562−22,07 dB
+5 dB1,5816,1nunca−15,30 dB
+6 dB1,99583nuncadiverge
+10 dB5,0—nuncadiverge

«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:

Simulación El mismo paso, otro nivel — la curva de aprendizaje del LMS entrenado, promedio de 200 corridas, con β fijo en 0,5 β_opt para la señal nominal. En gris punteado, la curva nominal. En 0 dB el AGC no tiene nada que corregir: mové el nivel.
φ₀ a la entrada — β / β_opt efectivo — hasta −20 dB — MSE a las 2000 —

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 g2, no con g: 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.

04 · La escala del slicer

El slicer también supone una escala. Los umbrales de una M-PAM con niveles ±1,±3,… están en 0,±2,±4,…, y si la señal llega a la salida del ecualizador multiplicada por s, el punto M−1 cae del lado equivocado de M−2 apenas s baja de (M−2)/(M−1), y el punto M−3 cruza el umbral M−2 apenas s pasa (M−2)/(M−3). Sin ruido, la ventana de escalas que decide todo bien es:

por ejeconstelacións entreen dB
2-PAMQPSK0 y ∞cualquiera
4-PAM16-QAM2/3 y 2−3,52 a +6,02
8-PAM64-QAM6/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 42≈6,48; 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.

05 · En los scripts de clase

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:

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 2βopt 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 φ0. 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.

06 · El análisis en MATLAB

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:

Para tener a mano

  1. El AGC lleva la potencia de la entrada del ecualizador a φ0=target2. En simulación, z=R·target/std(R); la filmina dice target 0,3, el script DD usa 0,1.
  2. Entrada g veces más grande con paso β es exactamente la entrada original con paso g2β, con los taps divididos por g.
  3. Por eso β/βopt se mueve con la potencia recibida. Con 0,5βopt, 6,02 dB más fuerte diverge (entrada blanca; con canal, antes); 10 dB más débil tarda diez veces más.
  4. El AGC cancela la g antes del ecualizador: un único β sirve para cualquier nivel. No mejora la SNR.
  5. La escala del slicer la fija la ganancia del ecualizador, no el AGC. Sin ruido, 16-QAM tolera de −3,52 a +6,02 dB de error de escala y 64-QAM de −1,34 a +1,58 dB; QPSK, cualquiera.
  6. En el script DD: βopt=1,59, step = 0,00126βopt, τ≈25000 símbolos. Cambiar el target de 0,1 a 0,3 hace el paso nueve veces más rápido.
← Anterior Siguiente → Inicio
Relacionados El algoritmo LMS Entrenamiento y modo dirigido por decisiones El transceptor con ecualizador adaptativo Más bits no compran SNR