Skip to content

Commit 4dbebd8

Browse files
committed
Tool for generating RFFT twiddle tables
Workaround for ARM-software/CMSIS-DSP#25 A quick spot check of the output against CMSIS-DSP realCoefAQ15 / realCoefBQ15 looks OK
1 parent 1464877 commit 4dbebd8

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

Misc/fft_table_generate.c

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
2+
/*
3+
FFT twiddle table generator for CMSIS-DSP
4+
5+
This is a workaround for CMSIS-DSP not having different tables for different lengths for q15/q31 RFFT.
6+
Meaning that it always always uses a table 4096 long FFT - which takes 32 kB of program memory.
7+
This wastes a lot of program space for short FFTs: 64/128/256/512 etc.
8+
9+
Ref: https://github.com/ARM-software/CMSIS-DSP/issues/25
10+
11+
Usage:
12+
13+
gcc -Wall -o fft_table_generate Misc/fft_table_generate.c -lm
14+
./fft_table_generate > User/fft_tables.h
15+
*/
16+
17+
18+
19+
#include <stdlib.h>
20+
#include <string.h>
21+
#include <stdio.h>
22+
#include <stdbool.h>
23+
#include <stdint.h>
24+
#include <math.h>
25+
26+
/*
27+
Original CMSIS-DSP documentation on generating the tables
28+
29+
@par
30+
Generation fixed-point realCoefAQ15 array in Q15 format:
31+
@par
32+
n = 4096
33+
<pre>for (i = 0; i < n; i++)
34+
{
35+
pATable[2 * i] = 0.5 * ( 1.0 - sin (2 * PI / (double) (2 * n) * (double) i));
36+
pATable[2 * i + 1] = 0.5 * (-1.0 * cos (2 * PI / (double) (2 * n) * (double) i));
37+
}</pre>
38+
@par
39+
Convert to fixed point Q15 format
40+
round(pATable[i] * pow(2, 15))
41+
42+
43+
@par
44+
Generation of real_CoefB array:
45+
@par
46+
n = 4096
47+
<pre>for (i = 0; i < n; i++)
48+
{
49+
pBTable[2 * i] = 0.5 * (1.0 + sin (2 * PI / (double) (2 * n) * (double) i));
50+
pBTable[2 * i + 1] = 0.5 * (1.0 * cos (2 * PI / (double) (2 * n) * (double) i));
51+
}</pre>
52+
@par
53+
Convert to fixed point Q15 format
54+
round(pBTable[i] * pow(2, 15))
55+
*/
56+
57+
int
58+
fill_table_a(double *table, int table_length, int fft_length)
59+
{
60+
if (table_length != 2*fft_length) {
61+
return -1;
62+
}
63+
64+
const int n = fft_length;
65+
for (int i = 0; i < n; i++) {
66+
table[2 * i] = 0.5 * ( 1.0 - sin (2 * M_PI / (double) (2 * n) * (double) i));
67+
table[2 * i + 1] = 0.5 * (-1.0 * cos (2 * M_PI / (double) (2 * n) * (double) i));
68+
}
69+
return 0;
70+
}
71+
72+
int
73+
fill_table_b(double *table, int table_length, int fft_length)
74+
{
75+
if (table_length != 2*fft_length) {
76+
return -1;
77+
}
78+
79+
const int n = fft_length;
80+
for (int i = 0; i < n; i++) {
81+
table[2 * i] = 0.5 * (1.0 + sin (2 * M_PI / (double) (2 * n) * (double) i));
82+
table[2 * i + 1] = 0.5 * (1.0 * cos (2 * M_PI / (double) (2 * n) * (double) i));
83+
}
84+
return 0;
85+
}
86+
87+
int
88+
print_table(const double *table, int table_length,
89+
const int fft_length,
90+
const char *prefix,
91+
const char *specifiers,
92+
const char *ctype,
93+
const int fixed_bits,
94+
const int width
95+
)
96+
{
97+
if (table_length != 2*fft_length) {
98+
return -1;
99+
}
100+
/*
101+
Prints table out as a C variable definition:
102+
103+
const q15_t __ALIGNED(4) realCoefBQ15[8192] = {
104+
(q15_t)0x4000, ...
105+
};
106+
*/
107+
108+
printf("const %s %s %s%d = {\n", ctype, specifiers, prefix, fft_length);
109+
110+
for (int i=0; i<table_length; i++) {
111+
const double value = table[i];
112+
const uint16_t fixed = round(value * pow(2, fixed_bits));
113+
const bool is_end = (i == table_length-1);
114+
const bool is_column_end = ((i+1) % width == 0);
115+
printf("(%s)0x%04x", ctype, fixed);
116+
if (!is_end) {
117+
printf(", ");
118+
}
119+
if (is_column_end) {
120+
printf("\n");
121+
}
122+
}
123+
124+
printf("};\n");
125+
126+
return 0;
127+
}
128+
129+
int main() {
130+
131+
// TODO: support FFT length as input
132+
// FIXME: q31 will probably need minor fixes
133+
const int fft_length = 8192/2;
134+
const int fixedpoint_bits = 15;
135+
const char *ctype = "q15_t";
136+
const char *specifiers = "__ALIGNED(4)";
137+
const int print_width = 8;
138+
139+
const int table_length = fft_length * 2;
140+
double *table = (double *)malloc(sizeof(double)*table_length);
141+
142+
fprintf(stderr, "init\n");
143+
144+
// A coefficients
145+
fill_table_a(table, table_length, fft_length);
146+
print_table(table, table_length, fft_length,
147+
"fft_table_q15_a_", specifiers, ctype, fixedpoint_bits, print_width);
148+
149+
// B coefficients
150+
fill_table_b(table, table_length, fft_length);
151+
print_table(table, table_length, fft_length,
152+
"fft_table_q15_b_", specifiers, ctype, fixedpoint_bits, print_width);
153+
154+
fprintf(stderr, "done\n");
155+
156+
// FIXME: check against CMSIS-DSP for FFT length = 8192
157+
}
158+
159+

0 commit comments

Comments
 (0)