Sembra esserci un po 'di confusione su come applicare metodi multi-step (ad es. Runge-Kutta) a ODE o sistemi di ODE di secondo ordine o superiori. Il processo è molto semplice una volta capito, ma forse non ovvio senza una buona spiegazione. Il seguente metodo è quello che trovo più semplice.
Nel tuo caso, l'equazione differenziale che vorresti risolvere è . Il primo passo è scrivere questo ODE del secondo ordine come un sistema di ODE del primo ordine. Questo è fatto comeF=mx¨
[x˙v˙]=[vF/m]
Tutte le equazioni di questo sistema devono essere risolti contemporaneamente, vale a dire che si dovrebbe non anticipo e poi anticipo , dovrebbero essere entrambi avanzato allo stesso tempo. Nelle lingue che supportano le operazioni vettoriali senza loop, questo è fatto facilmente facendo tutti i termini necessari nei vettori di codice di lunghezza 2. La funzione che calcola il lato destro (il tasso di cambiamento) del tuo ODE dovrebbe restituire un vettore di lunghezza 2 , a dovrebbe essere vettori di lunghezza 2, e la vostra variabile di stato dovrebbe essere un vettore di lunghezza 2. In MATLAB il codice necessario per il tempo di fare un passo può essere scritta come: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
dove e restituisce un vettore contenente . Come puoi vedere, vettorializzando cose che non hai nemmeno bisogno di cambiare la sintassi del codice RK4, indipendentemente da quante equazioni ci siano nel tuo sistema ODE.X
=(x,v)RHS( t, X )
(x˙(t),v˙(t))
Sfortunatamente C ++ non supporta nativamente operazioni vettoriali come questa, quindi è necessario utilizzare una libreria vettoriale, utilizzare loop o scrivere manualmente le parti separate. In C ++ puoi usare std::valarray
per ottenere lo stesso effetto. Ecco un semplice esempio funzionante con accelerazione costante.
#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;
}