Example #1
0
        /*
        private static void Butterfly(WWDecimalComplex vFrom0, WWDecimalComplex vFrom1, WWDecimalComplex wn, WWDecimalComplex[] vTo, int toPos) {
            vTo[toPos].CopyFrom(vFrom0);
            var t = new WWDecimalComplex(vFrom1);
            t.Mul(wn);
            vTo[toPos].Mul(t);

            vTo[toPos + 1].CopyFrom(vFrom0);
            t.Mul(-1);
            vTo[toPos + 1].Mul(t);
        }
        */
        public WWDecimalComplex[] ForwardFft(WWDecimalComplex[] aFrom, decimal scale = 1M)
        {
            if (aFrom == null || aFrom.Length != mNumPoints) {
                throw new ArgumentOutOfRangeException("aFrom");
            }
            var aTo = new WWDecimalComplex[aFrom.Length];

            var aTmp0 = new WWDecimalComplex[mNumPoints];
            for (int i=0; i < aTmp0.Length; ++i) {
                aTmp0[i] = new WWDecimalComplex(aFrom[mBitReversalTable[i]]);
            }
            var aTmp1 = new WWDecimalComplex[mNumPoints];
            for (int i=0; i < aTmp1.Length; ++i) {
                aTmp1[i] = new WWDecimalComplex();
            }

            var aTmps = new WWDecimalComplex[2][];
            aTmps[0] = aTmp0;
            aTmps[1] = aTmp1;

            for (int i=0; i < mNumStage - 1; ++i) {
                FftStageN(i, aTmps[((i & 1) == 1) ? 1 : 0], aTmps[((i & 1) == 0) ? 1 : 0]);
            }
            FftStageN(mNumStage - 1, aTmps[(((mNumStage - 1) & 1) == 1) ? 1 : 0], aTo);

            if (scale != 1M) {
                for (int i=0; i < aTo.Length; ++i) {
                    aTo[i].Mul(scale);
                }
            }
            return aTo;
        }
Example #2
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);
            }
        }
        public static WWDecimalComplex Mul(WWDecimalComplex a, WWDecimalComplex b)
        {
            var r = new WWDecimalComplex(a);

            r.Mul(b);
            return(r);
        }
        public static WWDecimalComplex Add(WWDecimalComplex a, WWDecimalComplex b)
        {
            var r = new WWDecimalComplex(a);

            r.Add(b);
            return(r);
        }
        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);
            }
        }
        public static WWDecimalComplex Sub(WWDecimalComplex a, WWDecimalComplex b)
        {
            var r = new WWDecimalComplex(a);

            r.Sub(b);
            return(r);
        }
Example #7
0
 public static WWDecimalComplex[] From(decimal[] from)
 {
     var to = new WWDecimalComplex[from.Length];
     for (int i = 0; i < from.Length; ++i) {
         to[i].real = from[i];
     }
     return to;
 }
Example #8
0
 public static decimal[] ExtractRealPart(WWDecimalComplex[] from)
 {
     var to = new decimal[from.Length];
     for (int i = 0; i < from.Length; ++i) {
         to[i] = from[i].real;
     }
     return to;
 }
        public static WWDecimalComplex[] From(decimal[] from)
        {
            var to = new WWDecimalComplex[from.Length];

            for (int i = 0; i < from.Length; ++i)
            {
                to[i].real = from[i];
            }
            return(to);
        }
Example #10
0
        public static WWDecimalComplex[] Add(WWDecimalComplex[] a, WWDecimalComplex[] b)
        {
            if (a.Length != b.Length) {
                throw new ArgumentException("input array length mismatch");
            }

            var c = new WWDecimalComplex[a.Length];
            for (int i = 0; i < a.Length; ++i) {
                c[i] = WWDecimalComplex.Add(a[i], b[i]);
            }
            return c;
        }
