第8回 MATLAB seminar 2021年07月26日
最終更新:2021/07/26
今日は, 常微分方程式を簡単に差分法で解いた. 特に, Lotka-Volterra方程式とLorenz Attractorは, 見た目の不思議さに加え面白い背景があるので, 興味があれば各自調べてみてほしい.
1変数:空気抵抗のある自由落下
モデル
これは, みなわかるでしょう. $k$ は空気抵抗係数.
初速度0で落とした場合, 理論値は以下となる. せっかくなので, 理論値も計算してプロットしている.
離散化
以下のように離散化する.
シミュレーション
% INPUTS
dt = 0.1; % 時間刻み [sec]
T = 10; % 計算時間 [sec]
g = 9.81; % 重力加速後 [m*s^(-2)]
m = 0.3; % 質量 [kg]
k = 0.24; % 空気抵抗係数 [kg/m]
v_init = 0; % 速度の初期値
% 計算
t = 0:dt:T; % 計算範囲 ( 時間 )
v = zeros(size(t)); % 事前割り当て
L = length(t);
v(1) = v_init;
for I = 1:L-1
v(I+1) = v(I) + dt * (g - (k/m) * v(I));
end
% 理論値
v_true = zeros(size(t));
for I = 1:L
v_true(I) = (m*g/k)*(1 - exp(-k*t(I)/m));
end
% OUTOUT (plot)
plot(t, v); hold on % 計算値
plot(t, v_true); hold off % 理論値
legend('計算値', '理論値')
xlabel('Time [sec]')
ylabel('Velocity [m/s]')

計算値の精度を少し落とすために時間刻みを少し大きめ ( $\Delta t = 0.1$ ) にとった.
2変数:Lotka-Volterra方程式
モデル
$x$ :被食者の個体数と $y$ :捕食者の個体数との関係が, 以下の4つのパラメータをもつ方程式で表されるときの, それぞれの個体数の時間発展を計算する. 詳しいことは, ロトカ・ヴォルテラの方程式 ( wikipedia ) など.
\begin{aligned} & \large{\frac{d x}{d t}=a x-b x y} \\ & \large{\frac{d y}{d t}=c x y-d y} \end{aligned}離散化
以下のように離散化する.
シミュレーション
% INPUT
dt = 0.002;
T = 30;
a = 2.0;
b = 0.3;
c = 0.2;
d = 1.0;
x_init = 10;
y_init = 5;
% calc
t = 0:dt:T;
x = zeros(size(t)); x(1) = x_init;
y = zeros(size(t)); y(1) = y_init;
L = length(t);
for I = 1:L-1
x(I+1) = x(I) + dt * (a * x(I) - b*x(I)*y(I));
y(I+1) = y(I) + dt * (-d*y(I) + c*x(I)*y(I));
end
% OUTPUT
plot(t, x); hold on
plot(t, y); hold off
xlabel('時間')
ylabel('個体数')
l = legend('被食者', '捕食者', 'Box', 'off');
l.Orientation = 'horizontal';

被食者が増えると, 捕食者が増え, 捕食者が増えると, 被食者が減るという関係が現れている. 是非, パラメータの意味を調べて, 色々パラメータを変えてみてほしい.
ちなみに, 被食者と捕食者の関係をプロットすると ( 一周する ) 閉曲線となることが理論的に知られている. しかし, このシミュレーションでは, 微妙に閉じていない. これは, 計算精度の問題である ( このモデルには保存量があるが, 離散的に計算する過程で減少し保存されていない ) . $\Delta t$ を色々変えて, このプロットがどうなるか見てみてほしい.

MATLABコード
MATLAB
plot(x, y)
xlabel('被食者')
ylabel('捕食者')
3変数:Lorenz Attractor
モデル
変数は, $x$, $y$, $z$ の3つ, パラメータも3つである. 詳しいことは, ローレンツ方程式 ( wikipedia ) など.
パラメータを $p = 10$, $r = 28$, $b = 8/3$ と設定したときの挙動が有名である.
離散化
以下のように離散化する.
シミュレーション
% INPUT
dt = 0.002;
T = 30;
r = 28;
s = 10;
b = 8/3;
x_init = 1;
y_init = 1;
z_init = 1;
% calc
t = 0:dt:T;
x = zeros(size(t)); x(1) = x_init;
y = zeros(size(t)); y(1) = y_init;
z = zeros(size(t)); z(1) = z_init;
L = length(t);
for I = 1:L-1
x(I+1) = x(I) + dt*(s*(y(I) - x(I)));
y(I+1) = y(I) + dt*(x(I)*(r - z(I)) - y(I));
z(I+1) = z(I) + dt*(x(I)*y(I) - b*z(I));
end
plot3(x, y, z)

カオス的なふるまいをする. 初期値鋭敏性をもっており, ほんの少しでも初期値を変えると途中から全然異なる動きをする. それが, 気象の予想の難しさなどと関係がある. 興味がある人は調べてみてほしい.
なお, 以下のコードを使うとアニメーションとしてみることができる.
plot3(x, y, z)
yl = ylim;
xl = xlim;
zl = zlim;
figure;
int = 50;
h = animatedline;
axis([xl yl zl])
temp = int - 1;
pause(3)
for k = 1:int:length(t)-temp
xvec = x(k:k+temp);
yvec = y(k:k+temp);
zvec = z(k:k+temp);
addpoints(h, xvec, yvec, zvec);
drawnow
end
参考文献
数理モデルに興味があれば, 以下の本がおすすめ. 微分方程式で数学モデルを作ろう