Wydaje się, że istnieje sporo zamieszania co do sposobu stosowania metod wieloetapowych (np. Runge-Kutta) do ODE drugiego lub wyższego rzędu lub systemów ODE. Proces jest bardzo prosty, gdy go zrozumiesz, ale być może nie jest oczywisty bez dobrego wyjaśnienia. Poniższa metoda jest najprostsza.
W twoim przypadku równanie różniczkowe, które chciałbyś rozwiązać, to . Pierwszym krokiem jest napisanie ODE drugiego rzędu jako systemu ODE pierwszego rzędu. Odbywa się to jakofa= m x¨
[ x˙v˙] = [ wfa/ m]
Wszystkie równania w tym systemie musi być rozwiązany równocześnie, co znaczy, że należy nie advance , a następnie postęp , powinny być rozszerzone zarówno w tym samym czasie. W językach, które obsługują operacje wektorowe bez pętli, można to łatwo zrobić, tworząc wszystkie niezbędne terminy w wektorach kodu o długości 2. Funkcja obliczająca prawą stronę (szybkość zmian) ODE powinna zwrócić wektor o długości 2 , aby powinny być wektory o długości 2, a zmienna stanu powinien być wektor o długości 2. W MATLAB kod niezbędny do intensyfikacji czasu można zapisać jako:x ( x , v )vxk1
k4
( x , v )
while (t<TMAX)
k1 = RHS( t, X );
k2 = RHS( t + dt / 2, X + dt / 2 * k1 );
k3 = RHS( t + dt / 2, X + dt / 2 * k2 );
k4 = RHS( t + dt, X + dt * k3 );
X = X + dt / 6 * ( k1 + 2 * k2 + 2 * k3 + k4 );
t = t + dt;
end
gdzie i zwraca wektor zawierający . Jak widać, poprzez wektoryzację rzeczy nie musisz nawet zmieniać składni kodu RK4 bez względu na to, ile równań znajduje się w twoim systemie ODE.X
( ˙ x ( t ) , ˙ v ( t ) )= ( x , v )RHS( t, X )
( x˙( t ) , v˙( t ) )
Niestety C ++ nie obsługuje natywnie takich operacji wektorowych, więc musisz albo użyć biblioteki wektorów, użyć pętli, albo ręcznie napisać osobne części. W C ++ możesz użyć std::valarray
tego samego efektu. Oto prosty działający przykład ze stałym przyspieszeniem.
#include <valarray>
#include <iostream>
const size_t NDIM = 2;
typedef std::valarray<double> Vector;
Vector RHS( const double t, const Vector X )
{
// Right hand side of the ODE to solve, in this case:
// d/dt(x) = v;
// d/dt(v) = 1;
Vector output(NDIM);
output[0] = X[1];
output[1] = 1;
return output;
}
int main()
{
//initialize values
// State variable X is [position, velocity]
double init[] = { 0., 0. };
Vector X( init, NDIM );
double t = 0.;
double tMax=5.;
double dt = 0.1;
//time loop
int nSteps = round( ( tMax - t ) / dt );
for (int stepNumber = 1; stepNumber<=nSteps; ++stepNumber)
{
Vector k1 = RHS( t, X );
Vector k2 = RHS( t + dt / 2.0, X + dt / 2.0 * k1 );
Vector k3 = RHS( t + dt / 2.0, X + dt / 2.0 * k2 );
Vector k4 = RHS( t + dt, X + dt * k3 );
X += dt / 6.0 * ( k1 + 2.0 * k2 + 2.0 * k3 + k4 );
t += dt;
}
std::cout<<"Final time: "<<t<<std::endl;
std::cout<<"Final position: "<<X[0]<<std::endl;
std::cout<<"Final velocity: "<<X[1]<<std::endl;
}