三体问题
三体问题可解吗?可否用JavaScript模拟一个三体系统?
是的,你没有听错,就是那个三体, 刘慈欣的《三体》,这篇文章就是教你怎么用JS模拟一个三体系统(绝对高大上,大刘都惊叹 )。
考虑到是二维绘图,本文只考虑了在同一平面内运动的三体问题(程序演示效果见文末)。
值得注意的是,三体问题本身是混沌的,受计算机浮点精度的限制,即使是细微的差别,也会导致一段时间过后天体的运动状态有极大的不同,为了尽量保证精度,在求解微分方程的过程中容差(Tolerance)也会设置得非常低,但是即便如此,也不能保证绝对精确,一旦时间线比较长,就可能会出现误差,正所谓“失之毫厘谬以千里”,看来即使是掌握了规律,未来也不见得就是可预测的啊!
所以,三体问题最终不可解
但是无解不代表不能做演示、不能对其进行最大可能的模拟预测、不能用来做果壳式高端教学
言归正传,三体问题的本质其实还是万有引力定律和牛顿第二定律,它的方程式如下:
三体问题
由于是同一平面内,每个向量有两个维度,在考虑到降阶的问题,上述方程组可以用12个一阶ODE表达(分别代表三个天体各自单位质量上受到的力的作用):
三体问题
实际编程中需要将极坐标转化成笛卡尔坐标来简化向量运算,以下为一些效果图:
三体问题
三体问题
JS部分动画就不作过多解释了,重点是ODE方程的程序化表达:
const ODE_DIM = 12;
const TOLERANCE = 1e-12;
class Vector2D {
constructor(a) {
this.a = a;
}
static fromPolar(radius, angle) {
const a = new Float64Array(3);
a[0] = radius * Math.cos(angle);
a[1] = radius * Math.sin(angle);
a[2] = radius;
return new Vector2D(a);
}
static fromCartesian(x, y) {
const a = new Float64Array(3);
a[0] = x;
a[1] = y;
a[2] = Math.hypot(x, y);
return new Vector2D(a);
}
add(v) {
return Vector2D.fromCartesian(this.a[0] + v.a[0], this.a[1] + v.a[1]);
}
sub(v) {
return Vector2D.fromCartesian(this.a[0] - v.a[0], this.a[1] - v.a[1]);
}
len() {
return this.a[2];
}
dot(v) {
return this.a[0] * v.a[0] + this.a[1] * v.a[1];
}
gravity(m) {
const l = this.a[2];
const k = m / (l * l * l);
const a = new Float64Array(3);
a[0] = this.a[0] * k;
a[1] = this.a[1] * k;
a[2] = this.a[2] * k;
return new Vector2D(a);
}
projectOn(v) {
return this.dot(v) / v.len();
}
toString() {
return this.a.join(',');
}
}
const threeBodySystem = function (m1, m2, m3) {
const PI_2 = Math.PI / 2;
return function (t, u) {
const r1 = Vector2D.fromPolar(u[0], u[1]),
r2 = Vector2D.fromPolar(u[4], u[5]),
r3 = Vector2D.fromPolar(u[8], u[9]);
const a1 = Vector2D.fromPolar(1, u[1] + PI_2),
a2 = Vector2D.fromPolar(1, u[5] + PI_2),
a3 = Vector2D.fromPolar(1, u[9] + PI_2);
const r12 = r1.sub(r2), r23 = r2.sub(r3), r31 = r3.sub(r1);
const F12 = r12.gravity(m1 * m2), F23 = r23.gravity(m2 * m3), F31 = r31.gravity(m3 * m1);
const F1 = F31.sub(F12), F2 = F12.sub(F23), F3 = F23.sub(F31);
const v = new Array(ODE_DIM);
v[0] = u[2];
v[1] = u[3];
v[2] = u[0] * u[3] * u[3] + F1.projectOn(r1) / m1;
v[3] = -(2 * u[2] * u[3] - F1.projectOn(a1) / m1) / u[0];
v[4] = u[6];
v[5] = u[7];
v[6] = u[4] * u[7] * u[7] + F2.projectOn(r2) / m2;
v[7] = -(2 * u[6] * u[7] - F2.projectOn(a2) / m2) / u[4];
v[8] = u[10];
v[9] = u[11];
v[10] = u[8] * u[11] * u[11] + F3.projectOn(r3) / m3;
v[11] = -(2 * u[10] * u[11] - F3.projectOn(a3) / m3) / u[8];
return v;
};
};
三体系统演示程序(演示证明三体问题不能精确求解):
三体问题
测试链接:https://elasticdogs.com/three-body/index.html
【彩蛋】三体人所在的三体星系拥有三个太阳
由于三体运动的混沌状态带来了三体星系气候的不稳定性
导致三体文明一次又一次的夭折在文明发展的初级阶段
在历经200多次残酷而痛苦的轮回之后终于进化到了航天时代
由于三体问题不能精确求解,最终三体行星一定会与恒星相撞……
唯有——向地球进军!
|