什么是物理引擎数值积分的好算法?

时间:2012-02-23 17:15:15

标签: c++ physics-engine

我一直在网上寻找一段时间用于物理引擎的集成方法,我正在尝试编码以获得乐趣(必须爱那里的书呆子:P)。我找到了Euler的方法,RK4和Verlet(以及时间校正版本)。我也一直试图想出一些自己的方法。我想知道你是否知道任何其他你认为直观或有帮助的人。感谢。

编辑:感谢您迄今为止的所有帮助。至于澄清:也许我的意思是数字整合。令人惊讶的是,在我的所有研究中,我没有找到我想要做的技术名称!也许描述我的具体问题会使我的问题更清楚。让我们说我想模拟一个球通过一个圆形(或一旦我实施3d球形)重力场。该球将遇到力矢量,该矢量可用于计算球在该特定刻度上的点的相应加速度矢量。从你的物理课,你知道速度=加速*时间,但我的问题是球在技术上只在一瞬间,在数学上以数学方式用dt表示。显然,我不能在C ++中使用无穷小的数字,所以我必须使用瞬时积分的方法来近似解决方案(我在一些阅读中听到的一个术语,但我可能完全错了)或者你认为所谓的数值积分(你可能是对,所以我改了标题。)

这是我(成功)尝试实现数值积分的欧拉方法:

    //For console output. Note: I know I could just put "using namespace std;" but I hate doing that.
    #include <iostream>
    using std::cout;
    using std::system;
    using std::endl;

    //Program entry
    int main (void)
    {
        //Variable decleration;
        double time = 0;
        double position = 0;
        double velocity = 0;
        double acceleration = 2;
        double dt = 0.000001; //Here is the "instantanious" change in time I was talking about.
        double count = 0; //I use count to make sure I am only displaying the data at whole numbers.

        //Each irritation of this loop is one tick
        while (true)
        {

            //This next bit is a simplified form of Euler's method. It is what I want to "upgrade"
            velocity += acceleration * dt;
            position += velocity * dt;

            if (count == 1/dt) //"count == 1/dt" will only return true if time is a whole number.
            {

                //Simple output to console
                cout << "Time: " << time << endl;
                cout << "Position: " << position << endl;
                cout << "------------------" << endl;
                system ("pause");

                count = 0; //To reset the counter.

            }

            //Update the counters "count" and "time"
            count++;
            time += dt;

        }
        return 1; //Program exit
    }

因为加速度是恒定的并且这种差异实际上是可以解决的(为什么我用它来测试,解决方案是位置=时间^ 2,这是相当准确的但是如果你让它变得更复杂,例如,随着时间的推移加速度变化,算法非常快速地失去准确性。再次,谢谢!

2 个答案:

答案 0 :(得分:2)

你有一个二阶微分方程(ODE)x''= f(x,x',t)。 x可以是向量,x'和x''是关于时间的第一个和第二个导数。在你的情况下,x是位置,x'是速度,x'是加速度。通常通过引入X = x,Y = x'将这个二阶ODE转换为第一个ODE并获得

X'= Y Y'= F(X,Y)

然后你可以使用经典方案来解决像Runge-Kutta,Dormand-Prince,Adams-Bashforth这样的ODE ......

其中许多方法都在odeint中实现,非常容易使用。

答案 1 :(得分:1)

有许多不同的算法用于数字积分ODE。有关概述,请参阅this Wikipedia article。哪种算法合适取决于您尝试解决的ODE的属性。 Euler方法很少表现良好,因为您经常需要一个非常小的步长来实现对解决方案的良好近似(但这很容易实现,因此第一次尝试可能会很好)。像落后的欧拉方法这样的变化可以做得更好。

Runge-Kutta methods是一类广泛的方法,包括Euler方法。当您增加方法的顺序时,通常需要较少的时间步长来达到相同的准确度,但是在每个时间步执行计算变得越来越昂贵 - 经常使用RK4,因为它往往会达到很好的平衡。

在实践中,adaptive step size技术通常用于控制时间步长以达到所需的准确度。

ODE求解器有很多现有的实现,人们已经做了很多工作 - 虽然你有兴趣知道它们是如何工作的,但这些求解器会变得相当复杂,所以如果你不是对您从自己的尝试中获得的结果感到满意,查看现有的例程可能是个更好的主意,例如those in the GNU Scientific Library.

相关问题