Comment tracer manuellement la réponse en fréquence d'un filtre Butterworth passe-bande dans MATLAB sans fonction freqz?

15

J'ai un code comme ci-dessous qui applique un filtre passe-bande sur un signal. Je suis tout à fait un noob chez DSP et je veux comprendre ce qui se passe dans les coulisses avant de continuer.

Pour ce faire, je veux savoir comment tracer la réponse en fréquence du filtre sans utiliser freqz.

[b, a] = butter(order, [flo fhi]);
filtered_signal = filter(b, a, unfiltered_signal)

Compte tenu des sorties, [b, a]comment pourrais-je faire cela? Cela semble être une tâche simple, mais j'ai du mal à trouver ce dont j'ai besoin dans la documentation ou en ligne.

J'aimerais également comprendre comment procéder le plus rapidement possible, par exemple en utilisant un fftou un autre algorithme rapide.

William
la source

Réponses:

25

On sait qu'en général la fonction de transfert d'un filtre est donnée par:

H(z)=k=0Mbkzkk=0Nakzk

Remplacez maintenant z=ejω pour évaluer la fonction de transfert sur le cercle unitaire:

H(ejω)=k=0Mbkejωkk=0Nakejωk

Cela devient donc seulement un problème d'évaluation polynôme à une donnée ω . Voici les étapes:

  • Créez un vecteur de fréquences angulaires ω=[0,,π] pour la première moitié du spectre (pas besoin de monter jusqu'à 2π ) et enregistrez-le w.
  • Pré-calculer l'exposant ejω sur chacun d'eux et le stocker dans une variable ze.
  • Utilisez la polyvalfonction pour calculer les valeurs du numérateur et du dénominateur en appelant polyval(b, ze):, divisez-les et enregistrez-les H. Parce que nous nous intéressons à l'amplitude, prenons alors la valeur absolue du résultat.
  • Convertir en échelle dB en utilisant: HdB=20log10H - dans ce cas, 1 est la valeur de référence.

Mettre tout cela dans le code:

%% Filter definition
a = [1 -0.5 -0.25]; % Some filter with lot's of static gain
b = [1 3 2];

%% My freqz calculation
N = 1024; % Number of points to evaluate at
upp = pi; % Evaluate only up to fs/2
% Create the vector of angular frequencies at one more point.
% After that remove the last element (Nyquist frequency)
w = linspace(0, pi, N+1); 
w(end) = [];
ze = exp(-1j*w); % Pre-compute exponent
H = polyval(b, ze)./polyval(a, ze); % Evaluate transfer function and take the amplitude
Ha = abs(H);
Hdb  = 20*log10(Ha); % Convert to dB scale
wn   = w/pi;
% Plot and set axis limits
xlim = ([0 1]);
plot(wn, Hdb)
grid on

%% MATLAB freqz
figure
freqz(b,a)

Sortie originale de freqz:

enter image description here

Et la sortie de mon script:

enter image description here

Et une comparaison rapide à l'échelle linéaire - a fière allure!

[h_f, w_f] = freqz(b,a);
figure
xlim = ([0 1]);
plot(w, Ha) % mine
grid on
hold on
plot(w_f, abs(h_f), '--r') % MATLAB
legend({'my freqz','MATLAB freqz'})

enter image description here

Vous pouvez maintenant le réécrire dans une fonction et ajouter quelques conditions pour le rendre plus utile.


Une autre façon (précédemment proposée est plus fiable) serait d'utiliser la propriété fondamentale, que la réponse en fréquence d'un filtre est une transformée de Fourier de sa réponse impulsionnelle:

H(ω)=F{h(t)}

Par conséquent, vous devez alimenter le signal δ(t) votre système , calculer la réponse de votre filtre et en prendre la FFT:

d = [zeros(1,length(w_f)) 1 zeros(1,length(w_f)-1)];
h = filter(b, a, d);
HH = abs(fft(h));
HH = HH(1:length(w_f));

En comparaison, cela produira ce qui suit:

enter image description here

jojek
la source
1
Explication détaillée
partida
Je pense à cette ligne a = [1 -0.5 -0.25]; % Some filter with lot's of static gain. Pouvez-vous m'expliquer ici la sélection de ces paramètres. Je lis le manuel de mon Matlab et il est écrit [h,w] = freqz(hfilt,n)dans une partie de la synapse. Vous donnez deux filtres (a, b) à freqz. Les deux filtres sont-ils en place hfilt? Ou un en n?
Léo Léopold Hertz
Juste pour clarifier pour les autres: "Pas besoin de monter jusqu'à 2 pi", c'est quand les coefficients sont réels. Il existe des applications pour des filtres à coefficients complexes et dans ce cas le spectre ne sera plus symétrique et voudrait dans ce cas étendre la fréquence à 2 pi.
Dan Boschen
14

ce n'est qu'un addendum à la réponse de jojek qui est plus générale et parfaitement bonne lorsque les mathématiques en double précision sont utilisées. quand il y a moins de précision, il y a un "problème de cosinus" qui surgit lorsque la fréquence dans la réponse en fréquence est très basse (beaucoup plus basse que Nyquist) et aussi quand les fréquences de résonance du filtre sont très basses.

|H(ejω)|2|H(ejω)|=|H(ejω)|

considérez cette identité trig:

cos(ω) = 12sin2(ω2)

péché2(ω2)ω0

péché2(ω2)

H(z)=b0+b1z-1+b2z-2une0+une1z-1+une2z-2

qui a une réponse en fréquence complexe

H(ejω)=b0+b1e-jω+b2e-j2ωune0+une1e-jω+une2e-j2ω

qui a une magnitude au carré:

|H(ejω)|2=|b0+b1ejω+b2ej2ω|2|a0+a1ejω+a2ej2ω|2=(b0+b1cos(ω)+b2cos(2ω))2+(b1sin(ω)+b2sin(2ω))2(a0+a1cos(ω)+a2cos(2ω))2+(a1sin(ω)+a2sin(2ω))2=b02+b12+b22+2b1(b0+b2)cos(ω)+2b0b2cos(2ω)a02+a12+a22+2a1(a0+a2)cos(ω)+2a0a2cos(2ω)

|H(ejω)|cos(ω)cos(2ω)ω11

en utilisant l'identité trig ci-dessus, vous obtenez pour la grandeur au carré:

|H(ejω)|2=b02+b12+b22+2b1(b0+b2)cos(ω)+2b0b2cos(2ω)a02+a12+a22+2a1(a0+a2)cos(ω)+2a0a2cos(2ω)=b02+b12+b22+2b1(b0+b2)(12sin2(ω2))+2b0b2(12sin2(ω))a02+a12+a22+2a1(a0+a2)(12sin2(ω2))+2a0a2(12sin2(ω))=b02+b12+b22+2b1(b0+b2)(12sin2(ω2))+2b0b2(2cos2(ω)1)a02+a12+a22+2a1(a0+a2)(12sin2(ω2))+2a0a2(2cos2(ω)1)=b02+b12+b22+2b1(b0+b2)(12sin2(ω2))+2b0b2(2(12sin2(ω2))21)a02+a12+a22+2a1(a0+a2)(12sin2(ω2))+2a0a2(2(12sin2(ω2))21)=b02+b12+b22+2b1(b0+b2)(12ϕ)+2b0b2(2(12ϕ)21)a02+a12+a22+2a1(a0+a2)(12ϕ)+2a0a2(2(12ϕ)21)=b02+b12+b22+2b1(b0+b2)(12ϕ)+2b0b2(18ϕ+8ϕ2)a02+a12+a22+2a1(a0+a2)(12ϕ)+2a0a2(18ϕ+8ϕ2)=b02+b12+b22+2b1b0+2b1b24(b1b0+b1b2)ϕ+2b0b216b0b2ϕ+16b0b2ϕ2a02+a12+a22+2a1a0+2a1a24(a1a0+a1a2)ϕ+2a0a216a0a2ϕ+16a0a2ϕ2=(b02+b12+b22+2b1b0+2b1b2+2b0b2)4(b1b0+b1b24b0b2)ϕ+16b0b2ϕ2(a02+a12+a22+2a1a0+2a1a2+2a0a2)4(a1a0+a1a24a0a2)ϕ+16a0a2ϕ2=14(b02+b12+b22+2b1b0+2b1b2+2b0b2)(b1b0+b1b24b0b2)ϕ+4b0b2ϕ214(a02+a12+a22+2a1a0+2a1a2+2a0a2)(a1a0+a1a24a0a2)ϕ+4a0a2ϕ2=(b0+b1+b22)2ϕ(4b0b2(1ϕ)+b1(b0+b2))(a0+a1+a22)2ϕ(4a0a2(1ϕ)+a1(a0+a2))

where ϕsin2(ω2)

if your gear is intending to plot this as dB, it comes out as

20log10|H(ejω)| = 10log10((b0+b1+b22)2ϕ(4b0b2(1ϕ)+b1(b0+b2)))10log10((a0+a1+a22)2ϕ(4a0a2(1ϕ)+a1(a0+a2)))

so your division turns into subtraction, but you have to be able to compute logarithms to some base or another. numerically, you will have much less trouble with this for low frequencies than doing it the apparent way.

robert bristow-johnson
la source
2
That's really cool, thank you Robert! +1
jojek
@Robert I "believe" similar to my comment for Jojek above that this only applies as well when the coefficients are real (and therefore the spectrum is symmetric and thus the magnitude converts to cosines as you show)... Am I correct?
Dan Boschen
yes. that commitment is made when you go from the first line of |H(ejω)|2=... to the second line. no going back after that.
robert bristow-johnson