public WWComplex[] ConvolutionFft(WWComplex[] h, WWComplex[] x) { var r = new WWComplex[h.Length + x.Length - 1]; int fftSize = WWRadix2Fft.NextPowerOf2(r.Length); var h2 = new WWComplex[fftSize]; Array.Copy(h, 0, h2, 0, h.Length); var x2 = new WWComplex[fftSize]; Array.Copy(x, 0, x2, 0, x.Length); var fft = new WWRadix2Fft(fftSize); var H = fft.ForwardFft(h2); var X = fft.ForwardFft(x2); var Y = WWComplex.Mul(H, X); var y = fft.InverseFft(Y); Array.Copy(y, 0, r, 0, r.Length); return(r); }
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 = new WWComplex(); 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 / 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); } } } }
public override double[] FilterDo(double[] inPcm) { System.Diagnostics.Debug.Assert(inPcm.LongLength <= NumOfSamplesNeeded()); var fft = new WWRadix2Fft(FFT_LEN); // Overlap and add continuous FFT var inTime = new WWComplex[FFT_LEN]; for (int i = 0; i < inPcm.Length; ++i) { inTime[i].real = inPcm[i]; } // FFTでinTimeをinFreqに変換 var inFreq = fft.ForwardFft(inTime); inTime = null; // FFT後、フィルターHの周波数ドメインデータを掛ける var mulFreq = WWComplex.Mul(inFreq, mFilterFreq); inFreq = null; // inFreqをIFFTしてoutTimeに変換 var outTime = fft.InverseFft(mulFreq); mulFreq = null; double [] outReal; if (mFirstFilterDo) { // 最初のFilterDo()のとき、フィルタの遅延サンプル数だけ先頭サンプルを削除する。 outReal = new double[NumOfSamplesNeeded() - FILTER_DELAY]; for (int i = 0; i < outReal.Length; ++i) { outReal[i] = outTime[i + FILTER_DELAY].real; } mFirstFilterDo = false; } else { outReal = new double[NumOfSamplesNeeded()]; for (int i = 0; i < outReal.Length; ++i) { outReal[i] = outTime[i].real; } } // 前回のIFFT結果の最後のFILTER_LENGTH-1サンプルを先頭に加算する if (null != mIfftAddBuffer) { for (int i = 0; i < mIfftAddBuffer.Length; ++i) { outReal[i] += mIfftAddBuffer[i]; } } // 今回のIFFT結果の最後のFILTER_LENGTH-1サンプルをmIfftAddBufferとして保存する mIfftAddBuffer = new double[FILTER_LENP1]; for (int i = 0; i < mIfftAddBuffer.Length; ++i) { mIfftAddBuffer[i] = outTime[outTime.Length - mIfftAddBuffer.Length + i].real; } outTime = null; return(outReal); }
public static WWComplex Mul(WWComplex a, WWComplex b) { var r = new WWComplex(a); r.Mul(b); return r; }
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 = new WWComplex(); 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 / 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); } } } }