Beispiel #1
0
        /// <summary>
        /// 逆FFTします。結果をcompensation倍します(compensationを指定しないとき1.0/N倍)
        /// </summary>
        /// <param name="aFrom">周波数ドメイン値X^m(q) 0≦m≦N</param>
        /// <param name="compensation">倍率。指定しないとき1.0/Nとなる。</param>
        /// <returns></returns>
        public WWComplex[] InverseFft(WWComplex[] aFrom, double?compensation = null)
        {
            for (int i = 0; i < aFrom.Length; ++i)
            {
                aFrom[i] = new WWComplex(aFrom[i].real, -aFrom[i].imaginary);
            }

            var aTo = ForwardFft(aFrom);

            double c = 1.0 / mNumPoints;

            if (compensation != null)
            {
                c = (double)compensation;
            }

            for (int i = 0; i < aTo.Length; ++i)
            {
                aTo[i] = new WWComplex(aTo[i].real * c, -aTo[i].imaginary * c);
            }

            return(aTo);
        }
Beispiel #2
0
        /// <summary>
        /// 1乗以上の項の係数項の表示。
        /// </summary>
        public static string FirstCoeffToString(WWComplex c, string variableString)
        {
            if (c.EqualValue(new WWComplex(1, 0)))
            {
                return(variableString); // 係数を表示せず、変数のみ表示する。
            }

            if (c.EqualValue(new WWComplex(-1, 0)))
            {
                return(string.Format("-{0}", variableString));
            }

            if (c.imaginary == 0)
            {
                // 実数。
                return(string.Format("{0}{1}", c.real, variableString));
            }

            if (c.EqualValue(new WWComplex(0, 1)))
            {
                return(string.Format("{0}{1}", WWComplex.imaginaryUnit, variableString));
            }

            if (c.EqualValue(new WWComplex(0, -1)))
            {
                return(string.Format("-{0}{1}", WWComplex.imaginaryUnit, variableString));
            }

            if (c.real == 0)
            {
                // 純虚数。
                return(string.Format("{0}{1}{2}", c.imaginary, WWComplex.imaginaryUnit, variableString));
            }

            // 純虚数ではない虚数。
            return(string.Format("({0}){1}", c, variableString));
        }
Beispiel #3
0
        RootListToCoeffList(WWComplex [] b, WWComplex c)
        {
            var coeff = new List <WWComplex>();

            if (b.Length == 0)
            {
                // 定数項のみ。(?)
                coeff.Add(c);
                return(coeff.ToArray());
            }

            var b2 = new List <WWComplex>();

            foreach (var i in b)
            {
                b2.Add(i);
            }

            // (p-b[0])
            coeff.Add(WWComplex.Mul(b2[0], -1));
            coeff.Add(WWComplex.Unity());

            b2.RemoveAt(0);

            WWComplex[] coeffArray = coeff.ToArray();
            while (0 < b2.Count)
            {
                // 多項式に(p-b[k])を掛ける。
                var s1 = ComplexPolynomial.MultiplyX(new ComplexPolynomial(coeffArray));
                var s0 = ComplexPolynomial.MultiplyC(new ComplexPolynomial(coeffArray),
                                                     WWComplex.Mul(b2[0], -1));
                coeffArray = ComplexPolynomial.Add(s1, s0).ToArray();
                b2.RemoveAt(0);
            }

            return(ComplexPolynomial.MultiplyC(new ComplexPolynomial(coeffArray), c).ToArray());
        }
        public WWComplex Next()
        {
            if (mFt == 0)
            {
                return(WWComplex.Unity());
            }

            // mFt != 0の場合。

            ++mCounter;
            if (mCounter == mLcm)
            {
                mLcm = 0;

                // 位相を0にリセットします。
                double gn = 3.0 / 2.0 - 0.5 * ((mYi * mYi) + (mYq * mYq));
                double yi = gn;
                double yq = 0;

                mYi = yi;
                mYq = yq;

                return(new WWComplex(yi, yq));
            }
            else
            {
                double gn = 3.0 / 2.0 - 0.5 * ((mYi * mYi) + (mYq * mYq));
                double yi = gn * (mYi * mCosθ - mYq * mSinθ);
                double yq = gn * (mYq * mCosθ + mYi * mSinθ);

                mYi = yi;
                mYq = yq;

                return(new WWComplex(yi, yq));
            }
        }
