写了一个 FFT 快速傅里叶变换
网上找了半天都找不到合适的代码,要么是太重量级了,比如 FFTW,要么就是不可用,写得垃圾。所以自己写了一个。
程序代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
void *fft_init (int len);
void fft_free (void *c);
void fft_execute(void *c, float *in, float *out);
typedef struct {
int N;
float *W;
float *T;
int *order;
} FFT_CONTEXT;
// r = c1 + c2
static inline void complex_add(float *r, float *c1, float *c2)
{
r[0] = c1[0] + c2[0];
r[1] = c1[1] + c2[1];
}
// r = c1 - c2
static inline void complex_sub(float *r, float *c1, float *c2)
{
r[0] = c1[0] - c2[0];
r[1] = c1[1] - c2[1];
}
// r = c1 * c2
static inline void complex_mul(float *r, float *c1, float *c2)
{
r[0] = c1[0] * c2[0] - c1[1] * c2[1];
r[1] = c1[1] * c2[0] + c1[0] * c2[1];
}
static int reverse_bits(int n)
{
n = ((n & 0xAAAAAAAA) >> 1 ) | ((n & 0x55555555) << 1 );
n = ((n & 0xCCCCCCCC) >> 2 ) | ((n & 0x33333333) << 2 );
n = ((n & 0xF0F0F0F0) >> 4 ) | ((n & 0x0F0F0F0F) << 4 );
n = ((n & 0xFF00FF00) >> 8 ) | ((n & 0x00FF00FF) << 8 );
n = ((n & 0xFFFF0000) >> 16) | ((n & 0x0000FFFF) << 16);
return n;
}
static void fft_execute_internal(FFT_CONTEXT *ctxt, float *data, int n, int w)
{
int i;
for (i=0; i<n/2; i++) {
// C = (A + B)
// D = (A - B) * W
float A[2] = { data[(0 + i) * 2 + 0], data[(0 + i) * 2 + 1] };
float B[2] = { data[(n/2 + i) * 2 + 0], data[(n/2 + i) * 2 + 1] };
float *C = &(data[(0 + i) * 2]);
float *D = &(data[(n/2 + i) * 2]);
float *W = &(ctxt->W[i*w*2]);
float T[2];
complex_add(C, A, B);
complex_sub(T, A, B);
complex_mul(D, T, W);
}
n /= 2;
w *= 2;
if (n > 1) {
fft_execute_internal(ctxt, data + 0 , n, w);
fft_execute_internal(ctxt, data + n * 2, n, w);
}
}
void *fft_init(int n)
{
int i;
FFT_CONTEXT *ctxt = (FFT_CONTEXT*)malloc(sizeof(FFT_CONTEXT));
if (!ctxt) return NULL;
ctxt->N = n;
ctxt->W = (float*)malloc(n * sizeof(float) * 1);
ctxt->T = (float*)malloc(n * sizeof(float) * 2);
ctxt->order = (int *)malloc(n * sizeof(int ) * 1);
if (!ctxt->W || !ctxt->T || !ctxt->order) {
fft_free(ctxt);
return NULL;
}
for (i=0; i<ctxt->N/2; i++) {
ctxt->W[i * 2 + 0] = cos(2 * M_PI * i / ctxt->N);
ctxt->W[i * 2 + 1] =-sin(2 * M_PI * i / ctxt->N);
}
int shift = (int)(32 - log(n)/log(2));
for (i=0; i<ctxt->N; i++) {
ctxt->order[i] = (unsigned)reverse_bits(i) >> shift;
}
return ctxt;
}
void fft_free(void *c)
{
FFT_CONTEXT *ctxt = (FFT_CONTEXT*)c;
if (!ctxt) return;
if (ctxt->W ) free(ctxt->W );
if (ctxt->T ) free(ctxt->T );
if (ctxt->order) free(ctxt->order);
free(ctxt);
}
void fft_execute(void *c, float *in, float *out)
{
int i;
FFT_CONTEXT *ctxt = (FFT_CONTEXT*)c;
memcpy(ctxt->T, in, sizeof(float) * 2 * ctxt->N);
fft_execute_internal(ctxt, ctxt->T, ctxt->N, 1);
for (i=0; i<ctxt->N; i++) {
out[ctxt->order[i] * 2 + 0] = ctxt->T[i * 2 + 0];
out[ctxt->order[i] * 2 + 1] = ctxt->T[i * 2 + 1];
}
}
#if 1
static void dft(float *in, float *out, int n)
{
int i, j;
float tmp[2];
float *w = (float*)malloc(n*2*sizeof(float));
for (i=0; i<n; i++) {
w[i * 2 + 0] = cos(2 * M_PI * i / n);
w[i * 2 + 1] =-sin(2 * M_PI * i / n);
}
for (j=0; j<n; j++) {
out[0] = out[1] = 0;
for (i=0; i<n; i++) {
// out += in[j] * w[(j*i)%n]
complex_mul(tmp, &in[i * 2], &w[((i * j) % n) * 2]);
complex_add(out, out, tmp);
}
out += 2;
}
free(w);
}
int main(void)
{
int i;
float in [16 * 2] = { 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
float out[16 * 2];
void *fft = NULL;
printf("\nin:\n");
for (i=0; i<16; i++) {
printf("( %9.6f, %9.6f )\n", in [i*2+0], in [i*2+1]);
}
printf("\n");
fft = fft_init(16);
fft_execute(fft, in, out);
fft_free(fft);
printf("\nout:\n");
for (i=0; i<16; i++) {
printf("( %9.6f, %9.6f )\n", out[i*2+0], out[i*2+1]);
}
printf("\n");
dft(in, out, 16);
printf("\nout:\n");
for (i=0; i<16; i++) {
printf("( %9.6f, %9.6f )\n", out[i*2+0], out[i*2+1]);
}
printf("\n");
}
#endif
[此贴子已经被作者于2016-5-26 16:09编辑过]








