You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
2.1KB

  1. #pragma once
  2. namespace rack {
  3. namespace ode {
  4. /** The callback function `f` in each of these stepping functions must have the signature
  5. void f(float t, const float x[], float dxdt[])
  6. A capturing lambda is ideal for this.
  7. For example, the following solves the system x''(t) = -x(t) using a fixed timestep of 0.01 and initial conditions x(0) = 1, x'(0) = 0.
  8. float x[2] = {1.f, 0.f};
  9. float dt = 0.01f;
  10. for (float t = 0.f; t < 1.f; t += dt) {
  11. rack::ode::stepRK4(t, dt, x, 2, [&](float t, const float x[], float dxdt[]) {
  12. dxdt[0] = x[1];
  13. dxdt[1] = -x[0];
  14. });
  15. printf("%f\n", x[0]);
  16. }
  17. */
  18. // free'd when fxn returns
  19. #ifdef _MSC_VER
  20. #define Dstack_farr(t, n, l) t *n = (t*)alloca(sizeof(t) * l)
  21. #else
  22. #define Dstack_farr(t, n, l) t n[l]
  23. #endif
  24. /** Solves an ODE system using the 1st order Euler method */
  25. template<typename F>
  26. void stepEuler(float t, float dt, float x[], int len, F f) {
  27. Dstack_farr(float, k, len);
  28. f(t, x, k);
  29. for (int i = 0; i < len; i++) {
  30. x[i] += dt * k[i];
  31. }
  32. }
  33. /** Solves an ODE system using the 2nd order Runge-Kutta method */
  34. template<typename F>
  35. void stepRK2(float t, float dt, float x[], int len, F f) {
  36. Dstack_farr(float, k1, len);
  37. Dstack_farr(float, k2, len);
  38. Dstack_farr(float, yi, len);
  39. f(t, x, k1);
  40. for (int i = 0; i < len; i++) {
  41. yi[i] = x[i] + k1[i] * dt / 2.f;
  42. }
  43. f(t + dt / 2.f, yi, k2);
  44. for (int i = 0; i < len; i++) {
  45. x[i] += dt * k2[i];
  46. }
  47. }
  48. /** Solves an ODE system using the 4th order Runge-Kutta method */
  49. template<typename F>
  50. void stepRK4(float t, float dt, float x[], int len, F f) {
  51. Dstack_farr(float, k1, len);
  52. Dstack_farr(float, k2, len);
  53. Dstack_farr(float, k3, len);
  54. Dstack_farr(float, k4, len);
  55. Dstack_farr(float, yi, len);
  56. f(t, x, k1);
  57. for (int i = 0; i < len; i++) {
  58. yi[i] = x[i] + k1[i] * dt / 2.f;
  59. }
  60. f(t + dt / 2.f, yi, k2);
  61. for (int i = 0; i < len; i++) {
  62. yi[i] = x[i] + k2[i] * dt / 2.f;
  63. }
  64. f(t + dt / 2.f, yi, k3);
  65. for (int i = 0; i < len; i++) {
  66. yi[i] = x[i] + k3[i] * dt;
  67. }
  68. f(t + dt, yi, k4);
  69. for (int i = 0; i < len; i++) {
  70. x[i] += dt * (k1[i] + 2.f * k2[i] + 2.f * k3[i] + k4[i]) / 6.f;
  71. }
  72. }
  73. } // namespace ode
  74. } // namespace rack