Beispiel #5
0
        public WWComplex Evaluate(WWComplex x)
        {
            WWComplex n  = WWComplex.Zero();
            WWComplex xN = WWComplex.Unity();

            for (int i = 0; i < numer.Length; ++i)
            {
                n  = WWComplex.Add(n, WWComplex.Mul(xN, numer[i]));
                xN = WWComplex.Mul(xN, x);
            }

            WWComplex d = WWComplex.Zero();

            xN = WWComplex.Unity();
            for (int i = 0; i < denom.Length; ++i)
            {
                d  = WWComplex.Add(d, WWComplex.Mul(xN, denom[i]));
                xN = WWComplex.Mul(xN, x);
            }

            WWComplex y = WWComplex.Div(n, d);

            return(y);
        }
Beispiel #6
0
        /// <summary>
        /// output string represents "c2x^2 + c1x + c0"
        /// </summary>
        public static string PolynomialToString(WWComplex c2, WWComplex c1, WWComplex c0, string variableSymbol)
        {
            if (c2.Magnitude() == 0)
            {
                // 1乗以下の項のみ。
                return(PolynomialToString(c1, c0, variableSymbol));
            }

            if (c1.Magnitude() == 0 && c0.Magnitude() == 0)
            {
                // 2乗の項のみ。
                return(FirstCoeffToString(c2, string.Format("{0}^2", variableSymbol)));
            }

            if (c0.Magnitude() == 0)
            {
                // 2乗の項と1乗の項。
                return(string.Format("{0}{1}",
                                     FirstCoeffToString(c2, string.Format("{0}^2", variableSymbol)),
                                     ContinuedCoeffToString(c1, variableSymbol)));
            }

            if (c1.Magnitude() == 0)
            {
                // 2乗の項と定数項。
                return(string.Format("{0}{1}",
                                     FirstCoeffToString(c2, string.Format("{0}^2", variableSymbol)),
                                     ZeroOrderCoeffToString(c0)));
            }

            // 2乗+1乗+定数
            return(string.Format("{0}{1}{2}",
                                 FirstCoeffToString(c2, string.Format("{0}^2", variableSymbol)),
                                 ContinuedCoeffToString(c1, variableSymbol),
                                 ZeroOrderCoeffToString(c0)));
        }
        public static WWComplex Div(WWComplex lhs, double rhs)
        {
            var recip = 1.0 / rhs;

            return(Mul(lhs, recip));
        }
        /// <summary>
        /// create copy and copy := L / R, returns copy.
        /// </summary>
        public static WWComplex Div(WWComplex lhs, WWComplex rhs)
        {
            var recip = Reciprocal(rhs);

            return(Mul(lhs, recip));
        }
 /// <summary>
 /// returns reciprocal. this instance is not changed.
 /// </summary>
 public WWComplex Reciplocal()
 {
     return(WWComplex.Reciprocal(this));
 }
