-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfft.c
111 lines (97 loc) · 4.24 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
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "constants.h"
#include "complex.h"
#include "fft.h"
void fft_2d(Complex *matrix, int number_channels)
{
// Calculate bit reversed indices
int* bit_reverse_indices = calloc(number_channels, sizeof(int));
calc_bit_reverse_indices(number_channels, bit_reverse_indices);
Complex *reverse_buffer = calloc(number_channels * number_channels, sizeof(Complex));
for(int row = 0; row < number_channels; ++row)
for(int col = 0; col < number_channels; ++col)
{
int row_reverse = bit_reverse_indices[row];
int col_reverse = bit_reverse_indices[col];
int bit_reverse_index = row_reverse * number_channels + col_reverse;
int matrix_index = row * number_channels + col;
reverse_buffer[matrix_index] = matrix[bit_reverse_index];
// printf("%d -> %d\n", matrix_index, bit_reverse_index);
}
memcpy(matrix, reverse_buffer, number_channels * number_channels * sizeof(Complex));
free(reverse_buffer);
free(bit_reverse_indices);
for(int m = 2; m <= number_channels; m *= 2)
{
Complex omegaM = (Complex) {.real = PREC_COS(PI * 2.0 / m), .imag = PREC_SIN(PI * 2.0 / m)};
for(int k = 0; k < number_channels; k += m)
{
for(int l = 0; l < number_channels; l += m)
{
Complex x = (Complex) {.real = 1.0, .imag = 0.0};
for(int i = 0; i < m / 2; i++)
{
Complex y = (Complex) {.real = 1.0, .imag = 0.0};
for(int j = 0; j < m / 2; j++)
{
// Perform 2D butterfly operation in-place at (k+j, l+j)
int in00Index = (k+i) * number_channels + (l+j);
Complex in00 = matrix[in00Index];
int in01Index = (k+i) * number_channels + (l+j+m/2);
Complex in01 = complex_multiply(matrix[in01Index], y);
int in10Index = (k+i+m/2) * number_channels + (l+j);
Complex in10 = complex_multiply(matrix[in10Index], x);
int in11Index = (k+i+m/2) * number_channels + (l+j+m/2);
Complex in11 = complex_multiply(complex_multiply(matrix[in11Index], x), y);
Complex temp00 = complex_add(in00, in01);
Complex temp01 = complex_subtract(in00, in01);
Complex temp10 = complex_add(in10, in11);
Complex temp11 = complex_subtract(in10, in11);
matrix[in00Index] = complex_add(temp00, temp10);
matrix[in01Index] = complex_add(temp01, temp11);
matrix[in10Index] = complex_subtract(temp00, temp10);
matrix[in11Index] = complex_subtract(temp01, temp11);
y = complex_multiply(y, omegaM);
}
x = complex_multiply(x, omegaM);
}
}
}
}
for(int row = 0; row < number_channels; ++row)
for(int col = 0; col < number_channels; ++col)
{
int matrix_index = row * number_channels + col;
PREC reciprocal = 1.0 / (number_channels * number_channels);
matrix[matrix_index] = complex_scale(matrix[matrix_index], reciprocal);
}
}
void calc_bit_reverse_indices(int n, int* indices)
{
for(int i = 0; i < n; ++i)
{
// Calculate index r to which i will be moved
unsigned int i_prime = i;
int r = 0;
for(int j = 1; j < n; j *= 2)
{
int b = i_prime & 1;
r = (r << 1) + b;
i_prime = (i_prime >> 1);
}
indices[i] = r;
}
}
void fft_shift_2d(Complex *matrix, int size)
{
for(int row = 0; row < size; ++row)
for(int col = 0; col < size; ++col)
{
int matrix_index = row * size + col;
PREC scalar = 1 - 2 * ((row + col) & 1);
matrix[matrix_index] = complex_scale(matrix[matrix_index], scalar);
}
}