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.

ode.hpp 1.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #pragma once
  2. #include <dsp/common.hpp>
  3. namespace rack {
  4. namespace dsp {
  5. /** The callback function `f` in each of these stepping functions must have the signature
  6. void f(T t, const T x[], T dxdt[])
  7. A capturing lambda is ideal for this.
  8. 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.
  9. float x[2] = {1.f, 0.f};
  10. float dt = 0.01f;
  11. for (float t = 0.f; t < 1.f; t += dt) {
  12. rack::ode::stepRK4(t, dt, x, 2, [&](float t, const float x[], float dxdt[]) {
  13. dxdt[0] = x[1];
  14. dxdt[1] = -x[0];
  15. });
  16. printf("%f\n", x[0]);
  17. }
  18. */
  19. /** Solves an ODE system using the 1st order Euler method */
  20. template <typename T, typename F>
  21. void stepEuler(T t, T dt, T x[], int len, F f) {
  22. T k[len];
  23. f(t, x, k);
  24. for (int i = 0; i < len; i++) {
  25. x[i] += dt * k[i];
  26. }
  27. }
  28. /** Solves an ODE system using the 2nd order Runge-Kutta method */
  29. template <typename T, typename F>
  30. void stepRK2(T t, T dt, T x[], int len, F f) {
  31. T k1[len];
  32. T k2[len];
  33. T yi[len];
  34. f(t, x, k1);
  35. for (int i = 0; i < len; i++) {
  36. yi[i] = x[i] + k1[i] * dt / 2.f;
  37. }
  38. f(t + dt / 2.f, yi, k2);
  39. for (int i = 0; i < len; i++) {
  40. x[i] += dt * k2[i];
  41. }
  42. }
  43. /** Solves an ODE system using the 4th order Runge-Kutta method */
  44. template <typename T, typename F>
  45. void stepRK4(T t, T dt, T x[], int len, F f) {
  46. T k1[len];
  47. T k2[len];
  48. T k3[len];
  49. T k4[len];
  50. T yi[len];
  51. f(t, x, k1);
  52. for (int i = 0; i < len; i++) {
  53. yi[i] = x[i] + k1[i] * dt / 2.f;
  54. }
  55. f(t + dt / 2.f, yi, k2);
  56. for (int i = 0; i < len; i++) {
  57. yi[i] = x[i] + k2[i] * dt / 2.f;
  58. }
  59. f(t + dt / 2.f, yi, k3);
  60. for (int i = 0; i < len; i++) {
  61. yi[i] = x[i] + k3[i] * dt;
  62. }
  63. f(t + dt, yi, k4);
  64. for (int i = 0; i < len; i++) {
  65. x[i] += dt * (k1[i] + 2.f * k2[i] + 2.f * k3[i] + k4[i]) / 6.f;
  66. }
  67. }
  68. } // namespace dsp
  69. } // namespace rack