Beispiel #10
0
        /// <summary>
        /// 1次元IDFT。compensationを出力値に乗算する。Dft1dとペアで使用すると値が元に戻る。
        /// </summary>
        /// <param name="from">入力</param>
        /// <param name="compensation">出力に乗算する係数。省略時1</param>
        /// <returns>出力IDFT結果</returns>
        public static WWComplex[] Idft1d(WWComplex[] from, double?compensation = null)
        {
            /*
             * W=e^(-j*2pi/N)
             * Sk= seriesSum([ Gp * W^(-k*p) ], p, 0, N-1) (k=0,1,2,…,(N-1))
             *
             * from == Gp
             * to   == Sk
             */

            // 要素数N
            int N = from.Length;

            var to = new WWComplex[N];

            // Wのテーブル
            var w = new WWComplex[N];

            for (int i = 0; i < N; ++i)
            {
                double re = Math.Cos(i * 2.0 * Math.PI / N);
                double im = Math.Sin(i * 2.0 * Math.PI / N);
                w[i] = new WWComplex(re, im);
            }

            // IDFT実行。
            for (int k = 0; k < N; ++k)
            {
                double sr = 0.0;
                double si = 0.0;
                for (int p = 0; p < N; ++p)
                {
                    int    posGr = p;
                    int    posWr = (p * k) % N;
                    double gR    = from[posGr].real;
                    double gI    = from[posGr].imaginary;
                    double wR    = w[posWr].real;
                    double wI    = w[posWr].imaginary;
                    sr += gR * wR - gI * wI;
                    si += gR * wI + gI * wR;
                }
                to[k] = new WWComplex(sr, si);
            }

            double c = 1.0;

            if (compensation != null)
            {
                c = (double)compensation;
            }

            if (c != 1.0)
            {
                var toC = new WWComplex[N];
                for (int i = 0; i < N; ++i)
                {
                    toC[i] = new WWComplex(to[i].real * c, to[i].imaginary * c);
                }

                return(toC);
            }
            else
            {
                return(to);
            }
        }
Beispiel #11
0
 /// <summary>
 /// create copy and copy := L - R, returns copy.
 /// </summary>
 public static WWComplex Sub(WWComplex lhs, WWComplex rhs)
 {
     return(new WWComplex(lhs.real - rhs.real, lhs.imaginary - rhs.imaginary));
 }
Beispiel #12
0
 /// <summary>
 /// create copy and copy := L + R, returns copy.
 /// </summary>
 public static WWComplex Add(WWComplex lhs, WWComplex rhs)
 {
     return(new WWComplex(lhs.real + rhs.real, lhs.imaginary + rhs.imaginary));
 }
Beispiel #13
0
        public static double Distance(WWComplex a, WWComplex b)
        {
            var s = WWComplex.Sub(a, b);

            return(s.Magnitude());
        }
