Esempio n. 1
0
        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);
        }
Esempio n. 4
0
 public static void TestSqrt()
 {
     for (int i = 0; i <= 10; ++i)
     {
         Console.WriteLine("sqrt({0})={1}", i, WWDecimalMath.Sqrt(i));
     }
 }
Esempio n. 5
0
 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));
     }
 }
Esempio n. 6
0
 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));
 }
Esempio n. 7
0
        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.");
        }
Esempio n. 8
0
        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);
        }
Esempio n. 10
0
        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));
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
 public decimal Magnitude()
 {
     return(WWDecimalMath.Sqrt(real * real + imaginary * imaginary));
 }
Esempio n. 13
0
        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);
                    }
                }
            }
        }