我试图了解如何用数字方法求解随机微分方程(SDE)(我没有任何语言的经验,但出于某些原因,我选择了Julia)。作为初始模型,我决定使用Lotka-Volterra equations。我读了手册,tutorial读了DifferentialEquations.jl。虽然我的模型是一个简单的ODE系统:
一切正常:
using DifferentialEquations
using Plots
function lotka(du,u,p,t);
, , , = p;
du[1] = *u[1]-*u[1]*u[2];
du[2] = *u[1]*u[2]-*u[2];
end
u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1);
tspan = (0.0,50.0);
prob = ODEProblem(lotka,u0,tspan,p);
sol = solve(prob);
plot(sol,vars = (1,2))
现在,我想添加Ornstein-Uhlenbeck噪声:
愚蠢的简单解决方案是:
using DifferentialEquations
using Plots
function lotka(du,u,p,t);
, , , , , = p;
du[1] = *u[1]-*u[1]*u[2]+u[3];
du[2] = *u[1]*u[2]-*u[2]+u[4];
du[3] = -u[3]/+sqrt((2.0*^2.0/))*randn();
du[4] = -u[4]/+sqrt((2.0*^2.0/))*randn();
end
u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1,0.1,0.1);
tspan = (0.0,50.0);
prob = ODEProblem(lotka,u0,tspan,p);
sol = solve(prob);
但是,正如预期的那样,它没有用,因为求解器不适用于此类SDE问题。
┌ Warning: Interrupted. Larger maxiters is needed.
└ @ DiffEqBase /home/jrun/.julia/packages/DiffEqBase/ujEgN/src/integrator_interface.jl:116
我尝试阅读SDE Julia documentation,但是没有好的榜样,我不明白如何处理。此外,我的数学背景很差,似乎我无法正确理解表示法。我该如何对SDE进行这项工作?
最后,我有以下代码:
using DifferentialEquations,Plots;
function lotka(du,u,p,t);
, , , , , = p;
du[1] = *u[1]-*u[1]*u[2];
du[2] = *u[1]*u[2]-*u[2];
end
function stoch(du,u,p,t)
, , , , , = p;
du[1] = 1
du[2] = 1
end
u0 = [15.0,1.0];
p = (0.3,0.05,0.7,0.1,0.9,0.1);
, , , , , = p;
OU = OrnsteinUhlenbeckProcess(1/, 0.0, , 0.0, 0.0);
tspan = (0.0,100.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p,noise = OU);
sol = solve(prob,EM(),dt = 1e-3, adaptive=false);
要结束本主题,我还有两个问题:
1)它是正确的代码吗? (恐怕我的声音在这种情况下不是对角线的)
2)我对两个方程式的初始噪声(W0)是否可以不同?
答案 0 :(得分:4)
似乎您有一个SDE,其中前两项是由随机的后两项驱动的?在这种情况下,您将使lotka
为确定性术语:
function lotka(du,u,p,t);
, , , , , = p;
du[1] = *u[1]-*u[1]*u[2]+u[3];
du[2] = *u[1]*u[2]-*u[2]+u[4];
du[3] = -u[3]/
du[4] = -u[4]/
end
然后是stoch
随机部分:
function stoch(du,u,p,t)
, , , , , = p;
du[1] = 0
du[2] = 0
du[3] = sqrt((2.0*^2.0/))
du[4] = sqrt((2.0*^2.0/))
end
现在以du = f(u,p,t)dt + g(u,p,t)dW
的形式编写。请注意,就像您不写dt
一样,您也不写randn()
,因为它是在求解器中处理的(更为复杂)。使用这些定义一个SDEProblem并解决:
u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1,0.1,0.1);
tspan = (0.0,50.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p);
sol = solve(prob);
(尽管您不能对此模型保持正值,但您仍需要小心,因为如果有太多的噪声,它可能会变得不稳定。不仅是积分器,而且是解决方案本身)
为清楚起见,您在上面所做的操作不起作用的原因有两个。首先,适应性基于解决方案属性做出假设。例如,一个标准的5阶积分器假设该解决方案的可微性是5倍,并在其误差估计中使用该解决方案来选择步长。 SDE的可微数是0倍:每个epsilon小于1/2时,它都是可微的。因此,当直接将ODE方法用于SDE时,错误估计和时间步长选择将大相径庭。
但是,第二,ODE求解器使用拒绝采样进行自适应。他们将选择一个dt,然后尝试一下,如果失败,则减小dt。在这里,您在导数内取一个随机数,一个五阶积分器将调用您的导数函数7次,获取7个不同的值(认为导数是多少),计算误差估计值,意识到它是疯狂的(因为它甚至没有可微分,因此整个算法做出了错误的假设),减少了时间步长,然后采用完全不同的随机数,因此较小的dt最终成为完全不同的轨迹。如您所知,整个过程非常不稳定,实际上并不能解决我们最初拥有的真实SDE。
您可以通过以下方法来解决此问题:更好地理解所说的随机数,如何定义误差估计以及使用假设STO组件为“ Ito可微性”(即“可微性”)的高阶方法)。描述in the paper which is the foundation of the current crop of adaptive SDE solvers。
对于您拥有的代码
using DifferentialEquations,Plots;
function lotka(du,u,p,t);
, , , , , = p;
du[1] = *u[1]-*u[1]*u[2];
du[2] = *u[1]*u[2]-*u[2];
end
function stoch(du,u,p,t)
, , , , , = p;
du[1] = 1
du[2] = 1
end
u0 = [15.0,1.0];
p = (0.3,0.05,0.7,0.1,0.9,0.1);
, , , , , = p;
OU = OrnsteinUhlenbeckProcess(1/, 0.0, , 0.0, 0.0);
tspan = (0.0,100.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p,noise = OU);
sol = solve(prob,EM(),dt = 1e-3, adaptive=false);
这对两个变量都添加了1 OU过程。如果您希望它们成对角线,即两个独立的OU进程,请使用:
OU = OrnsteinUhlenbeckProcess(1/, 0.0, , 0.0, [0.0,0.0]);
更一般地,[0.0,0.0]
是起点,您可以更改它们以解决(2)。对于小的性能优化,您可以选择:
OU = OrnsteinUhlenbeckProcess!(1/, 0.0, , 0.0, [0.0,0.0]);
该配方和使用布朗SDE的配方均可工作。 SDE公式可以使用自适应方法,但是是一个较大的系统,而OUProcess公式是一个较小的系统,但仅适用于EM()
和固定时间步长。哪个更好取决于问题,但在大多数情况下我可能更喜欢SDE。 OUProcess表单在RODE上会更好。