物理引擎的数值积分有哪些好算法

What are some good algorithms for numerical integration for a physics engine?

本文关键字:算法 数值积分 引擎      更新时间:2023-10-16

我已经在网上寻找了一段时间的物理引擎的集成方法,我正试图为一个有趣的代码编写(一定喜欢那里的书呆子气:p)。我找到了欧拉方法、RK4和Verlet(以及时间校正版本)。我也一直在尝试想出一些自己的方法。我想知道你是否知道其他你觉得直观或有用的东西。谢谢

编辑:谢谢你到目前为止的帮助。至于澄清:也许我的意思是数字积分。令人惊讶的是,在我所有的研究中,我还没有找到我想要做的事情的技术名称!也许描述我的具体问题会让我的问题更清楚。比方说,我想模拟一个球在圆形(或球形)引力场中移动。该球将遇到力矢量,该力矢量可用于计算球在特定刻度上所处点的相应加速度矢量。从你的物理课上,你知道速度=加速度*时间,但我的问题是,从技术上讲,球在那个点上只停留了一瞬间,在微积分中用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,这是相当准确的,但如果你让它变得更复杂,例如,使加速度随时间变化,算法会非常快地失去准确性。再次感谢!

您有一个二阶微分方程(ODE)x''=f(x,x',t)。x可以是一个向量,x’和x’’是相对于时间的一阶导数和二阶导数。在你的例子中,x是位置,x是速度,x是加速度。通常,通过引入X=X,Y=X',可以将二阶ODE转换为一阶ODE,从而获得

X'=YY'=f(X,Y)

然后你可以使用经典的方案来求解常微分方程,如Runge Kutta,Dormand Prince,Adams Bashforth。。。

其中许多方法都是在odeint中实现的,这很容易使用。

对常微分方程进行数值积分有许多不同的算法。请参阅维基百科上的这篇文章以获得概述。哪种算法是合适的在很大程度上取决于您试图解决的ODE的属性。Euler方法很少表现得很好,因为你通常需要一个很小的步长来实现对解决方案的良好近似(但这很容易实现,所以第一次尝试可能很好)。还有一些变体,比如向后的欧拉方法,可以做得更好一点。

龙格-库塔方法是一类广泛的方法,其中包括欧拉方法。随着方法阶数的增加,通常需要更少的时间步长才能达到相同的精度,但在每个时间步长执行计算变得越来越昂贵-RK4经常使用,因为它往往能达到良好的平衡。

在实践中,自适应步长技术通常用于控制时间步长以实现期望的精度。

ODE解算器有很多现有的实现,人们对此做了大量的工作-虽然你有兴趣了解它们是如何工作的是件好事,但这些解算器可能会变得非常复杂,所以如果你对自己的尝试结果不满意,那么最好研究现有的例程,比如GNU科学库中的例程。