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.

73 lines
1.4KB

  1. #pragma once
  2. namespace rack {
  3. /** The callback function `f` in each of these stepping functions must have the signature
  4. void f(float x, const float y[], float dydt[])
  5. A capturing lambda is ideal for this.
  6. */
  7. /** Solves an ODE system using the 1st order Euler method */
  8. template<typename F>
  9. void stepEuler(float x, float dx, float y[], int len, F f) {
  10. float k[len];
  11. f(x, y, k);
  12. for (int i = 0; i < len; i++) {
  13. y[i] += dx * k[i];
  14. }
  15. }
  16. /** Solves an ODE system using the 2nd order Runge-Kutta method */
  17. template<typename F>
  18. void stepRK2(float x, float dx, float y[], int len, F f) {
  19. float k1[len];
  20. float k2[len];
  21. float yi[len];
  22. f(x, y, k1);
  23. for (int i = 0; i < len; i++) {
  24. yi[i] = y[i] + k1[i] * dx / 2.f;
  25. }
  26. f(x + dx / 2.f, yi, k2);
  27. for (int i = 0; i < len; i++) {
  28. y[i] += dx * k2[i];
  29. }
  30. }
  31. /** Solves an ODE system using the 4th order Runge-Kutta method */
  32. template<typename F>
  33. void stepRK4(float x, float dx, float y[], int len, F f) {
  34. float k1[len];
  35. float k2[len];
  36. float k3[len];
  37. float k4[len];
  38. float yi[len];
  39. f(x, y, k1);
  40. for (int i = 0; i < len; i++) {
  41. yi[i] = y[i] + k1[i] * dx / 2.f;
  42. }
  43. f(x + dx / 2.f, yi, k2);
  44. for (int i = 0; i < len; i++) {
  45. yi[i] = y[i] + k2[i] * dx / 2.f;
  46. }
  47. f(x + dx / 2.f, yi, k3);
  48. for (int i = 0; i < len; i++) {
  49. yi[i] = y[i] + k3[i] * dx;
  50. }
  51. f(x + dx, yi, k4);
  52. for (int i = 0; i < len; i++) {
  53. y[i] += dx * (k1[i] + 2.f * k2[i] + 2.f * k3[i] + k4[i]) / 6.f;
  54. }
  55. }
  56. } // namespace rack