【问题标题】:Simple bouncing ball in haskell keeps bouncing higherHaskell中的简单弹跳球不断弹跳更高
【发布时间】:2014-06-29 22:25:21
【问题描述】:

所以,我做了一个简单的弹跳球模拟来学习haskell。球应该会在图像边界上反弹并通过重力向下加速。

问题在于随着时间的推移,球“神奇地”弹得更高。我希望它保持相同的最大高度。

我怀疑bouncemove 有问题,因为bounce 将球“传送”回框架内,这在物理上并不准确。我尝试了不同的方法来模拟正确的行为,但找不到任何正确的方法。

这样做的正确方法是什么?

这是代码,在CodeWorld上运行:

main = simulationOf initial step draw

data World = Ball Point Vector

radius = 40
border = 250 - radius
g = -500

initial (x:y:vx:vy:_) = Ball (400*x  - 200, 400*y  - 200)
                             (400*vx - 200, 400*vy - 200)

step t world = bounce (move t world)

move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy + g*t)

bounce (Ball (x,y) (vx,vy)) = Ball (nx,ny) (nvx, nvy)
  where nx  = fence (-border) border x
        ny  = fence (-border) border y
        nvx = if nx /= x then -vx else vx
        nvy = if ny /= y then -vy else vy

fence lo hi x = max lo (min hi x)

draw (Ball (x,y) _) = translate x y (solidCircle radius)

【问题讨论】:

    标签: haskell simulation physics


    【解决方案1】:

    这是您用来积分运动微分方程的算法的著名工件。

    “真正的物理”是(我将只讨论 y 组件)

    y/∂t = v(t)
    v/∂t = g

    您通过高度和速度的离散序列对此进行建模

    yi = yi - 1 sub> + vi − 1 ⋅ Δt
    vi
    = vi − 1 + g ⋅ Δt em>

    这肯定类似于微分方程,只是写成差商——但它不是一回事(除了极限 Δt → 0):实际上,速度本身会随着时间而变化步,因此仅根据该时间步之前的常量 v 值更改位置并不完全正确。简单地忽略这种复杂性是一种称为Euler's method 的近似值,众所周知它非常糟糕。

    更准确的标准替代方案是四阶Runge-Kutta method,试试看。

    n.m. 关于弹跳的观点也是有效的,但要真正正确地做到这一点,您应该计算确切的撞击时间,既不要忽视太多的加速度,也不要得到太多实际上从未发生过的事情.

    【讨论】:

    • 当然,Runge-Kutta 可以很好地工作,问题是如何保持模拟极其简单,甚至牺牲数值精度,但保持系统的明显属性,如能量守恒。
    • 作为@n.m。说,我更想得到看起来真实的东西,而不是真正准确的东西。 Runge-Kutta 仍然是一个很好的调用,因为它实现起来并不复杂,而且可以重复使用。
    【解决方案2】:

    假设球正好在时间量的中间撞到地面。在现实中(或者更确切地说,在无摩擦的“现实”中)速度的绝对值在量子的开始和结束时保持不变,但在您的模型中它会增加。

    应该在bounce 中处理加速。最简单的方法是这样做:

    move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy)
    
    step t world = bounce (move t world) t
    bounce (Ball (x,y) (vx,vy)) t = Ball (nx,ny) (nvx, nvy) 
       ...
       nvy = if ny /= y then -vy else vy + g * t
    

    弹跳过程中速度不会增加。

    这仍然不完全准确,速度仍然在缓慢上升,但速度较慢。

    【讨论】:

    • 虽然弹跳确实是一个问题(尽管集成算法的选择更糟糕 IMO),但这不是解决它的好方法。重力加速度与弹跳有什么关系?这个函数当然不应该再被调用了。最好的方法可能是将积分器作为 参数 传递给 bounce,但也可以将其全部内联到 step 中。
    • 如果我们关心没有数值准确性的实际行为,这对于弹跳问题来说是一个“足够好”的解决方案。我认为仍然需要像 Runge-Kutta 这样的集成。
    猜你喜欢
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    相关资源
    最近更新 更多