Saya menerapkan 4-point radix-4 FFT dan menemukan bahwa saya perlu melakukan beberapa manipulasi persyaratan output untuk mendapatkannya agar cocok dengan DFT.
Kode saya adalah implementasi langsung dari formulasi matriks jadi saya tidak jelas tentang apa masalahnya
// |
// 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)
// |
Adakah yang bisa melihat kesalahan saya?
Terima kasih,
-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()
Jawaban:
Saya baru saja porting radix-4 DIF fft dari kode S. Burrus Fortran ke Jawa. Sebenarnya itu tidak memiliki beberapa optimasi, pertama-tama faktor twiddle didorong oleh tabel (faktor dosa dan cos harus dihitung sebelumnya). Ini akan mempercepat fft lebih banyak (mungkin 50%). Saya harus sedikit meretas untuk itu tetapi jika seseorang memiliki jawaban yang benar saya akan sangat senang dan berterima kasih. Saya akan memposting kode yang dioptimalkan secepatnya saya harap mungkin dengan beberapa tes kecepatan vs radix-2 algoritma.
Terlebih lagi, perkalian dengan 1 dan sqrt (-1) tidak dihapus. Menghapusnya akan mempercepat sedikit lagi. Tapi secara keseluruhan IMHO radix-4 tampaknya tidak lebih dari 25% lebih cepat daripada radix-2, jadi saya tidak tahu apakah rasio kecepatan / kompleksitas benar-benar bernilai. Ingatlah bahwa perpustakaan yang sangat dioptimalkan seperti FFTW sebagian besar tersedia dan digunakan, sehingga upaya ini bisa jadi hanya 'pengalihan' pribadi!
Ini adalah kode java. Porting ke C, C ++ atau C # seharusnya sangat mudah.
Berikut adalah kode asli Radix-4 DIF FORTRAN oleh Sidney Burrus:
Radix-4, DIF, One Butterfly FFT
sumber
Pertama, 'kupu-kupu radix-4' Anda seharusnya adalah DFT 4 poin, bukan FFT. Ini memiliki 16 operasi kompleks (yaitu: N kuadrat). FFT 4 poin biasanya hanya memiliki Nlog (basis 2) N (= 8 untuk N = 4). Kedua, Anda memiliki beberapa faktor w [] .r dan w [] .i 'skala' yang tidak termasuk. Mungkin Anda mendapatkannya dari kupu-kupu radix-4 yang ditampilkan dalam grafik yang lebih besar. Seekor kupu-kupu seperti itu akan memiliki beberapa rumbai interstage ditambahkan ke dalamnya, tetapi mereka sebenarnya bukan bagian dari kupu-kupu. Sebuah 4 poin FFT hanya memiliki kupu-kupu internal -j ketika dirancang untuk FFT eksponen negatif.
Daripada mencoba memperbaiki kode Anda, lebih mudah untuk menulis sendiri, seperti yang ditunjukkan di bawah ini (kompilator DevC ++; output ditambahkan di akhir kode):
Pertama, data input (4 nyata, 4 imajiner) dicetak. Kemudian DFT 4 poin diambil. Hasilnya (yr [] dan yi [] plus amp / fase) dicetak. Karena r [] dan i [] data asli tidak ditimpa ketika melakukan DFT, input tersebut digunakan kembali sebagai input ke 4 titik FFT. Perhatikan bahwa yang terakhir memiliki lebih sedikit operasi +/- daripada DFT.
Kode untuk FFT tidak terlalu elegan dan juga tidak efisien - ada banyak cara untuk melakukan kupu-kupu. Kode di atas sesuai dengan empat kupu-kupu radix-2 yang ditunjukkan dalam buku Rabiner dan Gold "Teori dan Aplikasi Pemrosesan Sinyal Digital" (hlm. 580, Gambar 10.9), dengan twiddle yang dimodifikasi untuk mencerminkan eksponen negatif (yang digunakan untuk angka dalam buku itu positif). Perhatikan bahwa hanya ada satu twiddle dari -j dalam kode, dan ini tidak memerlukan multiply (ini adalah perubahan swap / tanda).
Setelah FFT, hasilnya dicetak. Mereka sama dengan DFT
Dan akhirnya, hasil skala dari FFT digunakan sebagai input ke FFT terbalik. Ini dicapai melalui metode 'pertukaran' atau 'membalikkan daftar' (yaitu: jika FFT (r, i) adalah FFT maju, maka FFT (i, r) adalah kebalikan - asalkan, tentu saja, bahwa FFT adalah mampu menangani input / output yang kompleks - dengan kata lain - tidak ada rutinitas 'nyata saja', yang biasanya menganggap bahwa input imajiner adalah nol). Metode ini dijelaskan hampir 25 tahun yang lalu di:
P. Duhamel, B. Piron, JM Etcheto, "Pada Komputasi DFT Invers," Transaksi IEEE pada Akustik, Pidato dan Pemrosesan Sinyal, vol. 36, Februari 1988, hlm. 285-286.
Hasil kebalikannya kemudian dicetak. Ini sama dengan data input asli.
sumber