JavaScript中的N体重力模拟

时间:2014-05-10 20:52:13

标签: javascript vector physics

所以,我正在尝试用JavaScript创建一个N-Body Gravity模拟:

http://jsfiddle.net/4M94x/

var Circle = function(c, r, cor, cof) { // Fix CoR & CoF // Had to add code for JSFiddle link :P
    this.c = c
    this.r = r
    this.m = r * r * Math.PI
    this.v = new Vector()
    this.cor = cor
    this.cof = cof
}

问题在于,当你产生(点击)并将2个球(意外地重命名为“粒子”)彼此相邻时,它们开始产生速度并且更快更快地推动彼此..我如何解决这个问题,顺便说一下我的引力实施正确吗?

1 个答案:

答案 0 :(得分:19)

这很容易解释:您正在将Euler前向实现为ODE的求解器,而在机械系统中,Euler前向的系统误差会增加能量。欧拉向后减少能量,因此交替显式和隐式欧拉方法的组合将使能量更加恒定。

但是你可以用相同甚至更少的努力来实现保存能量和其他物理不变量的二阶辛方法,无论是(隐式)中点方法还是Verlet-(Stoermer-Cromer -...- Newton- )方法

甚至更高阶的Runge-Kutta,尽管不是辛的,但它也会将能量保持在更高的阶数。

请参阅Stoermer-Verlet上的Hairer -...- Newton方法,postprintpreprint以及“移动星星”tutorial text using C++Ruby


关于物理学的一个注释:总而言之,这些实现非常简单且可读性很好。但引力是

g*m1*m2*(p2-p1)/norm(p2-p1)^3

的负梯度
g*m1*m2/norm(p2-p1)

你只使用标准的平方,其中力将是重力势能的负梯度

 g*m1*m2*ln(norm(p2-p1))

适用于平地物理,但不适用于3D空间的2D部分。


工作代码

具有速度Verlet和能量保存:

向圆形对象添加一个新字段a = Vector(),并使用以下专用函数集合替换update()函数的厨房接收器

function compute_forces() {
    for (var i = 0; i < particles.length; i++) {
        var p = particles[i];
        p.a.set(0);

        for (var j = 0; j < i; j++) {
            var p2 = particles[j];

            var d = p.c.sub(p2.c);
            var norm = Math.sqrt(100.0 + d.lengthSq());
            var mag = gravity / (norm * norm * norm);

            p.a.set(p.a.sub(d.mul(mag * p2.m)));
            p2.a.set(p2.a.add(d.mul(mag * p.m)));

        }
    }

}


function do_collisions() {
    for (var i = 0; i < particles.length; i++) {
        var p = particles[i];
        for (var j = 0; j < i; j++) {
            var p2 = particles[j];

            if (checkCCCol(p, p2)) {
                resCCCol(p, p2);
            }
        }
    }
}


function do_physics(dt) {
    // do velocity Verlet 
    // with consistent state at interval half points
    // x += 0.5*v*dt
    for (var i1 = 0; i1 < particles.length; i1++) {
        var p1 = particles[i1];
        p1.c.set(p1.c.add(p1.v.mul(0.5 * dt)));
    }
    // a = A(x)
    compute_forces();
    // v += a*dt
    for (var i2 = 0; i2 < particles.length; i2++) {
        var p2 = particles[i2];
        p2.v.set(p2.v.add(p2.a.mul(dt)));
    }
    // x += 0.5*v*dt
    for (var i3 = 0; i3 < particles.length; i3++) {
        var p3 = particles[i3];
        p3.c.set(p3.c.add(p3.v.mul(0.5 * dt)));
    }
    do_collisions();
}

function update() {

    for (var k = 0; k < 4; k++) {
        do_physics(1.0 / 4);
    }

    render();

    RAF(update);
}

请参阅http://jsfiddle.net/4XVPH/


更改的示例,其中的粒子根据其质量着色(希望更好地显示其交互),修复了一个错误,以及一些其他注释:http://jsfiddle.net/24mg6ctg/12/