public kiss_fft_cpx <double> Multiply(kiss_fft_cpx <double> a, kiss_fft_cpx <double> b) { return(new kiss_fft_cpx <double>( a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r )); }
public kiss_fft_cpx <float> Multiply(kiss_fft_cpx <float> a, kiss_fft_cpx <float> b) { return(new kiss_fft_cpx <float>( a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r )); }
protected void kf_bfly4(Array <kiss_fft_cpx <kiss_fft_scalar> > Fout, int fstride, int m) { Array <kiss_fft_cpx <kiss_fft_scalar> > tw1, tw2, tw3; kiss_fft_cpx <kiss_fft_scalar>[] scratch = new kiss_fft_cpx <kiss_fft_scalar> [6]; int k = m; int m2 = 2 * m; int m3 = 3 * m; tw1 = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); tw2 = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); tw3 = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); do { Fout[0] = A.FixDivide(Fout[0], 4); Fout[m] = A.FixDivide(Fout[m], 4); Fout[m2] = A.FixDivide(Fout[m2], 4); Fout[m3] = A.FixDivide(Fout[m3], 4); scratch[0] = A.Multiply(Fout[m], tw1[0]); scratch[1] = A.Multiply(Fout[m2], tw2[0]); scratch[2] = A.Multiply(Fout[m3], tw3[0]); scratch[5] = A.Subtract(Fout[0], scratch[1]); Fout[0] = A.Add(Fout[0], scratch[1]); scratch[3] = A.Add(scratch[0], scratch[2]); scratch[4] = A.Subtract(scratch[0], scratch[2]); Fout[m2] = A.Subtract(Fout[0], scratch[3]); tw1 += fstride; tw2 += fstride * 2; tw3 += fstride * 3; Fout[0] = A.Add(Fout[0], scratch[3]); if (Inverse) { Fout[m].r = A.Subtract(scratch[5].r, scratch[4].i); Fout[m].i = A.Add(scratch[5].i, scratch[4].r); Fout[m3].r = A.Add(scratch[5].r, scratch[4].i); Fout[m3].i = A.Subtract(scratch[5].i, scratch[4].r); } else { Fout[m].r = A.Add(scratch[5].r, scratch[4].i); Fout[m].i = A.Subtract(scratch[5].i, scratch[4].r); Fout[m3].r = A.Subtract(scratch[5].r, scratch[4].i); Fout[m3].i = A.Add(scratch[5].i, scratch[4].r); } ++Fout; } while (--k != 0); }
/* * This works by tackling one dimension at a time. * * In effect, * Each stage starts out by reshaping the matrix into a DixSi 2d matrix. * A Di-sized fft is taken of each column, transposing the matrix as it goes. * * Here's a 3-d example: * Take a 2x3x4 matrix, laid out in memory as a contiguous buffer * [ [ [ a b c d ] [ e f g h ] [ i j k l ] ] * [ [ m n o p ] [ q r s t ] [ u v w x ] ] ] * * Stage 0 ( D=2): treat the buffer as a 2x12 matrix * [ [a b ... k l] * [m n ... w x] ] * * FFT each column with size 2. * Transpose the matrix at the same time using kiss_fft_stride. * * [ [ a+m a-m ] * [ b+n b-n] * ... * [ k+w k-w ] * [ l+x l-x ] ] * * Note fft([x y]) == [x+y x-y] * * Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix, * [ [ a+m a-m b+n b-n c+o c-o d+p d-p ] * [ e+q e-q f+r f-r g+s g-s h+t h-t ] * [ i+u i-u j+v j-v k+w k-w l+x l-x ] ] * * And perform FFTs (size=3) on each of the columns as above, transposing * the matrix as it goes. The output of stage 1 is * (Legend: ap = [ a+m e+q i+u ] * am = [ a-m e-q i-u ] ) * * [ [ sum(ap) fft(ap)[0] fft(ap)[1] ] * [ sum(am) fft(am)[0] fft(am)[1] ] * [ sum(bp) fft(bp)[0] fft(bp)[1] ] * [ sum(bm) fft(bm)[0] fft(bm)[1] ] * [ sum(cp) fft(cp)[0] fft(cp)[1] ] * [ sum(cm) fft(cm)[0] fft(cm)[1] ] * [ sum(dp) fft(dp)[0] fft(dp)[1] ] * [ sum(dm) fft(dm)[0] fft(dm)[1] ] ] * * Stage 2 ( D=4) treats this buffer as a 4*6 matrix, * [ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ] * [ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ] * [ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ] * [ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ] * * Then FFTs each column, transposing as it goes. * * The resulting matrix is the 3d FFT of the 2x3x4 input matrix. * * Note as a sanity check that the first element of the final * stage's output (DC term) is * sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] ) * , i.e. the summation of all 24 input elements. * */ public void kiss_fftnd(Array <kiss_fft_cpx <kiss_fft_scalar> > fin, Array <kiss_fft_cpx <kiss_fft_scalar> > fout) { Array <kiss_fft_cpx <kiss_fft_scalar> > bufin = new Array <kiss_fft_cpx <kiss_fft_scalar> >(fin); Array <kiss_fft_cpx <kiss_fft_scalar> > bufout; /*arrange it so the last bufout == fout*/ if ((Ndims & 1) != 0) { bufout = new Array <kiss_fft_cpx <kiss_fft_scalar> >(fout); if (fin == fout) { for (int i = 0; i < Tmpbuf.Length; ++i) { Tmpbuf[i] = new kiss_fft_cpx <kiss_fft_scalar>(fin[i]); } bufin = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Tmpbuf); } } else { bufout = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Tmpbuf); } for (int k = 0; k < Ndims; ++k) { int curdim = Dims[k]; int stride = Dimprod / curdim; for (int i = 0; i < stride; ++i) { States[k].kiss_fft_stride(bufin + i, bufout + i * curdim, stride); } /*toggle back and forth between the two buffers*/ if (bufout == Tmpbuf) { bufout = new Array <kiss_fft_cpx <kiss_fft_scalar> >(fout); bufin = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Tmpbuf); } else { bufout = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Tmpbuf); bufin = new Array <kiss_fft_cpx <kiss_fft_scalar> >(fout); } } }
public void kiss_fft_stride(Array <kiss_fft_cpx <kiss_fft_scalar> > fin, Array <kiss_fft_cpx <kiss_fft_scalar> > fout, int in_stride) { if (fin == fout) { //NOTE: this is not really an in-place FFT algorithm. //It just performs an out-of-place FFT into a temp buffer kiss_fft_cpx <kiss_fft_scalar>[] tmpbuf = new kiss_fft_cpx <kiss_fft_scalar> [Nfft]; kf_work(new Array <kiss_fft_cpx <kiss_fft_scalar> >(tmpbuf), fin, 1, in_stride, new Array <int>(Factors)); for (int i = 0; i < Nfft; ++i) { fout[i] = new kiss_fft_cpx <kiss_fft_scalar>(tmpbuf[i]); } } else { kf_work(fout, fin, 1, in_stride, new Array <int>(Factors)); } }
protected void kf_bfly3(Array <kiss_fft_cpx <kiss_fft_scalar> > Fout, int fstride, int m) { int k = m; int m2 = 2 * m; Array <kiss_fft_cpx <kiss_fft_scalar> > tw1, tw2; kiss_fft_cpx <kiss_fft_scalar>[] scratch = new kiss_fft_cpx <kiss_fft_scalar> [5]; kiss_fft_cpx <kiss_fft_scalar> epi3; epi3 = Twiddles[fstride * m]; tw1 = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); tw2 = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); do { Fout[0] = A.FixDivide(Fout[0], 3); Fout[m] = A.FixDivide(Fout[m], 3); Fout[m2] = A.FixDivide(Fout[m2], 3); scratch[1] = A.Multiply(Fout[m], tw1[0]); scratch[2] = A.Multiply(Fout[m2], tw2[0]); scratch[3] = A.Add(scratch[1], scratch[2]); scratch[0] = A.Subtract(scratch[1], scratch[2]); tw1 += fstride; tw2 += fstride * 2; Fout[m].r = A.Subtract(Fout[0].r, A.Half(scratch[3].r)); Fout[m].i = A.Subtract(Fout[0].i, A.Half(scratch[3].i)); scratch[0] = A.Multiply(scratch[0], epi3.i); Fout[0] = A.Add(Fout[0], scratch[3]); Fout[m2].r = A.Add(Fout[m].r, scratch[0].i); Fout[m2].i = A.Subtract(Fout[m].i, scratch[0].r); Fout[m].r = A.Subtract(Fout[m].r, scratch[0].i); Fout[m].i = A.Add(Fout[m].i, scratch[0].r); ++Fout; } while (--k != 0); }
/* perform the butterfly for one stage of a mixed radix FFT */ protected void kf_bfly_generic(Array <kiss_fft_cpx <kiss_fft_scalar> > Fout, int fstride, int m, int p) { int u, k, q1, q; Array <kiss_fft_cpx <kiss_fft_scalar> > twiddles = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); kiss_fft_cpx <kiss_fft_scalar> t; int Norig = Nfft; kiss_fft_cpx <kiss_fft_scalar>[] scratch = new kiss_fft_cpx <kiss_fft_scalar> [p]; for (u = 0; u < m; ++u) { k = u; for (q1 = 0; q1 < p; ++q1) { scratch[q1] = new kiss_fft_cpx <kiss_fft_scalar>(Fout[k]); scratch[q1] = A.FixDivide(scratch[q1], p); k += m; } k = u; for (q1 = 0; q1 < p; ++q1) { int twidx = 0; Fout[k] = new kiss_fft_cpx <kiss_fft_scalar>(scratch[0]); for (q = 1; q < p; ++q) { twidx += fstride * k; if (twidx >= Norig) { twidx -= Norig; } t = A.Multiply(scratch[q], twiddles[twidx]); Fout[k] = A.Add(Fout[k], t); } k += m; } } }
public kiss_fft_cpx <float> Add(kiss_fft_cpx <float> a, kiss_fft_cpx <float> b) { return(new kiss_fft_cpx <float>(a.r + b.r, a.i + b.i)); }
public kiss_fft_cpx(kiss_fft_cpx <kiss_fft_scalar> other) { r = other.r; i = other.i; }
public kiss_fft_cpx <double> FixDivide(kiss_fft_cpx <double> a, int b) { return(a); }
public kiss_fft_cpx <double> Multiply(kiss_fft_cpx <double> a, double b) { return(new kiss_fft_cpx <double>(a.r * b, a.i * b)); }
public kiss_fft_cpx <float> Multiply(kiss_fft_cpx <float> a, float b) { return(new kiss_fft_cpx <float>(a.r * b, a.i * b)); }
public kiss_fft_cpx <double> Subtract(kiss_fft_cpx <double> a, kiss_fft_cpx <double> b) { return(new kiss_fft_cpx <double>(a.r - b.r, a.i - b.i)); }
public kiss_fft_cpx <double> Add(kiss_fft_cpx <double> a, kiss_fft_cpx <double> b) { return(new kiss_fft_cpx <double>(a.r + b.r, a.i + b.i)); }
public kiss_fft_cpx <float> Subtract(kiss_fft_cpx <float> a, kiss_fft_cpx <float> b) { return(new kiss_fft_cpx <float>(a.r - b.r, a.i - b.i)); }
protected void kf_work(Array <kiss_fft_cpx <kiss_fft_scalar> > Fout, Array <kiss_fft_cpx <kiss_fft_scalar> > f, int fstride, int in_stride, Array <int> factors) { Array <kiss_fft_cpx <kiss_fft_scalar> > Fout_beg = Fout; int p = factors++[0]; /* the radix */ int m = factors++[0]; /* stage's fft length/p */ Array <kiss_fft_cpx <kiss_fft_scalar> > Fout_end = Fout + p * m; // OpenMP /* * // use openmp extensions at the * // top-level (not recursive) * if (fstride == 1 && p <= 5) * { * int k; * * // execute the p different work units in different threads #pragma omp parallel for * for (k = 0; k < p; ++k) * kf_work(Fout + k * m, f + fstride * in_stride * k, fstride * p, in_stride, factors, st); * // all threads have joined by this point * * switch (p) * { * case 2: * kf_bfly2(Fout, fstride, st, m); * break; * case 3: * kf_bfly3(Fout, fstride, st, m); * break; * case 4: * kf_bfly4(Fout, fstride, st, m); * break; * case 5: * kf_bfly5(Fout, fstride, st, m); * break; * default: * kf_bfly_generic(Fout, fstride, st, m, p); * break; * } * return; * } */ if (m == 1) { do { Fout[0] = new kiss_fft_cpx <kiss_fft_scalar>(f[0]); f += fstride * in_stride; } while (++Fout != Fout_end); } else { do { // recursive call: // DFT of size m*p performed by doing // p instances of smaller DFTs of size m, // each one takes a decimated version of the input kf_work(Fout, f, fstride * p, in_stride, factors); f += fstride * in_stride; } while ((Fout += m) != Fout_end); } Fout = Fout_beg; // recombine the p smaller DFTs switch (p) { case 2: kf_bfly2(Fout, fstride, m); break; case 3: kf_bfly3(Fout, fstride, m); break; case 4: kf_bfly4(Fout, fstride, m); break; case 5: kf_bfly5(Fout, fstride, m); break; default: kf_bfly_generic(Fout, fstride, m, p); break; } }
protected void kf_bfly5(Array <kiss_fft_cpx <kiss_fft_scalar> > Fout, int fstride, int m) { Array <kiss_fft_cpx <kiss_fft_scalar> > Fout0, Fout1, Fout2, Fout3, Fout4; int u; kiss_fft_cpx <kiss_fft_scalar>[] scratch = new kiss_fft_cpx <kiss_fft_scalar> [13]; Array <kiss_fft_cpx <kiss_fft_scalar> > twiddles = new Array <kiss_fft_cpx <kiss_fft_scalar> >(Twiddles); Array <kiss_fft_cpx <kiss_fft_scalar> > tw; kiss_fft_cpx <kiss_fft_scalar> ya, yb; ya = twiddles[fstride * m]; yb = twiddles[fstride * 2 * m]; Fout0 = Fout; Fout1 = Fout0 + m; Fout2 = Fout0 + 2 * m; Fout3 = Fout0 + 3 * m; Fout4 = Fout0 + 4 * m; tw = new Array <kiss_fft_cpx <kiss_fft_scalar> >(twiddles); for (u = 0; u < m; ++u) { Fout[0] = A.FixDivide(Fout[0], 5); Fout1[0] = A.FixDivide(Fout1[0], 5); Fout2[0] = A.FixDivide(Fout2[0], 5); Fout3[0] = A.FixDivide(Fout3[0], 5); Fout4[0] = A.FixDivide(Fout4[0], 5); scratch[0] = new kiss_fft_cpx <kiss_fft_scalar>(Fout[0]); scratch[1] = A.Multiply(Fout1[0], tw[u * fstride]); scratch[2] = A.Multiply(Fout2[0], tw[2 * u * fstride]); scratch[3] = A.Multiply(Fout3[0], tw[3 * u * fstride]); scratch[4] = A.Multiply(Fout4[0], tw[4 * u * fstride]); scratch[7] = A.Add(scratch[1], scratch[4]); scratch[10] = A.Subtract(scratch[1], scratch[4]); scratch[8] = A.Add(scratch[2], scratch[3]); scratch[9] = A.Subtract(scratch[2], scratch[3]); Fout[0].r = A.Add(Fout[0].r, A.Add(scratch[7].r, scratch[8].r)); Fout[0].i = A.Add(Fout[0].i, A.Add(scratch[7].i, scratch[8].i)); scratch[5].r = A.Add(scratch[0].r, A.Add(A.Multiply(scratch[7].r, ya.r), A.Multiply(scratch[8].r, yb.r))); scratch[5].i = A.Add(scratch[0].i, A.Add(A.Multiply(scratch[7].i, ya.r), A.Multiply(scratch[8].i, yb.r))); scratch[6].r = A.Add(A.Multiply(scratch[10].i, ya.i), A.Multiply(scratch[9].i, yb.i)); scratch[6].r = A.Negate(A.Add(A.Multiply(scratch[10].r, ya.i), A.Multiply(scratch[9].r, yb.i))); Fout1[0] = A.Subtract(scratch[5], scratch[6]); Fout4[0] = A.Add(scratch[5], scratch[6]); scratch[11].r = A.Add(scratch[0].r, A.Add(A.Multiply(scratch[7].r, yb.r), A.Multiply(scratch[8].r, ya.r))); scratch[11].i = A.Add(scratch[0].i, A.Add(A.Multiply(scratch[7].i, yb.r), A.Multiply(scratch[8].i, ya.r))); scratch[12].r = A.Subtract(A.Multiply(scratch[9].i, ya.i), A.Multiply(scratch[10].i, yb.i)); scratch[12].i = A.Subtract(A.Multiply(scratch[10].r, yb.i), A.Multiply(scratch[9].r, ya.i)); Fout2[0] = A.Add(scratch[11], scratch[12]); Fout3[0] = A.Subtract(scratch[11], scratch[12]); ++Fout0; ++Fout1; ++Fout2; ++Fout3; ++Fout4; } }
public kiss_fft_cpx <float> FixDivide(kiss_fft_cpx <float> a, int b) { return(a); }