/* * ODE solver * * This code implements the runge-kutta (4th order) algorithm to solve a system of * ordinary differential equations (ODEs). The code requires a given time step dt * and will continue indefinitely as long as the arduino runs (unless an exit condition * is added). * * The ODE needs to be implemented in state-representation. Instead of Matlab convention * y'=f(y,t), the function ODE(t,y,y_p) is used, where t is a given time, y the state * vector and y_p the array which will be updated. * * Created: April 2015, Daniel Heinrich * Updated: August 2016, Daniel Heinrich: changed data type to double, * fixed errors on numerical constants (2.0 instead of 2) * released as CC BY-SA 4.0 licence, see https://creativecommons.org/licenses/by-sa/4.0/ * * Data type considerations: on most arduinos except due, double is treated as float * (4-bit precision). On a due, double is 8-bit precision. If you want to use float on * a due, open the sketch in a text editor, hit STRG+H and replace double with float. * (you can also use #define to swich data types easily, but it makes the code less * readable so I decided against it) * Also, on a due, values entered numerically (e.g. "0.5") are automatically treated as * double. To get float, (float)0.5 needs to be used (improves speed by ~5% for float). * * calculation time for the 1000 steps with the ODE included below: * arduino UNO / Nano: ~760 ms (~ 1300 steps / second) * arduino due: ~140 ms (~ 7000 steps / second) * arduion due with float (see comments above): ~115 ms (~8700 steps / second) */ const double dt=0.001; // Timestep used by the algorithm const int n=4; // number of state variables in the ODE int steps=0; // number of calculated steps double t=0; // current time double Y_current[n]={1, 0, 0, 0}; // Initial state of the ODE double Y_temp[n]; // temp array for the ODE function output. double K1[n], K2[n], K3[n], K4[n]; // arrays for the Runge-Kutta intermediate points // ODE parameters: const double c1=1; const double c2=1; const double d1=0.01; const double d2=0.01; // Debugging parameters: long time_lastprintout = millis(); void setup() { // initialize Serial to output the integrator results. Serial.begin(9600); } void loop() { // calculate another timestep: t0 --> t1 // K1 = Y_p(t0, Y_current) ODE(t, Y_current, K1); // K2 = Y_p(t0 + dt/2, Y_current + dt/2 * K1) for (int i=0; i=1000) { Serial.print("state at "); Serial.print(t); Serial.print("s: "); for (int i=0; i