|
- #pragma once
- template <typename T, int order>
- class Poly
- {
- public:
- Poly();
- float run(float x, float inputGain);
- void setGain(int index, float value)
- {
- assert(index >= 0 && index < order);
- gains[index] = value;
- }
-
- T getOutput(int index) const
- {
- return outputs[index];
- }
-
- private:
- T gains[order];
-
- // powers[0] = x, powers[1] = x**2
- T powers[order];
-
- T outputs[order];
-
- // since DC offset changes with gain, we need to compute it.
- static const int numEvenHarmonics = order / 2;
- T dcComponent[numEvenHarmonics];
-
- void fillPowers(T);
- T doSum();
- void calcDC(T gain);
- };
-
- template <typename T, int order>
- inline Poly<T, order>::Poly()
- {
- assert(order == 10); // Although this class it templated, internally it's hard coded.
- for (int i = 0; i < order; ++i) {
- gains[i] = 0;
- powers[i] = 0;
- outputs[i] = 0;
- }
-
- for (int i = 0; i < numEvenHarmonics; ++i) {
- dcComponent[i] = 0;
- }
- }
-
- template <typename T, int order>
- inline float Poly<T, order>::run(float x, float inputGain)
- {
- fillPowers(x);
- calcDC(inputGain);
- return (float) doSum();
- }
-
- template <typename T, int order>
- inline void Poly<T, order>::fillPowers(T x)
- {
- T value = x;
- for (int i = 0; i < order; ++i) {
- powers[i] = value;
- value *= x;
- }
- }
-
- template <typename T, int order>
- inline T Poly<T, order>::doSum()
- {
- outputs[0] = powers[0];
- T sum = outputs[0] * gains[0];
-
- outputs[1] = (2 * powers[1] - dcComponent[0]);
- sum += outputs[1] * gains[1];
-
- outputs[2] = (4 * powers[2] - 3 * powers[0]);
- sum += outputs[2] * gains[2];
-
- outputs[3] = (8 * powers[3] - 8 * powers[1] - dcComponent[1]);
- sum += outputs[3] * gains[3];
-
- outputs[4] = (16 * powers[4] - 20 * powers[2] + 5 * powers[0]);
- sum += outputs[4] * gains[4];
-
- outputs[5] = (32 * powers[5] - 48 * powers[3] + 18 * powers[1] - dcComponent[2]);
- sum += outputs[5] * gains[5];
-
- outputs[6] = (64 * powers[6] - 112 * powers[4] + 56 * powers[2] - 7 * powers[0]);
- sum += outputs[6] * gains[6];
-
- outputs[7] = (128 * powers[7] - 256 * powers[5] + 160 * powers[3] - 32 * powers[1] - dcComponent[3]);
- sum += outputs[7] * gains[7];
-
- outputs[8] = (256 * powers[8] - 576 * powers[6] + 432 * powers[4] - 120 * powers[2] + 9 * powers[0]);
- sum += outputs[8] * gains[8];
-
- outputs[9] = (512 * powers[9] - 1280 * powers[7] + 1120 * powers[5] - 400 * powers[3] + 50 * powers[1] - dcComponent[4]);
- sum += outputs[9] * gains[9];
-
- return sum;
- }
- #if 0 // old way
- template <typename T, int order>
- inline T Poly<T, order>::doSum()
- {
- T ret = gains[0] * powers[0];
- ret += gains[1] * (2 * powers[1] - dcComponent[0]);
- ret += gains[2] * (4 * powers[2] - 3 * powers[0]);
- ret += gains[3] * (8 * powers[3] - 8 * powers[1] - dcComponent[1]);
- ret += gains[4] * (16 * powers[4] - 20 * powers[2] + 5 * powers[0]);
- ret += gains[5] * (32 * powers[5] - 48 * powers[3] + 18 * powers[1] - dcComponent[2]);
- ret += gains[6] * (64 * powers[6] - 112 * powers[4] + 56 * powers[2] - 7 * powers[0]);
- ret += gains[7] * (128 * powers[7] - 256 * powers[5] + 160 * powers[3] - 32 * powers[1] - dcComponent[3]);
- ret += gains[8] * (256 * powers[8] - 576 * powers[6] + 432 * powers[4] - 120 * powers[2] + 9 * powers[0]);
- ret += gains[9] * (512 * powers[9] - 1280 * powers[7] + 1120 * powers[5] - 400 * powers[3] + 50 * powers[1] - dcComponent[4]);
- return ret;
- }
- #endif
-
- template <typename T, int order>
- void Poly<T, order>::calcDC(T gain)
- {
- // first calculate "sinEnergy", which is the integral of sin^n(gain * x) over a period
- const double W2 = 2.0 / 4.0;
- const double W4 = W2 * 3.0 / 4.0;
- const double W6 = W4 * 5.0 / 6.0;
- const double W8 = W6 * 7.0 / 8.0;
- const double W10 = W8 * 9.0 / 10.0;
-
- T sinEnergy = gain;
- T sinEnergy2 = sinEnergy * sinEnergy;
- T sinEnergy4 = sinEnergy2 * sinEnergy2;
- T sinEnergy6 = sinEnergy4 * sinEnergy2;
- T sinEnergy8 = sinEnergy6 * sinEnergy2;
- T sinEnergy10 = sinEnergy8 * sinEnergy2;
-
- sinEnergy2 *= W2;
- sinEnergy4 *= W4;
- sinEnergy6 *= W6;
- sinEnergy8 *= W8;
- sinEnergy10 *= W10;
-
- // for harmonic 1 (first even)
- dcComponent[0] = T(2 * sinEnergy2);
- dcComponent[1] = T(8 * sinEnergy4 - 8 * sinEnergy2);
- dcComponent[2] = T(32 * sinEnergy6 - 48 * sinEnergy4 + 18 * sinEnergy2);
- dcComponent[3] = T(128 * sinEnergy8 - 256 * sinEnergy6 + 160 * sinEnergy4 - 32 * sinEnergy2);
- dcComponent[4] = T(512 * sinEnergy10 - 1280 * sinEnergy8 + 1120 * sinEnergy6 - 400 * sinEnergy4 + 50 * sinEnergy2);
- }
|