使用时间序列参数来解决R中的ODE

我试图使用deSolve在R中解决一个简单的ODE:dQ / dt = f(Q)*(P – E).整个事情是Q的时间序列.诀窍是P和E是固定的时间序列数据本身,因此diff eq仅在Q中有效.

用固定的时间步长迭代地解决这个问题是相对简单的,但是我试图找到一种在R中使用自适应时间步长的方法.因为P和E是离散的,连续的时间步长可能具有相同的P和E值,很好.我一直在玩deSolve,但一直无法解决这个问题.理想情况下,我想使用标准的4阶Runge-Kutta.

有任何想法吗?在MATLAB中做到这一点?

编辑可重现的例子.我希望能够使用可变时间步Runge-Kutta 4方法进行此计算.我可以很容易地编程一个固定的时间步骤rk4,而不是那么自适应.

working <- structure(list(datetime = structure(c(1185915600, 1185919200, 
1185922800, 1185926400, 1185930000, 1185933600, 1185937200, 1185940800, 
1185944400, 1185948000, 1185951600), class = c("POSIXct", "POSIXt"
), tzone = "UTC"), p = c(0, 0, 0, 1.1, 0.5, 0.7, 0, 0, 1.3, 0, 
0), e = c(0.15, 0.14, 0.13, 0.21, 0.15, 0.1, 0.049, 0, 0, 0, 
0), qsim = c(-1.44604436552566, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA)), .Names = c("datetime", "p", "e", "qsim"), row.names = c(NA, 11L), 
class = "data.frame")


# this is the derivative function dQ/dt = f(Q,p,e) where p and e are time series
dqdt <- function(qsim, pcp, pet) {
  dq <- (qsim ^ 2) * ((pcp - pet) / qsim) 
  return(dq)
}

# loops through and calculates the Q at each time step using the Euler method
for (i in 1:(nrow(working) - 1)) {
  dq <- dqdt(working$qsim[i], pcp = working$p[i], pet = working$e[i])
  working$qsim[i + 1] <- working$qsim[i] + dq
}

最佳答案 也许不是最复杂的方法,但快速而肮脏的方法是将依赖于时间的强制变量保持为外部(全局)变量.

我使用pmax(1,ceiling(t))从时间索引转换为数据帧的行索引(如果你想从t = 0开始因为ceiling(0)为0,则需要pmax,并且x [ R中的0]通常是一个空向量,然后它会破坏东西).可能还有其他方法可以进行索引.

library(deSolve)
gradfun <- function(t,y,parms) {
   pcp <- working$p[pmax(1,ceiling(t))]
   pet <- working$e[pmax(1,ceiling(t))]
   list(y^2*((pcp-pet)/y),NULL)
}

gradfun(0,working$qsim[1],1)   ## test
ode1 <- ode(y=c(qsim=working$qsim[1]),func=gradfun,
                time=seq(0,nrow(working),length.out=101),
                parms=NULL,method="rk4")
plot(ode1)
点赞