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.

151 lines
4.6KB

  1. #pragma once
  2. template <typename T, int order>
  3. class Poly
  4. {
  5. public:
  6. Poly();
  7. float run(float x, float inputGain);
  8. void setGain(int index, float value)
  9. {
  10. assert(index >= 0 && index < order);
  11. gains[index] = value;
  12. }
  13. T getOutput(int index) const
  14. {
  15. return outputs[index];
  16. }
  17. private:
  18. T gains[order];
  19. // powers[0] = x, powers[1] = x**2
  20. T powers[order];
  21. T outputs[order];
  22. // since DC offset changes with gain, we need to compute it.
  23. static const int numEvenHarmonics = order / 2;
  24. T dcComponent[numEvenHarmonics];
  25. void fillPowers(T);
  26. T doSum();
  27. void calcDC(T gain);
  28. };
  29. template <typename T, int order>
  30. inline Poly<T, order>::Poly()
  31. {
  32. assert(order == 10); // Although this class it templated, internally it's hard coded.
  33. for (int i = 0; i < order; ++i) {
  34. gains[i] = 0;
  35. powers[i] = 0;
  36. outputs[i] = 0;
  37. }
  38. for (int i = 0; i < numEvenHarmonics; ++i) {
  39. dcComponent[i] = 0;
  40. }
  41. }
  42. template <typename T, int order>
  43. inline float Poly<T, order>::run(float x, float inputGain)
  44. {
  45. fillPowers(x);
  46. calcDC(inputGain);
  47. return (float) doSum();
  48. }
  49. template <typename T, int order>
  50. inline void Poly<T, order>::fillPowers(T x)
  51. {
  52. T value = x;
  53. for (int i = 0; i < order; ++i) {
  54. powers[i] = value;
  55. value *= x;
  56. }
  57. }
  58. template <typename T, int order>
  59. inline T Poly<T, order>::doSum()
  60. {
  61. outputs[0] = powers[0];
  62. T sum = outputs[0] * gains[0];
  63. outputs[1] = (2 * powers[1] - dcComponent[0]);
  64. sum += outputs[1] * gains[1];
  65. outputs[2] = (4 * powers[2] - 3 * powers[0]);
  66. sum += outputs[2] * gains[2];
  67. outputs[3] = (8 * powers[3] - 8 * powers[1] - dcComponent[1]);
  68. sum += outputs[3] * gains[3];
  69. outputs[4] = (16 * powers[4] - 20 * powers[2] + 5 * powers[0]);
  70. sum += outputs[4] * gains[4];
  71. outputs[5] = (32 * powers[5] - 48 * powers[3] + 18 * powers[1] - dcComponent[2]);
  72. sum += outputs[5] * gains[5];
  73. outputs[6] = (64 * powers[6] - 112 * powers[4] + 56 * powers[2] - 7 * powers[0]);
  74. sum += outputs[6] * gains[6];
  75. outputs[7] = (128 * powers[7] - 256 * powers[5] + 160 * powers[3] - 32 * powers[1] - dcComponent[3]);
  76. sum += outputs[7] * gains[7];
  77. outputs[8] = (256 * powers[8] - 576 * powers[6] + 432 * powers[4] - 120 * powers[2] + 9 * powers[0]);
  78. sum += outputs[8] * gains[8];
  79. outputs[9] = (512 * powers[9] - 1280 * powers[7] + 1120 * powers[5] - 400 * powers[3] + 50 * powers[1] - dcComponent[4]);
  80. sum += outputs[9] * gains[9];
  81. return sum;
  82. }
  83. #if 0 // old way
  84. template <typename T, int order>
  85. inline T Poly<T, order>::doSum()
  86. {
  87. T ret = gains[0] * powers[0];
  88. ret += gains[1] * (2 * powers[1] - dcComponent[0]);
  89. ret += gains[2] * (4 * powers[2] - 3 * powers[0]);
  90. ret += gains[3] * (8 * powers[3] - 8 * powers[1] - dcComponent[1]);
  91. ret += gains[4] * (16 * powers[4] - 20 * powers[2] + 5 * powers[0]);
  92. ret += gains[5] * (32 * powers[5] - 48 * powers[3] + 18 * powers[1] - dcComponent[2]);
  93. ret += gains[6] * (64 * powers[6] - 112 * powers[4] + 56 * powers[2] - 7 * powers[0]);
  94. ret += gains[7] * (128 * powers[7] - 256 * powers[5] + 160 * powers[3] - 32 * powers[1] - dcComponent[3]);
  95. ret += gains[8] * (256 * powers[8] - 576 * powers[6] + 432 * powers[4] - 120 * powers[2] + 9 * powers[0]);
  96. ret += gains[9] * (512 * powers[9] - 1280 * powers[7] + 1120 * powers[5] - 400 * powers[3] + 50 * powers[1] - dcComponent[4]);
  97. return ret;
  98. }
  99. #endif
  100. template <typename T, int order>
  101. void Poly<T, order>::calcDC(T gain)
  102. {
  103. // first calculate "sinEnergy", which is the integral of sin^n(gain * x) over a period
  104. const double W2 = 2.0 / 4.0;
  105. const double W4 = W2 * 3.0 / 4.0;
  106. const double W6 = W4 * 5.0 / 6.0;
  107. const double W8 = W6 * 7.0 / 8.0;
  108. const double W10 = W8 * 9.0 / 10.0;
  109. T sinEnergy = gain;
  110. T sinEnergy2 = sinEnergy * sinEnergy;
  111. T sinEnergy4 = sinEnergy2 * sinEnergy2;
  112. T sinEnergy6 = sinEnergy4 * sinEnergy2;
  113. T sinEnergy8 = sinEnergy6 * sinEnergy2;
  114. T sinEnergy10 = sinEnergy8 * sinEnergy2;
  115. sinEnergy2 *= W2;
  116. sinEnergy4 *= W4;
  117. sinEnergy6 *= W6;
  118. sinEnergy8 *= W8;
  119. sinEnergy10 *= W10;
  120. // for harmonic 1 (first even)
  121. dcComponent[0] = T(2 * sinEnergy2);
  122. dcComponent[1] = T(8 * sinEnergy4 - 8 * sinEnergy2);
  123. dcComponent[2] = T(32 * sinEnergy6 - 48 * sinEnergy4 + 18 * sinEnergy2);
  124. dcComponent[3] = T(128 * sinEnergy8 - 256 * sinEnergy6 + 160 * sinEnergy4 - 32 * sinEnergy2);
  125. dcComponent[4] = T(512 * sinEnergy10 - 1280 * sinEnergy8 + 1120 * sinEnergy6 - 400 * sinEnergy4 + 50 * sinEnergy2);
  126. }