////////////////////////////////////////////////////////////////// // Simple (not optimized) implementation of Runge-Kutta 4 // used for solving of initial value problem (Circle test) // Needs linking with math library (GCC option: -lm) // Copyright: (c) Petr Peringer, FIT TU Brno, 2012, 2022 #include <stdio.h> #include <math.h> // sin() - for error computation ////////////////////////////////////////////////////////////////// // System: circle test (ODE: y'' + y = 0) #define SIZE 2 // state vector size // "Dynamic section" = continuous system description // Input: t = time of step start, // y = state vector = integrator outputs // Output: der = vector of derivatives = integrators input values void f(double t, double *y, double *der) { der[0] = y[1]; // y' == w der[1] = -y[0]; // y'' == w' == -y } ////////////////////////////////////////////////////////////////// // Runge-Kutta 4-th order method // Parameters: t = step start time, // h = step size, // y = state vector // Output: new state in y // Warning: it does NOT update time void RK4step(double t, double h, double *y) { double der[SIZE]; // integrator inputs = derivatives double ystart[SIZE]; // initial state // 4 stages results: double k1[SIZE]; double k2[SIZE]; double k3[SIZE]; double k4[SIZE]; int i; for (i = 0; i < SIZE; i++) // save initial value ystart[i] = y[i]; f(t, y, der); // der = f(t, y(t)) for (i = 0; i < SIZE; i++) { k1[i] = h * der[i]; // k1 = h * f(t, y(t)) y[i] = ystart[i] + k1[i] / 2; } f(t + h / 2, y, der); // der = f(t+h/2, y(t)+k1/2) for (i = 0; i < SIZE; i++) { k2[i] = h * der[i]; // k2 = h * f(t+h/2, y(t)+k1/2) y[i] = ystart[i] + k2[i] / 2; } f(t + h / 2, y, der); // der = f(t+h/2, y(t)+k2/2) for (i = 0; i < SIZE; i++) { k3[i] = h * der[i]; // k3 = h * f(t+h/2, y(t)+k2/2) y[i] = ystart[i] + k3[i]; } f(t + h, y, der); // der = f(t+h, y(t)+k3) for (i = 0; i < SIZE; i++) { k4[i] = h * der[i]; // k4 = h * f(t+h, y(t)+k3) // Result: y(t+h) = y(t) + k1/6 + k2/3 + k3/3 + k4/6; y[i] = ystart[i] + k1[i] / 6 + k2[i] / 3 + k3[i] / 3 + k4[i] / 6; } // Return: y = new state at time t+h } ////////////////////////////////////////////////////////////////// // Simulation experiment control int main() { double y[SIZE] = { 0, 1 }; // initial values: y'(0)=1, y(0)=0 double stepsize = 0.1; printf("# Circle test solution (RK4, step=%g)\n", stepsize); printf("# time y y' yerror\n"); double t = 0; // initial time while (t < 20) { printf("%8.3f % -11g % -11g % e\n", t, y[0], y[1], y[0] - sin(t)); RK4step(t, stepsize, y); // compute new state of system t += stepsize; // advance the simulation time } printf("%8.3f % -11g % -11g % e\n", t, y[0], y[1], y[0] - sin(t)); }