Comment puis-je remplacer la méthode Euler par Runge-Kutta 4e ordre pour déterminer le mouvement de chute libre dans une amplitude gravitationnelle non constante (par exemple, chute libre à partir de 10 000 km au-dessus du sol)?
Jusqu'à présent, j'ai écrit une intégration simple par la méthode Euler:
while()
{
v += getMagnitude(x) * dt;
x += v * dt;
time += dt;
}
x variable signifie la position actuelle, v signifie la vitesse, getMagnitude (x) renvoie l'accélération sur la position x.
J'ai essayé d'implémenter RK4:
while()
{
v += rk4(x, dt) * dt; // rk4() instead of getMagintude()
x += v * dt;
time += dt;
}
où le corps de la fonction rk4 () est:
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;
}
Mais quelque chose ne va pas, car je n'intègre qu'une seule fois en utilisant RK4 (accélération). L'intégration de la vitesse à l'aide de RK4 n'a pas de sens car c'est la même chose que v * dt.
Pourriez-vous me dire comment résoudre des équations différentielles de second ordre en utilisant l'intégration Runge-Kutta? Dois-je implémenter RK4 en calculant les coefficients k1, l1, k2, l2 ... l4? Comment puis je faire ça?
Réponses:
Il semble y avoir un peu de confusion sur la façon d'appliquer des méthodes à plusieurs étapes (par exemple Runge-Kutta) à des ODE d'ordre 2 ou supérieur ou à des systèmes d'ODE. Le processus est très simple une fois que vous le comprenez, mais peut-être pas évident sans une bonne explication. La méthode suivante est celle que je trouve la plus simple.
k1
k4
X
RHS( t, X )
Malheureusement, C ++ ne prend pas en charge nativement les opérations vectorielles comme celle-ci, vous devez donc utiliser une bibliothèque vectorielle, utiliser des boucles ou écrire manuellement les parties distinctes.En C ++, vous pouvez utiliserstd::valarray
pour obtenir le même effet. Voici un exemple de travail simple avec une accélération constante.la source
typedef std::valarray<double> Vector
pour les types couramment utilisés. 3) Utiliserconst int NDIM = 2
au lieu de#define
pour la sécurité et l'exactitude du type. 4) Depuis C ++ 11, vous pouvez simplement remplacer le corps de RHS parreturn {X[1], 1}
. 5) Il est vraiment rare en C ++ (contrairement à C) de déclarer d'abord des variables, puis de les initialiser plus tard, préférez déclarer des variables au même endroit où vous les initialisez (double t = 0.
, etc.)RHS()
calcule le côté droit de l'équation différentielle. Le vecteur d'état X est (x, v) donc dX / dt = (dx / dt, dv / dt) = (v, a). Pour votre problème (si a = G * M / x ^ 2) RHS devrait revenir{ X[1], G*M/(X[0]*X[0]) }
.