FFT now uses a lookup-table for sin and cos values
On x86, this makes the program approx. 5 times faster.
This commit is contained in:
parent
9f196ba5e2
commit
f6173965f5
4
Makefile
4
Makefile
|
@ -3,8 +3,8 @@ CFLAGS+=-O3 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -
|
||||||
LIBS=-lm -lpthread -lrt
|
LIBS=-lm -lpthread -lrt
|
||||||
|
|
||||||
TARGET=musiclight2
|
TARGET=musiclight2
|
||||||
SOURCE=main.c fft.c utils.c ws2801.c
|
SOURCE=main.c fft.c utils.c ws2801.c lut.c
|
||||||
DEPS=config.h fft.h utils.h ws2801.h
|
DEPS=config.h fft.h utils.h ws2801.h lut.h
|
||||||
|
|
||||||
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
||||||
|
|
||||||
|
|
2
config.h
2
config.h
|
@ -19,7 +19,7 @@
|
||||||
#define PORT 2703
|
#define PORT 2703
|
||||||
|
|
||||||
// FFT transformation parameters
|
// FFT transformation parameters
|
||||||
#define FFT_EXPONENT 10
|
#define FFT_EXPONENT 10 // ATTENTION: when you change this, run gen_lut.py with this value as argument
|
||||||
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
|
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define DATALEN (BLOCK_LEN / 2)
|
#define DATALEN (BLOCK_LEN / 2)
|
||||||
|
|
12
fft.c
12
fft.c
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "lut.h"
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
|
|
||||||
value_type hanning_buffer[BLOCK_LEN];
|
value_type hanning_buffer[BLOCK_LEN];
|
||||||
|
@ -68,7 +69,6 @@ void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm)
|
||||||
int left, right;
|
int left, right;
|
||||||
|
|
||||||
value_type x_left_re, x_left_im, x_right_re, x_right_im;
|
value_type x_left_re, x_left_im, x_right_re, x_right_im;
|
||||||
value_type param;
|
|
||||||
value_type sinval, cosval;
|
value_type sinval, cosval;
|
||||||
|
|
||||||
// re-arrange the input array according to the lookup table
|
// re-arrange the input array according to the lookup table
|
||||||
|
@ -105,12 +105,10 @@ void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm)
|
||||||
x_right_re = resultRe[right];
|
x_right_re = resultRe[right];
|
||||||
x_right_im = resultIm[right];
|
x_right_im = resultIm[right];
|
||||||
|
|
||||||
// precalculate the parameter for sin and cos
|
// use lookup table to get sinus and cosinus values for param
|
||||||
param = -M_PI * element / (1 << layer);
|
//param = -M_PI * element / (1 << layer);
|
||||||
|
sinval = lookup_sin(layer, element);
|
||||||
// precalculate sinus and cosinus values for param
|
cosval = lookup_cos(layer, element);
|
||||||
sinval = sin(param);
|
|
||||||
cosval = cos(param);
|
|
||||||
|
|
||||||
// combine the values according to a butterfly diagram
|
// combine the values according to a butterfly diagram
|
||||||
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
|
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
|
||||||
|
|
68
gen_lut.py
Executable file
68
gen_lut.py
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from math import *
|
||||||
|
|
||||||
|
preamble = """// This file was auto-generated using gen_lut.py
|
||||||
|
|
||||||
|
#include "lut.h"
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
postamble = """
|
||||||
|
|
||||||
|
value_type lookup_sin(int layer, int element) {
|
||||||
|
return sin_lut[layer][element];
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type lookup_cos(int layer, int element) {
|
||||||
|
return cos_lut[layer][element];
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Argument required: FFT_EXPONENT")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
fft_exponent = int(sys.argv[1])
|
||||||
|
|
||||||
|
with open("lut.c", "w") as ofile:
|
||||||
|
ofile.write(preamble)
|
||||||
|
|
||||||
|
# generate the sin() lookup table
|
||||||
|
for layer in range(1, fft_exponent+1):
|
||||||
|
num_elements = (1 << layer)
|
||||||
|
ofile.write("value_type sin_lut%i[%i] = {" % (layer, num_elements))
|
||||||
|
|
||||||
|
ofile.write("0")
|
||||||
|
|
||||||
|
for element in range(1, num_elements):
|
||||||
|
ofile.write(", %.10f" % sin(-pi * element / num_elements));
|
||||||
|
|
||||||
|
ofile.write("};\n\n")
|
||||||
|
|
||||||
|
ofile.write("value_type *sin_lut[%i] = {sin_lut1" % fft_exponent);
|
||||||
|
|
||||||
|
for i in range(2, fft_exponent+1):
|
||||||
|
ofile.write(", sin_lut" + str(i));
|
||||||
|
ofile.write("};\n");
|
||||||
|
|
||||||
|
# generate the cos() lookup table
|
||||||
|
for layer in range(1, fft_exponent+1):
|
||||||
|
num_elements = (1 << layer)
|
||||||
|
ofile.write("value_type cos_lut%i[%i] = {" % (layer, num_elements))
|
||||||
|
|
||||||
|
ofile.write("0")
|
||||||
|
|
||||||
|
for element in range(1, num_elements):
|
||||||
|
ofile.write(", %.10f" % cos(-pi * element / num_elements));
|
||||||
|
|
||||||
|
ofile.write("};\n\n")
|
||||||
|
|
||||||
|
ofile.write("value_type *cos_lut[%i] = {cos_lut1" % fft_exponent);
|
||||||
|
|
||||||
|
for i in range(2, fft_exponent+1):
|
||||||
|
ofile.write(", cos_lut" + str(i));
|
||||||
|
ofile.write("};\n");
|
||||||
|
|
||||||
|
ofile.write(postamble)
|
Loading…
Reference in a new issue