deSolve中Runge-Kutta方法ode45的自适应时间步长

时间:2013-12-15 13:26:30

标签: r ode runge-kutta

我想使用 deSolve R包中的显式Runge-Kutta方法 ode45 (别名rk45dp7)来解决具有可变步长的ODE问题。< / p>

根据deSolve文档,可以使用ode45方法对 rk 求解器函数使用自适应或可变时间步长,而不是等距时间步,但我很遗憾怎么做。

rk函数的调用方式如下:

rk(y, times, func, parms, rtol = 1e-6, atol = 1e-6, verbose = FALSE, tcrit = NULL,
hmin = 0, hmax = NULL, hini = hmax, ynames = TRUE, method = rkMethod("rk45dp7", ... ), 
maxsteps = 5000, dllname = NULL, initfunc = dllname, initpar = parms, rpar = NULL, 
ipar = NULL, nout = 0, outnames = NULL, forcings = NULL, initforc = NULL, fcontrol = 
NULL, events = NULL, ...)

是需要对y进行显式估计的时间向量。

对于距离为0.01的等距时间步长,我可以将写为

times <- seq(0, 100, 0.01)

假设我想解决从0到100的间隔的等式,如何在不给步长的情况下定义

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:5)

这里有两个问题。首先,如果要指定具有多个增量的时间向量,请使用此(例如):

times <- c(seq(0,0.9,0.1),seq(1,10,1))
times
#  [1]  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0

这里,[0,1]为0.1,[1,10]为1。

但实际上你不必这样做:参数times=告诉rk(...)报告结果的时间。自适应算法内部调整时间增量,以便在参数中指定的时间产生准确的结果。因此,对于自适应算法,例如method="rk45dp7",您不必做任何事情。对于非自适应算法,例如method="euler",算法使用的时间增量实际上是times=中指定的增量。你可以在这个简单的例子中看到这个效果,它集成了Van der Pol振荡器。

y.prime <- function(t,y.vector,b) {    # Van der Pol oscillator
  x <- y.vector[1]
  y <- y.vector[2]
  x.prime <- y
  y.prime <- b*y*(1-x)^2 - x
  return(list(c(x=x.prime,y=y.prime)))
}
h  <- .001                  # time increment
t  <-  seq(0,10,h)          # times to report results
y0 <- c(0.01,0.01)          # initial conditions
euler   <- rk(y0, t,func=y.prime,parms=1,method="euler")
rk45dp7 <- rk(y0, t,func=y.prime,parms=1, method="rk45dp7")
# plot x vs. y
par(mfrow=c(1,2))
plot(euler[,2],euler[,3], type="l",xlab="X",ylab="Y",main=paste("Euler: h =",format(h,digits=3)))
plot(rk45dp7[,2],rk45dp7[,3], type="l",xlab="X",ylab="Y",main=paste("RK45DP7: h =",format(h,digits=3)))

以下是h的多个值的结果比较。请注意,对于method="rk45dp7"h < 0.5的结果是稳定的。这是因为rk45dp7在内部根据需要调整时间增量。对于method="euler",结果与rk45dp7之前的h~0.01不匹配。