Module: numx/ode.h | Category: Foundation | Phase: P1.27–P1.28
Numerically integrates an initial-value problem (IVP) of the form:
Two Runge–Kutta methods are provided: a classic fixed-step RK4 and an adaptive-step RKF45 (Fehlberg's embedded pair) that automatically adjusts step size to meet a user-specified tolerance.
The four-stage fixed-step method advances from
Local truncation error:
Uses six stages to produce two solutions of different orders simultaneously. The 4th-order solution is used to advance the state; the difference between the 4th and 5th-order solutions gives a local error estimate with no extra function evaluations beyond the six stages.
The six stage slopes use Fehlberg's coefficients:
| Stage | Time | Weight vector |
|---|---|---|
| — | ||
Error estimate (
Step-size control — if the step is accepted (
The factor
| Function | Evaluations per step | Stack (float32, NUMX_MAX_ODE_DIM = 16) |
|---|---|---|
numx_ode_rk4 |
4 | ~256 B ( |
numx_ode_rk45 |
6 | ~384 B ( |
Both solvers return only the final state
-
RK4: globally
$O(h^4)$ . Stable for non-stiff systems when$h \leq h_{\max}$ , which depends on the eigenvalues of the Jacobian$\partial\mathbf{f}/\partial\mathbf{y}$ . -
RKF45: adaptive step ensures the local error stays near
tol. Not suitable for stiff systems (step size collapses to maintain stability). ReturnsNUMX_ERR_NO_CONVERGEifNUMX_MAX_ITERsteps are exhausted without reaching$t_1$ . - For a harmonic oscillator
$\mathbf{y}' = [y_1, -y_0]$ , RK4 dissipates energy slightly over long integration. RKF45 matches the tolerance.
-
RK4: real-time control loops where a fixed time step is required (e.g. motor FOC, PID outer loop); step
$h$ is chosen offline based on system bandwidth. - RKF45: simulation, batch processing, or offline parameter estimation where accuracy matters more than fixed timing.
- Stiff systems (e.g. fast electrical dynamics coupled to slow mechanical dynamics) — use an implicit solver instead.
- Systems with $n > $
NUMX_MAX_ODE_DIM— increase the config limit (affects stack). - RK4 for very long integration times without error monitoring — error accumulates as
$O((t_1 - t_0) h^4)$ .
- Fehlberg, E. — "Low-order classical Runge–Kutta formulas with step size control", NASA Technical Report TR R-315, 1969.
- Hairer, E., Nørsett, S. P. & Wanner, G. — Solving Ordinary Differential Equations I: Nonstiff Problems, 2nd ed., Springer, 1993.
- Press, W. H. et al. — Numerical Recipes in C, 3rd ed., §17.2 (RKF45), Cambridge, 2007.
#include "numx/ode.h"
/* Harmonic oscillator: [y0, y1]' = [y1, -y0]
* Exact: y0(t) = cos(t), y1(t) = -sin(t) */
static numx_status_t harmonic(numx_real_t t, const numx_real_t *y,
numx_size_t n, numx_real_t *dydt)
{
(void)t; (void)n;
dydt[0] = y[1];
dydt[1] = -y[0];
return NUMX_OK;
}
numx_real_t y[] = { 1.0f, 0.0f }; /* y(0) = [1, 0] */
/* Fixed-step RK4: 1000 steps to t=1 */
numx_ode_rk4(harmonic, 0.0f, y, 2, 1e-3f, 1000, y);
/* y ≈ [cos(1), -sin(1)] ≈ [0.5403, -0.8415] */
/* Adaptive RKF45 to t=10, tolerance 1e-5 */
numx_real_t y2[] = { 1.0f, 0.0f };
numx_ode_rk45(harmonic, 0.0f, 10.0f, y2, 2, 1e-5f, y2);