1. Z変換とは何か?
Z変換は、離散時間信号 $x[n]$(サンプリングされたデータなど、飛び飛びの値を持つ信号)を、複素平面上の関数 $X(z)$ に変換する数学的手法です。この変換により、時間領域で扱いにくい差分方程式を、$z$ 領域での単純な代数方程式に変換できます。
基本定義式
$$X(z) = \sum_{n=0}^{\infty} x[n] z^{-n}$$
この式は、信号 $x[n]$ を $z^{-1}$ のべき級数として表現していると考えることができます。$z^{-n}$ は時間遅延 $n$ に対応し、各項の係数が信号の値 $x[n]$ です。
2. Z変換の重要な性質と代表例
Z変換を使いこなす上で不可欠な、基本的な変換ペアと重要な性質をまとめます。
代表的な変換ペア
-
インパルス応答 $\delta[n]$:
- $x[n] = \delta[n] = {1, n=0; 0, n \neq 0}$
- $X(z) = \sum_{n=0}^{\infty} \delta[n] z^{-n} = \delta[0] z^0 = 1$
- 単位入力(インパルス)が $z$ 領域では単位元 $1$ になります。
-
単位ステップ関数 $u[n]$:
- $x[n] = u[n] = {1, n \ge 0; 0, n < 0}$
- $X(z) = \sum_{n=0}^{\infty} 1 \cdot z^{-n} = 1 + z^{-1} + z^{-2} + \cdots$
- これは公比 $z^{-1}$ の無限等比級数であり、収束条件 $|z^{-1}| < 1$、つまり $|z| > 1$ のもとで以下のようになります。
- $X(z) = \frac{1}{1 - z^{-1}}$
-
等比数列 $a^n u[n]$:
- $x[n] = a^n u[n]$
- $X(z) = \sum_{n=0}^{\infty} a^n z^{-n} = \sum_{n=0}^{\infty} (az^{-1})^n$
- 同様に、公比 $az^{-1}$ の等比級数として、収束条件 $|az^{-1}| < 1$、つまり $|z| > |a|$ のもとで以下のようになります。
- $X(z) = \frac{1}{1 - az^{-1}}$
Z変換の性質
- 線形性: $ax[n] + by[n] \leftrightarrow aX(z) + bY(z)$
-
シフト定理: 時間領域での信号のシフトは、$z$ 領域での $z$ のべき乗の掛け算に対応します。
- 右シフト(遅延): $x[n-q] \leftrightarrow z^{-q} X(z)$
- 左シフト(進み): $x[n+q] \leftrightarrow z^q \left[ X(z) - \sum_{k=0}^{q-1} x[k] z^{-k} \right]$
- これは、差分方程式をZ変換する際の主要なツールとなります。
-
畳み込み定理: 時間領域での畳み込み演算 $x[n] * v[n] = \sum_{i=0}^{\infty} x[i]v[n-i]$ は、$z$ 領域では単純な積 $X(z)V(z)$ に変換されます。
- これは、離散時間システムの入出力関係を解析する上で極めて重要です。
- 初期値定理: $x[0] = \lim_{z \to \infty} X(z)$
- 最終値定理: $\lim_{n \to \infty} x[n] = \lim_{z \to 1} (z-1)X(z)$
3. Z逆変換の方法
Z変換された関数 $X(z)$ から、元の信号 $x[n]$ を求めるZ逆変換には、主に2つの方法があります。
(1) べき級数展開法(長除法)
- 手順: $X(z) = \frac{B(z)}{A(z)}$ の形式を持つ有理関数を、$z^{-1}$ のべき級数として展開します。分子を分母で割り算(長除法)することで、各項の係数を求めることができます。
-
例: $X(z) = \frac{z^2 - 1}{z^3 + 2z + 4}$
- 長除法を行うと、$X(z) = z^{-1} - 2z^{-3} - 4z^{-4} + \cdots$ となります。
- この展開から、係数 $x[n]$ は $x[0]=0, x[1]=1, x[2]=0, x[3]=-2, x[4]=-4, \dots$ と直接読み取ることができます。
(2) 部分分数展開法
- 手順: Z変換対照表を利用して逆変換を行うために、$X(z)$ を既知のZ変換ペアの形に分解します。一般的に、逆変換を容易にするために $X(z)/z$ の形で展開します。
-
例: $X(z) = \frac{z}{z^2 - 0.5z - 0.5}$
- $X(z)/z = \frac{1}{z^2 - 0.5z - 0.5} = \frac{1}{(z-1)(z+0.5)}$
- これを部分分数に分解すると、$\frac{X(z)}{z} = \frac{A}{z-1} + \frac{B}{z+0.5}$ となります。
- 係数 $A, B$ を求め、元の形に戻すと $X(z) = \frac{A z}{z-1} + \frac{B z}{z+0.5}$ となり、等比数列の変換ペアを利用して逆変換できます。
4. 差分方程式と伝達関数
Z変換は、離散時間システムを解析するための強力なツールです。システムの入出力関係は、差分方程式で表現されます。
差分方程式と伝達関数の関係
-
一般形: N次系の差分方程式は、次のように表されます。
- $\sum_{i=0}^{N} a_i y[n-i] = \sum_{i=0}^{M} b_i x[n-i]$
-
Z変換の適用: この差分方程式の両辺をZ変換し、シフト定理を適用します。初期値をゼロと仮定すると、次のようになります。
- $\sum_{i=0}^{N} a_i z^{-i} Y(z) = \sum_{i=0}^{M} b_i z^{-i} X(z)$
-
伝達関数 $H(z)$: 入力 $X(z)$ に対する出力 $Y(z)$ の比として、伝達関数 $H(z)$ が得られます。
- $H(z) = \frac{Y(z)}{X(z)} = \frac{\sum_{i=0}^{M} b_i z^{-i}}{\sum_{i=0}^{N} a_i z^{-i}}$
- これは、システムの動特性を周波数独立に表現する重要な概念です。
5. 伝達関数の応用と基本フィルタ
伝達関数 $H(z)$ は、システムの特性を分析するための中心的な役割を果たします。
インパルス応答と伝達関数
- 伝達関数 $H(z)$ は、システムのインパルス応答 $h[n]$ のZ変換です。
- $H(z) = \sum_{n=0}^{\infty} h[n] z^{-n}$
- したがって、システムのインパルス応答を知ることは、その伝達関数を知ることと同義です。
周波数特性
- $z$ 平面上の単位円上に $z = e^{j\omega T_s}$ を代入することで、システムの周波数特性を調べることができます。
- $H(e^{j\omega T_s}) = |H(e^{j\omega T_s})| e^{j\theta(\omega)}$
- ここで、$|H(\omega)|$ はゲイン特性(振幅の変化率)、$\theta(\omega)$ は位相特性(位相のずれ)を表します。
基本的なフィルタ例
基本的なフィルタのZ変換について、より詳細に解説します。ご提示いただいた3つのフィルタに加えて、さらに2つの重要なフィルタを追加し、それぞれの差分方程式、伝達関数、そしてその特性について詳しく見ていきましょう。
1. 移動平均フィルタ (FIR ローパスフィルタ)
移動平均フィルタは、隣接する複数のサンプルの平均を計算することで信号を平滑化するフィルタです。これは、過去の入力のみに依存する有限インパルス応答(FIR)フィルタの代表例で、主に高周波ノイズを除去する目的で使われます。
-
差分方程式:
$$y[n] = \frac{1}{M+1}\sum_{m=0}^{M} x[n-m]$$
この式は、現在の出力 $y[n]$ が、現在の入力 $x[n]$ と過去 $M$ 個の入力の平均であることを示しています。 -
伝達関数:
上記の差分方程式をZ変換すると、線形性とシフト定理により、以下の伝達関数が得られます。
$$H(z) = \frac{Y(z)}{X(z)} = \frac{1}{M+1}\sum_{m=0}^{M} z^{-m}$$
このフィルタは分母を持たないため、極は原点にあり、常に安定です。 -
周波数特性:
$z = e^{j\omega T_s}$ を代入すると、ゲインは周波数 $\omega$ が高くなるにつれて減衰します。この特性から、ローパスフィルタとして機能することがわかります。
2. 差分回路 (FIR ハイパスフィルタ)
差分回路は、隣り合うサンプルの差分を計算することで、信号の急激な変化を強調するフィルタです。
-
差分方程式:
$$y[n] = x[n] - x[n-1]$$ -
伝達関数:
Z変換により、伝達関数は以下のようになります。
$$H(z) = 1 - z^{-1}$$
これもFIRフィルタであり、常に安定です。 -
周波数特性:
$z = e^{j\omega T_s}$ を代入すると、ゲインは以下の式で表されます。
$$|H(\omega)| = 2\left|\sin\left(\frac{\omega T_s}{2}\right)\right|$$
このゲインは、低周波($\omega \to 0$)ではほぼゼロになり、高周波($\omega \to \frac{\pi}{T_s}$)では最大値になります。これにより、低周波を減衰させ高周波を通過させるハイパスフィルタとして機能します。
3. 共振器 (IIR フィルタ)
共振器は、特定の周波数帯域を強く増幅するフィルタです。フィードバック(過去の出力)を利用するため、無限インパルス応答(IIR)フィルタに分類されます。
-
差分方程式:
$$y[n] = x[n] + a_1 y[n-1] + a_2 y[n-2]$$ -
伝達関数:
Z変換により、伝達関数は以下のようになります。
$$H(z) = \frac{1}{1 - a_1 z^{-1} - a_2 z^{-2}}$$ -
安定性:
システムの安定性は、伝達関数の極(分母多項式の根)が、$z$ 平面上の単位円の内側にあるかどうかで決まります。極が単位円の近くにある場合、その周波数で共振が発生します。
4. 1次ローパスフィルタ (IIR フィルタ)
これは最もシンプルで一般的なIIRフィルタの一つで、指数移動平均とも呼ばれます。
-
差分方程式:
$$y[n] = (1-\alpha)y[n-1] + \alpha x[n]$$
ここで、$0 < \alpha < 1$ はフィルタの平滑化係数です。 -
伝達関数:
Z変換により、伝達関数は以下のようになります。
$$H(z) = \frac{\alpha}{1 - (1-\alpha)z^{-1}}$$
分母の根(極)は $z = 1-\alpha$ となります。$\alpha$ が0と1の間にあるため、極は単位円の内側にあり、常に安定です。 -
特性:
このフィルタは、入力信号の急激な変化を抑制し、低周波成分を通過させるため、ローパスフィルタとして機能します。
5. 共振子 (IIR バンドパスフィルタ)
これは特定の周波数のみを通過させるバンドパスフィルタの例です。
-
差分方程式:
$$y[n] = x[n] + 2r \cos(\omega_0) y[n-1] - r^2 y[n-2]$$
ここで、$r$ は極の半径、$ \omega_0 $は共振周波数です。 -
伝達関数:
Z変換すると、以下の伝達関数が得られます。
$$H(z) = \frac{1}{1 - 2r \cos(\omega_0) z^{-1} + r^2 z^{-2}}$$ -
特性:
このフィルタは、特定の周波数 $\omega_0$ 付近の信号を強く通過させ、それ以外の周波数を減衰させます。これは、特定の音を抽出したり、特定の周波数のノイズを除去したりするのに使われます。極は $z = r e^{\pm j\omega_0}$ となります。安定性の条件は $|r| < 1$ です。
import numpy as np
import matplotlib.pyplot as plt
# ================= Parameters =================
N = 100 # Number of time steps
# ================= Common Simulation Functions =================
def simulate_response(filter_function, params, title, input_type="step"):
"""
Simulate and plot step or impulse response of a given filter.
input_type: "step" or "impulse"
"""
n = np.arange(N)
if input_type == "step":
x = np.ones(N) # Unit step
elif input_type == "impulse":
x = np.zeros(N)
x[0] = 1.0 # Unit impulse
else:
raise ValueError("input_type must be 'step' or 'impulse'")
y = filter_function(x, params)
plt.figure(figsize=(10, 6))
plt.plot(n, x, 'b--', label=f'Input ({input_type.capitalize()} Signal)')
plt.plot(n, y, 'r-', label='Output (Response)')
plt.title(f'{input_type.capitalize()} Response of {title}')
plt.xlabel('Time Step (n)')
plt.ylabel('Amplitude')
plt.grid(True)
plt.legend()
plt.show()
# ================= Filter Implementations =================
def moving_average_filter(x, M):
"""FIR low-pass: Moving Average Filter"""
y = np.zeros_like(x, dtype=float)
for n in range(len(x)):
sum_x = 0
for m in range(M + 1):
if n - m >= 0:
sum_x += x[n - m]
y[n] = sum_x / (M + 1)
return y
def difference_filter(x, params):
"""FIR high-pass: Difference Circuit"""
y = np.zeros_like(x, dtype=float)
y[0] = x[0]
for n in range(1, len(x)):
y[n] = x[n] - x[n-1]
return y
def resonator_filter(x, params):
"""IIR resonator filter"""
a1, a2 = params
y = np.zeros_like(x, dtype=float)
y[0] = x[0]
y[1] = x[1] + a1 * y[0]
for n in range(2, len(x)):
y[n] = x[n] + a1 * y[n-1] + a2 * y[n-2]
return y
def first_order_lp_filter(x, alpha):
"""IIR first-order low-pass filter"""
y = np.zeros_like(x, dtype=float)
y[0] = alpha * x[0]
for n in range(1, len(x)):
y[n] = (1 - alpha) * y[n-1] + alpha * x[n]
return y
def band_pass_resonator(x, params):
"""IIR band-pass resonator"""
r, omega_0 = params
a1 = 2 * r * np.cos(omega_0)
a2 = -r**2
y = np.zeros_like(x, dtype=float)
y[0] = x[0]
y[1] = a1 * y[0] + x[1]
for n in range(2, len(x)):
y[n] = x[n] + a1 * y[n-1] + a2 * y[n-2]
return y
# ================= Simulation Execution =================
# Example responses for each filter
# Moving Average Filter (M=4)
simulate_response(lambda x, p: moving_average_filter(x, p), 4, "Moving Average Filter (M=4)", "step")
simulate_response(lambda x, p: moving_average_filter(x, p), 4, "Moving Average Filter (M=4)", "impulse")
# Difference Circuit
simulate_response(difference_filter, None, "Difference Circuit (High-pass)", "step")
simulate_response(difference_filter, None, "Difference Circuit (High-pass)", "impulse")
# Resonator (Unstable example: a1=1.5, a2=-0.5)
simulate_response(resonator_filter, (1.5, -0.5), "Resonator (IIR, Unstable)", "step")
simulate_response(resonator_filter, (1.5, -0.5), "Resonator (IIR, Unstable)", "impulse")
# First-Order Low-pass Filter (alpha=0.5)
simulate_response(lambda x, p: first_order_lp_filter(x, p), 0.5, "First-Order Low-pass Filter (alpha=0.5)", "step")
simulate_response(lambda x, p: first_order_lp_filter(x, p), 0.5, "First-Order Low-pass Filter (alpha=0.5)", "impulse")
# Band-pass Resonator (Stable: r=0.9, omega_0=pi/4)
simulate_response(band_pass_resonator, (0.9, np.pi/4), "Band-pass Resonator (IIR)", "step")
simulate_response(band_pass_resonator, (0.9, np.pi/4), "Band-pass Resonator (IIR)", "impulse")