예제 #1
0
        /// <summary>
        /// Linear Convolution x ** h を計算。
        /// </summary>
        /// <param name="h">コンボリューションカーネル。左右反転される。</param>
        /// <param name="x">入力数列。</param>
        public WWComplex[] ConvolutionFft(WWComplex[] h, WWComplex[] x) {
            var r = new WWComplex[h.Length + x.Length - 1];
            int fftSize = Functions.NextPowerOf2(r.Length);
            
            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 x2 = new WWComplex[fftSize];
            Array.Copy(x, 0, x2, 0, x.Length);
            for (int i = x.Length; i < x2.Length; ++i) {
                x2[i] = WWComplex.Zero();
            }

            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;
        }
예제 #2
0
        /// <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>
        /// 周波数ドメインの値を入力。
        /// 時間ドメインの値を出力。
        /// </summary>
        /// <param name="X">周波数ドメインの値。サンプル数=processBlockSize</param>
        /// <returns>時間ドメインの値。</returns>
        private double[] Process1(WWComplex[] X)
        {
            System.Diagnostics.Debug.Assert(X.Length == WantSamples);

            var x = WWComplex.ToRealArray(mFFT.InverseFft(X));

            if (0 == mProcessCounter)
            {
                // 1回目。
                // 前半のデータは埋め草なので破棄。後半のみ意味があるデータ。
                var r = new double[ProcessSize / 2];
                Array.Copy(x, ProcessSize / 2, r, 0, ProcessSize / 2);

                mOverlapBuff = r;

                ++mProcessCounter;

                return(new double[0]);
            }

            {
                // 2回目以降。
                var r = new double[ProcessSize / 2];
                for (int i = 0; i < r.Length; ++i)
                {
                    r[i] = x[i] + mOverlapBuff[i];
                }

                // 次回計算用にオーバーラップ部分を保存。
                for (int i = 0; i < r.Length; ++i)
                {
                    mOverlapBuff[i] = x[ProcessSize / 2 + i];
                }

                if (0 <= mNumSamples && mNumSamples < mProcessedSamples + r.Length)
                {
                    // 必要サンプル数を超えて出力する必要はない。
                    var tmp = new double[mNumSamples - mProcessedSamples];
                    Array.Copy(r, 0, tmp, 0, tmp.Length);
                    r = tmp;
                }

                ++mProcessCounter;
                mProcessedSamples += r.Length;
                return(r);
            }
        }