Por lo que las entradas a este m ´odulo ser ´an el valor de la se ˜nal de controlu(k−2)dos instantes antes al actual, y los valores de la variable de proceso eny(k−1)yy(k−2). Por lo que el vector regresorU(k)particularizado para este caso ser ´a:
U(k) =u=hu(k−2) y(k−2) y(k−1) i
(8.8.0.2)
El algoritmo de m´ınimos cuadrados se implementa mediante el c ´odigo del Anexo 11.10
siguiendo los pasos del Apartado3.4.2. Tal y como se especifica en dicho apartado, la matriz de covarianzas memo p y el vector de pesos memo pesos est ´an inicializados a los siguientes valores: P(0) =memo p= 150∗ 1 0 0 0 1 0 0 0 1 (8.8.0.3) ˆ w(0) =memo pesos= 3,75 3,75 3,75 (8.8.0.4)
Las operaciones no siguen las reglas de dimensionamiento de la Figura7.3.0.4desarrolladas por David Bishop [2] porque se agotar´ıan todos los multiplicadores hardwarede la FPGA. Por ello se ha decidido fijar el tama ˜no de las operaciones a formato Q20.20 mediante la instrucci ´on
resizeya que resulta suficiente como para que no se produzcan desbordamientos. Dado que este algoritmo necesita que se implementen operaciones cuyos operandos son se ˜nales que representan vectores y matrices, ha sido necesario definir tipos (types) que permitan declarar estas se ˜nales de manera c ´omoda. Los tipos creados se muestran en la Tabla8.8.0.1.
Nombre del Tipo Dimensiones Entero/Coma fija Formato
matriz type 3×3 Coma fija Q20.20
matriz type2 3×3 Entero Q40.0
vector type1 1×3 Coma fija Q7.10
vector type2 1×3 Coma fija Q20.20
vector type4 1×3 Coma fija Q41.40
Tabla 8.8.0.1 –Tipos de datos creados para esta implementaci ´on del algoritmo RLS.
As´ı, definiendo los tipos descritos en la Tabla 8.8.0.1 se puede a partir de este momento describir operaciones entre se ˜nales multidimensionales mediante procesos basados en bucles
for...loop.
Tal y como se indica en la descripci ´on del Apartado3.4.2se calcula:
1. CalcularK(k)como:
K(k) = λ
−1u(k)P(k−1)
1 +λ−1u(k)P(k−1)uT(k)
a) Para ello se calcula primero la inversa del denominador de la siguiente forma:
−−PRODUCTOS DENOMINADOR k(n)
u(1)<=resize(u 2 ,u(1)); u(2)<=resize(y 2 ,u(2)); u(3)<=resize(y 1 ,u(3)); −−producto u(k)*P(k−1) −−Se har´a la operaci´on −− /p11 p12 p13\ −−(u1 u2 u3 ) *|p21 p22 p23| −− \p31 p32 p33/ process(u,p)
variable i,j: integer range 1 to 3; variable producto: sfixed(20 downto −20); variable sumando: sfixed(22 downto −20); variable elemento: sfixed(20 downto −20); begin for i in 1 to 3 loop elemento:=(others=>'0'); for j in 1 to 3 loop producto:=resize(p(i,j)*u(j),producto); sumando:=resize(producto,sumando); elemento:=resize((elemento+sumando),elemento); end loop; columna(i)<=elemento; end loop;
end process;
−−producto u(k)*P(k−1)*uˆT(k)
−−Se hace
−− /u11\
−−(columna11 columna21 columna31 ) *|u12| Resultando el escalar "salida"
−− \u13/
process (u,columna,salida)
variable i: integer range 1 to 3; variable prod: sfixed(20 downto −20); variable sumando: sfixed(22 downto −20); begin
sumando:=(others=>'0'); for i in 1 to 3 loop
prod:=(others=>'0');
prod:=resize(u(i)*resize(columna(i),20,−4),prod); prod fallo(i)<=prod;−−SE˜NAL DE PRUEBA
sumando:=resize((prod+sumando),sumando); end loop;
salida<=resize(sumando,salida); end process;
−−producto inv(lambda)*u(k)*P(k−1)*uˆT(k)
sum1 den<=resize(lambda*salida,sum1 den); −−suma 1+inv(lambda)*u(k)*P(k−1)*uˆT(k)
suma den<=resize(sum1 den+uno,suma den); den k<=resize(suma den,den k);
−−INVERSA DEL PRODUCTO DEL DENOMINADOR DE k(n)
−−1/[1+inv(lambda)*u(k)*P(k−1)*uˆT(k)]
−−Se calcular´ıa como 1/salida
Inst Pruebadivisor: Pruebadivisor PORT MAP( clk => CLK,
rst => RST,
valid => Ini Inversa, divisor => den k,
fin inversa => Fin Inversa, inversa => inversa
);
Se puede observar que los productos de matrices se implementan de manera similar a como se har´ıa en un lenguaje de programaci ´on como C. Como las instrucciones de los procesos son secuenciales, las operaciones intermedias deben almacenarse en variables que, al terminar los bucles vuelcan su valor a se ˜nales. Esto se hace porque las variables toman el valor en el momento en que se pasa por ellas en el proceso, mientras que las se ˜nales toman el valor al terminar el proceso.
Aunque los bucles for sugieren una ejecuci ´on secuencial, lo cierto es que en el proceso delproducto u(k)*P(k-1)se implementan 9 multiplicadoreshardwareen
paralelo, ya que se realizan3×3 = 9productos. Al implementarse en paralelo, estas operaciones no consumen m ´as tiempo que el retardo de propagaci ´on de las se ˜nales por los multiplicadores.
Se define la constante lambda para representar el valor de la inversa del factor de olvido exponencialλ−1. Al final de este tramo de c ´odigo se puede observar la se ˜nalden k, que contiene el valor de la operaci ´on1 +λ−1u(k)P(k−1)uT(k), y que
ser ´a la entrada del m ´odulo Inst Pruebadivisor, que se encargar ´a de calcular la
inversa 1
1 +λ−1u(k)P(k−1)uT(k) y volcarla a la se ˜nalinversatras recibir la se ˜nal
de validaci ´onIni Inversa.
b) Tras esto, es necesario calcular el numerador deK(k)de la siguiente manera:
−−Se calcula el numerador de K(k) como:
−−(num lambda11 num lambda12 num lambda13) = (1/lambda)*(columna11 columna21 columna31)
process (lambda,columna,num lambda) variable i: integer range 1 to 3; begin
for i in 1 to 3 loop
num lambda(i)<=resize(resize(columna(i),20,−20)*lambda,num lambda(i)); end loop;
end process;
Se calcula el numerador num lambda como columna*lambda siendo columna ex- tra´ıdo del bloque de c ´odigo anterior para economizar recursos.
c) Se calcula el vectorK(k)mediante el c ´odigo:
−−Se calcula k como
−−(k11 k12 k13)=(num lambda11 num lambda12 num lambda13)*inversa
process (num lambda,inversa,k) variable i: integer range 1 to 3; begin
for i in 1 to 3 loop
k(i)<=resize(resize(num lambda(i),20,−20)*inversa,k(i)); end loop;
end process;
2. Tras obtener el valor deK(k), es necesario conocer el error de estimaci ´one(k) =y(k)−
u(k) ˆw(k−1)para ello se genera el c ´odigo:
−−Calculamos el error
−−Se calcula u(k)*w(k−1) como
−− /pesos11\
−− \pesos31/
process(y act,pesos,u)
variable i: integer range 1 to 3;
variable producto: sfixed(20 downto −20); variable sumando: sfixed(22 downto −20); begin sumando:=(others=>'0'); for i in 1 to 3 loop producto:=resize(pesos(i)*u(i),producto); sumando:=resize(producto+sumando,sumando); prod(i)<=producto; end loop; suma<=sumando; end process; −−Se calcula e(k)
error<=resize(y act−suma,error);
Donde en primer lugar se calcula el productou(k) ˆw(k−1)en el proceso que se acaba vol- cando a la se ˜nalsuma, y finalmente se calculae(k)comoerror<=resize(y act-suma,error);
3. El siguiente paso ser ´a actualizar el vector wˆ de pesos implementando la operaci ´on ˆ
w(k) = ˆw(k−1) +e(k)KT(k)mediante el c ´odigo:
−−Se calcula w(k)=w(k−1)−e(k)KˆT(k) como
−−/pesos actualizados11\ /pesos11\ /k11\ −−|pesos actualizados21|=|pesos21|−error *|k12| −−\pesos actualizados31/ \pesos31/ \k13/
process(pesos,k,error,pesos actualizados) variable i: integer range 1 to 3;
variable mult: sfixed (20 downto −20); begin
for i in 1 to 3 loop
mult:=resize(resize(k(i),4,−20)*error,mult);
pesos actualizados(i)<=resize(pesos(i)+mult,pesos actualizados(i)); end loop;
end process;
−−Actualizaci´on Matriz de pesos (trabajar con memo pesos)
process(CLK) begin
if CLK'event and CLK='1' then if RST='1' then
memo pesos<=("000000111100000000","000000111100000000","000000111100000000"); elsif act pesos='1' then
memo pesos<=pesos actualizados; end if;
end process; pesos<=memo pesos;
En el primer proceso, para cada ´ındice, se calcula en la variablemultel producto de ese ´ındice del vectorK(k)por la se ˜nale(k)para, posteriormente, volcar en cada posici ´on de la se ˜nalpesos actualizadosla suma de la variable textttmult y del valor para ese ´ındice del vectorpesoscorrespondiente awˆ(k−1)(el valor del vector de pesos en el instante anterior).
Tras llevar a cabo esta operaci ´on, el segundo proceso lleva a cabo la actualizaci ´on del vector de pesos. Consiste en un registro que introduce el valor depesos actualizados
antes calculado en la se ˜nalmemo pesoscuando recibe un pulso en la entradaact pesos. Tras finalizar este proceso,memo pesosse vuelca en la se ˜nalpesospara que sea visible en la salida del m ´odulo. Ahorapesospasa de contenerwˆ(k−1)a contenerwˆ(k).
4. Por ´ultimo, es necesario actualizar la matriz de covarianzasP(k)para dejarla actualizada para la siguiente ejecuci ´on del algoritmo. Se implementar ´a la operaci ´onP(k) =λ−1P(k− 1)−λ−1KT(k)u(k)P(k−1)siguiendo los pasos a continuaci ´on descritos:
a) Se calcular ´a el productoKT(k)u(k)P(k−1)de la siguiente manera:
−−Actualizamos la matriz de covarianzas
−−Producto u*P se lleva a cabo como:
−− /p11 p12 p13\
−−(fila p11 fila p12 filap 13)=(u11 u12 u13 ) *|p21 p22 p23|
−− \p31 p32 p33/
process(u,p)
variable i,j: integer range 1 to 3;
variable producto,elemento: sfixed(20 downto −20); variable sumando: sfixed(22 downto −20);
begin for i in 1 to 3 loop elemento:=(others=>'0'); for j in 1 to 3 loop producto:=resize(u(j)*p(i,j),producto); sumando:=resize(producto,sumando); elemento:=resize(elemento+sumando,elemento); end loop;
fila p(i)<=elemento; end loop;
end process;
−−Producto kˆT*u*P se calcula como:
−−/mat aux11 mat aux12 mat aux13\ /k11\
−−|mat aux21 mat aux22 mat aux23|=|k12|* ( fila p11 fila p12 filap 13)
process(fila p,k)
variable i,j: integer range 1 to 3; variable producto:sfixed(20 downto −20); begin
for i in 1 to 3 loop for j in 1 to 3 loop
producto:=resize(resize(k(j),4,−20)*fila p(i),producto); mat aux(j,i)<=producto;
end loop; end loop; end process;
De este producto resultar ´a una matriz cuadradamat aux(3×3)que se podr ´a restar a la matrizP(k−1).
b) Ahora se har ´a la operaci ´onP(k−1)−KT(k)u(k)P(k−1)restando a la matrizPla matrizmat auxcalculada en el apartado anterior:
−−Resta P−k*uˆH*P se calcula como:
−−/p resta11 p resta12 p resta13\ /p11 p12 p13\ /mat aux11 mat aux12 mat aux13\ −−|p resta21 p resta22 p resta23|=|p21 p22 p23| −|mat aux21 mat aux22 mat aux23| −−\p resta31 p resta32 p resta33/ \p31 p32 p33/ \mat aux31 mat aux32 mat aux33/
process(p,mat aux,p resta)
variable i,j: integer range 1 to 3; begin
for i in 1 to 3 loop for j in 1 to 3 loop
p resta(i,j)<=resize(P(i,j)−mat aux(i,j),p resta(i,j)); end loop;
end loop; end process;
Esta operaci ´on se volcar ´a a la se ˜nalp restapara continuar en el siguiente punto.
c) Se obtiene en este punto el valor actualizado de la matriz de covarianzas como
P(k) =λ−1(P(k−1)−KT(k)u(k)P(k−1))y se vuelca en la se ˜nalp actualizada:
−−Producto (1/lambda)*(P−kˆT*u*P) se implementa como:
−−/p actualizada11 p actualizada12 p actualizada13\ −−|p actualizada21 p actualizada22 p actualizada23|=
−−\p actualizada31 p actualizada32 p actualizada33/
−−
−− /p resta11 p resta12 p resta13\ −−=lambda *|p resta21 p resta22 p resta23| −− \p resta31 p resta32 p resta33/
process(p actualizada,lambda,p resta) variable i,j: integer range 1 to 3; begin
for i in 1 to 3 loop for j in 1 to 3 loop
p actualizada(i,j)<=resize(lambda*p resta(i,j),p actualizada(i,j)); end loop;
end loop; end process;
No obstante, los valores de esta matriz de covarianzas van a ir creciendo indefini- damente durante la ejecuci ´on del algoritmo. Como el formato en coma fija elegido es susceptible de sufrir desbordamientos, se ha decidido saturar la matriz de cova- rianzas de la siguiente manera:
−−Se convierte la matriz a standard logic vector para comparar en el proceso de evitar overflow
process (p actualizada)
variable i,j: integer range 1 to 3; begin
for i in 1 to 3 loop for j in 1 to 3 loop
p comparador(i,j)<=to slv(p actualizada(i,j)); end loop;
end loop; end process;
−−Evitar que la matriz de covarianzas se salga del rango [−1024,1024]
process(p comparador,p actualizada) variable i,j: integer range 1 to 3; begin
for i in 1 to 3 loop for j in 1 to 3 loop
if p comparador(i,j)>"00000000001000000000000000000000000000000" then p act nooverflow(i,j)<="00000000001000000000000000000000000000000"; elsif p comparador(i,j)<"11111111111000000000000000000000000000000" then
p act nooverflow(i,j)<="11111111111000000000000000000000000000000"; else
p act nooverflow(i,j)<=p actualizada(i,j); end if;
end loop; end loop; end process;
Se puede observar en el segundo proceso que se ha definido un rango[−1024,1024]. Si el valor de cualquier elemento de la matriz de covarianzas se sale del intervalo, se fuerza el valor al extremo del intervalo. El valor dep act nooverflowser ´a el que se utilice realmente para la actualizaci ´on de la matriz de covarianzas.
−−Actualizaci´on Matriz de covarianzas
process(CLK) begin
if CLK'event and CLK='1' then if RST='1' then memo p<=(("00000000000001001011000000000000000000000", (others=>'0'),(others=>'0')), ((others=>'0'), "00000000000001001011000000000000000000000",(others=>'0')), ((others=>'0'), (others=>'0'),"00000000000001001011000000000000000000000")); elsif act covarianzas='1' then
memo p<=p act nooverflow; end if;
end if; end process; p<=memo p;
Se puede observar que cuando el registro recibe un pulso de activaci ´on en su en- trada act covarianzas, se vuelca el valor de la matriz de covarianzas saturada
p act nooverflowa la se ˜nalmemo p. Finalmente se vuelca el valor del registro a la se ˜nalppara hacerlo visible al resto de m ´odulos.
As´ı se concluye la implementaci ´on en VHDL sintetizable de un m ´odulo que haga la identi- ficaci ´on por m´ınimos cuadrados recursivos de un sistema de segundo orden siendo necesario verificar su funcionamiento.
8.8.1. Verificaci ´on del m ´odulo de identificaci ´on RLS
Para verificar el correcto funcionamiento del m ´odulo descrito en VHDL se har ´a primero una simulaci ´on funcional mediante la creaci ´on de un Test Benchen el mismo lenguaje. El c ´odigo para generar la simulaci ´on se encuentra en el Anexo11.10.1.
Para que el algoritmo funcione correctamente en simulaci ´on, es necesario crear las se ˜nales de habilitaci ´on descritas para los m ´odulos del apartado anterior en el siguiente orden:
1. La se ˜nal de habilitaci ´onIni Inversainiciar ´a el c ´alculo de la inversa del denominador de
K(k).
2. La se ˜nalact pesosprovocar ´a que se actualice el vectorpesosque representa awˆ(k). 3. Por ´ultimo actualizar la matriz de covarianzasP(k)con la se ˜nalact covarianzas.
Es crucial que estas se ˜nales se generen en el orden arriba descrito, por ello, se ha gene- rado el siguiente c ´odigo para garantizarlo:
IniInversa process :process begin
Ini inversa <= '0';
wait for T mues−48*CLK period; Ini inversa <= '1';
wait for CLK period; Ini inversa <= '0'; wait for 47*CLK period; end process;
Actpesos process :process begin
act pesos<= '0';
wait for T mues−2*CLK period; act pesos<= '1';
wait for CLK period; act pesos<= '0'; wait for CLK period; end process;
Actcov process :process begin
act covarianzas<= '0'; wait for T mues−CLK period; act covarianzas<= '1'; wait for CLK period; end process;
Que genera las se ˜nales en el orden mostrado en la Figura8.8.1.1.
Figura 8.8.1.1 –Se ˜nales generadas por la simulaci ´on.
Con las se ˜nales generadas tal y como se muestra en la Figura8.8.1.1ya se puede asegurar que el algoritmo se ejecuta de manera correcta, por lo que ahora se le dar ´an valores a las entradas y se generar ´a una simulaci ´on que tendr ´a como resultado los pesos de la funci ´on de transferencia identificada tras 30 iteraciones. Para ello, se muestran los valores iniciales de los pesos y de las entradas en la Tabla8.8.1.1
Se ˜nal Valor en coma fija Formato Valor en nº real y act 11425 Q7.10 11425/210= 11,1572 y 1 11425 Q7.10 11425/210= 11,1572 y 2 11425 Q7.10 11425/210= 11,1572 u 2 46796805 Q20.20 46796805/220= 44,6289 pesos(i) 3840 Q7.10 3840/210= 3,75 Tabla 8.8.1.1 –Valor de las entradas y del vector inicial de pesos
Figura 8.8.1.2 –Resultado de la simulaci ´on funcional tras 30µs.
Se puede observar en la Figura8.8.1.2y con las entradas de la Tabla8.8.1.1se obtiene un vector en formato Q7.10pesos=
pesos= h
−1052 2617 2617 i
, un error de estimaci ´on error=-22850 en formato Q20.20, y una matriz de covarianzas en formato Q20.20p= p= 23164726 −46329420 −46329420 −46331652 196908994 −11582353 −46331652 −11582353 196908994
Teniendo en cuenta que el vectorpesos tiene un formato Q7.10, se convierte a n ´umeros reales dividiendo por 1024 y se obtiene:
pesos=h−1,0273 2,5557 2,5557 i