Как я могу заменить метод Эйлера на 4-й порядок Рунге-Кутты, чтобы определить движение свободного падения с не постоянной гравитационной величиной (например, свободное падение с высоты 10 000 км над землей)?
До сих пор я писал простую интеграцию по методу Эйлера:
while()
{
v += getMagnitude(x) * dt;
x += v * dt;
time += dt;
}
Переменная x означает текущую позицию, v означает скорость, getMagnitude (x) возвращает ускорение в позиции x.
Я попытался реализовать RK4:
while()
{
v += rk4(x, dt) * dt; // rk4() instead of getMagintude()
x += v * dt;
time += dt;
}
где тело функции rk4 ():
inline double rk4(double tx, double tdt)
{
double k1 = getMagnitude(tx);
double k2 = getMagnitude(tx + 0.5 * tdt * k1);
double k3 = getMagnitude(tx + 0.5 * tdt * k2);
double k4 = getMagnitude(tx + tdt * k3);
return (k1 + 2*k2 + 2*k3 + k4)/6.0;
}
Но что-то не так, потому что я интегрирую только один раз, используя RK4 (ускорение). Интеграция скорости с использованием RK4 не имеет смысла, потому что она такая же, как v * dt.
Не могли бы вы рассказать, как решать дифференциальные уравнения второго порядка с помощью интегрирования Рунге-Кутты? Должен ли я реализовать RK4 путем вычисления коэффициентов k1, l1, k2, l2 ... l4? Как я могу это сделать?
Ответы:
Похоже, существует некоторая путаница в отношении того, как применять многошаговые (например, Рунге-Кутта) методы к ODE 2-го или более высокого порядка или системам ODE. Процесс очень прост, если вы понимаете это, но, возможно, не очевиден без хорошего объяснения. Следующий метод, который я считаю самым простым.
k1
k4
X
RHS( t, X )
К сожалению, C ++ изначально не поддерживает векторные операции, подобные этой, поэтому вам нужно либо использовать векторную библиотеку, либо использовать циклы, либо выписывать отдельные части вручную.В C ++ вы можете использоватьstd::valarray
для достижения того же эффекта. Вот простой рабочий пример с постоянным ускорением.источник
typedef std::valarray<double> Vector
для часто используемых типов. 3) Используйтеconst int NDIM = 2
вместо#define
для безопасности типа и правильности. 4) Начиная с C ++ 11, вы можете просто заменить тело RHSreturn {X[1], 1}
. 5) В C ++ очень редко (в отличие от C) сначала объявляют переменные, а затем инициализируют их, предпочитают объявлять переменные в том же месте, где вы их инициализируете (double t = 0.
и т. Д.)RHS()
вычисляет правую часть дифференциального уравнения. Вектор состояния X имеет вид (x, v), поэтому dX / dt = (dx / dt, dv / dt) = (v, a). Для вашей проблемы (если a = G * M / x ^ 2) RHS должен вернуться{ X[1], G*M/(X[0]*X[0]) }
.