Beispiel #14
0
        public static void Test()
        {
            {
                /*
                 * 部分分数分解のテスト。
                 *           s + 3
                 * X(s) = -------------
                 *         (s+1)s(s-2)
                 *
                 * 部分分数分解すると
                 *
                 *          2/3      -3/2      5/6
                 * X(s) = ------- + ------ + -------
                 *         s + 1       s      s - 2
                 */
                var numerCoeffs = new WWComplex [] {
                    new WWComplex(3, 0),
                    new WWComplex(1, 0)
                };

                var dRoots = new WWComplex [] {
                    new WWComplex(-1, 0),
                    WWComplex.Zero(),
                    new WWComplex(2, 0)
                };

                var p = WWPolynomial.PartialFractionDecomposition(numerCoeffs, dRoots);

                for (int i = 0; i < p.Count; ++i)
                {
                    Console.WriteLine(p[i].ToString("s"));
                    if (i != p.Count - 1)
                    {
                        Console.WriteLine(" + ");
                    }
                }

                Console.WriteLine("");
            }

            {
                // 約分のテスト
                //  p-1        (p+1) -(p+1) + (p-1)            -2
                // ─────  ⇒  ──────────────────────  ⇒  1 + ─────
                //  p+1                  p+1                   p+1

                var numerC = new List <WWComplex>();
                numerC.Add(new WWComplex(-1, 0)); // 定数項。
                numerC.Add(WWComplex.Unity());    // 1乗の項。

                var denomR = new List <WWComplex>();
                denomR.Add(new WWComplex(-1, 0));

                var r = Reduction(numerC.ToArray(), denomR.ToArray());
                r.Print("p");
            }

            {
                // 約分のテスト
                //  p^2+3x+2            (p^2+3x+2) -(p^2+7x+12)            -4x-10
                // ────────────  ⇒ 1+ ─────────────────────────  ⇒  1 + ────────────
                //  (p+3)(p+4)           p^2+7x+12                         (p+3)(p+4)

                var numerC = new WWComplex [] {
                    new WWComplex(2, 0), // 定数項。
                    new WWComplex(3, 0), // 1乗の項。
                    WWComplex.Unity()
                };                       // 2乗の項。

                var denomR = new WWComplex [] {
                    new WWComplex(-3, 0),
                    new WWComplex(-4, 0)
                };

                var r = Reduction(numerC, denomR);
                r.Print("p");
            }
            {
                // 部分分数分解。
                //  -4x-10             2      -6
                // ────────────  ⇒  ───── + ─────
                //  (p+3)(p+4)        p+3     p+4

                var numerC = new WWComplex [] {
                    new WWComplex(-10, 0),
                    new WWComplex(-4, 0)
                };

                var denomR = new WWComplex [] {
                    new WWComplex(-3, 0),
                    new WWComplex(-4, 0)
                };

                var p = WWPolynomial.PartialFractionDecomposition(numerC, denomR);

                for (int i = 0; i < p.Count; ++i)
                {
                    Console.WriteLine(p[i].ToString("s"));
                    if (i != p.Count - 1)
                    {
                        Console.WriteLine(" + ");
                    }
                }

                Console.WriteLine("");
            }

            {
                var deriv = new RealPolynomial(new double[] { 1, 1, 1, 1 }).Derivative();
                Console.WriteLine("derivative of p^3+p^2+p+1={0}",
                                  deriv.ToString("p"));
            }

            {
                var r2 = AlgebraicLongDivision(new RealPolynomial(new double[] { 6, 3, 1 }),
                                               new RealPolynomial(new double[] { 1, 1 }));
                Console.WriteLine("(p^2+3x+6)/(p+1) = {0} r {1}",
                                  r2.quotient.ToString(), r2.remainder.ToString());
            }
        }
Beispiel #15
0
        PartialFractionDecomposition(
            WWComplex [] nCoeffs, WWComplex [] dRoots)
        {
            var result = new List <FirstOrderComplexRationalPolynomial>();

            if (dRoots.Length == 1 && nCoeffs.Length == 1)
            {
                result.Add(new FirstOrderComplexRationalPolynomial(WWComplex.Zero(),
                                                                   nCoeffs[0], WWComplex.Unity(), WWComplex.Minus(dRoots[0])));
                return(result);
            }

            if (dRoots.Length < 2)
            {
                throw new ArgumentException("denomR");
            }
            if (dRoots.Length < nCoeffs.Length)
            {
                throw new ArgumentException("nCoeffs");
            }

            for (int k = 0; k < dRoots.Length; ++k)
            {
                // cn = ... + nCoeffs[2]s^2 + nCoeffs[1]s + nCoeffs[0]
                // 係数c[0]は、s==denomR[0]としたときの、cn/(s-denomR[1])(s-denomR[2])(s-denomR[3])…(s-denomR[p-1])
                // 係数c[1]は、s==denomR[1]としたときの、cn/(s-denomR[0])(s-denomR[2])(s-denomR[3])…(s-denomR[p-1])
                // 係数c[2]は、s==denomR[2]としたときの、cn/(s-denomR[0])(s-denomR[1])(s-denomR[3])…(s-denomR[p-1])

                // 分子の値c。
                var c = WWComplex.Zero();
                var s = WWComplex.Unity();
                for (int j = 0; j < nCoeffs.Length; ++j)
                {
                    c = WWComplex.Add(c, WWComplex.Mul(nCoeffs[j], s));
                    s = WWComplex.Mul(s, dRoots[k]);
                }

                for (int i = 0; i < dRoots.Length; ++i)
                {
                    if (i == k)
                    {
                        continue;
                    }

                    c = WWComplex.Div(c, WWComplex.Sub(dRoots[k], dRoots[i]));
                }

                result.Add(new FirstOrderComplexRationalPolynomial(
                               WWComplex.Zero(), c,
                               WWComplex.Unity(), WWComplex.Minus(dRoots[k])));
            }

            return(result);
        }
