forked from jtfell/c-fft
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fft.c
147 lines (125 loc) · 4.04 KB
/
fft.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "fft.h"
#include <stdlib.h>
#define PI 3.1415926535897932384626434
complex* DFT_naive(complex* x, int N) {
complex* X = (complex*) malloc(sizeof(struct complex_t) * N);
int k, n;
for(k = 0; k < N; k++) {
X[k].re = 0.0;
X[k].im = 0.0;
for(n = 0; n < N; n++) {
X[k] = add(X[k], multiply(x[n], conv_from_polar(1, -2*PI*n*k/N)));
}
}
return X;
}
/** Implements the Good-Thomas FFT algorithm.
*
* @expects: N1 and N2 must be relatively prime
* @expects: N1*N2 = N
*/
complex* FFT_GoodThomas(complex* input, int N, int N1, int N2) {
int k1, k2, z;
/* Allocate columnwise matrix */
complex** columns = (complex**) malloc(sizeof(struct complex_t*) * N1);
for(k1 = 0; k1 < N1; k1++) {
columns[k1] = (complex*) malloc(sizeof(struct complex_t) * N2);
}
/* Allocate rowwise matrix */
complex** rows = (complex**) malloc(sizeof(struct complex_t*) * N2);
for(k2 = 0; k2 < N2; k2++) {
rows[k2] = (complex*) malloc(sizeof(struct complex_t) * N1);
}
/* Reshape input into N1 columns (Using Good-Thomas Indexing) */
for(z = 0; z < 30; z++) {
k1 = z % N1;
k2 = z % N2;
columns[k1][k2] = input[z];
}
/* Compute N1 DFTs of length N2 using naive method */
for (k1 = 0; k1 < N1; k1++) {
columns[k1] = DFT_naive(columns[k1], N2);
}
/* Transpose */
for(k1 = 0; k1 < N1; k1++) {
for (k2 = 0; k2 < N2; k2++) {
rows[k2][k1] = columns[k1][k2];
}
}
/* Compute N2 DFTs of length N1 using naive method */
for (k2 = 0; k2 < N2; k2++) {
rows[k2] = DFT_naive(rows[k2], N1);
}
/* Flatten into single output (Using chinese remainder theorem) */
complex* output = (complex*) malloc(sizeof(struct complex_t) * N);
for(k1 = 0; k1 < N1; k1++) {
for (k2 = 0; k2 < N2; k2++) {
z = N1*k2 + N2*k1;
output[z%N] = rows[k2][k1];
}
}
/* Free all alocated memory except output and input arrays */
for(k1 = 0; k1 < N1; k1++) {
free(columns[k1]);
}
for(k2 = 0; k2 < N2; k2++) {
free(rows[k2]);
}
free(columns);
free(rows);
return output;
}
/** Implements the Cooley-Tukey FFT algorithm.
*
* @expects: N1*N2 = N
*/
complex* FFT_CooleyTukey(complex* input, int N, int N1, int N2) {
int k1, k2;
/* Allocate columnwise matrix */
complex** columns = (complex**) malloc(sizeof(struct complex_t*) * N1);
for(k1 = 0; k1 < N1; k1++) {
columns[k1] = (complex*) malloc(sizeof(struct complex_t) * N2);
}
/* Allocate rowwise matrix */
complex** rows = (complex**) malloc(sizeof(struct complex_t*) * N2);
for(k2 = 0; k2 < N2; k2++) {
rows[k2] = (complex*) malloc(sizeof(struct complex_t) * N1);
}
/* Reshape input into N1 columns */
for (k1 = 0; k1 < N1; k1++) {
for(k2 = 0; k2 < N2; k2++) {
columns[k1][k2] = input[N1*k2 + k1];
}
}
/* Compute N1 DFTs of length N2 using naive method */
for (k1 = 0; k1 < N1; k1++) {
columns[k1] = DFT_naive(columns[k1], N2);
}
/* Multiply by the twiddle factors ( e^(-2*pi*j/N * k1*k2)) and transpose */
for(k1 = 0; k1 < N1; k1++) {
for (k2 = 0; k2 < N2; k2++) {
rows[k2][k1] = multiply(conv_from_polar(1, -2.0*PI*k1*k2/N), columns[k1][k2]);
}
}
/* Compute N2 DFTs of length N1 using naive method */
for (k2 = 0; k2 < N2; k2++) {
rows[k2] = DFT_naive(rows[k2], N1);
}
/* Flatten into single output */
complex* output = (complex*) malloc(sizeof(struct complex_t) * N);
for(k1 = 0; k1 < N1; k1++) {
for (k2 = 0; k2 < N2; k2++) {
output[N2*k1 + k2] = rows[k2][k1];
}
}
/* Free all alocated memory except output and input arrays */
for(k1 = 0; k1 < N1; k1++) {
free(columns[k1]);
}
for(k2 = 0; k2 < N2; k2++) {
free(rows[k2]);
}
free(columns);
free(rows);
return output;
}