public WWDecimalFft(int numPoints) { if (!IsPowerOfTwo(numPoints) || numPoints < 2) { throw new ArgumentException("numPoints must be power of two integer and larger than 2"); } mNumPoints = numPoints; mWn = new WWDecimalComplex[mNumPoints]; for (int i = 0; i < mNumPoints; ++i) { decimal angle = -2.0M * WWDecimalMath.M_PI * i / mNumPoints; mWn[i] = new WWDecimalComplex(WWDecimalMath.Cos(angle), WWDecimalMath.Sin(angle)); } // mNumStage == log_2(mNumPoints) int t = mNumPoints; for (int i = 0; 0 < t; ++i) { t >>= 1; mNumStage = i; } mBitReversalTable = new uint[mNumPoints]; for (uint i = 0; i < mNumPoints; ++i) { mBitReversalTable[i] = BitReversal(mNumStage, i); } }
// this algorithm is very inefficient public static decimal Ln(decimal v) { if (v <= 0M) { throw new ArgumentOutOfRangeException("v"); } // algorithm is based on area hyperbolic tangent // https://en.wikipedia.org/wiki/Logarithm decimal x = 0; decimal t = (v - 1M) / (v + 1M); decimal tMul = t * t; for (int i = 0; i < 1000 * 1000 * 1000; ++i) { decimal diff = 2M / (i * 2 + 1M) * t; if (WWDecimalMath.IsExtremelySmall(diff)) { break; } x += diff; t *= tMul; //Console.WriteLine(" {0} {1}", i, x); } return(x); }
// this method is slow public static decimal Ln(decimal x) { if (x <= 0M) { throw new ArgumentOutOfRangeException("x"); } // algorithm is Newton's method decimal expy = 1; decimal y = 2M * (x - expy) / (x + expy); for (int i = 0; i < 1000 * 1000; ++i) { expy = Exp(y); decimal diff = 2M * (x - expy) / (x + expy); if (WWDecimalMath.IsRelativelySmall(diff, y)) { break; } y += diff; } return(y); }
public static void TestSqrt() { for (int i = 0; i <= 10; ++i) { Console.WriteLine("sqrt({0})={1}", i, WWDecimalMath.Sqrt(i)); } }
public static void TestSin() { for (int i = -360; i <= 720; i += 30) { Console.WriteLine("sin({0})={1}", i, WWDecimalMath.Sin(WWDecimalMath.M_2PI * i / 180)); } }
public override string ToString() { if (WWDecimalMath.IsExtremelySmall(imaginary)) { return(string.Format("{0:0.#######}", real)); } if (WWDecimalMath.IsExtremelySmall(real)) { return(string.Format("{0:0.#######}i", imaginary)); } return(string.Format("{0:0.#######} {1:+0.#######;-0.#######}i", real, imaginary)); }
void Run(ValueType t) { // 1024 samples of 44100Hz PCM contains 23 periods of 998.5Hz sine wave decimal frequency = 23 * WWDecimalMath.M_2PI; var signalTime = new WWDecimalComplex[LENGTH]; for (int i = 0; i < LENGTH; ++i) { decimal r = WWDecimalMath.Cos(frequency * i / LENGTH); switch (t) { case ValueType.VT_Int16: r = ((int)(r * 32767)) / 32767M; break; case ValueType.VT_Int24: r = (decimal)((int)(r * 8388607) / 8388607M); break; case ValueType.VT_Int32: r = (decimal)((int)(r * Int32.MaxValue) / ((decimal)(Int32.MaxValue))); break; case ValueType.VT_Float32: r = (decimal)((float)r); break; case ValueType.VT_Float64: r = (decimal)((double)r); break; case ValueType.VT_Int64: r = (decimal)(((long)(r * Int64.MaxValue)) / ((decimal)(Int64.MaxValue))); break; case ValueType.VT_Decimal: break; } signalTime[i] = new WWDecimalComplex(r, 0); } FftSpectrum(signalTime); Console.WriteLine("Done."); }
void FftSpectrum(WWDecimalComplex[] signalTime) { WWDecimalFft fft = new WWDecimalFft(LENGTH); var signalFreq = fft.ForwardFft(signalTime, 1M / LENGTH); var result = new Dictionary <double, double>(); Parallel.For(0, LENGTH / 2, i => { decimal magnitude = signalFreq[i].Magnitude(); double db = (double)(20M * WWDecimalMath.Log10(magnitude)); lock (result) { result.Add((double)(SAMPLERATE * i / LENGTH), db); } }); foreach (var item in result) { Console.WriteLine("{0},{1}", item.Key, item.Value); } }
public static decimal Exp(decimal x) { decimal y = 0M; // algorithm is simple Taylor series decimal diff = 1M; for (int i = 1; i < 1000 * 1000; ++i) { y += diff; diff *= x / i; if (WWDecimalMath.IsRelativelySmall(diff, y)) { break; } } return(y); }
public static void TestLog10() { for (int i = 1; i < 10; ++i) { Console.WriteLine("log10({0})={1}", i, WWDecimalMath.Log10(i)); } Console.WriteLine("log10({0})={1}", 10M, WWDecimalMath.Log10(10M)); Console.WriteLine("log10({0})={1}", 1.0M, WWDecimalMath.Log10(1.0M)); Console.WriteLine("log10({0})={1}", 1.0e-1M, WWDecimalMath.Log10(1.0e-1M)); Console.WriteLine("log10({0})={1}", 1.0e-2M, WWDecimalMath.Log10(1.0e-2M)); Console.WriteLine("log10({0})={1}", 1.0e-3M, WWDecimalMath.Log10(1.0e-3M)); Console.WriteLine("log10({0})={1}", 1.0e-4M, WWDecimalMath.Log10(1.0e-4M)); Console.WriteLine("log10({0})={1}", 1.0e-5M, WWDecimalMath.Log10(1.0e-5M)); Console.WriteLine("log10({0})={1}", 1.0e-6M, WWDecimalMath.Log10(1.0e-6M)); Console.WriteLine("log10({0})={1}", 1.0e-7M, WWDecimalMath.Log10(1.0e-7M)); Console.WriteLine("log10({0})={1}", 1.0e-8M, WWDecimalMath.Log10(1.0e-8M)); Console.WriteLine("log10({0})={1}", 1.0e-9M, WWDecimalMath.Log10(1.0e-9M)); Console.WriteLine("log10({0})={1}", 1.0e-10M, WWDecimalMath.Log10(1.0e-10M)); Console.WriteLine("log10({0})={1}", 1.0e-11M, WWDecimalMath.Log10(1.0e-11M)); Console.WriteLine("log10({0})={1}", 1.0e-12M, WWDecimalMath.Log10(1.0e-12M)); Console.WriteLine("log10({0})={1}", 1.0e-13M, WWDecimalMath.Log10(1.0e-13M)); Console.WriteLine("log10({0})={1}", 1.0e-14M, WWDecimalMath.Log10(1.0e-14M)); Console.WriteLine("log10({0})={1}", 1.0e-15M, WWDecimalMath.Log10(1.0e-15M)); Console.WriteLine("log10({0})={1}", 1.0e-16M, WWDecimalMath.Log10(1.0e-16M)); Console.WriteLine("log10({0})={1}", 1.0e-17M, WWDecimalMath.Log10(1.0e-17M)); Console.WriteLine("log10({0})={1}", 1.0e-18M, WWDecimalMath.Log10(1.0e-18M)); Console.WriteLine("log10({0})={1}", 1.0e-19M, WWDecimalMath.Log10(1.0e-19M)); Console.WriteLine("log10({0})={1}", 1.0e-20M, WWDecimalMath.Log10(1.0e-20M)); Console.WriteLine("log10({0})={1}", 1.0e-21M, WWDecimalMath.Log10(1.0e-21M)); Console.WriteLine("log10({0})={1}", 1.0e-22M, WWDecimalMath.Log10(1.0e-22M)); Console.WriteLine("log10({0})={1}", 1.0e-23M, WWDecimalMath.Log10(1.0e-23M)); Console.WriteLine("log10({0})={1}", 1.0e-24M, WWDecimalMath.Log10(1.0e-24M)); Console.WriteLine("log10({0})={1}", 1.0e-25M, WWDecimalMath.Log10(1.0e-25M)); Console.WriteLine("log10({0})={1}", 1.0e-26M, WWDecimalMath.Log10(1.0e-26M)); Console.WriteLine("log10({0})={1}", 1.0e-27M, WWDecimalMath.Log10(1.0e-27M)); }
public static decimal Sqrt(decimal v) { if (v < 0M) { throw new ArgumentOutOfRangeException("v"); } // Algorithm is Newton's method // https://en.wikipedia.org/wiki/Newton's_method#Square_root_of_a_number // x^2 = v // f(x) = x^2 - v // f'(x) = 2x // x0 = 10 // x1 = x0 - f(x0)/f'(x0) // x2 = x1 - f(x1)/f'(x1) // f(x)/f'(x) = (x^2-v)/(2x) = (1/2)*(x -v/x) decimal x = 10M; for (int i = 0; i < 128; ++i) { decimal diff = (x - v / x) / 2; if (WWDecimalMath.IsRelativelySmall(diff, x)) { break; } x -= diff; // Console.WriteLine(" {0} {1}", i, x); } return(x); }
public decimal Magnitude() { return(WWDecimalMath.Sqrt(real * real + imaginary * imaginary)); }
private void FftStageN(int stageNr, WWDecimalComplex[] x, WWDecimalComplex[] y) { /* * stage0: 2つの入力データにバタフライ演算 (length=8の時) 4回 (nRepeat=4, nSubRepeat=2) * y[0] = x[0] + w_n^(0*4) * x[1] * y[1] = x[0] + w_n^(1*4) * x[1] * * y[2] = x[2] + w_n^(0*4) * x[3] * y[3] = x[2] + w_n^(1*4) * x[3] * * y[4] = x[4] + w_n^(0*4) * x[5] * y[5] = x[4] + w_n^(1*4) * x[5] * * y[6] = x[6] + w_n^(0*4) * x[7] * y[7] = x[6] + w_n^(1*4) * x[7] */ /* * stage1: 4つの入力データにバタフライ演算 (length=8の時) 2回 (nRepeat=2, nSubRepeat=4) * y[0] = x[0] + w_n^(0*2) * x[2] * y[1] = x[1] + w_n^(1*2) * x[3] * y[2] = x[0] + w_n^(2*2) * x[2] * y[3] = x[1] + w_n^(3*2) * x[3] * * y[4] = x[4] + w_n^(0*2) * x[6] * y[5] = x[5] + w_n^(1*2) * x[7] * y[6] = x[4] + w_n^(2*2) * x[6] * y[7] = x[5] + w_n^(3*2) * x[7] */ /* * stage2: 8つの入力データにバタフライ演算 (length=8の時) 1回 (nRepeat=1, nSubRepeat=8) * y[0] = x[0] + w_n^(0*1) * x[4] * y[1] = x[1] + w_n^(1*1) * x[5] * y[2] = x[2] + w_n^(2*1) * x[6] * y[3] = x[3] + w_n^(3*1) * x[7] * y[4] = x[0] + w_n^(4*1) * x[4] * y[5] = x[1] + w_n^(5*1) * x[5] * y[6] = x[2] + w_n^(6*1) * x[6] * y[7] = x[3] + w_n^(7*1) * x[7] */ /* * stageN: */ int nRepeat = Pow2(mNumStage - stageNr - 1); int nSubRepeat = mNumPoints / nRepeat; var t = new WWDecimalComplex(); for (int i = 0; i < nRepeat; ++i) { int offsBase = i * nSubRepeat; bool allZero = true; for (int j = 0; j < nSubRepeat / 2; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); if (!WWDecimalMath.IsExtremelySmall(x[offs].Magnitude())) { allZero = false; break; } if (!WWDecimalMath.IsExtremelySmall(x[offs + nSubRepeat / 2].Magnitude())) { allZero = false; break; } } if (allZero) { for (int j = 0; j < nSubRepeat / 2; ++j) { y[j + offsBase].Set(0, 0); } } else { for (int j = 0; j < nSubRepeat; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); y[j + offsBase].CopyFrom(x[offs]); t.CopyFrom(mWn[j * nRepeat]); t.Mul(x[offs + nSubRepeat / 2]); y[j + offsBase].Add(t); } } } }