【问题标题】:In an elastic collision between two two-dimensional bodies, is total speed (magnitude of velocity) between the bodies conserved?在两个二维物体之间的弹性碰撞中,物体之间的总速度(速度大小)是否守恒?
【发布时间】:2012-11-30 04:29:15
【问题描述】:

问题

在一个封闭的系统中,运动的二维圆形物体(它们具有质量和速度属性)以完美的弹性相互碰撞,是所有物体的总 velocity 速度(速度的大小)在系统内守恒?

背景

我正在基于this Stack Overflow question 中概述的碰撞解决方法在 Python 中实现一个简单的二维物理引擎。我的期望是,当两个物体发生碰撞时,总速度(与每个物体相关的速度矢量的长度之和)应该在它们之间保持恒定,我根据这个期望为我的解析方法设计了一个单元测试。但我发现我的测试失败了。所以我想首先确保我的假设是正确的。

如果正确,我邀请您查看我的代码并解释测试失败的原因:

冲突解决

class Physics:

    @staticmethod
    def reflect_colliding_circles(
        (c1_x, c1_y, c1_vx, c1_vy, c1_r, c1_m, c1_e),
        (c2_x, c2_y, c2_vx, c2_vy, c2_r, c2_m, c2_e)):
        # inverse masses, mtd, restitution
        im1 = 1.0 / c1_m
        im2 = 1.0 / c2_m
        mtd = Physics.calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r))
        normal_mtd = mtd.normalized()
        restitution = c1_e * c2_e

        # impact speed
        v = vec2d(c1_vx, c1_vy) - vec2d(c2_vx, c2_vy)
        vn = v.dot(normal_mtd)

        # circle moving away from each other already -- return
        # original velocities
        if vn > 0.0:
            return vec2d(c1_vx, c1_vy), vec2d(c2_vx, c2_vy)

        # collision impulse
        i = (-1.0 * (1.0 + restitution) * vn) / (im1 + im2)
        impulse = normal_mtd * i

        # change in momentun
        new_c1_v = vec2d(c1_vx, c1_vy) + (impulse * im1)
        new_c2_v = vec2d(c2_vx, c2_vy) - (impulse * im2)

        return new_c1_v, new_c2_v

    @staticmethod
    def calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r)):
        """source: https://stackoverflow.com/q/345838/1093087"""
        delta = vec2d(c1_x, c1_y) - vec2d(c2_x, c2_y)
        d = delta.length
        mtd = delta * (c1_r + c2_r - d) / d
        return mtd

单元测试

def test_conservation_of_velocity_in_elastic_collisions(self):
    for n in range(10):
        r = 2
        m = 10
        e = 1.0

        c1_pos = vec2d(0, 0)
        c1_v = vec2d(random.randint(-100,100), random.randint(-100,100))

        c2_delta = vec2d(random.randint(-100,100), random.randint(-100,100))
        c2_delta.length = random.randint(50, 99) * r / 100.0
        c2_pos = c1_pos + c2_delta
        c2_v = vec2d(random.randint(-100,100), random.randint(-100,100))

        c1_np, c2_np = Physics.translate_colliding_circles(
            (c1_pos.x, c1_pos.y, r, m),
            (c2_pos.x, c2_pos.y, r, m))

        c1_nv, c2_nv = Physics.reflect_colliding_circles(
            (c1_np.x, c1_np.y, c1_v.x, c1_v.y, r, m, e),
            (c2_np.x, c2_np.y, c2_v.x, c2_v.y, r, m, e))

        old_v = c1_v.length + c2_v.length
        new_v = c1_nv.length + c2_nv.length

        self.assertTrue(Physics.circles_overlap(
            (c1_pos.x, c1_pos.y, r), (c2_pos.x, c2_pos.y, r)))
        self.assertTrue(old_v - new_v < old_v * .01)

我正在使用这个 pygame 矢量类:http://www.pygame.org/wiki/2DVectorClass

【问题讨论】:

  • 旁白:如果恢复系数不为 1,系统不应该整体失去能量吗?
  • @Cameron:根据定义,理想的弹性碰撞会保留机械能。
  • “速度”是指速度吗?
  • @AndreyT 是的,我指的是速度的总幅度——这是我的测试正在测量的。感谢您指出了这一点。我会更新问题,使其更准确。

