#pragma once template 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 inline Poly::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 inline float Poly::run(float x, float inputGain) { fillPowers(x); calcDC(inputGain); return (float) doSum(); } template inline void Poly::fillPowers(T x) { T value = x; for (int i = 0; i < order; ++i) { powers[i] = value; value *= x; } } template inline T Poly::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 inline T Poly::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 void Poly::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); }