Beispiel #16
0
            public void Print(string x)
            {
                if (0 < coeffList.Length)
                {
                    bool bFirst = true;
                    for (int i = coeffList.Length - 1; 0 <= i; --i)
                    {
                        if (coeffList[i].AlmostZero())
                        {
                            continue;
                        }

                        if (bFirst)
                        {
                            bFirst = false;
                        }
                        else
                        {
                            Console.Write(" + ");
                        }

                        if (i == 0)
                        {
                            Console.Write("{0}", coeffList[i]);
                        }
                        else if (i == 1)
                        {
                            Console.Write("{0}*{1}", coeffList[i], x);
                        }
                        else
                        {
                            Console.Write("{0}*({1}^{2})", coeffList[i], x, i);
                        }
                    }
                    if (!bFirst)
                    {
                        Console.Write(" + ");
                    }
                }

                Console.Write(" { ");
                {
                    bool bFirst = true;
                    for (int i = numerCoeffList.Length - 1; 0 <= i; --i)
                    {
                        if (numerCoeffList[i].AlmostZero())
                        {
                            continue;
                        }

                        if (bFirst)
                        {
                            bFirst = false;
                        }
                        else
                        {
                            Console.Write(" + ");
                        }
                        if (i == 0)
                        {
                            Console.Write("{0}", numerCoeffList[i]);
                        }
                        else if (i == 1)
                        {
                            Console.Write("{0}*{1}", numerCoeffList[i], x);
                        }
                        else
                        {
                            Console.Write("{0}*({1}^{2})", numerCoeffList[i], x, i);
                        }
                    }
                }

                Console.Write(" } / { ");

                {
                    for (int i = 0; i < denomRootList.Length; ++i)
                    {
                        if (denomRootList[i].AlmostZero())
                        {
                            Console.WriteLine(" {0} ", x);
                            continue;
                        }

                        Console.Write("({0}+({1}))", x, WWComplex.Minus(denomRootList[i]));
                    }
                }
                Console.WriteLine(" }");
            }
Beispiel #17
0
        /// <summary>
        /// 窓関数をかけた周波数ドメイン値X^m(q)を戻す。
        /// 同様の処理をWWGoertzel (Stable Goertzel algorithm)で行うこともできるだろう。
        /// </summary>
        public WWComplex[] FilterWithWindow(double x, WWWindowFunc.WindowType wt)
        {
            var r  = Filter(x);
            var rW = new WWComplex[r.Length];

            var w = WWWindowFunc.FreqDomainWindowCoeffs(wt);

            switch (w.Length)
            {
            case 2:
                for (int i = 0; i < mN; ++i)
                {
                    int il = i - 1;
                    if (il < 0)
                    {
                        il = mN - 1;
                    }
                    int ir = i + 1;
                    if (mN <= ir)
                    {
                        ir = 0;
                    }

                    rW[i] = WWComplex.Add(
                        WWComplex.Mul(r[il], w[1] * 0.5),
                        WWComplex.Mul(r[i], w[0]),
                        WWComplex.Mul(r[ir], w[1] * 0.5));
                }
                return(rW);

            case 3:
                for (int i = 0; i < mN; ++i)
                {
                    var pos = new int[5];
                    for (int offs = -2; offs <= 2; ++offs)
                    {
                        int p = i + offs;
                        if (p < 0)
                        {
                            p += mN;
                        }
                        if (mN <= p)
                        {
                            p -= mN;
                        }

                        pos[offs + 2] = p;
                    }

                    rW[i] = WWComplex.Add(
                        WWComplex.Mul(r[pos[0]], w[2] * 0.5),
                        WWComplex.Mul(r[pos[1]], w[1] * 0.5),
                        WWComplex.Mul(r[pos[2]], w[0]),
                        WWComplex.Mul(r[pos[3]], w[1] * 0.5),
                        WWComplex.Mul(r[pos[4]], w[2] * 0.5));
                }
                return(rW);

            default:
                System.Diagnostics.Debug.Assert(false);
                return(null);
            }
        }
