Ejemplo n.º 1
0
        public static void FullForwardFFT(this ComplexNumber[] data, RealNumber[] temporaryArray = null)
        {
            int N = data.Length;

            int precisionDigits = 1;

            for (int i = data.Length; --i >= 0;)
            {
                precisionDigits = Math.Max(precisionDigits, data[i].GetPrecisionDigits());
            }
            FFTRealConstants precision = new FFTRealConstants(precisionDigits);

            List <int> factors = FourierTransform235.GetSlowFactorization(N).OrderBy(x => x).ToList();

            ComplexNumber[] roots       = null;
            ComplexNumber[] temp        = null;
            ComplexNumber[] simpleRoots = null;

            List <int>           factorDigits          = new List <int>();
            List <int>           decimalRepresentation = new List <int>();
            List <ComplexNumber> incrementalProduct    = new List <ComplexNumber>();

            int totalProduct = 1;
            int N1           = N;
            int count        = 1;

            foreach (int factor in factors)
            {
                int N2 = N1;
                N1           /= factor;
                totalProduct *= factor;

                factorDigits.Add(factor);
                incrementalProduct.Clear();
                int partialProduct = totalProduct;
                for (int i = 0; i < factorDigits.Count; i++)
                {
                    incrementalProduct.Add(ComplexNumber.FromPolarAngle((precision.PI << 1) / partialProduct));
                    partialProduct /= factorDigits[i];
                }
                ComplexNumber[] exactProduct = new ComplexNumber[factorDigits.Count - 1];
                if (factorDigits.Count > 1)
                {
                    exactProduct[factorDigits.Count - 2] = incrementalProduct[factorDigits.Count - 2];
                    for (int i = factorDigits.Count - 2; --i >= 0;)
                    {
                        exactProduct[i] = exactProduct[i + 1] * (incrementalProduct[i] * incrementalProduct[i + 2].Conjugate);
                    }
                }

                decimalRepresentation.Clear();
                decimalRepresentation.AddRange(Enumerable.Repeat(0, factorDigits.Count - 1));

                ComplexNumber exactPower = ComplexNumber.One;
                for (int i = 0; i < count; i++)
                {
                    DirectFFTWithStartTwiddle(data, i * N2, N1, N1, factor, precision, ref roots, ref temp, ref simpleRoots, exactPower);
                    getIncrement(ref exactPower, decimalRepresentation, factorDigits, exactProduct);
                }

                count = totalProduct;
            }

            if (temporaryArray == null || temporaryArray.Length < N * 2)
            {
                Array.Resize(ref temporaryArray, N * 2);
            }
            for (int i = N; --i >= 0;)
            {
                var number = data[i];
                temporaryArray[i * 2]     = number.Real;
                temporaryArray[i * 2 + 1] = number.Imaginary;
            }
            FourierTransform235.ReversedBaseIterate(factors, (i, reversed) => data[reversed] = new ComplexNumber(temporaryArray[i * 2], temporaryArray[i * 2 + 1]));
        }
Ejemplo n.º 2
0
        private static void DirectFFTWithStartTwiddle(ComplexNumber[] data, int index, int multiplier, int length, int prime,
                                                      FFTRealConstants precision, ref ComplexNumber[] roots, ref ComplexNumber[] temp, ref ComplexNumber[] simpleRoots, ComplexNumber requiredPower)
        {
            if (roots == null || roots.Length < prime)
            {
                Array.Resize(ref roots, prime);
            }
            roots[1] = requiredPower;
            for (int i = 2; i < prime; i++)
            {
                roots[i] = roots[i >> 1] * roots[(i + 1) >> 1];
            }

            for (; --length >= 0; index++)
            {
                switch (prime)
                {
                case 2:
                {
                    var v0 = data[index];
                    var v1 = data[index + multiplier] * roots[1];
                    data[index] = v0 + v1;
                    data[index + multiplier] = v0 - v1;
                }
                break;

                case 3:
                    //w^2 = -1-w
                {
                    ComplexNumber
                        z0 = data[index],
                        z1 = data[index + multiplier] * roots[1],
                        z2 = data[index + 2 * multiplier] * roots[2];
                    ComplexNumber
                        t1 = z1 + z2,
                        t2 = z0 - (t1 >> 1),
                        t3 = (z1 - z2).MulI() * precision.M_SQRT_3_4;
                    data[index] = z0 + t1;
                    data[index + multiplier]     = t2 + t3;
                    data[index + 2 * multiplier] = t2 - t3;
                }
                break;

                case 5:
                    //http://www2.itap.physik.uni-stuttgart.de/lehre/vorlesungen/SS08/simmeth/fftalgorithms.pdf
                {
                    ComplexNumber
                        z0 = data[index],
                        z1 = data[index + multiplier] * roots[1],
                        z2 = data[index + 2 * multiplier] * roots[2],
                        z3 = data[index + 3 * multiplier] * roots[3],
                        z4 = data[index + 4 * multiplier] * roots[4];
                    ComplexNumber
                        t1  = z1 + z4,
                        t2  = z2 + z3,
                        t3  = z1 - z4,
                        t4  = z2 - z3,
                        t5  = t1 + t2,
                        t6  = (t1 - t2) * precision.M_ROOT5_C2,
                        t7  = z0 - (t5 >> 2),
                        t8  = t7 + t6,
                        t9  = t7 - t6,
                        t10 = (t3 * precision.M_ROOT5_C4 + t4 * precision.M_ROOT5_C3).MulI(),
                        t11 = (t3 * precision.M_ROOT5_C3 - t4 * precision.M_ROOT5_C4).MulI();
                    data[index] = z0 + t5;
                    data[index + multiplier]     = t8 + t10;
                    data[index + 2 * multiplier] = t9 + t11;
                    data[index + 3 * multiplier] = t9 - t11;
                    data[index + 4 * multiplier] = t8 - t10;
                }
                break;

                default:
                    if (simpleRoots == null || simpleRoots.Length != prime)
                    {
                        Array.Resize(ref simpleRoots, prime);
                        simpleRoots[1] = ComplexNumber.FromPolarAngle((precision.PI << 1) / prime);
                        for (int i = 2; i < prime; i++)
                        {
                            simpleRoots[i] = simpleRoots[i >> 1] * simpleRoots[(i + 1) >> 1];
                        }
                    }
                    if (temp == null || temp.Length < prime)
                    {
                        Array.Resize(ref temp, prime);
                    }
                    var sum = temp[0] = data[index];
                    for (int i = prime; --i > 0;)
                    {
                        temp[i] = data[index + i * multiplier] * roots[i];
                        sum    += temp[i];
                    }
                    data[index] = sum;
                    for (int i = prime; --i > 0;)
                    {
                        var result = temp[0];
                        for (int j = prime, k = 0; --j > 0;)
                        {
                            k      -= i;
                            k       = k < 0 ? k + prime : k; //k = i * j mod prime.
                            result += temp[j] * simpleRoots[k];
                        }
                        data[index + i * multiplier] = result;
                    }
                    break;
                }
            }
        }