Filtry
Spis treści
AS/ Funkcja przejścia i filtry
Cyfrowe filtry liniowe niezmiennicze w czasie \(x[n] \longrightarrow \boxed{LTI} \longrightarrow y[n]\) opisuje liniowe równanie różnicowe o stałych współczynnikach
- \( \displaystyle y[n] = - \sum_{k=1}^K a_k y[n-k] + \sum_{l=0}^L b_l x[n-l] \)
gdzie \(a_k\) i \(b_l\) to współczynniki, \(x[n]\) to sygnał wejściowy, a \(y[n]\) — wyjście. Przenosząc wyrazy z \(y\) na lewą stronę i przyjmując \(a_0=1\), równanie to można zapisać w symetrycznej postaci
- \( \displaystyle \sum_{k=0}^K a_k y[n-k] = \sum_{l=0}^L b_l x[n-l] \)
Znaki: taki zapis (ten sam co np. w scipy.signal) różni się od zapisu modelu AR, \(s[n]=\sum_i a_i s[n-i]+\epsilon[n]\): współczynnik \(a_k\) filtra odpowiada współczynnikowi \(-a_k\) modelu AR.
Funkcja przejścia (transfer function)
Zastosujmy do obu stron powyższego równania transformatę \(\mathcal{Z}\):
- \( \displaystyle \mathcal{Z}\left\{\sum_{k=0}^K a_k y[n-k] \right\} = \mathcal{Z}\left\{ \sum_{l=0}^L b_l x[n-l] \right\} \)
- \( \displaystyle \sum_{k=0}^K a_k \mathcal{Z}\left\{ y[n-k]\right\} = \sum_{l=0}^L b_l \mathcal{Z} \left\{x[n-l]\right\} \)
- \( \displaystyle \sum_{k=0}^K a_k z^{-k} Y(z) = \sum_{l=0}^L b_l z^{-l} X(z) \)
- \( \displaystyle Y(z) \sum_{k=0}^K a_k z^{-k} = X(z) \sum_{l=0}^L b_l z^{-l} \)
- \( \displaystyle \frac{Y(z)}{X(z)} \equiv H(z) = \frac{\sum_{l=0}^L b_l z^{-l}}{\sum_{k=0}^K a_k z^{-k}} \)
Filtry
Funkcja przejścia \(H(z)\) pozwala zwięźle przedstawić działanie filtra LTI na sygnał \(x\) w przestrzeni transformaty \(\mathcal{Z}\):
- \( \displaystyle Y(z)=H(z)X(z)=\frac{b_0 + b_1 z^{-1}+\dots +b_{L} z^{-L}}{a_0+a_1 z^{-1}+\dots +a_{K} z^{-K}}X(z) \)
gdzie \(X(z)\) to transformata \(\mathcal{Z}\) filtrowanego sygnału (wejścia \(x\)), \(Y(z)\) — wyjścia, a \(H(z)\) to wprowadzona powyżej funkcja przejścia filtra. Filtrowanie w przestrzeni transformaty \(\mathcal{Z}\) odpowiada przemnożeniu transformaty sygnału przez funkcję przejścia filtra. Analogicznie w przestrzeni częstości — dla \(z = e^{i\omega}\) funkcja przejścia zależy od częstości \(\omega\).
- \( \displaystyle Y(e^{i\omega})=H(e^{i\omega})X(e^{i\omega})=\frac{b_0+b_1 e^{-i\omega}+\dots +b_L e^{-i L\omega}}{a_0+a_1 e^{-i\omega}+\dots +a_K e^{-i K\omega}}X(e^{i\omega}) \)
Działanie funkcji przejścia (czyli filtra) na składową sygnału \(x\) o częstości \(\omega_k\), przedstawioną we współrzędnych biegunowych jako \(|X_k| e^{i (\omega_k n + \theta_k)}\), odpowiada wymnożeniu jej przez liczbę zespoloną \(H(e^{i\omega_k})\), którą również można przedstawić we współrzędnych biegunowych, jako \(|A_k| e^{i \phi_k}\):
- \(y_k[n] = |A_k| e^{i \phi_k} |X_k| e^{i (\omega n + \theta_k)} = |A_k| |X_k| e^{i ( \phi_k +\theta_k)} e^{i \omega n} \)
W wyniku filtrowania sinusoidalna składowa sygnału o danej częstości może zmienić amplitudę i fazę, ale nie zmienia częstości.
Finite Impulse Response (FIR) — filtr o skończonej odpowiedzi impulsowej
Jeśli w równaniu
- \( \displaystyle \sum_{k=0}^K a_k y[n-k] = \sum_{l=0}^L b_l x[n-l] \)
położymy \(a_i = 0\) poza \(a_0=1\), dostaniemy
- \( \displaystyle y[n] = \sum_{l=0}^L b_l x[n-l] \)
W funkcji przejścia mianownik będzie stały i dostaniemy
\( \displaystyle Y[z]=H[z]X[z]=\left(b_0+b_1 z^{-1}+\dots +b_L z^{-L}\right) X[z] \)
a w dziedzinie czasu, z pełnego równania
- \( \displaystyle y[n] = b_0 x[n]+ b_1 x[n-1] + \dots + b_L x[n-L] \,\,\, - \,\,\, a_1 y[n-1] - \dots - a_K y[n-K] \)
pozostaje
- \( \displaystyle y(n) = b_0 x[n] + b_1 x[n-1] + \dots + b_L x[n-L] \)
Jeśli współczynniki \(b_i\) zapiszemy jako sekwencję \(b[i]\), zobaczymy, że działanie takiego filtra na sygnał \(x[n]\) w dziedzinie czasu jest splotem sekwencji współczynników filtra z sygnałem:
- \( \displaystyle y(n) = b[0] x[n] + b[1] x[n-1] + \dots + b[L] x[n-L] = b[n]*x[n] \)
gdzie \(*\) oznacza splot. Podstawiając \(x=\delta\) widzimy, że odpowiedzią impulsową jest sam ciąg współczynników: \(h[n]=b[n]\). Taki filtr nazywamy filtrem o skończonej odpowiedzi impulsowej (Finite Impulse Response, FIR), bo odpowiedź na impuls kończy się po \(L+1\) próbkach. Inna nazwa to średnia biegnąca (Moving Average, MA).
Filtr FIR o symetrycznych współczynnikach, \(b_l=b_{L-l}\), ma dokładnie liniową fazę. Wyciągając przed sumę czynnik \(e^{-i\omega L/2}\) dostajemy
- \( \displaystyle H(e^{i\omega})=\sum_{l=0}^L b_l e^{-i\omega l} = e^{-i\omega L/2}\sum_{l=0}^L b_l e^{-i\omega (l-L/2)} = e^{-i\omega L/2}\sum_{l=0}^L b_l \cos\big(\omega(l-L/2)\big) \)
W ostatnim kroku wyrazy \(l\) i \(L-l\) mają równe współczynniki i przeciwne wykładniki, więc ich suma jest rzeczywista i (wzór Eulera) daje kosinus. Zmiana znaku tej rzeczywistej sumy to tylko skok fazy o \(\pi\). Czynnik \(e^{-i\omega L/2}\) odpowiada przesunięciu w czasie o \(L/2\) próbek. Dla niesymetrycznych współczynników faza filtra FIR na ogół nie jest liniowa.
Infinite Impulse Response (IIR) — filtr o nieskończonej odpowiedzi impulsowej
Jeśli w równaniu
- \( \displaystyle \sum_{k=0}^K a_k y[n-k] = \sum_{l=0}^L b_l x[n-l] \)
położymy \(b_i = 0\) poza \(b_0=1\), dostaniemy
- \( \displaystyle \sum_{k=0}^K a_k y[n-k] = x[n] \)
w funkcji przejścia licznik będzie stały
- \( \displaystyle Y[z]=H[z]X[z]=\frac{1}{a_0+a_1 z^{-1}+\dots +a_{K} z^{-K}}X[z] \)
Operacja splotu działa tu na sekwencji wyjściowej:
- \( y[n] = x[n] - a[1] y[n-1] - \dots - a[n_a] y[n-K] \)
dlatego taki filtr nazwać można filtrem rekursywnym, autoregresyjnym (AR), lub filtrem o nieskończonej odpowiedzi impulsowej (Infinite Impulse Response IIR), bo potencjalnie raz wzbudzony (sekwencją jednostkową) może dowolnie długo produkować niezerowe wyjście. Faza filtrowanego sygnału zaburzana jest nieliniowo (nonlinear phase filter).
Liniowe i nieliniowe opóźnienie fazy, opóźnienie grupowe
Jak ustaliliśmy powyżej, filtry liniowe odpowiadają mnożeniu poszczególnych składowych sygnału wejściowego \(x[n]\) przez liczbę zespoloną, mającą charakterystyczną dla danego filtra amplitudę i fazę, które dla każdej częstości \(\omega\) można wyliczyć z funkcji przejścia \(H(\omega)=|H(\omega)|e^{i\phi(\omega)}\).
Różna dla różnych częstości zmiana amplitudy jest kwintesencją i celem całego procesu filtrowania, w którym z sygnału usuwamy (w praktyce raczej osłabiamy) niechciane częstości. Jednak wywołana tym procesem zmiana faz dla różnych częstości nie jest już tak oczywista. Weźmy sygnał złożony z dwóch oscylacji, o częstościach \(\omega\) i \(2 \omega\):
- \(x(t) = \sin(\omega t) + \sin(2 \omega t)\)
Suma tych dwóch składowych (niebieskie krzywe) na poniższym rysunku przedstawiona jest kolorem czerwonym:
Przesuńmy teraz fazę obydwu sygnałów składowych o tę samą wartość, na przykład \(\pi/2\), i ponownie dodajmy do siebie. Odpowiada to sytuacji, kiedy po przejściu przez filtr sygnału \(x(t) = \sin(\omega t) + \sin(2 \omega t)\) dostajemy \(y(t) = \sin(\omega t + \pi/2) + \sin(2 \omega t + \pi/2)\)
Po przejściu przez system, przesuwający fazę \(\phi\) jednolicie (o \(\Delta\phi=\pi/{2}\)) dla wszystkich częstości, sygnał wyjściowy wygląda zupełnie inaczej, niż sygnał wejściowy. Przed ponownym "złożeniem" każdy z sygnałów składowych został przesunięty o inny odcinek czasu, który dla częstości \(\omega\) wynosi \(\phi/{\omega}\):
- \(\displaystyle \sin(\omega t + \phi) = sin\left(\,\,\omega (t + \phi/{\omega}) \,\, \right) = \sin\left(\,\, \omega (t + \Delta t)\,\, \right) \)
Formalnie, opóźnienie fazy \(\phi\) dla danej częstości \(\omega\) określamy mianem opóźnienia fazowego, i definiujemy jako \(-\phi/\omega\).
Przesunięcie składowej sygnału w czasie zwiemy opóźnieniem grupowym, i definiujemy jako \(-\frac{d \phi(\omega)}{d \omega}\).
Żeby otrzymać sygnał, którego wszystkie składowe będą przesunięte o ten sam odcinek czasu \(\Delta t\), czyli będą miały stałe przesunięcie grupowe, trzeba fazę przesuwać liniowo w zależności od częstości: \(\Delta\phi(\omega) = \omega\Delta t\), wtedy opóźnienie grupowe \(\frac{d \phi(\omega)}{d \omega} = \frac{d (\omega\Delta t)}{d \omega} = \Delta t\) będzie stałe.
W każdym innym przypadku sygnał na wyjściu nie będzie odtwarzał własności fazowych (czyli "kształtu", obserwowanego w dziedzinie czasu) sygnału oryginalnego, nawet w zakresie częstości nie zmienianych w procesie filtrowania — zgadzać się będzie tylko widmo w paśmie przenoszenia.
| kod (uproszczony) |
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 3, 0.01)
s1 = np.sin(2 * np.pi * t)
s2= np.sin(2 * np.pi * t + np.pi/2)
s3= np.sin(2*2 * np.pi * t)
s4= np.sin(2*2 * np.pi * t + np.pi/2)
s5= np.sin(2*2 * np.pi * t + 2*np.pi/2)
fig1, ax1 = plt.subplots(3, 1)
ax1[0].plot(t, s1)
ax1[1].plot(t, s3)
ax1[2].plot(t, s1+s3, 'r')
ax1[0].set_title('sin(wt)')
ax1[1].set_title('sin(2wt)')
ax1[2].set_title('sin(wt) + sin(2wt)')
fig2, ax2 = plt.subplots(3, 1)
ax2[0].plot(t, s2)
ax2[1].plot(t, s4)
ax2[2].plot(t, s2+s4, 'r')
ax2[0].set_title('sin(wt+pi/2)')
ax2[1].set_title('sin(2wt+pi/2)')
ax2[2].set_title('sin(wt+pi/2) + sin(2wt+pi/2)')
fig3, ax3 = plt.subplots(3, 1)
ax3[0].plot(t, s2)
ax3[1].plot(t, s5)
ax3[2].plot(t, s2+s5, 'r')
ax3[0].set_title('sin(w(t+pi/2))')
ax3[1].set_title('sin(2wt+2*pi/2)')
ax3[2].set_title('sin(wt+pi/2) + sin(2wt+2*pi/2)')
plt.show()
|
| kod generujący obrazki |
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 3, 0.01)
s1 = np.sin(2 * np.pi * t)
s2 = np.sin(2 * np.pi * t + np.pi / 2)
s3 = np.sin(2 * 2 * np.pi * t)
s4 = np.sin(2 * 2 * np.pi * t + np.pi / 2)
s5 = np.sin(2 * 2 * np.pi * t + 2 * np.pi / 2)
def fix_axes():
for i in range(0, 3):
ax[i].set_yticks([0], [])
ax[i].set_xlim([0, 3])
ax[i].grid(True)
ax[i].set_frame_on(False)
ax[i].tick_params(length=0)
ax[i].set_ylim(-2, 2)
fig1, ax = plt.subplots(3, 1, dpi=200)
ax[0].plot(t, s1)
ax[1].plot(t, s3)
ax[2].plot(t, s1 + s3, 'r')
ax[0].set_title('sin( $\omega$t )', loc='left')
ax[1].set_title('sin( 2*$\omega$t )', loc='left')
ax[2].set_title('sin( $\omega$t ) + sin( 2*$\omega$t )', loc='left')
fix_axes()
for i in range(0, 3):
ax[i].set_xticks(np.arange(.25, 3, 1), [])
plt.show()
fig2, ax = plt.subplots(3, 1, dpi=200)
ax[0].plot(t, s2)
ax[1].plot(t, s4)
ax[2].plot(t, s2 + s4, 'r')
ax[0].set_title('sin( $\omega$t + $\pi$/2 )', loc='left')
ax[1].set_title('sin( 2*$\omega$t + $\pi/2$ )', loc='left')
ax[2].set_title('sin( $\omega$t + $\pi$/2 ) + sin( 2*$\omega$t + $\pi$/2 )', loc='left')
fix_axes()
for i in range(0, 3):
ax[i].set_xticks(np.arange(0, 3, 1), [])
plt.show()
fig3, ax = plt.subplots(3, 1, dpi=200)
ax[0].plot(t, s2)
ax[1].plot(t, s5)
ax[2].plot(t, s2 + s5, 'r')
ax[0].set_title('sin( $\omega$(t + $\pi$/2) )', loc='left')
ax[1].set_title('sin( 2*$\omega$t + 2*$\pi$/2 )', loc='left')
ax[2].set_title('sin( $\omega$t + $\pi$/2 ) + sin( 2*$\omega$t + 2*$\pi$/2 )', loc='left')
fix_axes()
for i in range(0, 3):
ax[i].set_xticks(np.arange(0, 3, 1), [])
plt.show()
|