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.

93 lines
2.0KB

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