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.