Beispiel #18
0
        Add(HighOrderComplexRationalPolynomial lhs, FirstOrderComplexRationalPolynomial rhs)
        {
            /*  nL          nR
             * p^2+2x+2    p+4
             * ───────── + ────
             * p^2+ p+1    p+3
             *  dL          dR
             *
             *          dL       dR
             * 分母 = (p^2+p+1) (p+3)
             * 分母の次数 = degree(dL) + degree(dR) + 1
             *
             *          nL       dR      nR    dL
             * 分子 = (p^2+2x+2)(p+3) + (p+4)(p^2+p+1)
             * 分子の次数 = degree(nL) + degree(dR) + 1 か degree(nR) * degree(dL) + 1の大きいほう
             */

            ComplexPolynomial denomL;
            {
                var d = new WWComplex[lhs.DenomDegree() + 1];
                for (int i = 0; i <= lhs.DenomDegree(); ++i)
                {
                    d[i] = lhs.D(i);
                }
                denomL = new ComplexPolynomial(d);
            }
            ComplexPolynomial numerL;
            {
                var n = new WWComplex[lhs.NumerDegree() + 1];
                for (int i = 0; i <= lhs.NumerDegree(); ++i)
                {
                    n[i] = lhs.N(i);
                }
                numerL = new ComplexPolynomial(n);
            }

            // 分母の項
            ComplexPolynomial denomResult;
            {
                var denomX = new ComplexPolynomial(new WWComplex[0]);
                if (1 == rhs.DenomDegree())
                {
                    denomX = ComplexPolynomial.MultiplyC(ComplexPolynomial.MultiplyX(denomL), rhs.D(1));
                }
                var denomC = ComplexPolynomial.MultiplyC(denomL, rhs.D(0));
                denomResult = ComplexPolynomial.Add(denomX, denomC);
            }

            // 分子の項
            ComplexPolynomial numerResult;

            {
                ComplexPolynomial numer0;
                {
                    var numerX0 = new ComplexPolynomial(new WWComplex[0]);
                    if (1 == rhs.DenomDegree())
                    {
                        numerX0 = ComplexPolynomial.MultiplyC(ComplexPolynomial.MultiplyX(numerL), rhs.D(1));
                    }
                    var numerC0 = ComplexPolynomial.MultiplyC(numerL, rhs.D(0));
                    numer0 = ComplexPolynomial.Add(numerX0, numerC0);
                }

                ComplexPolynomial numer1;
                {
                    var numerX1 = new ComplexPolynomial(new WWComplex[0]);
                    if (1 == rhs.NumerDegree())
                    {
                        numerX1 = ComplexPolynomial.MultiplyC(ComplexPolynomial.MultiplyX(denomL), rhs.N(1));
                    }
                    var numerC1 = ComplexPolynomial.MultiplyC(denomL, rhs.N(0));
                    numer1 = ComplexPolynomial.Add(numerX1, numerC1);
                }

                numerResult = ComplexPolynomial.Add(numer0, numer1);
            }

            return(new HighOrderComplexRationalPolynomial(numerResult.ToArray(), denomResult.ToArray()));
        }
