【问题标题】:The momentum is not conserved after collision resolution between balls球之间的碰撞解决后动量不守恒
【发布时间】:2013-05-03 11:14:13
【问题描述】:

我在球之间的碰撞解决方面有问题。 其实碰撞反应很真实,但是动量不守恒,为什么?

我使用基于此文档的算法:http://www.vobarian.com/collisions/2dcollisions2.pdf

在 Java 代码中,我的算法是:

/**
* Resolve the collision creating new velocities according to physical laws. 
*/
public void resolveCollisionWith(Ball ball) {
    //First resolve intersection for calculate correct new velocities.
    resolveIntersectionWith(ball);

    //Unit normal vector uN is the unit-vector that links the two centers.
    Vector uN = mPosition.subtraction(ball.getPosition()).normalize();

    //Unit tangent vector uT is the unit-vector normal to uN. It's tangent to both the    two balls.
    Vector uT = new Vector(-uN.getY(), uN.getX());

    //Project the two balls velocities onto the collision axis(uT and uN vectors).
    double v1n = uN.dot(mVelocity), v1t = uT.dot(mVelocity);
    double v2n = uN.dot(ball.getVelocity()), v2t = uT.dot(ball.getVelocity());

    //Calculate the post collision normal velocities (tangent velocities don't change).
    double v1nPost = (v1n*(mMass-ball.getMass()) + 2*ball.getMass()*v2n)/(mMass+ball.getMass());
    double v2nPost = (v2n*(ball.getMass()-mMass) + 2*mMass*v1n)/(mMass+ball.getMass());

    //Convert scalar velocities to vectors.
    Vector postV1N = uN.multiplication(v1nPost), postV1T = uT.multiplication(v1t);
    Vector postV2N = uN.multiplication(v2nPost), postV2T = uT.multiplication(v2t);

    //Change the balls velocities.
    mVelocity.set(postV1N.addition(postV1T));
    ball.getVelocity().set(postV2N.addition(postV2T));
}

 /**
 * When two balls collide can occur an intersection(the distance between the centers
 * is less than the sum of the radii) that dephases the response. 
 * The method fix this situation bringing back the two ball according to their mass.
 */
private void resolveIntersectionWith(Ball ball){
    Vector n = mPosition.subtraction(ball.getPosition());
    // How much the distance between centers is less than the radii's sum.
    double offset = getRadius() + ball.getRadius() - n.length();
    n.normalize();
    n.multiply(offset);
    // Bring back the two ball according to their mass.
    mPosition.add(n.multiplication(ball.getMass() * 1.0 / (mMass + ball.getMass())));
    ball.getPosition().subtract(n.multiplication(mMass * 1.0 / (mMass + ball.getMass())));
}

 /**
 * Normalizes and returns this vector.
 */
 // ***INSIDE VECTOR CLASS***
public Vector normalize() {
    //Avoid division by zero.
    if (mX != 0 || mY != 0) {
        double lenght = length();
        mX /= lenght;
        mY /= lenght;
    }
    return this;
}

谢谢!

【问题讨论】:

  • “动量不守恒”是什么意思?球慢下来了?加快速度?
  • 动量守恒当: m1*v1 + m2*v2 = m1*v1' + m2*v2' (m1是第一个球的质量,v1是碰撞前的速度,v1'是碰撞后的速度)
  • 你能发帖resolveIntersectionWith吗?
  • 我知道什么是动量守恒。告诉我程序实际在做什么。
  • @Robert 它似乎试图模拟弹性碰撞。当然,如果 Java 有运算符重载,事情会更清楚。

标签: physics


【解决方案1】:

假设精确的数学,方程本身将转换动量。所以自然怀疑是浮点错误。在正常情况下,错误会非常小,尽管它们仍然会随着时间的推移而累积。但是,除以小数会放大错误。

当你对一个非常小的向量进行归一化时,你最终可能会得到一个幅度不接近 1 的东西,这要归功于每个分量划分中的放大误差。这反过来又会大大改变势头。事实上,你的代码编写方式可能会给你无穷大或 NaN,尽管我想你会注意到如果是这样的话。

事实上,在某些情况下,您甚至根本不会对向量进行归一化(当两个分量都为 0 时)。但是你仍然盲目地继续使用虚假向量。

编辑:我刚刚注意到您的向量是可变的。我强烈建议让它们不可变。它简化了代码并减少了因丢失副本而导致的错误范围。

【讨论】:

  • 关于问题:在您看来可以改变一些东西使用 float 而不是 double?在这个问题stackoverflow.com/questions/5008252/… 中,用户确认使用相同的算法(使用浮点数)获得动量守恒...
  • 那么上面的用户是如何得到保护的呢?
  • 首先,您看到了什么样的错误?随时间累积的小错误,还是单个时间步后的大错误?如果是后者,你有什么样的位移向量?你检查标准化后的幅度了吗?
  • 例如,我看到 2 个球以 24 和 0 的速度长度开始,因此动量为 24(质量均为 1),第一次碰撞后动量为 34,另一次碰撞后为 28 , ---> 32 ---> 33 ---> 32. 我在归一化后检查 uN 向量的大小,它几乎总是 1.0,有时是 0.9999999999999999。
  • 这些速度是否都在同一个方向?因为如果是这样,那真的不应该发生。尝试打印出每个变量的数字并通过第一次碰撞来查看错误来自哪里。展示您如何计算动量也可能会有所帮助。
【解决方案2】:

我的程序有一个类似的问题,我有一个用户定义的具有随机质量、半径和速度的球不断相互碰撞。该问题是由于无法避免的小数舍入错误引起的。

我想到的使我的动量始终保持在起始动量的正负约 1% 的解决方案如下:

创建一个名为 firstRun 的布尔值,以及两个双精度数 totalMomentum 和 totalMomentum2。计算循环中第一次运行的总动量并将其保存到 totalMomentum。然后,每隔一次运行,计算总动量并将其保存到 totalMomentum2。

然后,对于第一次之后的每一次跑动,将球的速度乘以比率 (totalMomentum/totalMomentum2)。

这样,如果动量太高,就会使总数降低。如果它太低,它会提高它。

我目前有一个设置,有 200 个球相互碰撞,初始动量约为 45000。我的范围始终保持在 44500 和 45500 之间。

希望这会有所帮助!

编辑:当我将球的数量减少到 5 个并增加质量时,总动量约为 22500,使用这种方法几乎完美地保存了动量。这种波动甚至在大多数情况下都不会发生,如果发生了,它会从 22500 到 22499,然后又回到 22500。

【讨论】:

    猜你喜欢
    • 2011-06-27
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    相关资源
    最近更新 更多