标签: python geometry pygame game-physics


【解决方案1】:

动量是守恒的,不管碰撞的弹性如何。总速度显然不是。严格来说,velocity 是一个向量,作为向量很容易看出它会发生变化:例如,一个球从一个不可移动的垂直壁上弹性反弹,其速度变为正好相反。

【讨论】:

  • 完全“不可移动”的墙是非实体的。相反,你可以说是“巨大的”墙,当球反弹时它只会获得很小的速度(速度比它进来的速度略低,因为一些动量被转移到了墙上)。
  • @Blckknght:如果墙的质量足够高,而系统中的可用能量相比之下足够低,那么就不可能可测量移动墙,即足够接近。
  • 你能想出一个简单的例子,在碰撞后总速度magnitudes明显变化吗? (我自己也遇到了麻烦。)
  • @Cameron:当然,AndreyT 的示例有效(只要您将“不可移动”解释为“大量”)。想象一个 1 克的球从 1000 公斤的墙上弹起。球的速度几乎完全相反,而墙壁的速度将可以忽略不计。系统总动量将保持不变,但总速度将发生很大变化。
  • @AndreyT:不正确。即使在完全弹性碰撞的情况下,幅度总和也不会在一维中保持恒定。想象一堵 1000 kg 的砖墙以 10 m/s 的速度向一个静止的 100 g 橡胶球移动。显然,砖墙仍将以 10 m/s 的速度移动,而球现在将以 20 m/s 的速度移动。速度大小的总和增加了三倍。它保持不变的唯一方法是如果球穿过墙壁,这显然是不可能的。
【解决方案2】:

AndreyT's answer 让我明白了。这是我想要的单元测试:

def test_conservation_of_momentum_in_elastic_collisions(self):
    """Some references:
    http://en.wikipedia.org/wiki/Elastic_collision
    http://en.wikipedia.org/wiki/Momentum
    https://stackoverflow.com/a/13639140/1093087"""
    for n in range(10):
        r = 2
        m = 10
        e = 1.0

        c1_pos = vec2d(0, 0)
        c1_v = vec2d(random.randint(-100,100), random.randint(-100,100))

        c2_delta = vec2d(random.randint(-100,100), random.randint(-100,100))
        c2_delta.length = random.randint(50, 99) * r / 100.0
        c2_pos = c1_pos + c2_delta
        c2_v = vec2d(random.randint(-100,100), random.randint(-100,100))

        momentum_before = (c1_v * m) + (c2_v * m)  

        c1_np, c2_np = collision.translate_colliding_circles(
            (c1_pos.x, c1_pos.y, r, m),
            (c2_pos.x, c2_pos.y, r, m))

        c1_nv, c2_nv = collision.reflect_colliding_circles(
            (c1_np.x, c1_np.y, c1_v.x, c1_v.y, r, m, e),
            (c2_np.x, c2_np.y, c2_v.x, c2_v.y, r, m, e))

        momentum_after = (c1_nv * m) + (c2_nv * m)  

        self.assertTrue(collision.circles_overlap(
            (c1_pos.x, c1_pos.y, r), (c2_pos.x, c2_pos.y, r)))
        self.assertEqual(momentum_before, momentum_after)

通过了。

【讨论】:

    【解决方案3】:

    这是一个很好的问题。我认为弹性碰撞理论中不存在正确的解决方案,因为它是在物理课程/书籍中教授的。

    在质心 (CM) 参考系中,相对速度在二元弹性碰撞(惠更斯)中反转。由于相对速度不取决于选择的参考系,因此相对速度在任何任意参考系中都会反转。这确保了与 CM 参考系中的速度之和相同的相对速度的大小保持恒定。

    本质上,上面所说的意思是:如果您计算 CM 框架中的速度之和(速度的大小),您的测试/代码必须没有失败。

    我可以通过补充信息的方式添加以下内容。

    还有另一种理论导致了只需要恢复相对速度而不坚持相对速度反转的结果。根据该理论,在任意参考系中,两个质量之间的动能 (KE) 转移是可能的,同时保持 KE 的总和不变。这种理论可能会导致您的代码/测试结果失败。

    我不了解您编写的代码,因为我不熟悉计算机代码/程序。因此,我无法建议对您的程序进行修改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-16
      • 2018-09-03
      • 1970-01-01
      相关资源
      最近更新 更多