Use Case
ODE Solvers for Control Systems
Control systems live and die by their integration step. The ode module gives you RK4 for loops where timing matters and RK45 where accuracy matters, both reentrant, both allocation-free, both running at exactly the speed the hardware allows.
RK4: for deterministic real-time loops
When your control loop runs at a fixed sample rate, RK4 is the right integrator. The step size equals your sample period. The cost is exactly 4 function evaluations per step. Timing is deterministic. No adaptive logic, no variable cost, no surprises in your RTOS task.
Spring-mass-damper simulation
#include "numx/numx.h"
/* Spring-mass-damper: m*x'' + c*x' + k*x = 0
Reduced to first-order: y = [x, x'], dy/dt = [x', -(c*x' + k*x)/m] */
typedef struct { numx_real_t m, c, k; } smd_t;
static void smd_rhs(
numx_real_t t, const numx_real_t *y,
size_t n, numx_real_t *dy, void *ctx
) {
(void)t; (void)n;
const smd_t *p = (const smd_t *)ctx;
dy[0] = y[1];
dy[1] = -(p->c * y[1] + p->k * y[0]) / p->m;
}
int main(void) {
smd_t sys = { .m = 1.0f, .c = 0.2f, .k = 4.0f }; /* underdamped */
numx_real_t y0[2] = { 1.0f, 0.0f }; /* x=1, v=0 */
numx_real_t y_final[2];
/* RK4: fixed 1 ms step, simulate 5 seconds */
numx_status_t s = numx_ode_rk4(
smd_rhs, y0, 2,
0.0f, 5.0f, 0.001f,
y_final, &sys
);
if (s != NUMX_OK) return 1;
/* y_final[0] = displacement at t=5s */
return 0;
}RK45 for accuracy-critical work
/* RK45: accuracy-critical simulation with adaptive step
Use when you need to meet an error tolerance
and do not need deterministic timing */
numx_status_t s = numx_ode_rk45(
smd_rhs, y0, 2,
0.0f, 5.0f,
1e-6f, /* relative tolerance */
1e-9f, /* absolute tolerance */
y_final, &sys
);When to use RK45
- Physics simulation where accuracy matters more than timing
- Variable dynamics where a fixed step would be either wasteful or inaccurate
- Offline computation (not real-time control loops)
Exact derivatives with autodiff
When your ODE right-hand side requires exact derivatives (stiff ODE solvers, sensitivity analysis, optimal control), the autodiff module computes them exactly using automatic differentiation, without finite-difference approximation errors.