Unidad 7 · PLL · el script de clase pieza por pieza, la transferencia en z, de s a z y la latencia
El PLL de la recuperación fina de portadora no tiene VCO ni capacitores: es aritmética que corre una vez por símbolo. Los dos integradores del lazo de la filmina pasan a ser dos acumuladores, Laplace pasa a ser la transformada Z, y aparece un bloque que en continuo no existe: la latencia. El script de la clase, phase_system.m, arma ese lazo en seis líneas. Hecha a mano, la cuenta da una transferencia de segundo orden con polos que se escriben en una línea, y resulta ser exactamente el lazo continuo pasado por Euler hacia atrás. Por eso valen el mismo y el mismo de la filmina, mientras el lazo sea lento frente a la tasa de símbolo.
Es el modelo equivalente de fase de la filmina, muestreado. Entra la fase de la portadora recibida y sale la fase del NCO, una muestra por símbolo. Linealizado alrededor del enganche, el lazo son tres ecuaciones:
La primera es el detector de fase: compara la entrada con la fase del NCO, que le llega Lat muestras tarde. La segunda es el filtro de lazo PI de la filmina, , con la integral cambiada por una suma: la rama proporcional mira el error de ahora y la integral, todos los errores hasta ahora. La tercera es el NCO, que acumula el control igual que el VCO lo integraba. En diagrama, θ[n] → (+) → L(z) → NCO → φ[n], con el retorno por z^−Lat.
En continuo el detector tenía ganancia y el VCO, . Acá las dos están normalizadas, por muestra, y lo que quede de ellas vive dentro de y . Es lo que permite usar las fórmulas de la filmina con los números del script sin arrastrar unidades.
fs = 16e9, con el comentario «fs = BR para el FCR». El lazo de recuperación fina de portadora corre una vez por símbolo, así que su frecuencia de muestreo es la tasa de símbolo, 16 GBd, y Ts son 62,5 ps. Ts sólo sirve para que los ejes salgan en segundos y en hertz: el lazo cuenta muestras.z = tf('z', Ts) crea como una transferencia discreta de período Ts. Desde ahí, toda expresión con z es otra tf, y MATLAB hace el álgebra de polinomios. Todas tienen que compartir el mismo Ts; mezclar períodos da error.L = Kp + Ki*z/(z-1) es el PI, con Kp = 0.005 y Ki = Kp/100. El cociente es el acumulador de la sección siguiente.NCO = z/(z-1) es otro acumulador, el mismo.G = L*NCO es el lazo abierto, de a . Con dos acumuladores en serie su denominador es : es un lazo de tipo 2.H = z^-Lat, con Lat = 0, es la latencia. Va en la realimentación; con cero queda H = 1.F = feedback(G, H) cierra el lazo: calcula , con realimentación negativa por omisión. Es la de la filmina, en .Y las cuatro figuras:
step(F) es un escalón de fase de 1 rad: la portadora recibida salta de golpe. La fase del NCO lo alcanza con un sobrepico de 39,72 % y entra en la banda del 2 % a las 1477 muestras, 92,3 ns.step(F*z/(z-1)) junto a step(z/(z-1)) es la rampa. No hay una función de rampa para una tf, y el truco es que un escalón que pasa por un acumulador es una rampa: , un radián por muestra. Una rampa de fase es un corrimiento de frecuencia, y las dos curvas terminan una encima de la otra: el PI lo sigue sin error.pzmap(F) muestra dos polos complejos en 0,997463 ± 0,006581j, adentro del círculo y pegados a , y dos ceros: uno en el origen y otro en .bode(F) es el pasabajos de fase de la filmina, dibujado hasta = 8 GHz: un pico de 4,97 dB en 16,35 MHz, cerca de , y el corte a −3 dB en 30,34 MHz, contra los 30,40 MHz de la fórmula continua de la filmina. Lo que pasa arriba de eso no lo copia el NCO: queda como error.Dos restos del script: clear all borra todo y close all está comentado, así que las figuras se acumulan entre corridas; y hold all es el nombre viejo de hold on.
La rama integral. Llamando a la suma de la segunda ecuación, cada muestra le suma el error nuevo a la anterior:
Es la propiedad de retardo de la transformada Z, , y nada más. La suma incluye la muestra actual, así que el acumulador no retarda: el error de hoy ya está en la salida de hoy.
El NCO. La tercera ecuación es la misma cuenta con en lugar de : . Con un control constante, la fase crece una cantidad fija por muestra: el NCO cambió de frecuencia, igual que el VCO de la filmina con tensión constante. Un NCO que sumara sólo hasta la muestra anterior tendría un más; en el script, eso es Lat = 1.
El polo en . vale infinito en , que es frecuencia cero. Es el que la tabla de filtros de la filmina pide para seguir una rampa de fase sin error, escrito en .
Con Lat = 0, que es como viene el script.
Paso 1: el PI con un solo denominador. Se multiplica por y se suma:
Paso 2: el lazo abierto. El NCO multiplica por otro :
Paso 3: cerrar el lazo. Con , se multiplica arriba y abajo por :
Paso 4: desarrollar el denominador. , y agrupando por potencias de :
Con los números de la clase, , que es lo que devuelve tfdata(F, 'v'). Contra feedback coinciden exactamente: la diferencia es 0 en los coeficientes normalizados y 0 en la respuesta en frecuencia, sobre 4000 puntos de 0 a . feedback llega a los mismos coeficientes por su propio camino, sumando los polinomios de .
Paso 5: la comprobación en . El numerador da , y el denominador, . : una fase constante se copia entera.
Paso 6: el error. La transferencia del error es lo que le falta a :
Doble cero en , uno por acumulador. Con el teorema del valor final discreto, , el escalón se lleva un cero y sobra otro, y la rampa se lleva los dos y deja una suelta: los dos errores son cero. Medido con lsim sobre una rampa de rad por muestra —a 16 GBd es un corrimiento de 2,546 MHz—, el error a las 20 000 muestras es de 8·10⁻¹² rad: redondeo sobre una fase que ya vale 20 rad. Sin la rama integral el error es , la rampa deja —la misma fila de la tabla de la filmina— y la medición da 0,2000 rad, 11,5°.
Son las raíces del denominador de . El discriminante es , porque el 4 y el se cancelan. Queda:
El módulo sale del producto de las raíces, que es el coeficiente independiente sobre el principal: . Tres lecturas:
Lat = 0 siempre son estables: para cualquier el módulo es menor que 1. Ninguna ganancia saca este lazo del círculo. La latencia sí (sección 07).pole(F), la fórmula difiere en 1,1·10⁻¹⁴.Con y el tiempo contado en muestras, la de la filmina con el PI es
Con los números de la clase, y rad por muestra; multiplicando por , MHz. El ancho de banda equivalente de ruido de la filmina, , da : 60 MHz contra 16 GBd. Ese producto es el que decide todo lo que sigue.
Paso 1: reemplazar cada integrador por un acumulador. El acumulador de la sección 03 es donde había . O sea, : la derivada aproximada por la diferencia hacia atrás, que es Euler hacia atrás con .
Paso 2: sustituir en . El numerador queda , y el denominador,
El cociente es, letra por letra, la de la sección 04. El lazo del script es el lazo continuo de la filmina discretizado por Euler hacia atrás, no una aproximación de él.
Paso 3: dónde caen los polos. Si , entonces , y cada polo continuo va a parar a ; contra pole(F) la diferencia es 1,1·10⁻¹⁴. Esa función manda todo el semiplano izquierdo adentro del círculo unidad, y por eso el lazo con Lat = 0 no se desestabiliza con ninguna ganancia. Un muestreo ideal del lazo continuo, en cambio, pondría el polo en . Las dos funciones coinciden al primer orden y se separan al segundo:
La diferencia es del orden de , y en radianes por muestra es proporcional a . Con la clase son 2,5·10⁻⁵ entre y el polo de pole(F): invisible. Es el sentido exacto de «el lazo es lento frente a la tasa de símbolo».
Cuándo deja de valer. Con fijo en el 0,3536 de la clase () y subiendo, el modelo continuo tiene siempre el mismo sobrepico, 40,08 %, porque con el tiempo medido en la forma de la curva depende sólo de . El discreto, medido con stepinfo:
| Kp | BnTs | sobrepico discreto | contra el continuo | ζ de los polos discretos |
|---|---|---|---|---|
| 0,005 | 0,00375 | 39,72 % | −0,36 | 0,357 |
| 0,01 | 0,0075 | 39,36 % | −0,72 | 0,360 |
| 0,02 | 0,015 | 38,65 % | −1,43 | 0,366 |
| 0,05 | 0,0375 | 36,63 % | −3,45 | 0,384 |
| 0,1 | 0,075 | 33,57 % | −6,52 | 0,412 |
| 0,2 | 0,15 | 28,41 % | −11,67 | 0,463 |
| 0,5 | 0,375 | 17,97 % | −22,11 | 0,580 |
| 1 | 0,75 | 10,94 % | −29,14 | 0,692 |
El sobrepico continuo sale de la forma cerrada de la tabla de la filmina; stepinfo, que la muestrea, da 40,07 %. La diferencia crece en proporción a : −0,36 puntos con la clase, el doble con el doble. Hasta el modelo continuo se equivoca en menos de 1,5 puntos; con 0,075 ya son 6,5, y con 0,375 el discreto tiene menos de la mitad del sobrepico que predice . El sentido es siempre el mismo: Euler hacia atrás amortigua. Los polos discretos, leídos de vuelta como , tienen un más alto que el diseñado: 0,357 con la clase, 0,412 con 0,075, 0,692 con 0,75.
Con H = z^-Lat en la realimentación, el detector compara con : corrige con una fase vieja. En continuo no hay nada parecido, y en el hardware es inevitable por dos razones.
La primera: Lat = 0 no se puede construir. Con Lat = 0, depende de y depende de . Es un lazo algebraico: MATLAB lo resuelve despejando,
y por eso ante el escalón la primera muestra ya se mueve: , el mismo valor que da step. Un circuito no despeja ecuaciones: entre medir el error y mover el NCO hay por lo menos un registro, que es Lat = 1.
La segunda: a 16 GBd nada corre a 16 GHz. El receptor procesa muchos símbolos en paralelo en cada ciclo de reloj, y cada etapa del pipeline —el detector, el filtro, el NCO, la rotación de la constelación— agrega ciclos. Contada en símbolos, que es lo que cuenta Lat, esa demora se multiplica por el paralelismo.
Lo que hace con los polos. Con , , y multiplicando por el denominador pasa a ser
de grado . Con tiene una raíz en el origen que se cancela con un cero del numerador, así que el lazo tiene polos: el par de siempre, cerca de , y nuevos. Con Lat = 1 el par casi no se mueve: 0,997475 ± 0,006605j. Con Lat = 50 está en 0,998590 ± 0,007756j, y los 49 nuevos forman un anillo de módulos entre 0,886 y 0,950, lejos de . El par de siempre se va corriendo hacia afuera, y el sobrepico, medido con stepinfo, sube con él:
| Lat | polos | sobrepico | módulo del polo mayor |
|---|---|---|---|
| 0 | 2 | 39,72 % | 0,997485 |
| 1 | 2 | 40,14 % | 0,997497 |
| 2 | 3 | 40,58 % | 0,997510 |
| 5 | 6 | 41,93 % | 0,997549 |
| 10 | 11 | 44,37 % | 0,997623 |
| 20 | 21 | 50,02 % | 0,997800 |
| 50 | 51 | 75,14 % | 0,998620 |
| 100 | 101 | inestable | 1,000555 |
Con 100 símbolos de latencia el par de siempre sale del círculo y el lazo de la clase, que con Lat = 0 no se desestabilizaba con ninguna ganancia, es inestable. El techo no lo pone la ganancia: lo pone el retardo.
Con los valores de la clase el discreto y el continuo son la misma curva, y los polos azules tapan a los rombos grises. Subí : la ventana de la derecha se agranda, los polos se alejan de y se despegan de sus , y el escalón discreto se queda por debajo del punteado. Con fijo, subir también sube , y las dos curvas cambian de forma; lo que mide la diferencia entre ellas es . Después volvé a la clase y subí la latencia: aparece el anillo de polos nuevos, el par de siempre se arrima al círculo, el escalón oscila cada vez más, y antes de los 100 símbolos sale. En toda esa excursión el modelo continuo no se mueve: no tiene cómo ver la latencia.
El script de la clase tal cual, y abajo la verificación de lo derivado a mano. Lo que figura como comentario es la salida real de correrlo en R2026a.
clear all %close all fs = 16e9; %GHz (fs = BR para el FCR) Ts = 1/fs; z = tf('z', Ts); %% % System modelling Kp = 0.005; Ki = Kp/100; L = Kp + Ki*z/(z-1); NCO = z/(z-1); G = L*NCO; Lat = 0; H = z^-Lat; F = feedback(G, H); %Funcion del PLL %% Step response figure step(F) %% Ramp response figure step(F*z/(z-1)) hold all step(z/(z-1)) % %% figure pzmap(F) %% figure bode(F) hold all %% Verificación 1: la transferencia derivada a mano contra feedback Fm = tf([Kp+Ki, -Kp, 0], [1+Kp+Ki, -(2+Kp), 1], Ts); [nF, dF] = tfdata(F, 'v'); [nM, dM] = tfdata(Fm, 'v'); fprintf('coeficientes: %.1e\n', max(abs([nF/dF(1) - nM/dM(1), dF/dF(1) - dM/dM(1)]))) % coeficientes: 0.0e+00 w = linspace(1e-4, pi, 4000) / Ts; fprintf('respuesta en frecuencia: %.1e\n', ... max(abs(squeeze(freqresp(F, w)) - squeeze(freqresp(Fm, w))))) % respuesta en frecuencia: 0.0e+00 %% Verificación 2: los polos, por la fórmula cerrada p = pole(F); pm = ((2+Kp) + [1; -1]*1j*sqrt(4*Ki - Kp^2)) / (2*(1+Kp+Ki)); fprintf('polos: %.6f +- %.6fj, |p| = %.6f, formula - pole = %.1e\n', ... real(pm(1)), imag(pm(1)), 1/sqrt(1+Kp+Ki), max(abs(sort(pm) - sort(p)))) % polos: 0.997463 +- 0.006581j, |p| = 0.997485, formula - pole = 1.1e-14 %% Verificación 3: el equivalente continuo zeta = Kp/(2*sqrt(Ki)); wn = sqrt(Ki); fprintf('zeta = %.4f, wn = %.5f rad/muestra, fn = %.2f MHz\n', zeta, wn, wn*fs/(2*pi)/1e6) % zeta = 0.3536, wn = 0.00707 rad/muestra, fn = 18.01 MHz sc = roots([1 Kp Ki]); % polos continuos, en rad/muestra fprintf('1/(1-s) - pole = %.1e; exp(s) - pole = %.1e\n', ... max(abs(sort(1./(1-sc)) - sort(p))), max(abs(sort(exp(sc)) - sort(p)))) % 1/(1-s) - pole = 1.1e-14; exp(s) - pole = 2.5e-05 %% Lo que dicen las figuras S = stepinfo(F); fprintf('sobrepico %.2f %%, asentamiento %.0f muestras, -3 dB en %.1f MHz\n', ... S.Overshoot, S.SettlingTime/Ts, bandwidth(F)/(2*pi)/1e6) % sobrepico 39.72 %, asentamiento 1477 muestras, -3 dB en 30.3 MHz
Tres detalles que muerden:
z se creó con Ts, step y stepinfo devuelven tiempos en segundos: el asentamiento sale 9,23·10⁻⁸ y hay que dividir por Ts para leer 1477 muestras. Lo mismo bandwidth, que da rad/s.tf no es comparar. F - Fm arma una transferencia nueva con denominador producto, y sus coeficientes no dicen si las dos eran iguales. Lo que compara es evaluar las dos por separado, con freqresp, o los coeficientes normalizados por el principal: feedback no garantiza que el denominador empiece en 1.pzmap muestra un polo y un cero de más en el origen. feedback no cancela factores comunes: con Lat = 5, pole(F) devuelve siete raíces y una es , tapada por un cero en el mismo lugar: en el gráfico no se distinguen.Lat = 0 es un lazo algebraico que el hardware no puede hacer. Con el lazo de la clase, 100 símbolos lo vuelven inestable.