Какие хорошие алгоритмы для численного интегрирования для физического движка? - PullRequest
1 голос
/ 23 февраля 2012

Я некоторое время искал в интернете методы интеграции для физического движка, который я пытаюсь написать для забавы (должен полюбить занудство там: P). Я нашел метод Эйлера, 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 ]

2 голосов
/ 05 мая 2012

У вас есть дифференциальное уравнение второго порядка (ОДУ) x '' = f (x, x ', t).x может быть вектором, а x 'и x' 'являются первой и второй производной по времени.В вашем случае x - это позиция, x - это скорость, а x - это ускорение.Обычно каждый преобразовывает ODE второго порядка в первый ODE, вводя X = x, Y = x ', и вы получаете

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

ТогдаВы можете использовать классические схемы для решения ODE, такие как Runge-Kutta, Dormand-Prince, Adams-Bashforth, ...

Многие из этих методов реализованы в odeint , что довольно легкоиспользовать.

1 голос
/ 23 февраля 2012

Существует множество различных алгоритмов для числовой интеграции ODE.См. эту статью Википедии для обзора.Какие алгоритмы подходят, сильно зависит от свойств ODE, которые вы пытаетесь решить.Метод Эйлера редко работает хорошо, так как вам часто требуется очень маленький размер шага для достижения хорошего приближения к решению (но это очень легко реализовать, поэтому может быть полезно с первой попытки).Существуют варианты, такие как метод Эйлера в обратном направлении, который может работать немного лучше.

Методы Рунге-Кутты представляют собой широкий класс методов, которые включают метод Эйлера.Когда вы увеличиваете порядок метода, вам обычно требуется меньше временных шагов для достижения той же точности, но выполнение вычислений на каждом временном шаге становится все более дорогостоящим - RK4 используется очень часто, поскольку он стремится обеспечить хороший баланс.

На практике методы адаптивного размера шага обычно используются для контроля временного шага для достижения желаемой точности.

Существует много существующих реализаций решателей ODE, которые люди ставятмного работы - хотя хорошо, что вам интересно знать, как они работают, эти решатели могут оказаться довольно сложными, поэтому, если вы не удовлетворены результатами, полученными в результате ваших собственных попыток, это может быть лучшей идеейизучить существующие подпрограммы, такие как те из научной библиотеки GNU.

...