LK法のパフォーマンス
こちらの記事では、1次元の場合についてLK法を実装し、パフォーマンスについて解説します。
この技術についての投稿は、一つの索引用の記事にまとめられています。 全体を俯瞰する場合はそちらを御覧ください。
前々回からLK法の式の導出をしてきました。
ここまでで求めた式は以下になります。
こちらの式で実際のhに収束する条件と、収束するための速度について考えます。
LK法の実装
ここで、F(x)とG(x)を以下の様に置きます。
こちらをpythonで実装します。 まず、F(x)とG(x)をグラフに描画してみます。
#!/usr/bin/env python #-*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt # hの真値 h_g = 0.3 def f(x): return np.sin(x) def g(x): return np.sin(x + h_g) def main(): x = np.arange(0, 2 * np.pi, 0.01) f_val = f(x) g_val = g(x) plt.plot(x, f_val, label="f(x)") plt.plot(x, g_val, label="g(x)") plt.legend() plt.show() if __name__ == "__main__": main()
こちらを実行すると、次のようなグラフが表示されます。
Fが正弦波で、Gがそれをhだけずらしたものになっています。
ここから、式\eqref{eq10}を用いてhを求めます。
def weight(x): diff = np.absolute(g_1st_deriv(x) - f_1st_deriv(x)) if diff == 0: return 0 return (1 / diff) ERROR = 10e-20 def estimate_h(f, g, x): itr_count = 0 h_estimated = [0] while True: cum = 0 sigma_count = 0 for sub_x in x: cum += ((g(sub_x) - f(sub_x + h_estimated[-1])) * weight(sub_x) * f_1st_deriv(sub_x + h_estimated[-1])) sigma_count += weight(sub_x) * f_1st_deriv(sub_x + h_estimated[-1]) * f_1st_deriv(sub_x + h_estimated[-1]) h_estimated.append(h_estimated[-1] + cum / sigma_count) if np.absolute(g(sub_x) - f(sub_x + h_estimated[-1])) < ERROR: break itr_count += 1 if 100 == itr_count: break
こちらの関数を使うと、3回のイテレーションで目的のhを求められました。
LK法で解が求まる条件
LKで解が求められる限界について考えます。
上で例に挙げたFの場合、
となる範囲でのみ解が正しく求められます。
試しに、先のプログラムでhを3.2に設定すると、値が発散して解が求められないことが確認できると思います。
LK法で解を求める場合、LPFを用いて低周波にしてからかけることで、解が収束する可能性が高くなります。
そこで、低周波の信号で解を求めた後に、その解を初期値として高周波の信号で解を求めるという戦略が考えられます。
LK法のパフォーマンス
LK法では、重みw(x)を設定することで、より正確に近似ができるということでした。
より正確な近似ができるということは、より少ない回数で解に近づけるということになります。こちらを実際にプログラムを動かして確かめます。
まず、重み関数w(x)を以下の様に変更します。
def weight(x): return 1
解が求めやすいと違いがわからないので、hを3、ERRORを10e-50に変更します。
すると、w(x)を1とした時のイテレーションは7回、w(x)を式\eqref{eq10}とした時のイテレーションは6回となり、たしかに計算回数が減っていることがわかります。
今回の記事は以上になります。次回は2次元へ拡張をする予定です。