はじめに
LMS(Least Mean Squares)アルゴリズムは、ウィーナーフィルタの最適解を確率的勾配降下法で逐次近似する適応フィルタ手法です。実装が極めて単純(演算量 \(O(L)\) )で安定性も高いため、エコーキャンセラ、ノイズキャンセレーション、チャネル等化、システム同定など幅広い分野で実用されています。
定常確率過程を前提としたウィーナーフィルタは、信号統計(自己相関 \(R_{yy}\) と相互相関 \(R_{sy}\) )が既知という強い仮定を置きます。LMSは統計が未知でも観測サンプルから直接フィルタ係数を更新できる点で、より実用的です。
問題設定
長さ \(L\) の FIR 適応フィルタを考えます。時刻 \(n\) における入力ベクトルとフィルタ係数ベクトルを以下のように定義します。
\[ \mathbf{x}(n) = [x(n), x(n-1), \dots, x(n-L+1)]^\top \tag{1} \] \[ \mathbf{w}(n) = [w_0(n), w_1(n), \dots, w_{L-1}(n)]^\top \tag{2} \]フィルタ出力と誤差は
\[ y(n) = \mathbf{w}(n)^\top \mathbf{x}(n), \qquad e(n) = d(n) - y(n) \tag{3} \]ここで \(d(n)\) は所望信号(教師信号)です。目的は、二乗誤差の期待値(コスト関数)
\[ J(\mathbf{w}) = E\bigl[e(n)^2\bigr] \tag{4} \]を最小化する \(\mathbf{w}\) を逐次的に求めることです。
LMSアルゴリズム
勾配の確率的近似
コスト関数 \(J(\mathbf{w})\) の勾配は
\[ \nabla J = -2\, E\bigl[e(n)\, \mathbf{x}(n)\bigr] \tag{5} \]ですが、期待値は実際には計算できません。LMSの核心は、期待値を瞬時値で置き換える確率的勾配近似です。
\[ \hat{\nabla} J(n) = -2\, e(n)\, \mathbf{x}(n) \tag{6} \]これを最急降下法に代入して、係数更新則が得られます。
\[ \mathbf{w}(n+1) = \mathbf{w}(n) + \mu\, e(n)\, \mathbf{x}(n) \tag{7} \]ここで \(\mu > 0\) はステップサイズ(学習率)です。係数 \(2\) は \(\mu\) に吸収しています。
収束条件
平均的な収束(係数の期待値が最適解 \(\mathbf{w}^\ast\) に収束)のためには、ステップサイズが入力相関行列 \(\mathbf{R} = E[\mathbf{x}(n)\mathbf{x}(n)^\top]\) の最大固有値 \(\lambda_{\max}\) に対して
\[ 0 < \mu < \frac{2}{\lambda_{\max}} \tag{8} \]を満たす必要があります。実用上は、入力パワーを使ったより緩い条件
\[ 0 < \mu < \frac{2}{L \cdot P_x}, \qquad P_x = E\bigl[x(n)^2\bigr] \tag{9} \]を採用することが多く、\(\lambda_{\max} \le \mathrm{tr}(\mathbf{R}) = L P_x\) から導かれます。
ステップサイズと挙動の関係は次のとおりです。
| \(\mu\) の大きさ | 挙動 |
|---|---|
| 小さい | 収束が遅いが定常誤差が小さい |
| 中程度 | 収束速度と定常誤差のバランスが良い |
| 大きい | 収束は速いが定常誤差が大きい |
| 上限超過 | 発散(誤差が増大し続ける) |
自己相関 \(\mathbf{R}\) の固有値広がり \(\chi(\mathbf{R}) = \lambda_{\max} / \lambda_{\min}\) が大きいほど収束が遅くなります。詳細は自己相関関数を参照してください。
NLMSアルゴリズム
正規化の動機
LMSの収束はステップサイズ \(\mu\) と入力パワー \(P_x\) の積に依存します。入力レベルが大きく変動する環境(音声信号など)では、\(\mu\) を固定値にすると過小・過大の両方が起き、安定性が損なわれます。
NLMS(Normalized LMS)は、入力ベクトルのノルムでステップサイズを正規化することでこの問題を解決します。
\[ \mathbf{w}(n+1) = \mathbf{w}(n) + \frac{\tilde{\mu}}{\lVert \mathbf{x}(n) \rVert^2 + \varepsilon}\, e(n)\, \mathbf{x}(n) \tag{10} \]\(\tilde{\mu} \in (0, 2)\) が正規化されたステップサイズで、入力パワーに依存せず収束条件を満たします。\(\varepsilon\) は分母が小さくなりすぎないようにするための小さい正の定数です。
LMSとの比較
| 特性 | LMS | NLMS |
|---|---|---|
| 計算量 | \(O(L)\) | \(O(L)\) |
| ステップサイズ | \(\mu < 2/(L P_x)\) (入力依存) | \(\tilde{\mu} < 2\) (入力非依存) |
| 入力変動への頑健性 | 弱い | 強い |
| 実装の手間 | 最小 | LMS に正規化項を追加 |
Python実装
システム同定の例
未知のFIRシステム \(\mathbf{w}^\ast\) を、白色雑音 \(x(n)\) を入力として LMS / NLMS で同定します。誤差 \(e(n)\) の二乗を学習曲線としてプロットします。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(0)
# --- 真のシステム(同定対象) ---
L = 16
w_true = np.array([0.5, -0.3, 0.2, 0.1, -0.05, 0.02,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0])
# --- 入力・観測信号 ---
N = 5000
x = np.random.randn(N)
v = 0.05 * np.random.randn(N) # 観測ノイズ
d = np.convolve(x, w_true, mode='full')[:N] + v
def lms(x, d, L, mu):
"""標準LMSアルゴリズム"""
N = len(x)
w = np.zeros(L)
e = np.zeros(N)
for n in range(L, N):
x_vec = x[n:n - L:-1] if n - L >= 0 else x[n::-1]
y = w @ x_vec
e[n] = d[n] - y
w = w + mu * e[n] * x_vec
return w, e
def nlms(x, d, L, mu_tilde, eps=1e-6):
"""正規化LMSアルゴリズム"""
N = len(x)
w = np.zeros(L)
e = np.zeros(N)
for n in range(L, N):
x_vec = x[n:n - L:-1]
y = w @ x_vec
e[n] = d[n] - y
norm = x_vec @ x_vec + eps
w = w + (mu_tilde / norm) * e[n] * x_vec
return w, e
# --- 実行 ---
mu_lms = 0.01
mu_nlms = 0.5
w_lms, e_lms = lms(x, d, L, mu_lms)
w_nlms, e_nlms = nlms(x, d, L, mu_nlms)
# --- 学習曲線(瞬時誤差の二乗を移動平均) ---
def smooth(v, win=50):
kernel = np.ones(win) / win
return np.convolve(v ** 2, kernel, mode='same')
plt.figure(figsize=(10, 5))
plt.semilogy(smooth(e_lms), label=f'LMS (μ={mu_lms})')
plt.semilogy(smooth(e_nlms), label=f'NLMS (μ̃={mu_nlms})')
plt.xlabel('Iteration n')
plt.ylabel('Mean Squared Error')
plt.title('Learning Curves: LMS vs NLMS')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"LMS final coeff error: {np.linalg.norm(w_lms - w_true):.4f}")
print(f"NLMS final coeff error: {np.linalg.norm(w_nlms - w_true):.4f}")
学習曲線(縦軸が対数)を見ると、最初は誤差が指数的に減少し、やがて定常誤差レベルで水平になります。\(\mu\) (または \(\tilde{\mu}\) )を大きくすると初期収束は速くなりますが、定常誤差レベルも上昇する典型的なトレードオフが観察できます。
ステップサイズの感度解析
plt.figure(figsize=(10, 5))
for mu in [0.005, 0.02, 0.05, 0.1]:
_, e = lms(x, d, L, mu)
plt.semilogy(smooth(e), label=f'μ={mu}', alpha=0.8)
plt.xlabel('Iteration n')
plt.ylabel('Mean Squared Error')
plt.title('LMS: Sensitivity to Step Size μ')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
\(\mu\) が小さすぎると収束が極めて遅く、\(\mu\) が上限近くでは初期から振動的になります。実用上は (8) 式の半分以下を目安に選ぶと安定です。
ウィーナーフィルタとの関係
LMSは、ウィーナー解 \(\mathbf{w}^\ast = \mathbf{R}^{-1}\mathbf{p}\) (\(\mathbf{p} = E[d(n)\mathbf{x}(n)]\) )に逐次的に収束します。
\[ E\bigl[\mathbf{w}(n)\bigr] \xrightarrow{n \to \infty} \mathbf{w}^\ast \tag{11} \]ただし、瞬時勾配を使うため有限の過剰平均二乗誤差(excess MSE)が残ります。RLS(再帰的最小二乗)はこれを高速化する代替手法です。
用途別ガイド
| 用途 | 推奨 | 理由 |
|---|---|---|
| 入力レベルが安定 | LMS | 実装最小、計算量も最少 |
| 音声・通信信号など変動大 | NLMS | 入力パワー変動に頑健 |
| 速い収束が必須 | RLS | 二次収束、ただし \(O(L^2)\) |
| 組み込み・低リソース | LMS / NLMS | \(O(L)\) で十分 |
関連記事
- ウィーナーフィルタ:最適線形フィルタの理論とPython実装 - LMSが逐次近似する最適解そのもの。バッチ処理(周波数領域)と適応処理(時間領域)の違いを比較できます。
- 適応フィルタ(LMS/RLS)の理論とPython実装 - LMSとRLSの比較、ノイズキャンセレーション応用を含む包括解説です。
- 自己相関関数の理論とPython実装 - LMSの収束速度を支配する入力相関行列 \(\mathbf{R}\) の理解に直結します。
- FFTの基礎:高速フーリエ変換の理論と実装 - 周波数領域版の適応アルゴリズム(FDAF)の前提となるFFTの解説です。
- カルマンフィルタの理論とPython実装 - 適応フィルタとは別系統の逐次推定手法。RLSはカルマンフィルタと数学的に等価です。
- 移動平均フィルタの種類と比較:SMA・WMA・EMAのPython実装 - 固定係数フィルタとの設計思想の違いを把握できます。
参考文献
- Haykin, S. (2014). Adaptive Filter Theory (5th ed.). Pearson. Chapters 5-6.
- Widrow, B., & Stearns, S. D. (1985). Adaptive Signal Processing. Prentice Hall.
- Sayed, A. H. (2008). Adaptive Filters. Wiley-IEEE Press.