/// <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); }
/// <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)); }
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)); } }
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); }
/// <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)); }
/// <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); } }
/// <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)); }
/// <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)); }
public static double Distance(WWComplex a, WWComplex b) { var s = WWComplex.Sub(a, b); return(s.Magnitude()); }
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()); } }
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); }
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(" }"); }
/// <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); } }
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())); }
/// <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); }
/// <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)); }
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); } } } }
/// <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); }
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)); }
public static WWComplex Mul(WWComplex lhs, double v) { return(new WWComplex(lhs.real * v, lhs.imaginary * v)); }
static WWComplex Get(WWComplex[] v, int pos) { if (pos < 0 || v.Length <= pos) { return WWComplex.Zero(); } return v[pos]; }
/// <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); }