public WWRadix2FftF(int numPoints) { if (!Functions.IsPowerOfTwo(numPoints) || numPoints < 2) { throw new ArgumentException("numPoints must be power of two integer and larger than 2"); } mNumPoints = numPoints; mWn = new WWComplexF[mNumPoints]; for (int i = 0; i < mNumPoints; ++i) { double angle = -2.0 * Math.PI * i / mNumPoints; mWn[i] = new WWComplexF((float)Math.Cos(angle), (float)Math.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 WWComplexF Reciprocal(WWComplexF uni) { float sq = uni.real * uni.real + uni.imaginary * uni.imaginary; float real = uni.real / sq; float imaginary = -uni.imaginary / sq; return(new WWComplexF(real, imaginary)); }
/// <summary> /// 複素数の配列をWWComplexComparerでソートする。 /// </summary> public static WWComplexF[] SortArray(WWComplexF[] inp) { var outp = new WWComplexF[inp.Length]; Array.Copy(inp, outp, inp.Length); Array.Sort(outp, new WWComplexComparer()); return(outp); }
/// <summary> /// すべての要素値が0の複素数配列をnewして戻す。 /// </summary> /// <param name="count">配列の要素数。</param> public static WWComplexF[] ZeroArray(int count) { var r = new WWComplexF[count]; for (int i = 0; i < r.Length; ++i) { r[i] = Zero(); } return(r); }
public static WWComplexF[] FromRealArray(double[] r) { var c = new WWComplexF[r.Length]; for (int i = 0; i < c.Length; ++i) { c[i] = new WWComplexF((float)r[i], 0); } return(c); }
/// <summary> /// 注:compensationが指定しないとき、結果をNで割りません。 /// </summary> /// <param name="aFrom">時間ドメイン値x[n] 0≦n<N</param> /// <param name="compensation">倍率。指定しないとき1.0f倍となる。</param> /// <returns>周波数ドメイン値X^m(q)</returns> public WWComplexF[] ForwardFft(WWComplexF[] aFrom, float?compensation = null) { if (aFrom == null || aFrom.Length != mNumPoints) { throw new ArgumentOutOfRangeException("aFrom"); } var aTo = new WWComplexF[aFrom.Length]; var aTmp0 = new WWComplexF[mNumPoints]; for (int i = 0; i < aTmp0.Length; ++i) { aTmp0[i] = aFrom[mBitReversalTable[i]]; } var aTmp1 = new WWComplexF[mNumPoints]; for (int i = 0; i < aTmp1.Length; ++i) { aTmp1[i] = WWComplexF.Zero(); } var aTmps = new WWComplexF[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); float c = 1.0f; if (compensation != null) { c = (float)compensation; } if (c != 1.0f) { var aToC = new WWComplexF[aTo.Length]; for (int i = 0; i < aTo.Length; ++i) { aToC[i] = new WWComplexF(aTo[i].real * c, aTo[i].imaginary * c); } return(aToC); } else { return(aTo); } }
public static WWComplexF[] Mul(WWComplexF[] a, WWComplexF[] b) { if (a.Length != b.Length) { throw new ArgumentException("input array length mismatch"); } var c = new WWComplexF[a.Length]; for (int i = 0; i < a.Length; ++i) { c[i] = WWComplexF.Mul(a[i], b[i]); } return(c); }
/// <summary> /// create copy and copy := L * R, returns copy. /// </summary> public static WWComplexF Mul(WWComplexF lhs, WWComplexF rhs) { #if false // straightforward but slow float tR = real * rhs.real - imaginary * rhs.imaginary; float tI = real * rhs.imaginary + imaginary * rhs.real; real = tR; imaginary = tI; #else // more efficient way float k1 = lhs.real * (rhs.real + rhs.imaginary); float k2 = rhs.imaginary * (lhs.real + lhs.imaginary); float k3 = rhs.real * (lhs.imaginary - lhs.real); float real = k1 - k2; float imaginary = k1 + k3; #endif return(new WWComplexF(real, imaginary)); }
/// <summary> /// 逆FFTします。結果をcompensation倍します(compensationを指定しないとき1.0f/N倍) /// </summary> /// <param name="aFrom">周波数ドメイン値X^m(q) 0≦m≦N</param> /// <param name="compensation">倍率。指定しないとき1.0f/Nとなる。</param> /// <returns></returns> public WWComplexF[] InverseFft(WWComplexF[] aFrom, float?compensation = null) { for (int i = 0; i < aFrom.Length; ++i) { aFrom[i] = new WWComplexF(aFrom[i].real, -aFrom[i].imaginary); } var aTo = ForwardFft(aFrom); float c = 1.0f / mNumPoints; if (compensation != null) { c = (float)compensation; } for (int i = 0; i < aTo.Length; ++i) { aTo[i] = new WWComplexF(aTo[i].real * c, -aTo[i].imaginary * c); } return(aTo); }
/// <summary> /// create copy and copy := complex conjugate of uni, returns copy. /// </summary> public static WWComplexF ComplexConjugate(WWComplexF uni) { return(new WWComplexF(uni.real, -uni.imaginary)); }
public static WWComplexF Add(WWComplexF a, WWComplexF b, WWComplexF c, WWComplexF d, WWComplexF e) { return(new WWComplexF( a.real + b.real + c.real + d.real + e.real, a.imaginary + b.imaginary + c.imaginary + d.imaginary + e.imaginary)); }
/// <summary> /// create copy and copy := L - R, returns copy. /// </summary> public static WWComplexF Sub(WWComplexF lhs, WWComplexF rhs) { return(new WWComplexF(lhs.real - rhs.real, lhs.imaginary - rhs.imaginary)); }
public static WWComplexF Mul(WWComplexF lhs, float v) { return(new WWComplexF(lhs.real * v, lhs.imaginary * v)); }
/// <summary> /// create copy and copy := L + R, returns copy. /// </summary> public static WWComplexF Add(WWComplexF lhs, WWComplexF rhs) { return(new WWComplexF(lhs.real + rhs.real, lhs.imaginary + rhs.imaginary)); }
/// <summary> /// 内容が全く同じときtrue /// </summary> public bool EqualValue(WWComplexF rhs) { return(real == rhs.real && imaginary == rhs.imaginary); }
/// <summary> /// returns reciprocal. this instance is not changed. /// </summary> public WWComplexF Reciplocal() { return(WWComplexF.Reciprocal(this)); }
public static float Distance(WWComplexF a, WWComplexF b) { var s = WWComplexF.Sub(a, b); return(s.Magnitude()); }
/// <summary> /// create copy and copy := L / R, returns copy. /// </summary> public static WWComplexF Div(WWComplexF lhs, WWComplexF rhs) { var recip = Reciprocal(rhs); return(Mul(lhs, recip)); }
public static WWComplexF Div(WWComplexF lhs, float rhs) { var recip = 1.0f / rhs; return(Mul(lhs, recip)); }
private void FftStageN(int stageNr, WWComplexF[] x, WWComplexF[] 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 = WWComplexF.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] = WWComplexF.Zero(); } } else { for (int j = 0; j < nSubRepeat; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); var v1 = x[offs]; var v2 = WWComplexF.Mul(mWn[j * nRepeat], x[offs + nSubRepeat / 2]); y[j + offsBase] = WWComplexF.Add(v1, v2); } } } }
/// <summary> /// create copy and copy := -uni, returns copy. /// argument value is not changed. /// </summary> public static WWComplexF Minus(WWComplexF uni) { return(new WWComplexF(-uni.real, -uni.imaginary)); }