无法让 Lotka-Volterra 方程在 math.js 下稳定振荡
Can't get Lotka-Volterra equations to oscillate stable with math.js
我正在尝试在 JavaScript 中实现一个简单的 Lotka-Volterra 系统,但得到的结果与我在学术论文和幻灯片中看到的不同。这是我的方程式:
sim2.eval("dxdt(x, y) = (2 * x) - (x * y)");
sim2.eval("dydt(x, y) = (-0.25 * y) + (x * y)");
使用系数 a = 2、b = 1、c = 0.25 和 d = 1。但是,我的结果如下所示:
当我期望在这些 PDF slides:
中看到稳定的振荡时
会不会是执行 ndsolve 导致的?还是由于浮点运算导致 JavaScript 中的机器错误?
无视,错误只是使用了太大的评估步骤(dt = 0.1,必须至少为 0.01)。此问题使用的数值方法是已知的。
对于严肃的目的使用高阶方法,最小值是固定步长经典龙格库塔。那你也可以用dt=0.1
,多期稳定,我试过tfinal=300
没有问题。但是您会在图中看到步长,因为它明显是分段线性的。这大大减少了一半的步长,dt=0.05
。
function odesolveRK4(f, x0, dt, tmax) {
var n = f.size()[0]; // Number of variables
var x = x0.clone(),xh=[]; // Current values of variables
var dxdt = [], k1=[], k2=[], k3=[], k4=[]; // Temporary variable to hold time-derivatives
var result = []; // Contains entire solution
var nsteps = math.divide(tmax, dt); // Number of time steps
dt2 = math.divide(dt,2);
dt6 = math.divide(dt,6);
for(var i=0; i<nsteps; i++) {
// compute the 4 stages if the classical order-4 Runge-Kutta method
k1 = f.map(function(fj) {return fj.apply(null, x.toArray()); } );
xh = math.add(x, math.multiply(k1, dt2));
k2 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k2, dt2));
k3 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k3, dt));
k4 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
x = math.add(x, math.multiply(math.add(math.add(k1,k4), math.multiply(math.add(k2,k3),2)), dt6))
if( 0==i%50) console.log("%3d %o %o",i,dt,x.toString());
result.push(x.clone());
}
return math.matrix(result);
}
math.import({odesolveRK4:odesolveRK4});
我正在尝试在 JavaScript 中实现一个简单的 Lotka-Volterra 系统,但得到的结果与我在学术论文和幻灯片中看到的不同。这是我的方程式:
sim2.eval("dxdt(x, y) = (2 * x) - (x * y)");
sim2.eval("dydt(x, y) = (-0.25 * y) + (x * y)");
使用系数 a = 2、b = 1、c = 0.25 和 d = 1。但是,我的结果如下所示:
当我期望在这些 PDF slides:
中看到稳定的振荡时会不会是执行 ndsolve 导致的?还是由于浮点运算导致 JavaScript 中的机器错误?
无视,错误只是使用了太大的评估步骤(dt = 0.1,必须至少为 0.01)。此问题使用的数值方法是已知的。
对于严肃的目的使用高阶方法,最小值是固定步长经典龙格库塔。那你也可以用dt=0.1
,多期稳定,我试过tfinal=300
没有问题。但是您会在图中看到步长,因为它明显是分段线性的。这大大减少了一半的步长,dt=0.05
。
function odesolveRK4(f, x0, dt, tmax) {
var n = f.size()[0]; // Number of variables
var x = x0.clone(),xh=[]; // Current values of variables
var dxdt = [], k1=[], k2=[], k3=[], k4=[]; // Temporary variable to hold time-derivatives
var result = []; // Contains entire solution
var nsteps = math.divide(tmax, dt); // Number of time steps
dt2 = math.divide(dt,2);
dt6 = math.divide(dt,6);
for(var i=0; i<nsteps; i++) {
// compute the 4 stages if the classical order-4 Runge-Kutta method
k1 = f.map(function(fj) {return fj.apply(null, x.toArray()); } );
xh = math.add(x, math.multiply(k1, dt2));
k2 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k2, dt2));
k3 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k3, dt));
k4 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
x = math.add(x, math.multiply(math.add(math.add(k1,k4), math.multiply(math.add(k2,k3),2)), dt6))
if( 0==i%50) console.log("%3d %o %o",i,dt,x.toString());
result.push(x.clone());
}
return math.matrix(result);
}
math.import({odesolveRK4:odesolveRK4});