我喜欢用Runge kutta方法解决R中的以下常微分方程。
dy1 <- (-51.33) * ((1-y[2]) / y[1])
dy2 <- 1.54 * y[1] * (1-y[2]) - 2.14 * y[2]
当y1
变为零时,dy1
将变为无穷大。为避免这种情况,我需要编写R代码,说明当y[1]
小于0.001时,停止y[1]
导数并保持为零。我粘贴了下面的R代码:
yini <- c(1,0)
intabs <- function (t, y, parms) {
ifelse (y[1] <= 0.01, dy1 <- 0, no)
dy1 <- -51.33 * ((1-y[2]) / y[1])
dy2 <- 1.54 * y[1] * (1-y[2]) - 2.14 * y[2]
list(c(dy1, dy2))
}
times <- seq(from = 0, to = 1, by = .002)
out <- ode (times = times, y=yini, func = intabs, parms = NULL, method = "rk4")
head (out, n=50)
我使用ifelse
语句来表示y[1]
小于或等于0.001,然后将dy1
保持为零。我收到了结果。但似乎我犯了一些错误,导致dy1
的结果为负值。我是编写程序的新手。如果发现错误,请帮忙..
答案 0 :(得分:0)
ODE函数中的这种跳转(如果编码正确)对于任何步长控制器都是有害的。 ODE函数必须至少与步长控制的积分方法的错误顺序一样平滑,以便按预期工作。如果ODE很僵硬,它仍然会失败。
将表达式1/y
去单元化的微创方法是使用
y/(1e-6+y*y)
y>1e-2
对1/y
有一个很好的近似值,并且在任何地方都很平滑。更改常量以适应偏离1/y
的区域。