Example #11
0
        public static decimal AverageDistance(WWDecimalComplex[] a, WWDecimalComplex[] b)
        {
            if (a.Length != b.Length) {
                throw new ArgumentException("input array length mismatch");
            }

            decimal d = 0M;
            for (int i=0; i<a.Length; ++i) {
                var s = WWDecimalComplex.Sub(a[i], b[i]);
                d += s.Magnitude();
            }

            d /= a.Length;
            return d;
        }
Example #12
0
        public static WWDecimalComplex[] Mul(WWDecimalComplex[] a, WWDecimalComplex[] b)
        {
            if (a.Length != b.Length)
            {
                throw new ArgumentException("input array length mismatch");
            }

            var c = new WWDecimalComplex[a.Length];

            for (int i = 0; i < a.Length; ++i)
            {
                c[i] = WWDecimalComplex.Mul(a[i], b[i]);
            }
            return(c);
        }
Example #13
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.");
        }
Example #14
0
        public static decimal AverageDistance(WWDecimalComplex[] a, WWDecimalComplex[] b)
        {
            if (a.Length != b.Length)
            {
                throw new ArgumentException("input array length mismatch");
            }

            decimal d = 0M;

            for (int i = 0; i < a.Length; ++i)
            {
                var s = WWDecimalComplex.Sub(a[i], b[i]);
                d += s.Magnitude();
            }

            d /= a.Length;
            return(d);
        }
Example #15
0
        public WWDecimalComplex Mul(WWDecimalComplex rhs)
        {
#if false
            // straightforward but slow
            decimal tR = real * rhs.real - imaginary * rhs.imaginary;
            decimal tI = real * rhs.imaginary + imaginary * rhs.real;
            real      = tR;
            imaginary = tI;
#else
            // more efficient way
            decimal k1 = real * (rhs.real + rhs.imaginary);
            decimal k2 = rhs.imaginary * (real + imaginary);
            decimal k3 = rhs.real * (imaginary - real);
            real      = k1 - k2;
            imaginary = k1 + k3;
#endif
            return(this);
        }
Example #16
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);
            }
        }
        /*
         * private static void Butterfly(WWDecimalComplex vFrom0, WWDecimalComplex vFrom1, WWDecimalComplex wn, WWDecimalComplex[] vTo, int toPos) {
         *  vTo[toPos].CopyFrom(vFrom0);
         *  var t = new WWDecimalComplex(vFrom1);
         *  t.Mul(wn);
         *  vTo[toPos].Mul(t);
         *
         *  vTo[toPos + 1].CopyFrom(vFrom0);
         *  t.Mul(-1);
         *  vTo[toPos + 1].Mul(t);
         * }
         */

        public WWDecimalComplex[] ForwardFft(WWDecimalComplex[] aFrom, decimal scale = 1M)
        {
            if (aFrom == null || aFrom.Length != mNumPoints)
            {
                throw new ArgumentOutOfRangeException("aFrom");
            }
            var aTo = new WWDecimalComplex[aFrom.Length];

            var aTmp0 = new WWDecimalComplex[mNumPoints];

            for (int i = 0; i < aTmp0.Length; ++i)
            {
                aTmp0[i] = new WWDecimalComplex(aFrom[mBitReversalTable[i]]);
            }
            var aTmp1 = new WWDecimalComplex[mNumPoints];

            for (int i = 0; i < aTmp1.Length; ++i)
            {
                aTmp1[i] = new WWDecimalComplex();
            }

            var aTmps = new WWDecimalComplex[2][];

            aTmps[0] = aTmp0;
            aTmps[1] = aTmp1;

            for (int i = 0; i < mNumStage - 1; ++i)
            {
                FftStageN(i, aTmps[((i & 1) == 1) ? 1 : 0], aTmps[((i & 1) == 0) ? 1 : 0]);
            }
            FftStageN(mNumStage - 1, aTmps[(((mNumStage - 1) & 1) == 1) ? 1 : 0], aTo);

            if (scale != 1M)
            {
                for (int i = 0; i < aTo.Length; ++i)
                {
                    aTo[i].Mul(scale);
                }
            }
            return(aTo);
        }
Example #18
0
 public WWDecimalComplex Sub(WWDecimalComplex rhs)
 {
     real      -= rhs.real;
     imaginary -= rhs.imaginary;
     return(this);
 }
