R には lsoda というパッケージがある。これを導入すると、常微分方程式の数値積分を行うことができる。
導入の仕方などについては、「Windows に Eclipse + R を導入する」を参照のこと。
使い方をいろいろ書くよりも、サンプルを示した方が簡単だと思うので、いくつかのサンプルを示す。
library(odesolve)
#
# 時間変化を記述する関数(微分方程式の右辺を与える関数)
#
# 引数 : t(現在時刻), y(現在の変数), parms(パラメタ)
# 返り値 : y の時間微分を list(c( )) の中に並べる。
#
# 今回の場合、
# y[1] : 座標
# y[2] : 速度
#
freefall <- function(t, y, parms){
y1dot <- y[2]
y2dot <- - parms['g']
return( list(c(y1dot, y2dot)) )
}
#
# パラメタ
# 上記関数の中で参照するために、名前をつけておく。
#
parms <- c( g=9.8, m=1 )
#
# 時刻
# 計算結果を表示したい時刻の値を配列で与える。
#
times <- seq(0,10,0.01)
#
# 初期値
# ここで変数に名前をつけておくこともできる。
#
y <- c( y=0, vy=0 )
#
# 計算と結果の記録
#
result <- lsoda(y, times, freefall, parms)
#
# 表示
#
plot(0, type='n',
xlim=c(min(times), max(times) ),
ylim=c(min(result[,'y']), max(result[,'y'])))
# #
# # 本来ならば
# points( result[,1], result[,2], pch='.')
# # などで表示がすむところを、あえて時間をかけて表示させる。
# # ちょっとアニメーション気分で
for( i in 1:length(result[,2]) ){
points( result[i,'time'], result[i,'y'], pch='.' , col='red')
}
library(odesolve)
#
# 時間変化を記述する関数(微分方程式の右辺を与える関数)
#
# 引数 : t(現在時刻), y(現在の変数), parms(パラメタ)
# 返り値 : y の時間微分を list(c( )) の中に並べる。
#
# 今回の場合、
# y[1] : 地球の x 座標
# y[2] : 地球の y 座標
# y[3] : 地球の 速度 x成分
# y[4] : 地球の 速度 y成分
#
# y[5] : 月の x 座標
# y[6] : 月の y 座標
# y[7] : 月の 速度 x成分
# y[8] : 月の 速度 y成分
#
Earth <- function(t, y, parms){
const <- parms['G'] * parms['massE'] * parms['massM']
distance2 <- (y[1] - y[5])^2 + (y[2] - y[6])^2
distance <- sqrt(distance2)
y1dot <- y[3]
y2dot <- y[4]
y3dot <- const / distance2 * ( y[5] - y[1] ) / distance / parms['massE']
y4dot <- const / distance2 * ( y[6] - y[2] ) / distance / parms['massE']
y5dot <- y[7]
y6dot <- y[8]
y7dot <- const / distance2 * ( y[1] - y[5] ) / distance / parms['massM']
y8dot <- const / distance2 * ( y[2] - y[6] ) / distance / parms['massM']
return( list(c(y1dot, y2dot, y3dot, y4dot,
y5dot, y6dot, y7dot, y8dot)) )
}
#
# パラメタ
# 上記関数の中で参照するために、名前をつけておく。
#
parms <- c( G=6.67300E-11, massE=5.9742E24, massM=7.347673E22 )
#
# 時刻
# 計算結果を表示したい時刻の値を配列で与える。
# 1 時間ごとに 90 日分
#
times <- seq(0, 60*60*24*90, 60*60)
#
# 初期値
# ここで変数に名前をつけておくこともできる。
#
# 地球 x y vx vy 月 x y vx vy
y <- c( Ex=0, Ey=0, Evx=0, Evy=0, Mx=3.844E8, My=0, Mvx=0, Mvy=1.023144e3)
#
# 計算と結果の記録
#
result <- lsoda(y, times, Earth, parms)
#
# 表示
#
plot(0, type='n',
xlim=c(-max(result[,'My']), max(result[,'My'])),
ylim=c(-max(result[,'My']), max(result[,'My'])))
# #
# # 本来ならば、
# points( result[,'Ex'], result[,'Ey'], pch='.', col='blue')
# points( result[,'Mx'], result[,'My'], pch='.', col='orange')
# # で済むところを、ちょっとアニメーション気分で。
# #
for( i in 1:length(result[,2]) ){
points( result[i,'Ex'], result[i,'Ey'], pch='.' , col='blue')
points( result[i,'Mx'], result[i,'My'], pch='.' , col='orange')
}