appunti della lezione
Transcript
appunti della lezione
Laboratorio di Elaborazione Numerica dei Segnali Prof. G.M. Cortelazzo – A.A. 2007/2008 LABORATORIO n. 1 Scopo dell’esercitazione Effettuare il filtraggio di un segnale con MATLAB. Effettuare il filtraggio di un file audio. Imparare i comandi MATLAB per la manipolazione di funzioni di trasferimento razionali (scomposizione in termini del secondo ordine, realizzazioni in cascata ed in parallelo). 1 Filtraggio di segnali con MATLAB In MATLAB il filtraggio di un segnale x viene effettuato usando la funzione y = filter(b, a, x), implementata attraverso una macchina a stati finiti. Consideriamo di voler filtrare il segnale x attraverso il filtro con risposta impulsiva h(n), la cui z-trasformata è un rapporto tra polinomi in z −1 , cioè: H(z) = b0 + b1 z −1 + · · · + bM z −M B(z) = . A(z) 1 + a1 z −1 + · · · + aN z −N (1) I due polinomi B(z) e A(z) possono essere rappresentati in MATLAB utilizzando i vettori b = [b0 , b1 , . . . , bM ] (ordinato in modo tale che b(1)=b0 e b(1+M )=bM ) e a = [a0 , a1 , . . . , aM ] (ordinato in modo tale che a(1)=a0 6= 0 e a(1+N )=aN ; se a0 6= 1, i vettori b e a vengono divisi per a0 , ottenendo una equazione alle differenze perfettamente equivalente a quella originale). Allora i parametri cui necessita filter sono: • b, ovvero il vettore dei coefficienti bk ; • a, ovvero il vettore dei coefficienti ak ; • x, ovvero il segnale da filtrare. L’uscita y ha lunghezza pari a quella di x. NB: quando si vuole filtrare un segnale con MATLAB si utilizza filter invece di conv (la funzione che calcola la convoluzione tra due segnali). La motivazione più rilevante consiste nel fatto che la realizzazione di filter attraverso stati finiti consente una maggiore velocità computazionale. Inoltre l’uscita ha la stessa lunghezza di quella del segnale d’ingresso, cosa che non avviene con conv. Non ultimo, nel caso di filtri IIR filter non necessita di calcolare i valori della risposta impulsiva. 1.1 Filtraggio di un file audio In questo esempio si userá un filtro notch per rimuovere un rumore sinusoidale sommato ad il segnale audio di ingresso. Il filtraggio sará effettuato mediante la funzione filter. es1_Audio.m clear all; clc; close all; [y,fs,nbits] = wavread(’precious_part.wav’); 2 Lab. ENS - Lezione n. 1 % [y,fs,nbits] = wavread(’chopin_pollini.wav’); % [y,fs,nbits] = wavread(’bach_gould.wav’); % Periodo di campionamento Tc = 1/fs; % Suona il file musicale soundsc(y(:,1),fs, nbits) % Numero di campioni su cui viene calcolata la fft N=1024; Y = 1/N*fftshift(fft(y(:,1),N)); % Crea l’asse delle frequenze F = -fs/2:fs/N:fs/2-fs/N; % Disegna il grafico del valore assoluto della Tf. plot(F,abs(Y)); grid % Limita l’analisi dello spettro tra -5kHz e 5kHz axis([-5000 5000 0 0.5]) % Si crea una sinusoide distorcente a 50 Hz f_sx = 500; n = 1:1:length(y); sinusoide_sx = sin(2*pi*f_sx*n*Tc); % Si inserisce il disturbo nel segnale y_dist(:,1) = y(:,1) + sinusoide_sx’; disp(’sono in pausa’) pause; % Suona il segnale audio distorto soundsc(y_dist(:,1),fs,nbits) Y_dist = 1/N*fftshift(fft(y_dist(:,1),N)); % Disegna lo spettro del segnale plot(F,abs(Y_dist)); grid axis([-5000 5000 0 0.5]) disp(’sono in pausa’) pause; % Si costruisce un filtro notch per eliminare il rumore inserito f0 = 500; theta0 = 2*pi*f0*Tc delta_f3dB = 20; 3 2 Trasformate z razionali delta = 2*pi*(delta_f3dB/fs)/2 r = 1 - delta p = r*exp(j*theta0) z = exp(j*theta0) b = conv([1,-z],[1,-conj(z)]) a = conv([1,-p],[1,-conj(p)]) freqz(b,a); % Effettua il filtraggio mediante una macchina a stati finiti y_pulito = filter(b,a,y_dist(:,1)); % Suona il segnale audio "ripulito" soundsc(y_pulito,fs,nbits) Y_pulito = 1/N*fftshift(fft(y_pulito(:,1),N)); % Ne fa vedere lo spettro plot(F,abs(Y_pulito)); grid axis([-5000 5000 0 0.5]) 2 Trasformate z razionali Nel caso di sistemi LTI causali e a dimensione di stato finita il legame tra le z-trasformate dell’ingresso, X(z), e della risposta forzata Y (z), é dato da N X ak z −k Y (z) = k=0 M X bk z −k X(z), (2) k=0 con a0 = 1 (ed anche (aN , bM ) 6= (0, 0)). Quindi possiamo scrivere Y (z) = H(z)X(z) in cui H(z), cioé la z-trasformata della risposta impulsiva h(n), é un rapporto tra polinomi in z −1 b0 + b1 z −1 + · · · + bM z −M B(z) = , (3) H(z) = A(z) 1 + a1 z −1 + · · · + aN z −N che possono essere rappresentati in MATLAB utilizzando i vettori b = [b0 , b1 , . . . , bM ] e a = [a0 , a1 , . . . , aM ]. Quindi, gli stessi vettori utilizzati per descrivere un’equazione alle differenze finite in MATLAB rappresentano anche numeratore e denominatore della trasformata della risposta impulsiva ad essa associata. Valutando la trasformata z di h(n) sul cerchio di raggio unitario, cioé nei punti ej2πf T , con f ∈ [0, 1/T ), si trova la risposta in frequenza del filtro. In particolare si ha: M X H̃(f ) = H(z)|z=ej2πf T = k=0 N X k=0 bk e−j2πf kT = −j2πf kT ak e B̃(f ) , Ã(f ) (4) 4 Lab. ENS - Lezione n. 1 e quindi per trovare H̃(f ) basta semplicemente valutare le risposte in frequenza delle sequenze discrete finite formate dai coefficienti bk ed ak . In MATLAB questo può essere fatto attraverso la funzione freqz: [H,f] = freqz(b,a,N,Fs,’whole’); trasFourier.m Essa calcola H(f ) corrispondente ai polinomi b e a su N punti equispaziati tra 0 ed Fs = 1/T, ritornati nel vettore f = 0:Fs/N:Fs-Fs/N. Si puó ipotizzare che freqz sia fatta in modo simile alla seguente funzione: % % % % % % % % % trasFourier: trova la risposta in frequenza [H, f] = trasFourier(b, a, NN, Fs); input: b = [b0, b1, ..., bM] (vettore riga) a = [a0, b1, ..., aN] (vettore riga) NN = numero di punti Fs = frequenza di campionamento output: H = risposta negli NN punti f = frequenza corrispondente ad ogni punto function [H, f] = trasFourier(b, a, NN, Fs); % Vettore delle frequenze f = 0 : Fs/NN : Fs - Fs/NN; % Punti in cui valutare la zeta-trasformata z = exp(j*2*pi*f/Fs); % % M N L Preparo una matrice con le potenze di z^-1 sulle righe = length(b) - 1; = length(a) - 1; = max(N, M); % La massima potenza che mi serve potenze = zeros(L + 1, NN); for i = 0 : L potenze(1 + i, :) = z.^(-i); end % Faccio il prodotto matriciale... B = b * potenze(1:M+1, :); A = a * potenze(1:N+1, :); % ...e divido num. per det. H = B./A; In realtà freqz usa un algoritmo piú efficiente per effettuare il calcolo di H̃(f ). La funzione precedente é però esplicativa del suo funzionamento. NB: freqz è una funzione molto usata perché permette di visualizzare l’andamento in frequenza di un filtro, dati il suo numeratore e denominatore. Imponendo a=[1], freqz si puó usare per calcolare la risposta in frequenza anche nel caso FIR. 2.1 Calcolo di poli e zeri 2.1 5 Calcolo di poli e zeri Assumendo che B(z) ed A(z) siano coprimi, gli N zeri di a rappresentano i poli della funzione di trasferimento H(z) (e ne impongono quindi la regione di convergenza), mentre gli zeri di b (che possono essere meno di M se b(1) = b0 = 0) ne rappresentano gli zeri. Nell’origine vi sará inoltre uno zero di ordine N − M se M < N oppure un polo di ordine M − N se N < M . MATLAB agevola il calcolo e la visualizzazione grafica di zeri e poli con le seguenti funzioni: • [z,p,k]=tf2zp(b,a): ritorna in vettore colonna gli zeri z ed i poli p della f.d.t. ed il suo guadagno in k; funziona solo per funzioni proprie (M ≤ N ); • [b,a]=zp2tf(z,p,k): ritorna il numeratore ed il denominatore cui corrispondono gli zeri ed i poli specificati nei vettori colonna z e p ed il guadagno k (imponengo a0 = 1). Se length(z) < length(p) utilizza per il numeratore lo stesso ordine del denominatore (e risulta b(1)=b0 =0); • zplane(z,p): visualizza sul piano complesso (tracciandone gli assi e la circonferenza di raggio unitario) gli zeri ed i poli specificati nei vettori colonna z e p (i primi indicati con ◦ ed i secondi con ×), indicandone eventualmente la molteplicitá; • zplane(b,a): è simile al caso precedente, ma visualizza zeri e poli corrispondenti alla f.d.t. razionale specificata dai polinomi (vettori riga) b e a. I polinomi vengono interpretati in z −1 , per potenze crescenti, e vengono visualizzati anche gli zeri o i poli nell’origine. Vediamo con un esempio il funzionamento di alcune di queste funzioni. close all; clear all; % Riprendiamo il filtro della IIR_flt.m b = [0.0393 0 0.0393]; % [b0 b1 b2] a = [1 -1.359 0.923]; % [a0 a1 a2] % Tracciamo zeri e poli [z, p] = tf2zp(b, a); figure(1); zplane(z, p); % Creiamo una griglia ortogonale di punti nel piano complesso: N = 100; % Numero di punti della griglia, su ogni asse punti = linspace(-1.2, 1.2, N); % Valori dei punti [re, im] = meshgrid(punti, punti); % re (im) e‘ una matrice NxN che contiene la parte reale % (immaginaria) di ogni punto del piano. Le sue righe (colonne) % sono tutte uguali e sono formate dagli elementi del vettore % punti % Possiamo ora valutare H(z) zeta = re + j*im; % Sono gli NxN punti in cui valutare H(z) Hz = polyval(b, zeta)./polyval(a, zeta); % (Ho moltiplicato num. es2_freqz.m 6 Lab. ENS - Lezione n. 1 % e den per z^2...) % Creo la superficie (mesh) figure(2); mesh(punti, punti, 20*log10(abs(Hz))); % Visual. il modulo (dB) % Faccio la trasformata di Fourier con freqz (assumo T=F=1) N = 1024; % Numero di punti (con potenza di 2 usa alg. veloce) [H, f] = freqz(b, a, N, 1, ’whole’); % La visualizzo in 3-D, utilizzando plot3(x, y, z)... hold on; plot3(cos(2*pi*f), sin(2*pi*f), 20*log10(abs(H)), ’k.’); xlabel(’parte reale’); ylabel(’parte immaginaria’); zlabel(’|H(z)| [dB]’); axis([-1.2 1.2 -1.2 1.2 -70 10]); % ...ed anche normalmente figure(3); plot(f, 20*log10(abs(H))); grid on; xlabel(’frequenza (Hz)’); ylabel(’|H(z)| [dB]’); % Ora proviamo a rendere il filtro FIR (solo zeri...) % Provare a variare M in funzione della costante di tempo (~25.5) % provare con multipli della costante di tempo e vedere come si comporta il sistema M = 26; h_ = filter(b, a, [1, zeros(1, M)]); % n = 0,1,...,40(=M) % Rivediamo gli zeri z = roots(h_); figure(4); zplane(z, []); % Rifacciamo la zeta-trasformata... Hz_ = polyval(h_, zeta).*zeta.^(-M); % Polyval funziona per % polinomi in z... figure(5); modulo = 20*log10(abs(Hz_)); % Ne faccio il modulo modulo( find(modulo>50) ) = NaN; % Non voglio visualizzare % i punti che esplodono mesh(punti, punti, modulo); % Visualizzo il modulo in dB xlabel(’parte reale’); ylabel(’parte immaginaria’); zlabel(’|H(z)| [dB]’); axis([-1.2 1.2 -1.2 1.2 -70 10]); 2.2 7 Scomposizione in fattori semplici % ... e la trasf. di Fourier H_ = freqz(h_, 1, N, 1, ’whole’); % Uso 1 al posto di a! hold on; plot3(cos(2*pi*f), sin(2*pi*f), 20*log10(abs(H_)), ’k.’); % Sovrappongo i due grafici figure(6) plot(f, 20*log10(abs(H)), ’b’, f, 20*log10(abs(H_)), ’r’); grid on; title(’Filtro vero (blu) e versione approssimata (rosso)’); xlabel(’Frequenza (Hz)’); ylabel(’|H(z)| [dB]’); 2.2 Scomposizione in fattori semplici Assumendo b0 6= 0 possiamo scomporre B(z) e A(z) in fattori del primo ordine ottenendo M Y (1 − zk z −1 ) B(z) , = b0 k=1 H(z) = N A(z) Y −1 (1 − pk z ) (5) k=1 in cui zk e pk sono gli M zeri e gli N poli della f.d.t., che, se complessi, si possono raccogliere in coppie complesse coniugate, visto che i coefficienti ak e bk sono tutti reali. Per funzioni razionali proprie (M ≤ N ) é quindi sempre possibile fattorizzare H(z) in termini a coefficienti reali del tipo H(z) = L L Y Y b0k + b1k z −1 + b2k z −2 = Hk (z), 1 + a1k z −1 + a2k z −2 k=1 (6) k=1 (in cui b0k 6= 0) che possono essere del primo ordine (se a2k = b2k = 0 e a1k 6= 0) oppure del secondo ordine (se a2k 6= 0). Si puó realizzare H(z) come cascata di f.d.t. del secondo ordine. MATLAB per effettuare tale scomposizione (trovare cioè le Second Order Sections), mette a disposizione queste funzioni: • [SOS,k] = tf2sos(b,a): ritorna i coefficienti di L ordine nella matrice SOS nel formato b01 b11 b21 1 a11 b b b 1 a12 02 12 22 ··· ··· ··· ··· ··· b0L b1L b2L 1 a1L termini di (massimo) secondo a21 a22 ··· a2L , (7) che realizzano la f.d.t. B(z)/A(z) se l’argomento k in uscita non é specificato, la prima sezione risulta avere guadagno pari a b0 /a0 e le altre unitario; altrimenti, hanno tutte guadagno unitario (b0k = 1)e k rappresenta il “fattore” b0 /a0 ; • [b,a] = sos2tf(SOS,k): genera la f.d.t. razionale rappresentata dalle sezioni di 8 Lab. ENS - Lezione n. 1 (massimo) secondo ordine specificate in SOS a cui viene aggiunto un termine di guadagno k. es3_cascata.m Vediamo con un esempio il funzionamento di alcune di queste funzioni. close all; clear all; % Genero un filtro passa basso (la funzione ellip ed il suo funzionamento % sara’ spiegato in seguito) % (ordine N = M = 4, "ripple" in banda passante 1 dB % attenuazione 40 dB e banda passante di Fs/5) [b, a] = ellip(4, 1, 40, (1/5)/2); % Genero un segnale in ingresso f0 = 1/30; f1 = 3/5; n = 0:1:1000; x = 2*sin(2*pi*f0*n) + cos(2*pi*f1*n); % Lo filtro con il filtro di ordine 4 y = filter(b, a, x); % Scompongo il filtro in 2 celle di ordine 2 SOS = tf2sos(b, a); % Estraggo i coefficienti per i 2 filtraggi b1 = SOS(1, 1:3); a1 = SOS(1, 4:6); b2 = SOS(2, 1:3); a2 = SOS(2, 4:6); % Effettuo fitraggio in cascata x_int = filter(b1, a1, x); y_cascata = filter(b2, a2, x_int); % Stimo la differenza tra i due modi di operare err = sum( abs(y - y_cascata).^2 ); % Visualizzo i segnali figure(1) plot(n, x, ’b’, n, y, ’r’, n, y_cascata, ’k.’); legend(’ingresso’, ’uscita (quarto ordine)’, ’uscita (cascata)’); axis([0 150 -2.1 2.1]) grid; xlabel(’n’); ylabel(’ampiezza’); [H, f] = freqz(b, a, 1024, 1, ’whole’); 2.3 9 Scomposizione in frazioni parziali % Visualizzo la risposta figure(2) subplot(2,1,1); plot(f, 20*log10(abs(H))); grid xlabel(’f (Hz)’) ylabel(’|H(f)| (dB)’); subplot(2,1,2); plot(f, unwrap(angle(H))/pi); grid xlabel(’f (Hz)’) ylabel(’angle(H(f))/\pi (rad)’); 2.3 Scomposizione in frazioni parziali Una qualunque f.d.t. razionale strettamente propria (con M < N ) con poli in pk di P molteplicità νk (tali che k νk = N ) si può scomporre univocamente nella somma di termini più semplici: νk XX rki . (8) H(z) = (1 − pk z −1 )i i=1 k Nel caso in cui tutti i poli siano semplici si ha dunque H(z) = N X k=1 rk , 1 − pk z −1 (9) in cui i residui rk si calcolano con rk = lim H(z)(1 − pk z −1 ). z→pk Ricomponendo nella (9) le coppie complesse coniugate di poli (i residui risultano complessi coniugati) si ottiene la seguente scomposizione a coefficienti reali: H(z) = L X k=1 L X c0k + c1k z −1 = Hk (z) 1 + a1k z −1 + a2k z −2 (10) k=1 in cui eventualmente risulta a2k = c1k = 0. Se M ≥ N , ci si puó ricondurre al caso considerato dividendo il numeratore per il denominatore, ovvero trovando i polinomi in z −1 Q(z) ed R(z) tali che H(z) = B(z) R(z) = Q(z) + A(z) A(z) (11) e con grado di R(z) (la sua massima potenza in z −1 ) minore del grado di A(z). Nel caso M ≤ N possiamo scrivere, inoltre, ν H(z) = k 0 XX b0 z N + b1 z N −1 + · · · + bM z N −M rki = b + 0 z N + a1 z N −1 + · · · + aN (z − pk )i i=1 (12) k dove pk e νk hanno il significato visto in (8) e b0 = H(∞). Se i poli sono semplici (ed 10 Lab. ENS - Lezione n. 1 0 allora rk1 = limz→pk H(z)(z − pk )), sommando i termini relativi alle coppie complesse coniugate otteniamo la seguente rappresentazione alternativa a coefficienti reali: H(Z) = b0 + L X k=1 L X d1k z −1 + d2k z −2 = b0 + Hk0 (z), −1 −2 1 + a1k z + a2k z (13) k=1 in cui eventualmente a2k = d2k = 0. La (10) e la (13) rappresentano delle realizzazioni in parallelo di H(z). MATLAB permette di trovare agevolmente i coefficienti di tali termini con le funzioni: • [r,p,k] = residuez(b,a): calcola i residui r ed i poli p corrispondenti alla (8) (od alla (9) nel caso di fattori semplici); se M ≥ N ritorna in k il polinomio (in z −1 ) quoziente della divisione tra b e a. Si puó utilizzare [b,a] = residuez(r,p,k) per ricostruire i polinomi a partire dai poli e dai residui specificati; • [r,p,k]=residue(b,a): simile a residuez calcola residui e poli, ma relativi alla (12) (NB: nel caso M < N per avere risultati corretti vanno aggiunti N − M zeri in coda al vettore b, rappresentando cosí il corretto polinomio in z al numeratore); in k viene ritornato b0 (oppure il polinomio quoziente, in z, della divisione tra b e a). Anche per questa funzione vale la sintesi inversa [b,a] = residue(r,p,k). es4_parallelo.m Consideriamo un esempio: close all; clear all; % Genero un filtro passa basso % (ordine N = M = 4, "ripple" in banda passante 1 dB % attenuazione 40 dB e banda passante di Fs/5) [b, a] = ellip(4, 1, 40, (1/5)/2); % Genero un segnale in ingresso f0 = 1/30; f1 = 3/5; n = 0:1:1000; x = 2*sin(2*pi*f0*n) + cos(2*pi*f1*n); % Lo filtro con il filtro di ordine 4 y = filter(b, a, x); % Scompongo il filtro in fratti semplici [r, p, k] = residuez(b, a); % Visualizzo le posizioni di zeri e poli figure(1) zplane(b, a); % Raggruppo i poli complessi coniugati a1 = conv([1 -p(1)], [1 -p(2)]); b1 = r(1) * [1 -p(2)] + r(2) * [1 -p(1)]; a2 = conv([1 -p(3)], [1 -p(4)]); 2.3 Scomposizione in frazioni parziali b2 = r(3) * [1 -p(4)] + r(4) * [1 -p(3)]; % Effettuo fitraggio in parallelo x_int1 = filter(b1, a1, x); x_int2 = filter(b2, a2, x); x_int3 = k * x; y_parallelo = x_int1 + x_int2 + x_int3; % Stimo la differenza tra i due modi di operare err = sum( abs(y - y_parallelo).^2 ); % Visualizzo i segnali figure(2) plot(n, x, ’b’, n, y, ’r’, n, y_parallelo, ’k.’); legend(’ingresso’, ’uscita (quarto ordine)’, ’uscita (parallelo)’); axis([0 150 -2.1 2.1]) grid; xlabel(’n’); ylabel(’ampiezza’); [H, f] = freqz(b, a, 1024, 1, ’whole’); % Visualizzo la risposta figure(3) subplot(2,1,1); plot(f, 20*log10(abs(H))); grid xlabel(’f (Hz)’) ylabel(’|H(f)| (dB)’); subplot(2,1,2); plot(f, unwrap(angle(H))/pi); grid xlabel(’f (Hz)’) ylabel(’angle(H(f))/\pi (rad)’); 11
Documenti analoghi
Ese_filtri_a_tempo_d..
plot ( f , angle ( H )) . Si deve notare come df possa essere scelta piccola a piacere.
II) Si può utilizzare la funzione freqz (⋅) per stimare la risposta in frequenza direttamente dalla
descrizio...
Guida al Control Toolbox
n (numero ingressi) colonne. In MATLAB ciò viene tradotto usando 2 celle di n×m vettori, uno con
tutti i numeratori delle funzioni di trasferimento e l'
altro con i denominatori, quindi la coppia
n...
Lez 2 - MATLAB
partire dalle sue equazioni parametriche.
Esempio
Dalle equazioni parametriche dell’elicoide