Beispiel #19
0
 /// <summary>
 /// create copy and copy := -uni, returns copy.
 /// argument value is not changed.
 /// </summary>
 public static WWComplex Minus(WWComplex uni)
 {
     return(new WWComplex(-uni.real, -uni.imaginary));
 }
        /// <summary>
        /// 連続FFT オーバーラップアド法でLinear convolution x ** hする。
        /// </summary>
        /// <param name="h">コンボリューションカーネル。左右反転される。</param>
        /// <param name="x">入力数列。</param>
        /// <param name="fragmentSz">個々のFFTに入力するxの断片サイズ。</param>
        public WWComplex[] ConvolutionContinuousFft(WWComplex[] h, WWComplex[] x, int fragmentSz)
        {
            System.Diagnostics.Debug.Assert(2 <= fragmentSz);

            if (x.Length < h.Length)
            {
                // swap x and h
                var tmp = h;
                h = x;
                x = tmp;
            }

            // h.Len <= x.Len

            int fullConvLen = h.Length + x.Length - 1;

            var r = new WWComplex[fullConvLen];

            for (int i = 0; i < r.Length; ++i)
            {
                r[i] = WWComplex.Zero();
            }

            // hをFFTしてHを得る。
            int fragConvLen = h.Length + fragmentSz - 1;
            int fftSize     = Functions.NextPowerOf2(fragConvLen);
            var h2          = new WWComplex[fftSize];

            Array.Copy(h, 0, h2, 0, h.Length);
            for (int i = h.Length; i < h2.Length; ++i)
            {
                h2[i] = WWComplex.Zero();
            }
            var fft = new WWRadix2Fft(fftSize);
            var H   = fft.ForwardFft(h2);

            for (int offs = 0; offs < x.Length; offs += fragmentSz)
            {
                // xFをFFTしてXを得る。
                var xF = WWComplex.ZeroArray(fftSize);
                for (int i = 0; i < fragmentSz; ++i)
                {
                    if (i + offs < x.Length)
                    {
                        xF[i] = x[offs + i];
                    }
                    else
                    {
                        break;
                    }
                }
                var X = fft.ForwardFft(xF);

                var Y = WWComplex.Mul(H, X);
                var y = fft.InverseFft(Y);

                // オーバーラップアド法。FFT結果を足し合わせる。
                for (int i = 0; i < fragConvLen; ++i)
                {
                    r[offs + i] = WWComplex.Add(r[offs + i], y[i]);
                }
            }

            return(r);
        }
Beispiel #21
0
 /// <summary>
 /// create copy and copy := complex conjugate of uni, returns copy.
 /// </summary>
 public static WWComplex ComplexConjugate(WWComplex uni)
 {
     return(new WWComplex(uni.real, -uni.imaginary));
 }
Beispiel #22
0
        private void FftStageN(int stageNr, WWComplex[] x, WWComplex[] 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          = WWComplex.Zero();

            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 (Double.Epsilon < x[offs].Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                    if (Double.Epsilon < x[offs + nSubRepeat / 2].Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                }

                if (allZero)
                {
                    for (int j = 0; j < nSubRepeat; ++j)
                    {
                        y[j + offsBase] = WWComplex.Zero();
                    }
                }
                else
                {
                    for (int j = 0; j < nSubRepeat; ++j)
                    {
                        int offs = offsBase + (j % (nSubRepeat / 2));

                        var v1 = x[offs];
                        var v2 = WWComplex.Mul(mWn[j * nRepeat], x[offs + nSubRepeat / 2]);
                        y[j + offsBase] = WWComplex.Add(v1, v2);
                    }
                }
            }
        }
Beispiel #23
0
 /// <summary>
 /// 内容が全く同じときtrue
 /// </summary>
 public bool EqualValue(WWComplex rhs)
 {
     return(real == rhs.real && imaginary == rhs.imaginary);
 }
 public WWComplex[] DenomCoeffs()
 {
     WWComplex[] d = new WWComplex[denom.Length];
     Array.Copy(denom, d, d.Length);
     return(d);
 }
Beispiel #25
0
 public static WWComplex Add(WWComplex a, WWComplex b, WWComplex c, WWComplex d, WWComplex e)
 {
     return(new WWComplex(
                a.real + b.real + c.real + d.real + e.real,
                a.imaginary + b.imaginary + c.imaginary + d.imaginary + e.imaginary));
 }
