Eu implementei um radix-4 FFT de 4 pontos e descobri que precisava fazer alguma manipulação dos termos de saída para que ele correspondesse a um dft.
Meu código é uma implementação bastante direta da formulação matricial, então não sei ao certo qual é o problema
// |
// 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)
// |
Alguém pode identificar onde eu errei?
Obrigado,
-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()