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.

125 lines
3.5KB

  1. #include <assert.h>
  2. #include "asserts.h"
  3. #include "StateVariableFilter.h"
  4. #include "TestSignal.h"
  5. /**
  6. * Simple test - can we get output that looks kind of low pass
  7. */
  8. template <typename T>
  9. static void test1()
  10. {
  11. StateVariableFilterParams<T> params;
  12. StateVariableFilterState<T> state;
  13. params.setMode(StateVariableFilterParams<T>::Mode::LowPass);
  14. params.setFreq(T(.05)); // TODO: make an even fraction
  15. params.setQ(T(.7));
  16. T lastValue = -1;
  17. for (int i = 0; i < 5; ++i) {
  18. T output = StateVariableFilter<T>::run(1, state, params);
  19. assert(output > lastValue);
  20. lastValue = output;
  21. }
  22. }
  23. /**
  24. * Measure freq response at some points
  25. */
  26. template <typename T>
  27. static void testLowpass()
  28. {
  29. const T fc = T(.001);
  30. const T q = T(1.0 / std::sqrt(2)); // butterworth
  31. StateVariableFilterParams<T> params;
  32. StateVariableFilterState<T> state;
  33. params.setMode(StateVariableFilterParams<T>::Mode::LowPass);
  34. params.setFreq(fc); // TODO: make an even fraction
  35. params.setQ(q);
  36. double g = TestSignal<T>::measureGain(fc / 4, [&state, &params](T input) {
  37. return StateVariableFilter<T>::run(input, state, params);
  38. });
  39. g = AudioMath::db(g);
  40. assert(AudioMath::closeTo(g, 0, .05));
  41. g = TestSignal<T>::measureGain(fc, [&state, &params](T input) {
  42. return StateVariableFilter<T>::run(input, state, params);
  43. });
  44. g = AudioMath::db(g);
  45. assert(AudioMath::closeTo(g, -3, .05));
  46. double g2 = TestSignal<T>::measureGain(fc * 4, [&state, &params](T input) {
  47. return StateVariableFilter<T>::run(input, state, params);
  48. });
  49. g2 = AudioMath::db(g2);
  50. double g3 = TestSignal<T>::measureGain(fc * 8, [&state, &params](T input) {
  51. return StateVariableFilter<T>::run(input, state, params);
  52. });
  53. g3 = AudioMath::db(g3);
  54. assert(AudioMath::closeTo(g2 - g3, 12, 2));
  55. }
  56. /**
  57. * Verify that passband gain tracks Q
  58. */
  59. static void testBandpass()
  60. {
  61. const float fc = .01f;
  62. const float q = (1.0f / float(std::sqrt(2))); // butterworth
  63. StateVariableFilterParams<float> params;
  64. StateVariableFilterState<float> state;
  65. params.setMode(StateVariableFilterParams<float>::Mode::BandPass);
  66. params.setFreq(fc); // TODO: make an even fraction
  67. params.setQ(q);
  68. double g0 = TestSignal<float>::measureGain(fc, [&state, &params](float input) {
  69. return StateVariableFilter<float>::run(input, state, params);
  70. });
  71. g0 = AudioMath::db(g0);
  72. for (int i = 2; i < 100; i *= 2) {
  73. const float q = float(i);
  74. params.setQ(q);
  75. double g = TestSignal<float>::measureGain(fc, [&state, &params](float input) {
  76. return StateVariableFilter<float>::run(input, state, params);
  77. });
  78. g = AudioMath::db(g);
  79. // printf("q = %f, gain db = %f qdb=%f\n", q, g, AudioMath::db(q));
  80. assertClose(g, AudioMath::db(q), .5);
  81. }
  82. }
  83. template <typename T>
  84. static void testSetBandwidth()
  85. {
  86. StateVariableFilterParams<T> params;
  87. params.setNormalizedBandwidth(T(.1));
  88. assertEQ(params.getNormalizedBandwidth(), T(.1));
  89. params.setNormalizedBandwidth(T(.5));
  90. assertEQ(params.getNormalizedBandwidth(), T(.5));
  91. params.setQ(10);
  92. assertEQ(params.getNormalizedBandwidth(), T(.1))
  93. }
  94. template <typename T>
  95. static void test()
  96. {
  97. test1<T>();
  98. testLowpass<T>();
  99. testSetBandwidth<T>();
  100. }
  101. void testStateVariable()
  102. {
  103. test<float>();
  104. test<double>();
  105. testBandpass();
  106. }