- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题
我实现了 Verlet 速度算法来计算 2 个物体在重力作用下相互作用的轨迹(仅限牛顿引力)。绕轨道运行的小天体质量很小,位于轨道中心的天体质量很大。
理论上,Velocity Verlet 不应改变系统的总能量(它会振荡,但随着时间的推移,平均值将保持接近初始能量)。
但在实践中,我观察到能量会随着时间的推移而增加。
结果
下面是一些说明问题的结果。所有模拟均以时间步长 dt = 0.001 执行。轨道天体质量为1000,宇宙万有引力常数G=1.0
在所有情况下,较小的物体初始位置为 {0, 0, 1},初始速度为 {0, 32, 0}。较大物体的初始速度为 {0,0,0}。
案例 1(小体重 = 0.00001)
这是较小的 body 的轨迹:
这是超过 10 万步的能量。
正如我们所见,能量变化不大。微小的变化可能是由于计算不准确造成的。
案例 1(小体重 = 0.001)
这是轨道天体的轨迹:
这是总能量:
正如我们现在看到的,系统正在获得能量。
案例 3(小体重 = 1)
这是轨道天体的轨迹:
这是总能量:
现在我们获得了很多能量。
代码
这是执行所有计算的源代码:
高级积分器代码:
void Universe::simulation_step()
{
for(std::size_t i=0; i<get_size(); i++)
{
// Verlet step 1: Compute v(t + dt/2) = v(t) + 0.5*dt*a(t)
const Vector3D<Real> vel_half_step = {
velocity(i, 0) + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 0),
velocity(i, 1) + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 1),
velocity(i, 2) + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 2)
};
// Verlet step 2: Compute x(t + dt) = x(t) + v(t + dt/2)*dt
position(i, 0) += vel_half_step.x*sim_config.timestep;
position(i, 1) += vel_half_step.y*sim_config.timestep;
position(i, 2) += vel_half_step.z*sim_config.timestep;
// Verlet step 3: update forces and update acceleration.
const Vector3D<Real> forces = compute_net_grawitational_force(i);
acceleration(i, 0) = forces.x/mass(i);
acceleration(i, 1) = forces.y/mass(i);
acceleration(i, 2) = forces.z/mass(i);
// Verlet step 4: update velocity to the full timestep.
velocity(i, 0) = vel_half_step.x + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 0);
velocity(i, 1) = vel_half_step.y + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 1);
velocity(i, 2) = vel_half_step.z + static_cast<Real>(0.5)*sim_config.timestep*acceleration(i, 2);
}
sim_time += sim_config.timestep;
}
下面是计算作用在 body 上的净重力的代码:
Vector3D<Real> Universe::compute_net_grawitational_force(std::size_t i)
{
Vector3D<Real> accumulated_force = {0,0,0};
const Vector3D<Real> r2 = {
position(i, 0),
position(i, 1),
position(i, 2)
};
const Real m1 = mass(i);
for(std::size_t k=0; k<get_size(); k++)
{
if(k == i)
continue;
const Vector3D<Real> distace_vec = {
r2.x - position(k, 0),
r2.y - position(k, 1),
r2.z - position(k, 2),
};
const Real distance = distace_vec.norm2();
// Compute term that will be multipled by distance vector.
const Real a = (-1*sim_config.G*m1*mass(k))/
(distance*distance*distance);
// Compute and add new force acting on the body.
accumulated_force.x += distace_vec.x*a;
accumulated_force.y += distace_vec.y*a;
accumulated_force.z += distace_vec.z*a;
}
return accumulated_force;
}
这是实现 norm2() 的代码:
template<typename T>
struct Vector3D
{
T x;
T y;
T z;
T norm2() const
{
return sqrt(x*x + y*y + z*z);
}
};
最后是计算先前绘制的结果的代码:
std::vector<Real> x, y, z, energy;
x.resize(NSTEPS);
y.resize(NSTEPS);
z.resize(NSTEPS);
energy.resize(NSTEPS);
for(std::size_t i=0; i<NSTEPS; i++)
{
universe.simulation_step();
const Vector3D<Real> pos1 =
{
universe.get_positions()(0, 0),
universe.get_positions()(0, 1),
universe.get_positions()(0, 2)
};
const Vector3D<Real> pos2 =
{
universe.get_positions()(1, 0),
universe.get_positions()(1, 1),
universe.get_positions()(1, 2)
};
x[i] = pos2.x;
y[i] = pos2.y;
z[i] = pos2.z;
// Compute total kinetic energy of the system.
const Vector3D<Real> vel1 =
{
universe.get_velocities()(0, 0),
universe.get_velocities()(0, 1),
universe.get_velocities()(0, 2),
};
const Vector3D<Real> vel2 =
{
universe.get_velocities()(1, 0),
universe.get_velocities()(1, 1),
universe.get_velocities()(1, 2),
};
const Real mass1 = universe.get_masses()(0);
const Real mass2 = universe.get_masses()(1);
const Real spd1 = vel1.norm2();
const Real spd2 = vel2.norm2();
energy[i] = (spd1*spd1)*mass1*static_cast<float>(0.5);
energy[i] += (spd2*spd2)*mass2*static_cast<float>(0.5);
// Compute total potential energy
const Vector3D<Real> distance_vec =
{
pos1.x - pos2.x,
pos1.y - pos2.y,
pos1.z - pos2.z
};
const Real G = universe.get_sim_config().G;
energy[i] += -G*((mass1*mass2)/distance_vec.norm2());
}
类型 Real
是 float
。
我的理论
我是数值积分的初学者(这就是我在这里发布这个问题的原因)。然而,这里有一些关于可能出错的理论:
能量漂移
。也许这就是这里发生的事情?轨道似乎没有解体,但不是我预期的结果我想知道为什么。
谁能帮我解开这个谜团?
编辑:
我测试了 double ,唯一的变化是现在最小轨道质量的能量更加稳定。
现在即使是最小的质量也可以看到增加的趋势。这暗示这不是计算精度的问题。
最佳答案
我发现了问题。
结果是一个问题是一个一个地更新 body 的位置。加速度的计算假设没有物体在时间步之间移动然而,一个一个地更新导致一些物体的位置来自 t 而一些物体来自 t + dt。这个特定系统中的差异导致轨道体速度的 vector 差异无法理想地指向质心。实际上,产生了一个小的切向分量,并且能量被添加到系统中。错误很小,但随着时间的推移它会累积并变得可见。
我通过一次对所有物体执行 verlet 算法的每个阶段来解决这个问题。这是集成器的修订代码:
for(std::size_t i=0; i<get_size(); i++)
{
position(i, 0) += velocity(i, 0)*sim_config.timestep + acceleration(i, 0)*sim_config.timestep*sim_config.timestep*static_cast<Real>(0.5);
position(i, 1) += velocity(i, 1)*sim_config.timestep + acceleration(i, 1)*sim_config.timestep*sim_config.timestep*static_cast<Real>(0.5);
position(i, 2) += velocity(i, 2)*sim_config.timestep + acceleration(i, 2)*sim_config.timestep*sim_config.timestep*static_cast<Real>(0.5);
}
for(std::size_t i=0; i<get_size(); i++)
{
velocity(i, 0) += acceleration(i, 0)*sim_config.timestep*static_cast<Real>(0.5);
velocity(i, 1) += acceleration(i, 1)*sim_config.timestep*static_cast<Real>(0.5);
velocity(i, 2) += acceleration(i, 2)*sim_config.timestep*static_cast<Real>(0.5);
}
for(std::size_t i=0; i<get_size(); i++)
{
const Vector3D<Real> forces = compute_net_grawitational(i);
acceleration(i, 0) = forces.x/mass(i);
acceleration(i, 1) = forces.y/mass(i);
acceleration(i, 2) = forces.z/mass(i);
}
for(std::size_t i=0; i<get_size(); i++)
{
velocity(i, 0) += acceleration(i, 0)*sim_config.timestep*static_cast<Real>(0.5);
velocity(i, 1) += acceleration(i, 1)*sim_config.timestep*static_cast<Real>(0.5);
velocity(i, 2) += acceleration(i, 2)*sim_config.timestep*static_cast<Real>(0.5);
现在即使对于最重的轨道天体,能量也不会增加:
能量仍在漂移,但随着时间的推移,差异似乎趋于平衡,并且相对于总值而言变化很小。绘图是自动调整范围的,所以变化看起来很大,但它们在总能量的 +- 1% 以内,这对我的应用来说是可以接受的。
关于c++ - Velocity verlet 算法 - n 体问题的能量增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66893929/
我使用此处找到的时间校正 Verlet 集成:http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-t
我正在尝试学习 Verlet 集成,主要是因为我很无聊,并且想为我正常的“弹跳球”学习练习增添趣味。 我在 http://sandbox.electricgrey.com:8080/physics/
有一个常用的verlet-integration Johnathan Dummer 在网上的公式,称为 Time-Corrected Verlet。但是我读过几个论坛帖子,人们在某些情况下会得到奇怪或
我正在使用 Haskell 制作 Verlet 积分器来模拟重力。积分器使用对象的前两个位置作为种子,并在此后生成其余位置。 我认为在 Haskell 中实现此目的的一个好方法是使用无限列表。然而,当
我知道这个标题让人大跌眼镜,但它主要是一个副作用问题。我正在编写一个 Android 应用程序,我可以将它与我在物理课上学习的数学一起使用。这是一个 2D 弹跳球应用程序。我正在使用时间校正的 Ver
我想为游戏创建一些 physx,我从小例子开始了解它是如何工作的。在此期间我遇到了一些问题,但我在 90% 内解决了它们。 为了创建我的示例,我研究了一些其他示例并创建了我使用的示例:codeflow
我正在尝试使用 verlet integration用于制作软体球体。 我主要是创建一个网格并通过 Spring 连接每个顶点。我正在使用 three.js 来渲染球体。我相信一切正常,但我不确定如何
我的印象是,如果被建模的系统确实如此,算法应该能够节约能源。我正在模拟太阳系,它应该节约能源。该程序保留了角动量并确实产生了稳定的轨道,但总能量(动能 + 重力势能)围绕某个基线振荡。振荡是显着的。是
我知道 Velocity Verlet 没有 Verlet 的初始化问题并且在其工作中有速度计算,而 Time Corrected Verlet 对于不同的时间步长是正确的但不包括速度计算。我想要像“
下面是我的 Verlet 函数代码,将从我的主脚本中调用。 % verlet.m % uses the verlet step algorithm to integrate the simple ha
我正在构建一个物理引擎,我有某种“伪 verlet”的东西在运行,我想将它升级到“真正的”verlet。所以我找到了一篇文章并开始工作。在我添加了我认为是一个很好的近似值之后,引擎不再工作了。有人可以
我是 Haskell 的新手,作为练习,我一直在尝试实现 Joel Franklin 的《物理计算方法》一书中的一些代码(用 Mathematica 编写)。我编写了以下代码以将 lambda 表达式
我正在尝试为具有周期性或反射性边界条件的二维盒子中的 lennard-jones 流体编写分子动力学模拟。模拟似乎在有反射边界的情况下运行良好,但出于某种原因,周期性盒子中的粒子在几百个积分步骤后开始
我的下面的代码(应该)求解两个物体的运动方程,但结果是粒子运行方式,我无法找到错误在哪里 import numpy as np import matplotlib.pyplot as plt plt.
对于我的建模和仿真类(class)项目,我想模拟一个太阳系。我从一颗恒星(太阳)和一颗行星(地球)开始,但我已经遇到了一些问题。我现在花了一些时间来回顾和学习不同的公式和方法来模拟行星的轨道将如何受到
问题 我实现了 Verlet 速度算法来计算 2 个物体在重力作用下相互作用的轨迹(仅限牛顿引力)。绕轨道运行的小天体质量很小,位于轨道中心的天体质量很大。 理论上,Velocity Verlet 不
我正在尝试通过速度 verlet 模拟地球-太阳系统,但不知何故,太阳不会围绕原点(质量减少的位置)运行,而是漂移。我花了很多时间查看我的算法,但找不到缺陷。 有人知道这里出了什么问题吗? 这是模拟图
我只是在测试游戏中轨道动力学的几种集成方案。我在这里以持续和适应性的步骤参加了 RK4 http://www.physics.buffalo.edu/phy410-505/2011/topic2/ap
我在理解我尝试使用 Three.js 和 yomboprime 的 GPUComputationRenderer 实现的逻辑时遇到了问题。 ( https://github.com/yomboprim
我是一名优秀的程序员,十分优秀!