APPENDICE A
Codice del software sviluppato.
Funzione step1.
function [Dphi,Dy,THETA] = step1 (y,m,n)
% function [Dphi,Dy,THETA] = step1 (y,m,n)
%
% Identificazione della non linearità di uscita
% per un sistema Hammerstein-Wiener.
% y contiene le uscite campionate con periodo h/2,
% m e il grado dell'approssimazione polinomiale
% dell'inversa della non linearità di uscita,
% n è l'ordine della G(z).
% Vengono restituiti la matrice ed il vettore
% dei termini noti del sistema lineare (Dphi,Dy)
% e la sua soluzione (THETA)
% conto per quanti periodi di campionamento T ho misurato la y steps = ceil(length(y)/(2*(n+1)));
Dy=[];
% costruisco il vettore DELTAy for i=1:(steps-1)
% y[l*T] - y[l*T - h] cioè
% y[l*(n+1)*h] - y[l*(n+1)*h - h]
Dy=[Dy;y(2*(n+1)*i+1)-y(2*(n+1)*i-1)];
end Dphi=[];
for i=1:(steps-1)
% se voglio calcolare phi1[k*h], tmpy conterrà % la y da k*h-n*h a k*h; in questo modo
% fornisco a buildphi tutte e sole le misure % dell'uscita che le servono.
tmpy=[];
% calcolo phi1[l*T]
for j=1:(n+1)
tmpy = [tmpy;y(2*(n+1)*i+1-2*(j-1))];
end
phi1 = buildphi(tmpy,m,n);
tmpy=[];
% calcolo phi1[l*T-h]
for j=1:(n+1)
tmpy = [tmpy;y(2*(n+1)*i-1-2*(j-1))];
end
phi2 = buildphi(tmpy,m,n);
% calcolo DELTAphi1[l]
Dphi = [Dphi;phi1-phi2];
end
% calcolo theta1 risolvendo il sistema lineare THETA = Dphi\Dy
Funzione buildphi.
function [phi] = buildphi (y,m,n)
% function [phi] = buildphi (y,m,n)
%
% Costruisce il vettore riga phi1[k*h].
% y contiene le misure dell'uscite a partire
% dall'istante k*h (primo elemento) a k*h-n*h
% (ultimo elemento).
% m e il grado dell'approssimazione polinomiale
% dell'inversa della non linearità di uscita,
% n è l'ordine della G(z).
% Viene restituito il vettore phi1 completo.
phi=[];
% costruisco i primi m-1 elementi del vettore:
% [-y^2[kh],...,-y^m[kh]]
for i=2:m
phi = [phi,-y(1)^i];
end
% costruisco i successivi m*n elementi del vettore:
% [y[(k-1)h],...,y[(k-n)h],...,y^m[(k-1)h],...,y^m[(k-n)h]]
for i=1:m for j=1:n
phi = [phi,y(j+1)^i];
end end
Funzione find_r_alpha.
function [r,alpha] = find_r_alpha (theta,m,n)
% function [r,alpha] = find_r_alpha (theta,m,n)
%
% Calcola i gli r_i e gli alpha_i a partire da theta1.
% theta è il vettore theta1 calcolato dalla funzione "bai",
% m e il grado dell'approssimazione polinomiale
% dell'inversa della non linearità di uscita,
% n è l'ordine della G(z).
% Viene restituito un vettore contenente i coefficienti
% dell'inversa della non linearità sull'uscita,
% da quello di primo grado a quello di grado m (quello di
% grado zero è 0); alpha contiene i coefficienti del
% denominatore della G~(z) in ordine crescente.
A =[];
% costruisco la matrice OMEGA1, contenente le
% componenti di theta per colonna for i=1:m
for j=1:n
A(j,i) = theta(n*(i-1)+j+m-1);
end end
[u,s,v] = svd(A);
% calcolo r e alpha a partire dalla SVD di OMEGA1 r = v(:,1) / v(1,1);
alpha = s(1,1) * u(:,1) * v(1,1);
Funzione step2.
function [THETA2] = step2 (y2,n,p)
% function [THETA2] = step2 (y2,n,p)
%
% Identificazione della parte lineare
% per un sistema Hammerstein-Wiener.
% y2 contiene le uscite campionate con periodo h/2
% (in modo tale da avere a disposizione i campioni
% corrispondenti agli istanti kT+T/2 indipendemente
% dal fatto che n sia pari o dispari),
% n è l'ordine della G(z),
% p è un vettore contenente i coefficienti polinomiali
% dell'inversa della non linearità di uscita in formato MATLAB.
% Viene restituito il vettore (THETA2) soluzione
% del sistema lineare x^[kT+T/2]=phi2[k]*theta2.
% conto per quanti periodi di campionamento T ho misurato la y steps = ceil(length(y2)/(2*(n+1)));
% trova le x^[kT], stima delle x[kT], a partire da y[kT]
xcap = polyval(p,y2);
phi2 = [];
xcap2 = [];
for k=(n-1):(steps-2) % uso questi estremi per evitare di uscire da xcap
% costruisco una riga della matrice phi2 (phi2[kT]) % e calcolo un elemento del vettore dei termini noti % (x^[kT+T/2])
[tmpphi2,tmpxcap2] = buildphi2(xcap,k,n);
phi2 = [phi2;tmpphi2];
xcap2 = [xcap2;tmpxcap2];
end
% risolvo il sistema lineare THETA2 = phi2\xcap2;
Funzione buildphi2.
function [phi,xc] = buildphi2 (xcap,k,n)
% function [phi,xc] = buildphi2 (xcap,k,n)
%
% Costruisce il vettore riga phi2[k]
% ed estrae x^[kT+T/2].
% xcap contiene le stime di x campionate
% con periodo h/2, k è il numero della
% riga di phi2 che voglio generare,
% n è l'ordine della G(z).
% Viene restituito il vettore phi2[k] e x^[kT+T/2].
phi=[];
% x^[kT+T/2]
xc = xcap(2*(n+1)*k + 1 + (n+1));
for i=2:n
% -x^[kT+T/2-(i-1)T]
phi = [phi, -xcap(2*(n+1)*k + 1 - (i-1)*(n+1)*2 + (n+1))];
end
for i=1:n+1
% x^[kT+T-(i-1)T]
phi = [phi, xcap(2*(n+1)*k + 1 - (i-2)*(n+1)*2)];
end
Funzione step3.
function [w2,ucap] = step3 (y2,w,n,p,alpha,beta,betasegnato)
% function [w2,ucap] = step3 (y2,w,n,p,alpha,beta,betasegnato)
%
% Identificazione della non linearità di ingresso
% per un sistema Hammerstein-Wiener.
% y2 contiene le uscite campionate con periodo h/2
% (in modo tale da avere a disposizione i campioni
% corrispondenti agli istanti kT+T/2 indipendemente
% dal fatto che n sia pari o dispari),
% w contiene gli ingressi del sistema campionati con periodo h/2,
% n è l'ordine della G(z),
% p è un vettore contenente i coefficienti polinomiali
% dell'inversa della non linearità di uscita,
% alpha e beta sono due vettori contenenti risp.
% i coefficienti del denominatore e del numeratore
% della G(z) (secondo lo standard usato dalla funzione filt),
% betasegnato contiene i coefficienti del numeratore della
% f.d.t. T.D. considerando i campioni negli istanti
% KT+T/2 anzichè KT (stesso formato di beta).
% Vengono restituiti due vettori, w2 e ucap, contenenti
% coppie di punti (w,u) che caratterizzano la g(w):
% la i-esima coppia è costituita dall'i-esima componente
% di w2 e dall'i-esima componente di ucap
% conto per quanti periodi di campionamento T ho misurato la y steps = ceil(length(y2)/(2*(n+1)));
% trova le x^[kT], stima delle x[kT], a partire da y[kT]
xcap = polyval(p,y2);
% min_ph indica se una delle due tra G(z) e G(z) segnato
% è a fase minima e se si quale (se lo sono entrambe indica G(z)) min_ph = 0;
% calcolo gli zeri di G(z)
zeri = roots(inverti(beta)).^(-1);
ok = 0;
% Verifico se G(z) è a fase minima, se sì pongo min_ph=1 for i=1:length(zeri)
% si noti che G(z) è strettamente propria
% perciò nel vettore "zeri", calcolato come sopra, % ho sempre almeno una componente infinita
if ((abs(zeri(i)) < 1) | isinf(zeri(i))) ok = ok + 1;
end end
if (ok == length(zeri)) min_ph = 1;
end
% Se G(z) non è a fase minima, verifico se G(z) segnato
% è a fase minima, e in questo caso pongo min_ph=2
if (min_ph == 0)
% calcolo gli zeri di G(z) segnato
zeri = roots(inverti(betasegnato)).^(-1);
ok = 0;
for i=1:length(zeri) if (abs(zeri(i)) < 1) ok = ok + 1;
end end
if (ok == length(zeri)) min_ph = 2;
end end
% Se min_ph è rimasto a zero, vuol dire che nè G(z)
% nè G(z) segnato sono a fase minima, perciò termino
% la funzione riportando un messaggio di errore if (min_ph == 0)
errordlg('G e Gsegnato non sono a fase minima!','Errore') return;
end
% w2 conterrà i valori di w(t) misurati negli istanti kT, k>=0 w2 = [];
% ucap(i) conterrà una stima della u relativa a w2(i) ucap = [];
% Per ora i primi n elementi di ucap conterranno
% i valori di u associati alla w misurata negli istanti
% che vanno da -nT a -T, mentre quello relativo a t=0
% è contenuto in ucap(n+1); supponendo che u=0 per t<0,
% inizializzo queste prime n componenti a zero for i=1:n
ucap(i,1) = 0;
end
% Analogamente a quanto fatto sopra, aggiungo n componenti
% nulle in testa al vettore xcap, in modo tale che la componente
% che contiene x[0] sia la n+1-esima. Faccio questo perchè
% nel calcolare la u[kT] mi servono i campioni della x anche per
% gli n periodi di campionamento che precedono kT e per k<n mi servono
% dei campioni per t<0, che non conosco for i=1:2*n*(n+1)
xcap = [0;xcap];
end
% Se G(z) è a fase minima la usa per calcolare le coppie (w,u) if (min_ph == 1)
% calcolo i vari u[kT] usando la formula che % li ricavadalla G(z) e dalle stime di x for i=1:steps-2
% uso tmpu come variabile temporanea per memorizzare
% ucap(i) man mano che sommo i termini che la costituiscono tmpu = 0;
% w[(i-1)T]
w2 = [w2; w(2*(n+1)*(i-1) + 1)];
for j=2:n
% beta contiene [0,beta_1,beta_2,...]
b = beta(j+1);
% ... - beta_(j+1)*u[(i-1)T-jT]
tmpu = tmpu - b * ucap(i - (j-1) + n);
end
for j=0:n
a = alpha(j+1);
% ... - alpha_(j+1)*x[(i-1)T+T/2-j*T]
% si ricordi che alpha contiene [1,-alpha_1,- alpha_2,...]
tmpu = tmpu + a * xcap(2*(n+1)*(i-1) + 1 - (j-1)*2*(n+1) + 2*n*(n+1));
end
ucap = [ucap; tmpu];
end
% Se G(z) segnato è fase minima e G(z) no, uso G(z) segnato
% per calcolare le coppie (w,u) else
% il seguito è del tutto analogo al ramo principale dell'if, ma % stavolta applico la formula che ricava u[kT] usando G(z) segnato
for i=1:steps-2 tmpu = 0;
w2 = [w2; w(2*(n+1)*(i-1) + 1)];
for j=1:n
b = betasegnato(j+1);
tmpu = tmpu - b * ucap(i - j + n);
end
for j=0:n
a = alpha(j+1);
tmpu = tmpu + a * xcap(2*(n+1)*(i-1) + 1 + (n+1) - j*2*(n+1) + 2*n*(n+1));
end
tmpu = tmpu / betasegnato(1);
ucap = [ucap; tmpu];
end
end
% elimino le prime n componenti di ucap, aggiunte
% artificiosamente (vedi sopra) ucap = ucap(n+1:length(ucap));
Funzione inverti.
function res = inverti (v)
% function res = inverti (v)
%
% Prende come argomento un vettore (v)
% e restituisce un vettore (res) con le
% stesse componenenti, ma in ordine inverso L = length(v);
for i=1:L
res(i) = v(L-i+1);
end
Procedura di identificazione.
% PROCEDURA AUTOMATICA PER L'IDENTIFICAZIONE DI SISTEMI HAMMERSTEIN- WIENER
% Nello workspace devono essere presenti le seguenti variabili:
% n: ordine della G(z)
% m: grado dell'inversa della n.l. di uscita
% q: grado della n.l. di uscita
% FASE 1:
% IDENTIFICAZIONE DELLA NON LINEARITA' DI USCITA
% eseguo l'algoritmo per trovare la non linearità di uscita
% e il denominatore della G(z) relativa ad h [dphi,dy,theta] = step1 (y2,m,n);
[r,alpha_h] = find_r_alpha(theta,m,n)
% p contiene i coefficienti dell'inversa della f(x) p = [inverti(r),0]
clear r;
% Stima della non linearità di uscita a partire dalla sua inversa ymin = min(y);
ymax = max(y);
% suddivido il range delle y ottenute dalla simulazione in 1000 intervalli
y1 = ymin:((ymax-ymin)/1000):ymax;
y1 = y1.';
% ricostruisco le x1 relative alle y1 sfruttando l'inversa di f(x) x1 = polyval(p,y1);
A = [];
% A = [x1^q,x1^(q-1),...,x^2,x]
% (matrice di Vandermonde senza la colonna relativa al termine noto) for i=1:q
A = [A,x1.^(q+1-i)];
end
% trovo i coefficienti (vettore est) risolvendo A*est=y1:
% coefficienti che meglio approssimano le coppie (x1,y1)
% nel senso dei minimi quadrati est = A\y1;
clear A;
clear x1;
clear y1;
% termine noto = 0 (non linearità passante per l'origine) est = [est;0]
% confronto tra la non linerità di uscita identificata
% e quella reale.
% N.B.: viene effettuato solo se nello workspace
% di base è presente una variabile di nome "xx"
% contenente il range della x ed un'altra di nome "yy"
% contenente i relativi valori della y reale.
if (evalin('base','exist(''xx'')') & evalin('base','exist(''yy'')')) xx = evalin('base','xx');
yy= evalin('base','yy');
plot(xx,polyval(est,xx),'ro',xx,yy,'b') legend('stima di f(x)','f(x)')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FASE 2:
% IDENTIFICAZIONE DELLA PARTE LINEARE [theta2] = step2(y2,n,p);
betasegnato = theta2(n:length(theta2)) beta = theta2(1:n-1);
beta = [0;1;beta].'
% calcolo di alpha
aa = roots([inverti(-alpha_h),1]);
aa = aa.^(-n-1); % calcolo i poli della G(z) pol = [];
for i=1:length(aa)
pol = [pol,[-aa(i);1]];
end
alpha = 1;
for i=1:length(aa)
alpha = conv(alpha,pol(:,i));
end
clear aa;
clear alpha_h;
alpha = real(alpha);
alpha = inverti(alpha)
if (evalin('base','exist(''T'')')) Gz = filt(beta,alpha,T)
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FASE 3:
% IDENTIFICAZIONE DELLA NON LINEARITA' DI INGRESSO [w2,ucap] = step3(y2,w,n,p,alpha,beta,betasegnato);
wu = [w2,ucap];
wu = sortrows(wu);
clear w2;
clear ucap;
% suddivido l'intervallo di valori tra cui varia la w
% in 50 sottointervalli e per ciascuno calcolo la media
% delle relative u
intervallo = (wu(size(wu,1),1) - wu(1,1)) / 50;
scorri = 1;
wu_media = [];
for i=1:50 temp = [];
j = 1;
while (wu(scorri,1) <= i * intervallo + wu(1,1)) temp(j,1) = wu(scorri,2);
scorri = scorri + 1;
if (scorri >= size(wu,1)) break;
end
j = j + 1;
end
wu_media(i,1) = i * intervallo - (intervallo/2) + wu(1,1);
wu_media(i,2) = mean(temp);
end figure;
plot(wu(:,1),wu(:,2),'ro',wu_media(:,1),wu_media(:,2),'gx')
Funzione hw_fun_mod.
function [p,est,num,den,nlc] = hw_fun_mod (np,nz,go,gi,m,y,t,w,y_fm,T)
% function [p,est,num,den,nlc] = hw_fun_mod (np,nz,go,gi,m,y,t,w,y_fm,T)
%
% Identificazione di sistemi Hammerstein-Wienere, con uso della
% tecnica delle funzioni modulanti per la parte Hammerstein.
% np: numero di poli della G(s),
% nz: numero di zeri della G(s),
% go: grado della n.l. di uscita,
% gi: grado della n.l. di ingresso,
% m: grado dell'inversa della n.l. di uscita,
% y: vettore contenente le misure dell'uscita campionate con periodo h/2,
% t: istanti di campionamento dei segnali per l'identificazione
% con la tecnica delle funzioni modulanti,
% w: segnale di ingresso per l'identificazione
% con la tecnica delle funzioni modulanti,
% y_fm: segnale di uscita per l'identificazione
% con la tecnica delle funzioni modulanti,
% T: finestra di integrazione per l'identificazione
% con la tecnica delle funzioni modulanti.
% p: coefficienti polinomiali dell'inversa della n.l. di uscita,
% est: coefficienti polinomiali della n.l. di uscita,
% num: coefficienti del numeratore della G(s),
% den: coefficienti del denominatore della G(s),
% nlc:coefficienti polinomiali della n.l. di ingresso.
% FASE 1:
% IDENTIFICAZIONE DELLA NON LINEARITA' DI USCITA
% ordine della G(z) = numero di poli della G(s) n = np;
q = go;
% eseguo l'algoritmo per trovare la non linearità di uscita [dphi,dy,theta] = step1 (y,m,n);
[r,alpha_h] = find_r_alpha(theta,m,n)
% p contiene i coefficienti dell'inversa della f(x) p = [inverti(r),0]
% Stima della non linearità di uscita a partire dalla sua inversa ymin = min(y);
ymax = max(y);
% suddivido il range delle y ottenute dalla simulazione in 1000 intervalli
y1 = ymin:((ymax-ymin)/1000):ymax;
y1 = y1.';
% ricostruisco le x1 relative alle y1 sfruttando l'inversa di f(x) x1 = polyval(p,y1);
A = [];
% A = [x1^q,x1^(q-1),...,x^2,x]
% (matrice di Vandermonde senza la colonna relativa al termine noto) for i=1:q
A = [A,x1.^(q+1-i)];
end
% trovo i coefficienti (vettore est) risolvendo A*est=y1
% coefficienti che meglio approssimano le coppie (x1,y1)
% nel senso dei minimi quadrati est = A\y1;
% termine noto = 0 (non linearità passante per l'origine) est = [est;0]
% confronto tra la non linerità di uscita identificata
% e quella reale.
% N.B.: viene effettuato solo se nello workspace
% di base è presente una variabile di nome "xx"
% contenente il range della x ed un'altra di nome "yy"
% contenente i relativi valori della y reale.
if (evalin('base','exist(''xx'')') & evalin('base','exist(''yy'')')) xx = evalin('base','xx');
yy= evalin('base','yy');
plot(xx,polyval(est,xx),'ro',xx,yy,'b') legend('stima di f(x)','f(x)')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FASE 2:
% APPLICAZIONE DEL METODO DELLE FUNZIONI MODULANTI
% ALLA PARTE HAMMERSTEIN DEL SISTEMA
y = polyval(p,y_fm); % ricostruisco le uscite della parte lineare save 'ywt.mat' y w t;
%chiamo la funzione per identificare un sistema Hammerstein con le f.m.
[num,den,nlc] = fun_mod_ham(T,np,nz,gi,'yut.mat');
% si riportano i coefficienti della n.l. di ingresso stimati
% nel formato polinomiale standard di MATLAB nlc = inverti(nlc);
nlc(length(nlc)+1) = 0;
% confronto tra le risposte al gradino
% N.B.: viene effettuato solo se nello workspace
% di base è presente una variabile di nome "G"
% contenente la G(s) NORMALIZZATA: il confronto
% ha senso solo se G HA GUADAGNO STATICO UNITARIO.
if (evalin('base','exist(''G'')')) G = evalin('base','G');
G_stimata = tf(num,den);
step(G,G_stimata);
legend('G(s)','G(s) stimata');
end