SoluzioniMatlab_1_06..

Transcript

SoluzioniMatlab_1_06..
Laboratorio di Strumentazione Biomedica 2
A.A. 2005-2006
Esercizio 1: soluzione
Un vettore di campioni t spaziati linearmente nell’intervallo [0,2π], può essere calcolato in vari
modi. Volendo suddividere l’intervallo in 100 campioni possiamo scrivere:
>> t = linspace(0, 2π,100);
In tal modo otteniamo un passo di campionamento Ts costante pari a
>> Ts = t(2)-t(1);
che risulta essere Ts=0.0635.
Se invece volessimo definire non il numero di campioni, ma bensì il passo di campionamento
potremmo scrivere:
>> Ts = 0.32;
>> t = 0:Ts: 2*π;
Con quest’ultimo vettore di campioni t disegniamo la funzione sin(ωt), con ω=100:
>> plot(t,sin(100*t));
In effetti la funzione disegnata sembra essere proprio un seno.
Ma quanti periodi ci aspettiamo di vedere nell’intervallo di t selezionato?
La pulsazione è ω=100, dunque ci si aspetta di osservare un periodo della funzione ogni 2π/100,
mentre dalla figura appare chiaro che vediamo un solo periodo.
La frequenza di Nyquist del segnale è fN = ω/(2π) = 15.9155, ed il teorema di Shannon mi dice che
per poter ricostruire il segnale in maniera corretta devo campionare il segnale con una frequenza fs:
fs > 2 fN
Dunque devo ricalcolare il vettore t tenendo conto di tale vincolo, e quindi utilizzare una frequenza
di campionamento strettamente maggiore di 2fN=31.8310. Scelgo un passo di campionamento Ts =
1/50:
>> Ts = 1/50;
>> t = 0:Ts: 2π;
>> plot(t,sin(100*t));
ed effettivamente ottengo la rappresentazione corretta della ricostruzione, come è possibile
osservando la figura in un intervallo pari al periodo:
>> axis([0,0.0628,-1,1]);
Se il campionamento è corretto, dal momento che la trasformata del seno è un delta di Dirac
centrato attorno alla frequenza del seno, calcolando il modulo della trasformata di Fourier del
sin(ωt), ci si aspetta di vedere una riga alla frequenza fN = ω/(2π) = 15.9155 e la sua ripetizione
periodica a (2fs - fN).
Se sull’asse delle frequenze si vuole visualizzare la pulsazione, si otterrà una riga ad ω=100, e la
sua ripetizione periodica a (4 π fs - ω).
>> x=sin(100*t)
>> y = fft(x);
>> m=abs(y);
>> f = (0:length(y)-1) /length(y) *(2*pi/Ts);
>> plot(f,m)
Per la seconda parte dell’esercizio, possiamo tenere lo stesso valore di Ts per calcolare il vettore t
nell’intervallo [0,6π]. Se inoltre utilizziamo ω =50, si ottiene:
2
>> Ts=1/50;
>> t=0:Ts:6*pi;
>> x=sin(t).*sin(50*t);
>> plot(t,x);
Lo spettro di un segnale di questo tipo si caratterizza per la presenza di due righe attorno alla
pulsazione del segnale modulato sin(ω t), a frequenza (ω - ω ) e (ω + ω ):
2
2
>> y = fft(x);
>> f = (0:length(y)-1)*2*pi/Ts/length(y);
>> m=abs(y);
>> plot(f,m)
>> axis([25,75,0,250])
1
2
1
Quando invece le frequenze sono vicine (ω =10 e ω =11), si osserva il fenomeno dei “battimenti”:
>> Ts=1/50;
1
2
>> t=0:Ts:6*pi;
>> x=sin(11*t).*sin(10*t);
>> plot(t,x);
Essi sono dovuti allla comparsa di frequenze che sono la somma e la differenza delle frequenze dei
due segnali originali. Nella fattispecie si osservano le frequenze ω - ω =1 e ω + ω =21:
2
>> y = fft(x);
>> m=abs(y);
>> f = (0:length(y)-1)*2*pi/Ts/length(y);
>> plot(f,m)
>> axis([0,30,0,250])
1
2
1
Esercizio 2: soluzione
Per calcolare la funzione Gaussiana bivariata:
g ( x, y ) =
1
2π Σ
e −0.5[( x , y ) − µ ]
T
1/ 2
Σ −1 [( x , y ) − µ ]
avendo come ingresso le coordinate (x,y) in cui calcolarne il valore, il vettore delle medie µ e la
matrice di covarianza Σ, il problema che si pone è la gestione del prodotto vettore-matrice
nell’esponenziale.
Il modo più diretto per calcolare g(x,y) è attraverso un doppio ciclo for che scorra tutti i possibili
valori di x e y.
function g=Ex2_a(xlim,ylim,mu,Sigma);
iSigma=inv(Sigma);
nfact=1/(2*pi*sqrt(det(Sigma)));
for ctx=xlim(1):xlim(2)
for cty=ylim(1):ylim(2)
e=([ctx,cty]-mu)*iSigma*([ctx,cty]-mu)';
g(ctx+xlim(1)+1,cty+ylim(1)+1)=nfact*exp(-0.5*e);
end;
end;
In tale funzione, le variabili di ingresso xlim ed ylim sono due vettori che contengono i limiti
inferiori e superiori dei valori di x ed y rispettivamente su cui si vuole considerare g(x,y); mu è un
vettore 1x2 contenente le medie lungo x e lungo y, e Sigma è la matrice di covarianza;
Le prime due righe calcolano il fattore di normalizzazione e l’inversa di Sigma . Da notare che in
Matlab gli indici di un elemento di una matrice devono essere strettamente positivi, cosicché non è
possibile scrivere all’interno del doppio ciclo:
g(ctx,cty)=nfact*exp(-0.5*e);
perché ctx e cty sono interi che variano da -50 a 50, e non sono dunque strettamente positivi.
Dopo aver salvato la funzione descritta, con i seguenti comandi è possibile ottenere la funzione
desiderata:
>>mu=[0,0];
>>Sigma=[400,0;0,100];
>>xlim=[-50,50];
>>ylim=[-50,50];
>>g=Ex2_a(xlim,ylim,mu,Sigma);
>>mesh(g)
>>axis([0,101,0,101,0,0.001])
E’ possibile pensare ad un modo più rapido di calcolare la stessa funzione, senza utilizzare cicli for:
si farà uso della funzione di Matlab meshgrid per ottenere tutti i punti del piano su cui valutare la
funzione.
Dal momento che meshgrid restituisce le coordinate su due matrici, non è più agevole utilizzare
direttamente la moltiplicazione vettore-matrice. Per farlo bisognerebbe scrivere:
function [g,imx,imy]=Ex2_c(xlim,ylim,mu,Sigma);
[imx,imy]=meshgrid(xlim(1):xlim(2),ylim(1):ylim(2));
iSigma=inv(Sigma);
nfact=1/(2*pi*sqrt(det(Sigma)));
for ctx=1:size(imx,1)
for cty=1:size(imx,2)
coord=[imx(ctx,cty), imy(ctx,cty)];
e=(coord-mu)*iSigma*(coord-mu)';
g(ctx,cty)=nfact*exp(-0.5*e);
end;
end;
Il vantaggio dell’uso di meshgrid in tal caso è semplicemente l’informazione aggiuntiva delle
coordinate del piano cui corrispondono i valori di g che vengono restituite nelle matrici imx ed imy.
E’ però possibile eliminare completamente l’uso dei cicli for, considerando lo sviluppo esplicito
della forma quadratica all’esponente:
[x
⎡a b ⎤
y ]⎢
⎥[x
⎣b c ⎦
y ] = ax 2 + 2bxy + cy 2
T
function [g,imx,imy]=Ex2_c(xlim,ylim,mu,Sigma);
[imx,imy]=meshgrid(xlim(1):xlim(2),ylim(1):ylim(2));
iSigma=inv(Sigma);
nfact=1/(2*pi*sqrt(det(Sigma)));
imxn=imx-mu(1);
imyn=imy-mu(2);
e=iSigma(1,1)*imxn.^2+2*iSigma(2,1).*imxn.*imyn+iSigma(2,2)*imyn.^2;
g=nfact*exp(-0.5*e);
e dunque invocando la funzione appena scritta:
>>[g,imx,imy]=Ex2_b(xlim,ylim,mu,Sigma);
>>mesh(imx,imy,g)
Seguendo lo stesso trucco (lo sviluppo esplicito di operazioni matriciali), è possibile scrivere la
funziona che calcola la gaussiana ruotata di un certo angolo:
function [g,imx,imy]=Ex2_d(xlim,ylim,mu,Sigma,theta);
[imx,imy]=meshgrid(xlim(1):xlim(2),ylim(1):ylim(2));
imxr=cos(theta)*(imx-mu(1))+sin(theta)*(imy-mu(2));
imyr=-sin(theta)*(imx-mu(1))+cos(theta)*(imy-mu(2));
iSigma=inv(Sigma);
nfact=1/(2*pi*sqrt(det(Sigma)));
e=iSigma(1,1)*imxr.^2+2*iSigma(2,1).*imxr.*imyr+iSigma(2,2)*imyr.^2;
g=nfact*exp(-0.5*e);
e dunque, essendo la rotazione richiesta dall’esercizio pari a ϑ =
π
3
:
>>xlim=[1,256];
>>ylim=[1,256];
>>mu=[128,128];
>>Sigma=[100^2,0;0,50^2];
>>[g,imx,imy]=Ex2_d(xlim,ylim,mu,Sigma,pi/3);
>>mesh(imx,imy,g)
>>axis([1,256,1,256,0,0.00004])
Per osservare la differenza fra la gaussiana rotata e quella originale, è possibile visualizzarle
appaiate:
>>subplot(1,2,1)
>>imagesc(g); axis xy
>>subplot(1,2,2)
>>imagesc(gr); axis xy
Esercizio 3: soluzione
Dal momento che è necessario calcolare dei vettori aleatori gaussiani bivariati, di matrice di
covarianza data, mentre la funzione randn di Matlab fornisce solo vettori a media nulla,
indipendenti e di varianza unitaria, è necessario calcolare la fattorizzazione di Cholesky della
matrice di covarianza Σ.
>>Sigma=[400,225;225,225];
>>mu=[64,64];
>>R=chol(Sigma);
e si ottiene che:
⎡20 11.25 ⎤
R=⎢
⎥
⎣ 0 9.9216⎦
Utilizzando la espansione esplicita del prodotto matrice-vettore, analogamente all’esercizio
precedente, possiamo scrivere:
>>n=randn(10000,2);
>>g(:,1)=n(:,1)*R(1,1)+n(:,2)*R(1,2)+mu(1);
>>g(:,2)=n(:,2)*R(2,2)+mu(2);
Posso dunque scrivere una funzione che, dati il numero di campioni della realizzazioni nsample, il
numero delle ripetizioni nrep, la media mu e la decomposizione di Cholesky R della matrice di
covarianza, restituisca una matrice contente le ripetizioni dei vettori aleatori richiesti:
function g=BiGaussRep(nrep,nsample,mu,R);
for ctrep=1:nrep
n=randn(nsample,2);
g(:,1,ctrep)=n(:,1)*R(1,1)+n(:,2)*R(1,2);
g(:,1,ctrep)=g(:,1,ctrep)+mu(1);
g(:,2,ctrep)=n(:,2)*R(2,2);
g(:,2,ctrep)=g(:,2,ctrep)+mu(2);
end
>> nrep=20;
>> nsample=10000;
>> g=BiGaussRep(nrep,nsample,mu,R);
A questo punto l’esercizio richiede di calcolare la densità campionaria della variabile aleatoria di
cui sono disponibili nrep realizzazioni. Ciò significa dividere la porzione del piano di interesse in
una griglia discreta, e per ogni intervallo della griglia contare quanti elementi del vettore aleatorio ci
cadono dentro. Dato un intervallo, posso trovare quali elementi vi cadono all’interno con la
funzione find di Matlab, usata come:
n=find(x>xlim(1) & x<xlim(2) & y>ylim(1) & y<ylim(2));
se xlim ed ylim sono i vettori contenenti i limiti dell’intervallo lungo x e lungo y; la lunghezza di n
fornisce il valore della densità in quel punto della griglia.
Posso scrivere dunque una funzione:
function dens=BiHist(xlim,ylim,g);
[imx,imy]=meshgrid(xlim(1):xlim(2),ylim(1):ylim(2));
for ctx=1:size(imx,1)-1
for cty=1:size(imx,2)-1
n=find(g(:,1)>imx(ctx,cty) & g(:,1)<imx(ctx,cty+1) ...
& g(:,2)>imy(ctx,cty) & g(:,2)<imy(ctx+1,cty));
dens(ctx,cty)=length(n);
end;
end;
Utilizzandola sulla prima realizzazione:
>> dens=BiHist([0,128],[0,128],g(:,:,1));
ottengo la densità campionaria mostrata in figura:
>> imagesc(dens)
>> axis xy
>> colorbar
Si può ora calcolare la densità per tutte le 20 ripetizioni:
for ct=1:nrep,
dens(:,:,ct)=BiHist([0,128],[0,128],g(:,:,ct));
subplot(5,4,ct);
imagesc(dens(:,:,ct));
end;
Ora è necessario calcolare la covarianza campionaria di ogni realizzazione, e di essa calcolare
l’autovettore corrispondente all’autovalore maggiore. Si deve poi calcolare la direzione di tale
autovetture ricordando che:
vy
ϑ = a tan( )
vx
si può cioè calcolare la direzione di un vettore v come l’arcotangente del rapporto fra la componente
y e quella x del vettore stesso:
for ctrep=1:nrep,
cv=cov(g(:,:,ctrep));
[eigenvector,lambda]=eig(cv);
if(lambda(1,1)>lambda(2,2))
v=eigenvector(1,:);
else
v1=eigenvector(2,:);
end;
theta(ctrep)=atan2(v(2),v(1));
end;
Si osservi che l’angolo ha una certa variabilità, ben riassumibile attraverso la sua media e
deviazione standard:
>>mtheta= mean(theta);
>> stheta=std(theta);
L’angolo della matrice di covarianza vera si può calcolare allo stesso modo:
[eigenvector,lambda]=eig(Sigma);
if(lambda(1,1)>lambda(2,2))
v1=eigenvector(1,:);
else
v1=eigenvector(2,:);
end;
theta_Sigma=atan2(v1(2),v1(1));
La stima della direzione effettuata utilizzando i dati ricavati da ogni realizzazione della variabile
aleatoria è affetta da un certo errore. Esso può essere valutato considerando la distanza media della
direzione stimata rispetto alla direzione vera:
merr=mean(theta-theta_Sigma);
e tale errore medio vale
merr=-0.3603.
Invece che calcolare la covarianza utilizzando le realizzazioni g(), è possibile effettuare il calcolo
esplicito utilizzando le distribuzioni campionarie calcolate:
µ x = ∑∑ f ( xi , y j ) xi
i
j
µ y = ∑∑ f ( xi , y j ) y j
i
j
σ = ∑∑ f ( xi , y j )( xi −µ x ) 2
2
x
i
j
σ = ∑∑ f ( xi , y j )( y j −µ y ) 2
2
y
i
j
rxy = ∑∑ f ( xi , y j )( xi − µ x )( y j −µ y )
i
j
Bisogna però notare che le distribuzioni ottenute dalla funzione BiHist non sono normalizzate,
perciò bisogna fare in modo che abbiano integrale unitario. Sapendo che il numero di elementi di
ogni realizzazione è nsample, tale è anche la somma degli elementi di ogni densità campionaria
dens(:,:,ct).
Calcoliamo prima la densità campionaria (normalizzata) media:
>> dens=dens/nsample;
>> mdens=mean(dens,3);
>> imagesc(mdens)
>> axis xy
>> colorbar
Poi calcoliamo le medie nelle due coordinate e gli elementi della matrice di covarianza, utilizzando
le formule riportate sopra:
[c,r]=find(mdens);
mx=0;
my=0;
for ct=1:length(c)
mx=mx+mdens(c(ct),r(ct)).*c(ct);
my=my+mdens(c(ct),r(ct)).*r(ct);
end;
rxy=0;
sx=0;
sy=0;
for ct=1:length(c)
sx=sx+mdens(r(ct),c(ct))*(c(ct)-mx)^2;
sy=sy+mdens(r(ct),c(ct))*(r(ct)-my)^2;
rxy=rxy+mdens(r(ct),c(ct))*(c(ct)-mx)*(r(ct)-my);
end;
Valutando poi gli autovettori ed autovalori della matrice di covarianza così ottenuta, e calcolando
infine la direzione dell’autovettore principale:
Sm=[sx,rxy;rxy,sy];
[eigenvector,lambda]=eig(Sm);
if(lambda(1,1)>lambda(2,2))
v1=eigenvector(1,:);
else
v1=eigenvector(2,:);
end;
theta_mean=atan2(v1(2),v1(1));
si ottiene che theta_mean=-2.5232, commettendo dunque un errore rispetto alla direzione vera di:
err = ϑΣ − ϑmean = 0.0184
Che è di molto inferiore all’errore medio ottenuto stimando la direzione sulle singole realizzazioni.