Ich habe eine 4-Punkt-Radix-4-FFT implementiert und festgestellt, dass ich einige Manipulationen an den Ausgangstermen vornehmen muss, damit sie mit einer dft übereinstimmen.
Mein Code ist eine ziemlich direkte Implementierung der Matrixformulierung, daher ist mir nicht klar, wo das Problem liegt
// |
// radix-4 butterfly matrix form | complex multiplication
// |
// +- -+ +- -+ | a+ib
// X[0] = | 1 1 1 1 | |x[0]| | * c+id
// X[1] = | 1 -i -1 i | |x[1]| | -------
// X[2] = | 1 -1 1 -1 | |x[2]| | ac + ibc
// X[3] = | 1 i -1 -i | |x[3]| | iad - bd
// +- -+ +- -+ | ------------------
// | (ac-bd) + i(bc+ad)
// |
Kann jemand erkennen, wo ich falsch gelaufen bin?
Vielen Dank,
-David
typedef double fp; // base floating-point type
// naiive N-point DFT implementation as reference to check fft implementation against
//
void dft(int inv, struct cfp *x, struct cfp *y, int N) {
long int i, j;
struct cfp w;
fp ang;
for(i=0; i<N; i++) { // do N-point FFT/IFFT
y[i].r = y[i].i = 0;
if (inv) ang = 2*PI*(fp)i/(fp)N;
else ang = -2*PI*(fp)i/(fp)N;
for (j=0; j<N; j++) {
w.r = cos(j*ang);
w.i = sin(j*ang);
y[i].r += (x[j].r * w.r - x[j].i * w.i);
y[i].i += (x[j].r * w.i + x[j].i * w.r);
}
}
// scale output in the case of an IFFT
if (inv) {
for (i=0; i<N; i++) {
y[i].r = y[i].r/(fp)N;
y[i].i = y[i].i/(fp)N;
}
}
} // dft()
void r4fft4(int inv, int reorder, struct cfp *x, struct cfp *y) {
struct cfp x1[4], w[4];
fp ang, temp;
int i;
// |
// radix-4 butterfly matrix form | complex multiplication
// |
// +- -+ +- -+ | a+ib
// y[0] = | 1 1 1 1 | |x[0]| | * c+id
// y[1] = | 1 -i -1 i | |x[1]| | -------
// y[2] = | 1 -1 1 -1 | |x[2]| | ac + ibc
// y[3] = | 1 i -1 -i | |x[3]| | iad - bd
// +- -+ +- -+ | ------------------
// | (ac-bd) + i(bc+ad)
// |
if (inv) ang = 2*PI/(fp)4; // invert sign for IFFT
else ang = -2*PI/(fp)4;
//
w[1].r = cos(ang*1); w[1].i = sin(ang*1); // twiddle1 = exp(-2*pi/4 * 1);
w[2].r = cos(ang*2); w[2].i = sin(ang*2); // twiddle2 = exp(-2*pi/4 * 2);
w[3].r = cos(ang*3); w[3].i = sin(ang*3); // twiddle3 = exp(-2*pi/4 * 3);
// *1 *1 *1 *1
y[0].r = x[0].r + x[1].r + x[2].r + x[3].r;
y[0].i = x[0].i + x[1].i + x[2].i + x[3].i;
// *1 *-i *-1 *i
x1[1].r = x[0].r + x[1].i - x[2].r - x[3].i;
x1[1].i = x[0].i - x[1].r - x[2].i + x[3].r;
// *1 *-1 *1 *-1
x1[2].r = x[0].r - x[1].r + x[2].r - x[3].r;
x1[2].i = x[0].i - x[1].i + x[2].i - x[3].i;
// *1 *i *-1 *-i
x1[3].r = x[0].r - x[1].i - x[2].r + x[3].i;
x1[3].i = x[0].i + x[1].r - x[2].i - x[3].r;
//
y[1].r = x1[1].r*w[1].r - x1[1].i*w[1].i; // scale radix-4 output
y[1].i = x1[1].i*w[1].r + x1[1].r*w[1].i;
//
y[2].r = x1[2].r*w[2].r - x1[2].i*w[2].i; // scale radix-4 output
y[2].i = x1[2].i*w[2].r + x1[2].r*w[2].i;
//
y[3].r = x1[3].r*w[3].r - x1[3].i*w[3].i; // scale radix-4 output
y[3].i = x1[3].i*w[3].r + x1[3].r*w[3].i;
// reorder output stage ... mystery as to why I need this
if (reorder) {
temp = y[1].r;
y[1].r = -1*y[1].i;
y[1].i = temp;
//
y[2].r = -1*y[2].r;
//
temp = y[3].r;
y[3].r = y[3].i;
y[3].i = -1*temp;
}
// scale output for inverse FFT
if (inv) {
for (i=0; i<4; i++) { // scale output by 1/N for IFFT
y[i].r = y[i].r/(fp)4;
y[i].i = y[i].i/(fp)4;
}
}
} // r4fft4()