Filtri Ideali e Reali
Introduzione
Section titled “Introduzione”La teoria dei Segnali e un Circuito in regime sinusoidale si incontrano al bar, ma non si salutano.
Tra i sistemi fisici ed in particolare sotto i cosiddetti sistemi LTI (lineari tempo-invariati), è opportuno porre l’accento sui filtri ideali. Un filtro è un sistema LTI selettivo nel dominio delle frequenze.
I filtri ideali sono non causali e sono il riferimento a cui approssimare filtri reali, costituiti da circuiti elettrici (resistori, induttori e condensatori). Dunque, grazie alla teoria dei circuiti, è possibile realizzare e studiare fisicamente i filtri.
Le quattro categorie principali di filtri sono:
- LP: passa-basso (low-pass)
- HP: passa-alto (high-pass)
- BP: passa-banda (band-pass)
- BR: elimina-banda (band-rejection)
La banda è l’intervallo di frequenze in cui il segnale assume valori maggiori di zero. Si considera il solo semiasse positivo.
Decibel
Section titled “Decibel”Le scale logaritmiche aiutano nella visualizzazione di grandezze fisiche molto estese su uno (o più) assi. Dalla teoria del circuiti è noto che la potenza elettrica è data dal prodotto tra tensione e corrente: .
Date due potenze e , il rapporto di potenze R è:
Il rapporto di potenze espresso in decibel è:
RdB rappresenta il valore di R espresso in decibel.
Il decibel (dB) è la decima parte del bel (simbolo B):
Il decibel viene adottato per evidenziare rapporti di potenza.
Se si vuole ottenere un valore assoluto, si sostituisce P1 con il riferimento di 1 milli-watt e si ottiene il dBm:
Il dBm può anche essere indicato come dBmW per esplicitare ancora meglio che si tratta di un rapporto di potenze.
A livello teorico, la definizione del dB per le tensioni (calcolate sulla stessa resistenza) è:
Si ottiene, come nel caso precedente, una grandezza relativa. Se si vuole ottenere una grandezza in valore assoluto, allora si deve porre a denominatore 1 milli-volt:
Data la funzione in ingresso al filtro e in uscita dal filtro. è la risposta in frequenza del filtro ed è il rapporto tra grandezze fisiche che rappresentano delle ampiezze. La risposta in ampiezza di un filtro, ovvero il modulo di , può essere scritta come:
Dalla tabella soprastante si nota che la banda a del segnale si ottiene .
Grafici di Filtri Fondamentali
Section titled “Grafici di Filtri Fondamentali”In questo articolo sono presenti simulazione effettuate con Simulink e codice scritto in MATLAB.
%%%% sample usage:% frequency_response(10, 2, 1, 4)%% parameters:% #1: horizontal plots limit (both positive and negative)% #2: band value% #3: lower bound for band-pass and band-rejection plots% #4: upper bound for band-pass and band-rejection plots%%%
function frequency_response(f_lim, B, fL, fH)
% fprintf('»»» number of arguments: %d «««\n', nargin);
if nargin ~= 4 fprintf(['»»» USAGE: ideal_filters(f_lim, B, fL, fH)\n' ... '\tf_lim:\thorizontal plots limit (both positive and negative)\n' ... '\tB:\tband value\n' ... '\tfL:\tlower bound for band-pass and band-rejection plots\n' ... '\tfH:\tupper bound for band-pass and band-rejection plots\n' ... '«««\n']); return; end
% take the absolute value of the first parameter and set as horizontal axes f_lim = abs(f_lim); f = linspace(-f_lim, f_lim, 1001);
% define the functions H_lp = low_pass(f, B); % rect(f ./(2 * B)); H_hp = high_pass(f, B); H_bp = band_pass(f, fL, fH); H_br = band_rejection(f, fL, fH);
% ---
figure('Name', 'Ideal Filters'); plots = [H_lp; H_hp; H_bp; H_br]; titles = ["Low Pass" "High Pass" "Band Pass" "Band Rejection"];
% the use of i1 as loop indexes could cause some issuces since % it is mainly used to represent the immaginary unit for a = 1:4 % fprintf('»»» i1 = %d', i1) subplot(2,2,a) plot(f, plots(a,:),'Color','blue','LineWidth',1.5) hold on plot(f, zeros(size(f)),zeros(size(f)),f,'Color','#808080','LineStyle','--','LineWidth',1.5) title(titles(a)) hold off grid on ylim([-0.1, 1.1]) end
end
% low_pass_plot.DataTipTemplate.DataTipRows(1).Label = "-B"% datatip(lp_plot,-B,0);% datatip(lp_plot,B,0);
function y = low_pass(x, B) y = rect(x ./ (2 * B)); % den = 2 * B; % denominator % y = zeros(1, length(x)); % y(abs(x./den) < 0.5) = 1; % y(abs(x./den) == 0.5) = 0.5;end
function y = high_pass(f, B) y = 1 - low_pass(f, B); % den = 2 * B; % denominator % y = zeros(1, length(x)); % y(abs(x./den) > 0.5) = 1; % y(abs(x./den) == 0.5) = 0.5;end
function y = band_pass(f, fL, fH) B = fH - fL; f0 = (fH + fL) / 2;
rect1 = rect((f-f0) ./ B); rect2 = rect((f+f0) ./ B); y = rect1 + rect2;end
function y = band_rejection(f, fL, fH) y = 1 - band_pass(f, fL, fH);end
function y = rect(x) y = zeros(1, length(x)); y(abs(x) < 0.5) = 1; y(abs(x) == 0.5) = 0.5;end
Le risposte in frequenza dei quattro filtri ideali più noti sono:
%%%% sample usage:% impulse_response(10, 2, 1, 4)%% parameters:% #1: horizontal plots limit (both positive and negative)% #2: band value% #3: lower bound for band-pass and band-rejection plots% #4: upper bound for band-pass and band-rejection plots%%%
function impulse_response(t_lim, B, fL, fH) if nargin ~= 4 fprintf(['»»» USAGE: impulse_response(t_lim, B, fL, fH)\n' ... '\tt_lim:\thorizontal plots limit (both positive and negative)\n' ... '\tB:\tband value\n' ... '\tfL:\tlower bound for band-pass and band-rejection plots\n' ... '\tfH:\tupper bound for band-pass and band-rejection plots\n' ... '«««\n']); return; end
% take the absolute value of the first parameter and set as horizontal axes t_lim = abs(t_lim); t = linspace(-t_lim, t_lim, 10001); B2 = (2 * B)+0.2;
% define the functions h_lp = impulsive_low_pass(t, B); h_hp = impulsive_high_pass(t, B); h_bp = impulsive_band_pass(t, fL, fH); h_br = impulsive_band_rejection(t, fL, fH);
% ---
figure('Name', 'Impulsive Responses'); plots = [h_lp; h_hp; h_bp; h_br]; titles = ["Low Pass" "High Pass" "Band Pass" "Band Rejection"];
% create separate plots for each impulse response % the outer loop determinates which figure to plot (all togheter or not) % the inner loop draws the subplots % the use of i1 and j1 as loop indexes could cause some issuces since % they are mainly used to represent the immaginary unit for a = 1:2 % fprintf('»»» \n i1 = %d', i1)
for b = 1:4 % fprintf('»»» \n j1 = %d', j1)
if a == 1 subplot(2,2,b) elseif a == 2 figure('Name', titles(b)) end
plot(t, plots(b,:), 'Color', 'blue','LineWidth',1.5) hold on plot(t, zeros(size(t)), zeros(size(t)), t, 'Color', '#808080', 'LineStyle','--','LineWidth',1.5) title(titles(b)) hold off grid on ylim([-B2, B2]) end endend
function y = impulsive_low_pass(x, B) y = 2 * B * sinc(2*B .* x);
% true_h_lp = zeros(1,length(t)); % two_b = B * 2; % true_h_lp(t==0)=1; % true_h_lp(t~=0)= two_b * sin(two_b * pi*t(t~=0))./(two_b * pi*t(t~=0));end
function y = impulsive_high_pass(x, B) y = dirac(x) - 2 * B * sinc(2*B .* x);end
function y = impulsive_band_pass(x, fL, fH) B = fH - fL; f0 = (fH + fL) / 2;
y = 2 * B * sinc(B .* x) .* cos(2 * pi * f0 .* x);end
function y = impulsive_band_rejection(x, fL, fH) y = dirac(x) - impulsive_band_pass(x, fL, fH);end
function y = sinc(x) y = zeros(1, length(x)); y(x==0) = 1; y(x~=0) = sin(pi*x(x~=0))./(pi*x(x~=0));end
Le risposte impulsive (nel dominio temporale) dei quattro filtri ideali più noti sono:
Passa-Basso Ideale
Section titled “Passa-Basso Ideale”Simbologia: due sinusoidi con quella più in alto barrata. Le frequenze più alte sono tagliate. La sigla LP in pedice significa low pass.
Il parametro B è la banda del filtro passa-basso.
La banda passante è compresa tra e B. La banda oscura si estende da B a .
Passa-Basso Reale RC
Section titled “Passa-Basso Reale RC”Un filtro passa-basso reale è un circuito formato da un resistore con valore di resistenza R in serie ad un condensatore con capacità elettrica C. Lo schema elettrico potrebbe trarre in inganno facendo sembrare i componenti in parallelo. Il segnale in ingresso è la tensione ai capi dei due componenti in serie, mentre il segnale di uscita è la tensione ai capi del solo condensatore. La corrente scorre nel circuito (idealmente dall’ingresso all’uscita).
Il 1° metodo di risoluzione consiste nel considerare il sistema LTI:
Al circuito è associato il seguente sistema di equazioni:
La risposta impulsiva del sistema passa-basso reale è la risposta all’impulso Delta di Dirac. Inoltre, si ricorda che la Delta di Dirac è la derivata della funzione gradino.
Un sistema LTI a cascata è invertibile, dunque:
con .
Allora rappresenta il transitorio di carica del condensatore:
La risposta impulsiva è la derivata del transitorio di carica:
Si nota la notevole somiglianza con la definizione di esponenziale monolatero:
La risposta in frequenza è la trasformata di Fourier della risposta impulsiva:
La risposta in ampiezza è il modulo della risposta in frequenza:
La risposta in fase è l’argomento della risposta in frequenza:
Il 2° metodo di risoluzione consiste nell’utilizzo del metodo dei fasori, il quale prevede il passaggio ai numeri complessi per rappresentare circuiti elettrici che operano in regime sinusoidale. L’analisi circuitale in regime sinusoidale prevede che ad ogni elemento sia associato un fasore, un valore di impedenza e la corrispondente ammettenza.
L’articolo Analisi in Regime Sinusoidale tratta in modo molto approfondito questo argomento. Si può usare la tabella che segue per ottenere l’impedenza relativa ad un componente:
Elemento | Tempo | Fasore | Impedenza | Ammettenza |
---|---|---|---|---|
R: Resistore | ||||
L: Induttore | ||||
C: Condensatore |
Da notare che la pulsazione è . Nelle formule che seguono, si esplicita la in quanto variabile indipendente dei grafici , e .
Si applica un partitore tra i valori di impedenza della resistenza e del condensatore. Dato il fasore VX della funzione in ingresso . Il fasore VY della tensione in uscita è dato da:
La risposta in frequenza è il rapporto tra il fasore della tensione in uscita e quello della tensione in ingresso:
La risposta in ampiezza è il modulo della risposta in frequenza:
La risposta in fase è l’argomento della risposta in frequenza:
%%%% sample usage:% real_low_pass_RC(1, 0.1)%% parameters:% #1: resistor value in Ohm% #2: capacitor value in Farad%%%
function real_low_pass_RC(R, C) f = linspace(-40, 40, 10001); f_size = zeros(size(f)); w = 2*pi.*f; Z_R = R; Z_C = 1./(1j*w*C); Hf = Z_C ./ (Z_R + Z_C);
% amplitude response: A(f) = |H(f)| Af = 1 ./ sqrt(1 + (2 * pi * R * C .* f) .^ 2);
% the filter is a low pass: f0 = 0; Af0 = 1 / sqrt(2);
% B_(-3) --> band value at -3 dB B3 = 1 / (2 * pi * R * C);
figure(Name="Real Low Pass"); tiledlayout(1, 2) nexttile plot(f, Af, 'LineWidth', 2.5, 'Color', 'blue') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold on yline(Af0, 'Color', 'red', 'LineStyle','-.') hold on xline(B3, 'Color', 'red', 'LineStyle','-.') hold off grid on ylim([-0.1, 1.1]) xlim([-20 20]) ax = gca; chart = ax.Children(5); datatip(chart,B3,Af0); chart = ax.Children(4); datatip(chart,B3,0); chart = ax.Children(3); datatip(chart,0,Af0,"Location","southwest"); title('Real LP - Amplitude Response', FontSize=20)
% ---
% risposta in fase nexttile Fasef = angle(Hf); plot(f, Fasef, 'LineWidth', 2.5, 'Color', 'red') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold off grid on ylim([-2 2]) xlim([-20 20]) title('Real LP - Phase Response', FontSize=20)end
Passa-Basso Reale LR
Section titled “Passa-Basso Reale LR”Un filtro passa-basso reale, a differenza di quanto visto sopra, può anche essere formato ad un induttore con valore di induttanza L in serie ad un resistore con valore di resistenza R. Il segnale in ingresso è la tensione ai capi dei due componenti in serie, mentre il segnale di uscita è la tensione ai capi del solo resistore.
Utilizzando il metodo dei fasori, si ottiene il fasore della tensione in uscita:
Nel dominio delle frequenze si può scrivere:
La risposta in frequenza è il rapporto tra il fasore della tensione in uscita e quello della tensione in ingresso:
La risposta in ampiezza è il modulo della risposta in frequenza:
Studiando la risposta in ampiezza al limite, si ricava che:
La risposta in ampiezza trova il proprio massimo per , quindi si tratta di un filtro passa-basso.
si ottiene grazie alla relazione che segue:
La banda a del filtro è il valore positivo (tra i due possibili) di :
La risposta in fase è l’argomento della risposta in frequenza:
%%%% sample usage:% real_low_pass_LR(1, 12.57)%% parameters:% #1: inductor value in Henry% #2: resistor value in Ohm%%%
function real_low_pass_LR(L, R) f = linspace(-40, 40, 10001); f_size = zeros(size(f)); % pulsazione (omega) w = 2*pi.*f; Z_R = R; Z_L = 1j*w*L; Hf = Z_R ./ (Z_R + Z_L); % amplitude response: A(f) = |H(f)| Af = 1 ./ sqrt(1 + (2 * pi * (L/R) .* f) .^ 2); Af0 = 1 / sqrt(2);
% B_(-3) --> band value at -3 dB B3 = R / (2 * pi * L); fprintf("»»» valore di banda B = %f\n", B3);
figure(Name="Real Low Pass - LR"); tiledlayout(1, 2) nexttile plot(f, Af, 'LineWidth', 2.5, 'Color', 'blue') % ... % risposta in fase nexttile Fasef = angle(Hf); plot(f, Fasef, 'LineWidth', 2.5, 'Color', 'red') % ...end
Calcolo dell’uscita dato l’ingresso
Section titled “Calcolo dell’uscita dato l’ingresso”Dato un ingresso nella forma:
N.B. La a cui si fa riferimento in questo paragrafo non è quella del paragrafo precedente.
Allora l’uscita è data da:
Esempio:
Sia con e .
Allora :
La risposta in ampiezza è:
La risposta in fase è:
Allora l’uscita è data da:
Passa-Alto Ideale
Section titled “Passa-Alto Ideale”Simbologia: due sinusoidi con quella più in basso barrata. Le frequenze più basse sono tagliate. La sigla HP in pedice significa high pass.
La banda passante si estende all’infinito. La banda oscura è compresa tra e B.
Passa-Alto Reale CR
Section titled “Passa-Alto Reale CR”Un filtro passa-alto reale è un circuito formato da un condensatore con capacità elettrica C in serie ad un resistore con valore di resistenza R. Lo schema elettrico potrebbe trarre in inganno facendo sembrare i componenti in parallelo. Il segnale in ingresso è la tensione ai capi dei due componenti in serie, mentre il segnale di uscita è la tensione ai capi del solo resistore. La corrente scorre nel circuito (idealmente dall’ingresso all’uscita).
Utilizzando il metodo dei fasori come spiegato per il passa basso, si ottiene il fasore della tensione in uscita. In questo caso, nella formula del partitore, l’impedenza del resistore e l’impedenza del condensatore sono invertite.
La risposta in frequenza è il rapporto tra il fasore della tensione in uscita e quello della tensione in ingresso:
La risposta in ampiezza è il modulo della risposta in frequenza:
Studiando la risposta in ampiezza per e poi per si ottengono i valori:
Allora si ottiene:
La risposta in fase è l’argomento della risposta in frequenza:
%%%% sample usage:% real_high_pass(1, 0.1)%% parameters:% #1: resistor value in Ohm% #2: capacitor value in Farad%%%
function real_high_pass(R, C) if nargin ~= 2 fprintf(['»»» USAGE: real_high_pass(R, C)\n' ... '\tR:\tresistor value [Ohm]\n' ... '\tC:\tcapacitor value [Farad]\n' ... '«««\n']); return; end
f = linspace(-40, 40, 10001); f_size = zeros(size(f)); w = 2*pi.*f; % pulsazione (omega) Z_R = R; Z_C = 1./(1j*w*C); Hf = Z_R ./ (Z_R + Z_C);
% amplitude response: A(f) = |H(f)| Af = 1 ./ sqrt(1 +(1./(2 * pi * R * C .* f) .^ 2));
Af0 = 1 / sqrt(2);
% B_(-3) --> band value at -3 dB B3 = 1 / (2 * pi * R * C); fprintf("»»» valore di banda B = %f\n", B3); figure(Name="Real High Pass"); tiledlayout(1, 2) nexttile plot(f, Af, 'LineWidth', 2.5, 'Color', 'blue') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold on yline(Af0, 'Color', 'red', 'LineStyle','-.') hold on xline(B3, 'Color', 'red', 'LineStyle','-.') hold off grid on ylim([-0.1, 1.1]) xlim([-20 20]) ax = gca; chart = ax.Children(5); datatip(chart,B3,Af0); chart = ax.Children(4); datatip(chart,B3,0); chart = ax.Children(3); datatip(chart,0,Af0,"Location","southwest"); title('Real HP - Amplitude Response', FontSize=20)
% ---
% risposta in fase nexttile Fasef = angle(Hf); plot(f, Fasef, 'LineWidth', 2.5, 'Color', 'red') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold off grid on
ylim([-2 2]) xlim([-20 20]) title('Real HP - Phase Response', FontSize=20)end
Passa-Alto RL
Section titled “Passa-Alto RL”Un filtro passa-alto reale di tipo RL è un circuito formato da un resistore con valore di resistenza R in serie ad un induttore con valore di induttanza L. Lo schema elettrico potrebbe trarre in inganno facendo sembrare i componenti in parallelo. Il segnale in ingresso è la tensione ai capi dei due componenti in serie, mentre il segnale di uscita è la tensione ai capi del solo induttore. La corrente scorre nel circuito (idealmente dall’ingresso all’uscita).
Utilizzando il metodo dei fasori come spiegato per il passa basso, si ottiene il fasore della tensione in uscita.
La risposta in frequenza è il rapporto tra il fasore della tensione in uscita e quello della tensione in ingresso:
La risposta in ampiezza è il modulo della risposta in frequenza:
La risposta in fase è l’argomento della risposta in frequenza:
%%%% sample usage:% real_high_pass_RL(50, 1)%% parameters:% #1: resistor value in Ohm% #2: inductor value in Henry%%%
function real_high_pass_RL(R, L) if nargin ~= 2 fprintf(['»»» USAGE: real_high_pass_RL(R, L)\n' ... '\tR:\tresistor value [Ohm]\n' ... '\tL:\tinductor value [Henry]\n' ... '«««\n']); return; end
f = linspace(-40, 40, 10001); f_size = zeros(size(f)); w = 2*pi.*f; % pulsazione (omega) Z_R = R; Z_L = 1j*w*L; Hf = Z_L ./ (Z_R + Z_L);
% amplitude response: A(f) = |H(f)| Af = 1./(sqrt(1+(R./(2*pi*L .*f)).^2));
Af0 = 1 / sqrt(2);
% B_(-3) --> band value at -3 dB B3 = R / (2 * pi * L); fprintf("»»» valore di banda B = %f\n", B3); figure(Name="Real High Pass"); tiledlayout(1, 2) nexttile plot(f, Af, 'LineWidth', 2.5, 'Color', 'blue') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold on yline(Af0, 'Color', 'red', 'LineStyle','-.') hold on xline(B3, 'Color', 'red', 'LineStyle','-.') hold off grid on ylim([-0.1, 1.1]) xlim([-20 20]) ax = gca; chart = ax.Children(5); datatip(chart,B3,Af0); chart = ax.Children(4); datatip(chart,B3,0); chart = ax.Children(3); datatip(chart,0,Af0,"Location","southwest"); title('Real HP - Amplitude Response', FontSize=20)
% ---
% risposta in fase nexttile Fasef = angle(Hf); plot(f, Fasef, 'LineWidth', 2.5, 'Color', 'red') hold on plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') hold off grid on
ylim([-2 2]) xlim([-20 20]) title('Real HP - Phase Response', FontSize=20)end
Passa-banda Ideale
Section titled “Passa-banda Ideale”Simbologia: tre sinusoidi con quelle esterne barrate. Le frequenze tagliate sono quelle più basse di (low) e più alte di (high). La sigla BP in pedice significa band pass.
La banda passante è compresa tra e , si può quindi affermare che .
La frequenza di centro-banda è:
Il fattore di selettività (o qualità) è:
Passa-Banda Reale RLC
Section titled “Passa-Banda Reale RLC”Un filtro passa-banda reale è un circuito formato da un resistore con valore di resistenza R in serie ad un bipolo costituito da un condensatore con capacità elettrica C in parallelo ad un induttore con induttanza L. Il segnale in ingresso è la tensione ai capi dei due componenti in serie (resistore e bipolo), mentre il segnale di uscita è la tensione ai capi del solo bipolo (condensatore in parallelo ad induttore).
Il metodo dei fasori prevede il passaggio a numeri complessi per rappresentare circuiti elettrici che operano in regime sinusoidale. Si ottengono i fasori:
Si calcola ZP, ovvero l’impedenza in parallelo tra ZL e ZC:
Dato il fasore VX della funzione in ingresso . Il fasore VY della tensione in uscita è dato da:
La risposta in frequenza è il rapporto tra il fasore della tensione in uscita e quello della tensione in ingresso:
La risposta in ampiezza è il modulo della risposta in frequenza:
La frequenza massima della risposta in ampiezza è:
La frequenza di centro banda coincide con la frequenza massima, nel semi-piano positivo:
La frequenza massima (sull’asse orizzontale) interseca il grafico della risposta in ampiezza per . Le frequenze ed intersecano il grafico per :
Bisogna fare qualche utile precisazione:
La banda è data da:
%%%% sample usage:% real_band_pass(5, 0.4, 0.01)%% parameters:% #1: resistor value in Ohm% #2: inductor value in Henry% #3: capacitor value in Farad%%%
function real_band_pass(R, L, C) f = linspace(-40, 40, 10001); f_size = zeros(size(f)); w = 2*pi.*f; % calcolo di H(f) Z_R = R; Z_L = 1j*w*L; Z_C = 1./(1j*w*C); Z_P = (Z_L .* Z_C)./(Z_L + Z_C);
Hf = Z_P ./ (Z_R + Z_P);
% amplitude response: A(f) = |H(f)| Af = abs(Hf); % amplitude response: A(f) = |H(f)| % 1 ./ sqrt(1 + (2 * pi * R * C .* f) .^ 2);
% center frequency: frequenza di centro banda f_0 = 1 / (2*pi*sqrt(L*C)); % x-axis % quality factor: Il fattore di selettività (o qualità) Q = 1/R * sqrt(L/C); % band value B = f_0 ./ Q; f_low = f_0 - (B/2); f_high = f_0 + (B/2);
fprintf("»»» valore di banda B = %f\n", B); fprintf("»»» frequenza di centro banda f0 = %f\n", f_0); fprintf("»»» quality factor Q = %f\n", Q); fprintf("»»» f_low = %f\n", f_low); fprintf("»»» f_high = %f\n", f_high); figure('Name', 'Real Low Pass - Amplitude Response'); plot(f, Af, 'LineWidth', 2.5, 'Color', 'blue') hold on % draw horizontal and vertical axes plot(f, f_size, f_size, f, 'Color', '#808080', 'LineStyle','--') % ... % risposta in fase Fasef = angle(Hf); figure('Name', 'Real Low Pass - Phase Response'); plot(f, Fasef, 'LineWidth', 2.5, 'Color', 'red') % ...end
Elimina-Banda
Section titled “Elimina-Banda”Simbologia: tre sinusoidi con quella interna barrata. Le frequenze tagliate sono quelle più alte di (low) e più basse di (high). La sigla BR in pedice significa band rejection.
Il valore di banda B e di sono uguali al filtro passa-banda.
La banda passante è compresa tra e e si estende da a .
Calcolo della Banda
Section titled “Calcolo della Banda”I filtri ideali sono definiti utilizzando il valore B di banda passante. Un filtro reale cerca di approssimare il comportamento di un filtro ideale ed è definito tramite circuito composto da resistenze, condensatori e induttori.
I filtri reali sono costruiti per ottenere un certo valore di banda, che diventa quindi il punto di arrivo dello sviluppo.
Passa-Basso RC e Passa-Alto CR
Section titled “Passa-Basso RC e Passa-Alto CR”Il valore B di banda passante di un filtro passa-alto/basso reale è legato ai valori di resistenza R e capacità elettrica C.
La costante di tempo del filtro è: .
Grazie alla natura del filtro, la banda coincide con la frequenza di taglio (cutoff):
Il calcolo della banda è uguale per entrambi i filtri. La differenza tra passa-alto e passa-basso sta nelle frequenze che possono passare: sopra o sotto il valore di banda.
N.B. La frequenza di taglio viene indicata con la c o lo zero in pedice: .
Passa-Basso LR
Section titled “Passa-Basso LR”Il valore B di banda passante di un filtro passa-basso LR (serie) è legato ai valore di induttanza L e resistenza R. La costante di tempo del filtro è:
La banda coincide con la frequenza di taglio (cutoff):
(Esisterà sicuramente un passa-alto del tipo RL. La sua banda si calcolerà sicuramente nel medesimo modo).
Passa-Banda RLC
Section titled “Passa-Banda RLC”In un filtro passa-banda RLC, le correlazioni tra i valori di resistenza R, induttanza L e capacità C forniscono i parametri caratteristici del filtro.
La frequenza di centro banda è:
Il fattore di selettività (o qualità) è:
La banda passante è:
Le frequenze di cutoff inferiore e superiore sono:
Il coefficiente di smorzamento è:
La frequenza angolare (natural frequency) è:
La costante di tempo si ottiene grazie al coefficiente di smorzamento e la frequenza angolare:
Applicazioni pratiche
Section titled “Applicazioni pratiche”I filtri studiati nella prima parte di questo articolo trovano importanti applicazioni “reali” nell’editing di immagini e nella modifica di file audio.
Filtri applicati a file audio
Section titled “Filtri applicati a file audio”Lo script filtro_audio
, che verrà illustrato alla fine del paragrafo, permette di applicare i quattro principali tipi di filtro ad una traccia audio fornita dall’utente. Lo script è stato opportunamente modificato, rispetto alla versione illustrata in classe, per permettere all’utente di selezionare i seguenti parametri:
filename
: file audio di ingresso,filter_type
: tipo di filtro da applicare al file di ingresso,B
: dimensione della banda inHz
,f0
: frequenza centrale inHz
.
Si prenda come esempio di file audio un arpeggio, una serie di accordi suonati con una chitarra classica o la canzone Scar Tissue dei Red Hot Chili Peppers.
Passando come filter_type
il valore bp
o band-pass
, lo script filtro_audio
filtra le frequenze al di fuori della banda B
centrate nella frequenza . Si può verificare che, diminuendo progressivamente il valore di B, l’audio in uscita risulterà sempre più selettivo attorno alla nota musicale relativa alla frequenza f0
passata come parametro. Mantenendo invece B
costante e facendo variare f0
, grazie al grafico delle trasformate dei segnali, è possibile apprezzare lo scostamento della banda passante.
%% Utilizzo:% filtro_audio("ScarTissue.wav", 'bp', 3.0e3, 3.0e3)% filename ~ nome del file da leggere (path, URL, ...)% filter_type ~ una stringa tra le seguenti:% 'bp','band-pass', 'br','band-rejection', 'lp','low-pass', 'hp', 'high-pass'% B ~ dimensione di banda [Hz]% f0 ~ frequenza centrale [Hz]function filtro_audio(filename, filter_type, B, f0)% --- Lettura campioni --- %info = audioinfo(filename); % informazioni sul file audiofreqC = 44.1e3; % [Hz]: frequenza di campionamentotempoC = 1 / freqC; % [s]: tempo di campionamentodurata = info.Duration; % [s]: durata del segnale audionumCampioni = freqC * durata; %%numCampioni=info.TotalSamples; % numero totale di campioni% funziona solo se il file è campionato a 44.1e3, altrimenti dà errore
[xstereo,fc] = audioread(filename,[1,numCampioni]);x = (xstereo(:,1))'; % solo canale sinistro% la frequenza di campionamento dipende dal file sorgente, es. CD: 44.1 kHzfprintf('»»» frequenza di campionamento = %d [Hz]\n', fc);
T = 50/B; % durata risposta impulsiva [s]tempoFiltro=0:tempoC:T;tempoNorm = tempoFiltro-T/2;% --- applica un filtro in base al parametro filter_type --- %switch filter_type case {'bp','band-pass'} % --- Filtro passa-banda ideale --- % % più opzioni per uno stesso blocco figure(Name="Filtro passa banda") g=2*B*sinc(B*tempoNorm).*rectpuls(tempoNorm/T).*cos(2*pi*f0*tempoNorm); case {'br','band-rejection'} % --- Filtro elimina-banda ideale --- % figure(Name="Filtro elimina banda") g=2*B*sinc(B*tempoNorm).*rectpuls(tempoNorm/T).*(cos(2*pi*f0*tempoNorm).^2); case {'lp','low-pass'} % --- Filtro passa-basso --- % figure(Name="Filtro passa basso") g=2*B*sinc(2*B*tempoNorm).*rectpuls(tempoNorm/T); case {'hp', 'high-pass'}% --- Filtro passa-alto --- % figure(Name="Filtro passa alto") g=2*B*sinc(B*tempoNorm).*rectpuls(tempoNorm/T).*cos(2*pi*f0*tempoNorm); otherwise warning('Unexpected filter type.') return;end
% --- Uscita filtrata --- %w = conv(g,x) * tempoC; % convoluzione tra g ed xw = w(length(g):length(w));
tempo = 0:tempoC:durata-tempoC;tempoW = tempo(1:length(w))+T/2;
durataTransitorio = 0.0250; % [s]A = 5; % amplificazione: rende più visibile il segnale filtrato (è un valore empirico)
tiledlayout(1, 2); nexttile;plot((tempo-durataTransitorio)*1e3, x, 'Color', 'cyan', 'LineWidth', 2.5);hold on;plot((tempoW-durataTransitorio)*1e3, A*w, 'Color', 'black', 'LineWidth', 1.5);grid on;xlabel('Tempo (ms)', FontSize=14);ylabel('Segnali temporali', FontSize=14);legend('x(t)', 'A\cdot{w(t)}', FontSize=12);axis([2000 2200 -1*max(abs(w)) max(abs(w)) ]);titoloGrafico=sprintf('Filtraggio %s con banda B = %.2f [Hz] e frequenza centrale %.2f [Hz]', filter_type, B, f0);title(titoloGrafico,'FontSize',16);hold off;
% --- Calcolo della trasformata di Fourier dell'ingresso --- %lunghezzaFft = 2^nextpow2(length(x));X = fft(x,lunghezzaFft)*tempoC;X = [X(lunghezzaFft/2+1:lunghezzaFft) X(1:lunghezzaFft/2+1)];frequenza = freqC*linspace(-0.5,0.5,lunghezzaFft+1);
% --- Calcolo della trasformata di Fourier dell'uscita --- %%lunghezzaFft=2^nextpow2(length(w));W = fft(w,lunghezzaFft)*tempoC;W = [W(lunghezzaFft/2+1:lunghezzaFft) W(1:lunghezzaFft/2+1)];%frequenza=freqC*linspace(-0.5,0.5,lunghezzaFft+1);
nexttile; % aggiunge una "piastrella" alla figuraplot(frequenza/1e3,abs(X), 'Color', 'cyan', 'LineWidth', 1.5);hold on;plot(frequenza/1e3,abs(W), 'Color', 'black', 'LineWidth', 1.5);grid on;xlabel('Frequenza (kHz)', FontSize=14);ylabel('Spettro di ampiezza', FontSize=14);legend('|X(f)|', '|W(f)|', FontSize=12);axis([0 8 0 1.2*max(abs(W))]);title('Trasformate di Fourier dei segnali convoluti', 'FontSize',16)hold off;
file = split(filename,".");name = string(file(1));out_filename = sprintf('./output/%s_output_%s_b%.0f_f%.0f.wav',name, filter_type, B, f0);audiowrite(out_filename,[w.'*0.99/max(abs(w)),w.'*0.99/max(abs(w))],freqC);
end
Clipping
Section titled “Clipping”Lo script clip_audio
prende tutto ciò che viene fatto in filtro_audio
ed aggiunge un blocco non lineare a cui il segnale (relativo al file audio) viene dato in pasto a seguito del filtraggio. Questo blocco ha un andamento lineare finché |y|<yM
. Superato questo limite, il valore di z
satura a yM
o –yM
.
Lo scopo del blocco è quello di tagliare il segnale in ingresso, aggiungendovi dei disturbi udibili nel file di output generato al termine del programma. I disturbi sono inversamente proporzionali al valore di yM
. Le trasformazioni non lineari aggiungono inoltre dei contributi in frequenza e contrastano quindi il lavoro dei filtri.
Per semplicità, clip_audio
permette di applicare solamente un filtro passa-basso.
Dato il seguente blocco:
% --- Blocco non lineare --- %switch block_number case 1 % --- blocco #1 --- % yM=0.12; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>yM)=yM; % clipping dei valori maggiori di yM z(y<-yM)=-yM; % clipping dei valori minori di -yM case 2 yM=0.10; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>0)=yM; % clipping dei valori maggiori di 0 z(y<0)=-yM; % clipping dei valori minori di 0 case 3 yM=0.10; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>0)=yM*(1-exp(-y(y>0)./yM)); % clipping dei valori maggiori di 0 z(y<0)=-yM*(1-exp(y(y<0)./yM));% clipping dei valori minori di 0 otherwise warning('Unexpected block number.') return;end
Fornita in ingresso una sinusoide di ampiezza 0.2
e periodo uguale alla dimensione della banda, è interessante notare il confronto del segnale prima e dopo l’applicazione del blocco non lineare.
Applicando il 3° blocco distorsivo all’introduzione della canzone Scar Tissue dei Red Hot Chili Peppers, si ottengono i seguenti grafici.
Si può chiaramente apprezzare il disturbo dovuto al blocco non-lineare. I grafici mostrano in modo chiaro la distorsione, ma ascoltare la traccia audio generata dal comando audiowrite
è sicuramente il modo migliore per comprendere l’entità della distorsione.
%% Utilizzo:% clip_audio('Scar_Tissue.mp3', 3, 1.0e3)% filename: nome del file da leggere (path, URL, ...)% block_number: numero del blocco non-lineare da applicare% B: dimensione di banda [Hz]function clip_audio(filename, block_number, B)
% --- Lettura campioni --- %freqC = 44.1e3; % [Hz]: frequenza di campionamento = 44.1 kHztempoC = 1/freqC; % [s] tempo di campionamentodurataTransitorio=0.1; % [s]durata = 10.0; % [s]numeroCampioni = durata * freqC; % numero totale di campioniinizioCampioni = durataTransitorio*freqC;[xstereo,~]=audioread(filename,[inizioCampioni+1,inizioCampioni+1+numeroCampioni]);x = (xstereo(:,1))'; % solo canale sinistrotempo=0:tempoC:durata;% x = 0.2 .* sin(B.*tempo);
% --- Filtro passa-basso --- %T = 50/B; % durata risposta impulsiva [s]tempoFiltro=0:tempoC:T;tempoNorm = tempoFiltro-T/2;h=2*B*sinc(2*B*tempoNorm).*rectpuls(tempoNorm/T);
% --- Filtraggio --- %y=conv(x,h)*tempoC; % uscita filtratay=y(length(h):length(y));tempoY=tempo(1:length(y))+T/2;tempoY_plot=tempoY-durataTransitorio;
figure;set(gcf,'defaultaxesfontname','Courier New')plot(tempo-durataTransitorio, x, 'Color', 'cyan', 'LineWidth', 1.5);hold on;plot(tempoY_plot, y, 'Color', 'black', 'LineWidth', 1.5);grid on;xlabel('Tempo (s)','FontSize',12);ylabel('Segnali temporali','FontSize',12)legend('x(t)', 'y(t)');axis([0 0.4 -0.8001 0.8001]);
% --- Blocco non lineare --- %switch block_number case 1 % --- blocco #1 --- % yM=0.12; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>yM)=yM; % clipping dei valori maggiori di yM z(y<-yM)=-yM; % clipping dei valori minori di -yM case 2 % --- blocco #2 --- % yM=0.10; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>0)=yM; % clipping dei valori maggiori di 0 z(y<0)=-yM; % clipping dei valori minori di 0 case 3 % --- blocco #3 --- % yM=0.10; % ampiezza della saturazione z=y; % copia non distorta del segnale di ingresso z(y>0)=yM*(1-exp(-y(y>0)./yM)); % clipping dei valori maggiori di 0 z(y<0)=-yM*(1-exp(y(y<0)./yM));% clipping dei valori minori di 0 otherwise warning('Unexpected block number.') return;end
figure;plot(tempoY_plot, y, 'Color', 'cyan', 'LineWidth', 1.5); hold on;plot(tempoY_plot, z, 'Color', 'black', 'LineWidth', 1.5); grid on;xlabel('Tempo (s)','FontSize',12);ylabel('Segnali temporali','FontSize',12);legend('y(t)', 'z(t)');axis([0 0.4 -0.2001 0.2001]);
% --- Calcolo della trasformata di Fourier dell'ingresso --- %lunghezzaFft=2^nextpow2(length(y));Y=fft(y,lunghezzaFft)*tempoC;Y=[Y(lunghezzaFft/2+1:lunghezzaFft) Y(1:lunghezzaFft/2+1)];frequenza=freqC*linspace(-0.5,0.5,lunghezzaFft+1);
% --- Calcolo della trasformata di Fourier dell'uscita --- %%lunghezzaFft=2^nextpow2(length(z));Z=fft(z,lunghezzaFft)*tempoC;Z=[Z(lunghezzaFft/2+1:lunghezzaFft) Z(1:lunghezzaFft/2+1)];%frequenza=freqC*linspace(-0.5,0.5,lunghezzaFft+1);
figure;plot(frequenza/1e3,20*log10(abs(Y)./max(abs(Y))), 'Color', 'cyan', 'LineWidth', 1.5);hold on;plot(frequenza/1e3,20*log10(abs(Z)./max(abs(Y))), 'Color', 'black', 'LineWidth', 1.5);plot(frequenza/1e3,20*log10(abs(Y)./max(abs(Y))), 'Color', 'cyan', 'LineWidth', 0.5);grid on;xlabel('Frequenza (kHz)','FontSize',12);ylabel('Spettro di ampiezza (dB)','FontSize',12);legend('|Y(f)|', '|Z(f)|');axis([0 8 -120 0]);
% scrittura del file audio a cui è stato applicato il filtro% N.B. se il filename è un path relativo e inizia con uno o più punti,% questo modo per estrapolare il nome senza estensione non funziona.% Dunque 'filename' deve essere un path assoluto, a meno che il file non si% trovi nella cartella nella quale è situato lo scriptfile = split(filename,".");name = string(file(1));out_filter= sprintf('./output/%s_output_filter_b%.0f.wav',name,B);out_dist = sprintf('./output/%s_output_dist_b%.0f.wav',name,B);
audiowrite(out_filter,[y.',y.'],freqC);audiowrite(out_dist,[z.',z.'],freqC);
Filtri applicati ad immagini
Section titled “Filtri applicati ad immagini”MATLAB è in grado di leggere il contenuto di un immagine mediante il comando imread
, ad esempio:
x=imread('unife', '.tif');% oppure, con singolo parametro:x=imread('unife.tif');
Ad x
viene assegnata la matrice bidimensionale contenente il segnale di intensità luminosa dell’immagine unife.tif
presente nel path corrente. Le componenti a bassa frequenza descrivono le caratteristiche generali dell’immagini (ai quali l’occhio umano è più sensibile). Le componenti ad alta frequenza descrivono invece i dettagli dell’immagine.
Il comando imgaussfilt
applica un filtraggio passa-basso di tipo Gaussiano. Si ha la possibilità di passare il parametro opzionale deviazione standard (sigma):
sigma = 20; % default: 0.5y1 = imgaussfilt(x, sigma);
Si può applicare un filtro passa-alto sottraendo al segnale originale il segnale ricavato dal filtraggio passa-basso.
z1=x-y1;
Si può ulteriormente filtrare l’immagine sottraendo il segnale filtrato ad un quadrato totalmente bianco.
quadratoBianco=255*ones(size(x),'uint8');y2=quadratoBianco-z1;
Lo script che segue applica questi concetti per generare e mostrare le immagini filtrate, a partire da un’immagine di partenza fornita come parametro, è il seguente:
%% Utilizzo:% filtro_lp_hp_immagine("Unife.tif")function filtro_lp_hp_immagine(filename)
% estrapolazione di nome ed estensione dal parametro in ingressofile = split(filename,".");name = file(1);ext = file(2);
x=imread(name, ext); % lettura immagine
figure;imshow(x); % effettua il grafico dell'immaginetitle('Immagine originale');
%% filtraggio passa-basso di tipo Gaussianosigma = 20;y1 = imgaussfilt(x, sigma);
figureimshow(y1);title('Immagine elaborata con il filtro passa-basso');
% genera un'immagine a partire dal vettore bidimensionale in ingresso% il nome di tale immagine è una concatenazione di stringheimwrite(y1,strcat(name,'_lp.', ext),ext);
%% Filtraggio passa-altoz1=x-y1;
figureimshow(z1);title('Immagine elaborata con il filtro passa-alto');imwrite(z1,strcat(name,'_hp.', ext),ext);
% si può filtrare l'immagine ottenuta sottraendo il segnale filtrato ad un quadrato totalmente biancoquadratoBianco=255*ones(size(x),'uint8');y2=quadratoBianco-z1;
figureimshow(y2);title('passa-alto (bianco)');imwrite(y2,strcat(name,'_white_hp.', ext),ext);
A partire dall’immagine del Dipartimento di Ingegneria di Unife, sono illustrati i risultati dello script precedente:
![]() | ![]() |
---|---|
![]() | ![]() |
Applicazioni della funzione fspecial
Section titled “Applicazioni della funzione fspecial”Tra gli innumerevoli modi per applicare filtri alle immagini, è bene parlare della funzione fspecial
, la quale permette di applicare un filtro avente una determinata risposta impulsiva h
passata come parametro. Per applicare un filtro con fspecial
bisogna fare uso di imfilter
, ad esempio:
# H = fspecial('nome-filtro', altri-parametri);
H = fspecial('motion',20,45);B = imfilter(I,H);imshow(B);
Estrazione delle componenti RGB
Section titled “Estrazione delle componenti RGB”È possibile applicare altre tipologie di filtraggio, tra le quali l’estrazione delle componenti RGB (red, green, blue).
function rgb_extractor(filename)% estrapolazione di nome ed estensione dal parametro in ingresso% N.B. se il filename è un path relativo e inizia con uno o più punti,% questo modo per estrapolare il nome senza estensione non funziona.% Dunque 'filename' deve essere un path assoluto, a meno che il file non si% trovi nella cartella nella quale è situato lo scriptfile = split(filename,".");name = file(1);ext = file(2);
my_image=imread(filename);
% componenti rossa, verde e blu in termini di intensità luminosared_brigh=my_image(:,:,1);green_brigh=my_image(:,:,2);blue_brigh=my_image(:,:,3);black=zeros(size(my_image,1),size(my_image,2));white=my_image(:,:,1:1:1);
% componenti rossa, verde e blu in termini di colorered_component=cat(3,red_brigh,black,black);green_component=cat(3,black,green_brigh,black);blue_component=cat(3,black,black,blue_brigh);just_black=cat(3,black,black,black);just_white=cat(3,white,white,white);
figureimshow(my_image);
figureimshow(red_component);imwrite(red_component,strcat('./output/', name,'_red.', ext),ext);
figureimshow(green_component);imwrite(green_component,strcat('./output/', name,'_green.', ext),ext);
figureimshow(blue_component);imwrite(blue_component,strcat('./output/', name,'_blue.', ext),ext);
figureimshow(just_black);figureimshow(just_white);end
La tabella che segue illustra i risultati ottenuti con lo script appena illustrato:
![]() | ![]() |
---|---|
![]() | ![]() |