Beispiel #26
0
 public static WWComplex Mul(WWComplex lhs, double v)
 {
     return(new WWComplex(lhs.real * v, lhs.imaginary * v));
 }
Beispiel #27
0
 static WWComplex Get(WWComplex[] v, int pos) {
     if (pos < 0 || v.Length <= pos) {
         return WWComplex.Zero();
     }
     return v[pos];
 }
Beispiel #28
0
        /// <summary>
        /// 1次元DFT。要素数N。compensationを出力値に乗算する。省略時1/N。Idft1dとペアで使用すると値が元に戻る。
        /// </summary>
        /// <param name="from">入力。</param>
        /// <param name="compensation">出力に乗算する係数。省略時1/N</param>
        /// <returns>出力DFT結果</returns>
        public static WWComplex[] Dft1d(WWComplex[] from, double?compensation = null)
        {
            /*
             * W=e^(j*2pi/N)
             * Gp = (1/N) * seriesSum(Sk * W^(k*p), k, 0, N-1) (p=0,1,2,…,(N-1))
             *
             * from == Sk
             * to   == Gp
             */

            // 要素数N
            int N = from.Length;

            var to = new WWComplex[N];

            // Wのテーブル
            var w = new WWComplex[N];

            for (int i = 0; i < N; ++i)
            {
                double re = Math.Cos(-i * 2.0 * Math.PI / N);
                double im = Math.Sin(-i * 2.0 * Math.PI / N);
                w[i] = new WWComplex(re, im);
            }

            for (int p = 0; p < N; ++p)
            {
                double gr = 0.0;
                double gi = 0.0;
                for (int k = 0; k < N; ++k)
                {
                    int    posSr = k;
                    int    posWr = ((p * k) % N);
                    double sR    = from[posSr].real;
                    double sI    = from[posSr].imaginary;
                    double wR    = w[posWr].real;
                    double wI    = w[posWr].imaginary;
                    gr += sR * wR - sI * wI;
                    gi += sR * wI + sI * wR;
                }
                to[p] = new WWComplex(gr, gi);
            }

            double c = 1.0 / N;

            if (compensation != null)
            {
                c = (double)compensation;
            }

            if (c != 1.0)
            {
                var toC = new WWComplex[N];
                for (int i = 0; i < N; ++i)
                {
                    toC[i] = new WWComplex(to[i].real * c, to[i].imaginary * c);
                }

                return(toC);
            }
            else
            {
                return(to);
            }
        }
        private void FftStageN(int stageNr, LargeArray <WWComplex> x, LargeArray <WWComplex> 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:
             */

            long nRepeat    = Pow2(mNumStage - stageNr - 1);
            long nSubRepeat = mNumPoints / nRepeat;

            for (long i = 0; i < nRepeat; ++i)
            {
                long offsBase = i * nSubRepeat;

                bool allZero = true;
                for (long j = 0; j < nSubRepeat / 2; ++j)
                {
                    long offs = offsBase + (j % (nSubRepeat / 2));
                    if (Double.Epsilon < x.At(offs).Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                    if (Double.Epsilon < x.At(offs + nSubRepeat / 2).Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                }

                if (allZero)
                {
                    for (long j = 0; j < nSubRepeat; ++j)
                    {
                        y.Set(j + offsBase, WWComplex.Zero());
                    }
                }
                else
                {
                    for (long j = 0; j < nSubRepeat; ++j)
                    {
                        long offs = offsBase + (j % (nSubRepeat / 2));
                        var  t    = x.At(offs);

                        var t2 = WWComplex.Mul(mWn.At(j * nRepeat), x.At(offs + nSubRepeat / 2));
                        var t3 = WWComplex.Add(t, t2);

                        y.Set(j + offsBase, t3);
                    }
                }
            }
        }
 public WWComplex[] NumerCoeffs()
 {
     WWComplex[] n = new WWComplex[numer.Length];
     Array.Copy(numer, n, n.Length);
     return(n);
 }