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