Pythonプログラミング(ステップ6・常微分方程式)
このページの目標
- 常微分方程式の数値解法が反復計算(総和のパターン)に還元できることを理解すること。
- 簡単な反復解法をコーディングできること。
1階の常微分方程式の数値解法
一階の常微分方程式(ordinary differential equation)
もしも、右辺が
ところが、式(1)の右辺に
そもそも、微分は差分の極限として定義されたことを思い出すと、以下の式で
陰解法
一方、微分を
以上を踏まえ、初期条件
に「十分に小さな」数値をセットする の間、以下を反復する:-
-
- 反復ここまで
このアルゴリズムは、基本的には総和計算と全く同じパターンであることに気づくはずだ。
具体的に、
exp-decay.py
この微分方程式の数学的な解は
# coding: utf-8 dt=0.01 T=2.0 t=0.0 x=1.0 while t<T: print("t=",t," x=",x) f=-x x=x+f*dt t=t+dt
練習:微分方程式
オイラー法(陽解法)を用いて、二つのパラメータ(
ヒント
この微分方程式は ロジスティック方程式 として知られ、生物の個体数や人口の変化を考える際の基本的なモデルである。
パラメータ
2階の常微分方程式の数値解法
物理学などで登場する微分方程式の多くは二階微分を含む。例えば、長さ
このような二階の微分方程式は、全く等価な、2つの連立した一階の微分方程式に書き直すことができる。
振り子の例では、
それぞれの方程式にオイラー法を適用すると、以下のようなコードを書くことができるだろう。
# coding: utf-8 import math g=9.8 L=1.0 dt=0.01 T=3.0 t=0.0 x=0.2 y=0.0 while t<T: print("t=",t," x=",x," y=",y) x1=x+y*dt y1=y-g/L*math.sin(x)*dt x=x1 y=y1 t=t+dt
ここで、
上記のコードで、変数 x1, y1
は、次の時間ステップの値を記憶しておくために使っており、両方の値が求まった時点で、改めて x, y
を更新するようになっている。
微分方程式を数値的に扱う際には、変数に「いつの時点」の値が保持されているのかを注意深く考える必要がある。
エネルギー保存を破らないように数値計算するためには、 オイラー法よりも高精度の公式(例えばこちら)を用いたり、 保存系の計算に適した方法(シンプレクティック解法)を選ぶ必要がある。
このコードを実行すると、振動の様子が再現されるかに見えるが、計算する時間を長くすると(変数T
の値を大きくすると)、振幅と角速度が徐々に増大することに気づく。
すなわち、本来ならば保存されるべき系の力学エネルギーが増加するという、非現実的な挙動を示す。
これは、振り子の系にオイラー法を適用すると、反復の過程で誤差が(一定のバイアスを持って)累積してしまうためで、
一見正しそうなデータが得られた場合でも、その結果をよく吟味する必要がある。
練習:摩擦のある振り子
摩擦があるような振り子の系