Example #19
0
        /*
         * /// <summary>
         * /// Phase in radians
         * /// </summary>
         * /// <returns>radians, -π to +π</returns>
         * public decimal Phase() {
         *  if (WWDecimalMath.IsTooSmall(Magnitude())) {
         *      return 0;
         *  }
         *
         *  return WWDecimalMath.Atan2(imaginary, real);
         * }
         */

        public WWDecimalComplex Add(WWDecimalComplex rhs)
        {
            real      += rhs.real;
            imaginary += rhs.imaginary;
            return(this);
        }
Example #20
0
 public static WWDecimalComplex Sub(WWDecimalComplex a, WWDecimalComplex b)
 {
     var r = new WWDecimalComplex(a);
     r.Sub(b);
     return r;
 }
Example #21
0
        /*
        /// <summary>
        /// Phase in radians
        /// </summary>
        /// <returns>radians, -π to +π</returns>
        public decimal Phase() {
            if (WWDecimalMath.IsTooSmall(Magnitude())) {
                return 0;
            }

            return WWDecimalMath.Atan2(imaginary, real);
        }
        */
        public WWDecimalComplex Add(WWDecimalComplex rhs)
        {
            real      += rhs.real;
            imaginary += rhs.imaginary;
            return this;
        }
Example #22
0
 public void CopyFrom(WWDecimalComplex rhs)
 {
     real      = rhs.real;
     imaginary = rhs.imaginary;
 }
Example #23
0
 public WWDecimalComplex(WWDecimalComplex rhs)
 {
     this.real      = rhs.real;
     this.imaginary = rhs.imaginary;
 }
Example #24
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.");
        }
Example #25
0
 public WWDecimalComplex Sub(WWDecimalComplex rhs)
 {
     real      -= rhs.real;
     imaginary -= rhs.imaginary;
     return this;
 }
Example #26
0
 public WWDecimalComplex(WWDecimalComplex rhs)
 {
     this.real      = rhs.real;
     this.imaginary = rhs.imaginary;
 }
Example #27
0
 public static WWDecimalComplex Add(WWDecimalComplex a, WWDecimalComplex b)
 {
     var r = new WWDecimalComplex(a);
     r.Add(b);
     return r;
 }
Example #28
0
 public static WWDecimalComplex Mul(WWDecimalComplex a, WWDecimalComplex b)
 {
     var r = new WWDecimalComplex(a);
     r.Mul(b);
     return r;
 }
Example #29
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);
                    }
                }
            }
        }
Example #30
0
        public WWDecimalComplex[] InverseFft(WWDecimalComplex[] aFrom, decimal? compensation = null)
        {
            for (int i=0; i < aFrom.LongLength; ++i) {
                aFrom[i].imaginary *= -1.0M;
            }

            var aTo = ForwardFft(aFrom);

            decimal c = 1.0M / mNumPoints;
            if (compensation != null) {
                c = (decimal)compensation;
            }

            for (int i=0; i < aTo.LongLength; ++i) {
                aTo[i].real      *= c;
                aTo[i].imaginary *= -1.0M * c;
            }

            return aTo;
        }
        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);
                    }
                }
            }
        }
Example #32
0
 public void CopyFrom(WWDecimalComplex rhs)
 {
     real      = rhs.real;
     imaginary = rhs.imaginary;
 }
Example #33
0
 public WWDecimalComplex Mul(WWDecimalComplex rhs)
 {
     #if false
     // straightforward but slow
     decimal tR = real * rhs.real      - imaginary * rhs.imaginary;
     decimal tI = real * rhs.imaginary + imaginary * rhs.real;
     real      = tR;
     imaginary = tI;
     #else
     // more efficient way
     decimal k1 = real          * (rhs.real  + rhs.imaginary);
     decimal k2 = rhs.imaginary * (real      + imaginary);
     decimal k3 = rhs.real      * (imaginary - real);
     real      = k1 - k2;
     imaginary = k1 + k3;
     #endif
     return this;
 }