Wie zeichne ich den Frequenzgang eines Butterworth-Bandpassfilters in MATLAB manuell ohne Frequenzfunktion?

15

Ich habe Code wie unten, der ein Bandpassfilter auf ein Signal anwendet. Ich bin ein ziemlicher Neuling bei DSP und möchte verstehen, was sich hinter den Kulissen abspielt, bevor ich fortfahre.

Um dies zu tun, möchte ich wissen, wie man den Frequenzgang des Filters grafisch darstellt, ohne ihn zu verwenden freqz.

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

[b, a]Wie würde ich das tun, wenn ich die Ausgaben annehmen würde? Dies scheint eine einfache Aufgabe zu sein, aber es fällt mir schwer, das zu finden, was ich in der Dokumentation oder online benötige.

Ich möchte auch verstehen, wie das so schnell wie möglich geht, z. B. mit einem fftoder anderen schnellen Algorithmus.

Wilhelm
quelle

Antworten:

25

Wir wissen, dass die Übertragungsfunktion eines Filters im Allgemeinen gegeben ist durch:

H(z)=k=0Mbkz-kk=0Neinkz-k

Setzen Sie nun z=ejω , um die Übertragungsfunktion auf dem Einheitskreis zu bewerten:

H(ejω)=k=0Mbke-jωkk=0Neinke-jωk

Somit wird dies nur ein Problem der Polynomauswertung bei einem gegebenen ω . Hier sind die Schritte:

  • Erstellen Sie einen Vektor der Winkelfrequenzen ω=[0,,π] für die erste Hälfte des Spektrums (Sie müssen nicht auf 2π ) und speichern Sie ihn in w.
  • Berechnen Sie den Exponenten e-jω und speichern Sie ihn in einer Variablen ze.
  • Verwenden Sie die polyvalFunktion, um die Werte von Zähler und Nenner durch Aufrufen von: zu berechnen polyval(b, ze), zu teilen und in zu speichern H. Da wir an der Amplitude interessiert sind, nehmen wir den absoluten Wert des Ergebnisses.
  • In dB-Skala umwandeln mit: HdB=20Log10H - in diesem Fall ist 1 der Referenzwert.

All das in Code einfügen:

%% 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)

Ursprüngliche Ausgabe von freqz:

Bildbeschreibung hier eingeben

Und die Ausgabe meines Skripts:

Bildbeschreibung hier eingeben

Und schneller Vergleich im linearen Maßstab - sieht gut aus!

[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'})

Bildbeschreibung hier eingeben

Jetzt können Sie es in eine Funktion umschreiben und einige Bedingungen hinzufügen, um es nützlicher zu machen.


Ein anderer Weg (der zuvor vorgeschlagen wurde, ist zuverlässiger) wäre die Verwendung der fundamentalen Eigenschaft, dass der Frequenzgang eines Filters eine Fourier-Transformation seines Impulsgangs ist:

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

δ(t)

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));

Im Vergleich ergibt sich folgendes:

Bildbeschreibung hier eingeben

jojek
quelle
1
Detaillierte Erklärung
Partida
Ich denke diese Linie a = [1 -0.5 -0.25]; % Some filter with lot's of static gain. Können Sie mir die Auswahl dieser Parameter hier erläutern? Ich lese das Handbuch meines Matlab und es steht [h,w] = freqz(hfilt,n)in einem Teil der Synapse. Sie geben zwei Filter (a, b) in freqz. Sind beide Filter in hfilt? Oder einer in n?
Léo Léopold Hertz 준영
Nur um für andere zu verdeutlichen: "Es ist nicht erforderlich, auf 2 pi zu steigen", wenn die Koeffizienten real sind. Es gibt Anwendungen für Filter mit komplexen Koeffizienten, und in diesem Fall ist das Spektrum nicht mehr symmetrisch und möchte in diesem Fall die Frequenz auf 2 pi erweitern.
Dan Boschen
14

Dies ist nur ein Nachtrag zu Jojeks Antwort, die allgemeiner gehalten ist und bei Verwendung von Mathematik mit doppelter Genauigkeit perfekt funktioniert. Wenn die Genauigkeit geringer ist, tritt ein "Kosinusproblem" auf, das auftritt, wenn entweder die Frequenz im Frequenzgang sehr niedrig ist (viel niedriger als in Nyquist), oder wenn die Resonanzfrequenzen des Filters sehr niedrig sind.

|H(ejω)|2|H(e-jω)|=|H(ejω)|

Betrachten Sie diese Trigger-Identität:

cos(ω) = 1-2Sünde2(ω2)

Sünde2(ω2)ω0

Also, was ich getan habe, ist, die oben angegebene Triggeridentität zu verwenden und alle Cosinus-Terme zu entfernen und sie im Wesentlichen durch Terme zu ersetzen, die wie aussehenSünde2(ω2)

H(z)=b0+b1z-1+b2z-2ein0+ein1z-1+ein2z-2

das hat einen komplexen Frequenzgang

H(ejω)=b0+b1e-jω+b2e-j2ωein0+ein1e-jω+ein2e-j2ω

welches die quadratische Größe hat:

|H(ejω)|2=|b0+b1e-jω+b2e-j2ω|2|ein0+ein1e-jω+ein2e-j2ω|2=(b0+b1cos(ω)+b2cos(2ω))2+(b1Sünde(ω)+b2Sünde(2ω))2(ein0+ein1cos(ω)+ein2cos(2ω))2+(ein1Sünde(ω)+ein2Sünde(2ω))2=b02+b12+b22+2b1(b0+b2)cos(ω)+2b0b2cos(2ω)ein02+ein12+ein22+2ein1(ein0+ein2)cos(ω)+2ein0ein2cos(2ω)

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

Mit der obigen Triggeridentität erhalten Sie das Quadrat der Größe:

|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
quelle
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