花了2个晚上, 总算把FFT从MP3编码器中提取出来并在keil上跑通, 主要还是对keil和C51不熟, 走了不少弯路
1 开始怎么都跑不过去, 总是报
MAIN.C(55): error C249: 'DATA': SEGMENT TOO LARGE
突然想起不是大模式编译
2 在fft函数内想printf出来一些数据看看, 发现总是报
FFT.C(101): warning C206: 'printf': missing function-prototype
而在main函数中则没错, 并不是忘记#include
3 找时间烧到51里头去看看
// -------------------------------- main.c --------------------------------
/*
void fft(float x_real[BLKSIZE],
float x_imag[BLKSIZE],
float energy[BLKSIZE],
float phi[BLKSIZE],
int N);
*/
#include
#include
#include
#include "fft.h"
static short int i;
static float wsamp_r[BLKSIZE_S]; //={0, 0, 0, 0, 0, 0, 0, 0};
static float wsamp_i[BLKSIZE_S];//;={0, 0, 0, 0, 0, 0, 0, 0};
static float energy[BLKSIZE_S];//={0, 0, 0, 0, 0, 0, 0, 0};
static float phi[BLKSIZE_S]; //={0, 0, 0, 0, 0, 0, 0, 0};
//char code dx516[3] _at_ 0x003b;//这是为了仿真设置的
void main( void )
{
SCON = 0x52;
TMOD = 0x20;
TH1 = 0xf3;
TR1 = 1;
// fft(float x_real[BLKSIZE], float x_imag[BLKSIZE], float energy[BLKSIZE], float phi[BLKSIZE], int N);
// 566
// fft( wsamp_r, wsamp_i, energy, phi, 1024 );
// 620
// short FFT, 576个样本点, 连续3次FFT(192*3)
// fft( wsamp_r, wsamp_i, &energy_s[sblock][0], &phi_s[sblock][0], 256 );
// 造假数据
for(i=0; i
{
wsamp_r[i] = (float)i;
wsamp_i[i] = 0.0; //(float)(BLKSIZE_S-i);
energy[i] = 0.0;
phi[i] = 0.0;
}
fft( wsamp_r, wsamp_i, energy, phi, BLKSIZE_S );
for(i=0; i
{
printf( "B %d---r=%f, i=%f, e=%f, p=%f/n", i, wsamp_r[i], wsamp_i[i], energy[i], phi[i] );
}
while( 1 );
}
// -------------------------------- fft.h --------------------------------
//#include
//#include
//#include
//#include
//#include
// 注意到pow(2,8)=256. 这个是短窗FFT使用的.
#define BLKSIZE_S 256
#define LOGBLKSIZE_S 8
//
#define BLKSIZE 1024 //
// 定义PI, PI4=PI/4, PI64=PI/64
#define PI 3.14159265358979
//#define PI4 PI/4
//#define PI64 PI/64
// sqrt(2)
//#define SQRT2 1.41421356237
//
#define LOGBLKSIZE 10
//
//#define LN_TO_LOG10 0.2302585093
void fft(float x_real[BLKSIZE],
float x_imag[BLKSIZE],
float energy[BLKSIZE],
float phi[BLKSIZE],
int N);
// -------------------------------- fft.c --------------------------------
//#include
#include
#include
#include
#include "fft.h"
/**
* N 点 FFT(原位FFT).
* 在MP3编码中, 有两种FFT, 一种是长窗FFT, 就是1024点FFT. 一种是短窗FFT, 就是256点FFT.
*
* x_real[index] 输入的实部, 也是输出的实部
* x_imag[index] 输入的虚部, 也是输出的虚部
* energy[index] 能量, 输出的x_real[index]*x_real[index]+x_imag[index]*x_imag[index]
* 能量的平方.
* 经过FFT后会得到一个频域输出, 谓之out_real, out_imag.
* energy[i]实际是out_real[i]*out_real[i] + out_imag[i]*out_imag[i];
* 那么可知对energy[i]开平方得到r[i]的就是以out_real[i]和out_imag[i]为直角边的
* 斜边, 或者r[i]称为半径.
* phi[index] 相位. 即real[index], imag[index]的夹角.
* N N点FFT
*/
void fft(float x_real[BLKSIZE],
float x_imag[BLKSIZE],
float energy[BLKSIZE],
float phi[BLKSIZE],
int N)
{
// M 可以分成多少个Layer. 如果是1024点FFT, 则FFT计算分成了10个Layer, pow(2,10)=1024.
// MM1 0
int M, MM1;
// 全局数据. 0则表示第一次调用FFT, 需要初始化一些数据, 比如计算旋转因子.
static int init = 0;
// NV2 0
// NM1 0
// MP 0
int NV2, NM1, MP;
// 旋转因子. 其中 :
// w_real[0], w_imag[0] 存储的是 1024 点FFT的旋转因子.
// w_real[1], w_imag[1] 存储的是 256 点FFT的旋转因子.
static double w_real[2][LOGBLKSIZE], w_imag[2][LOGBLKSIZE];
// i 0
// j 0
// k 0
// L 当前Layer, 也就是现在在那个Layer上运算.
int i, j, k, L;
//
int ip, le, le1;
//
double t_real, t_imag, u_real, u_imag;
// 如果是第一次调用FFT则计算出旋转因子来, 其实旋转因子不需要计算, 采用查表方式会更快.
if(init == 0)
{
// preset statics to 0
memset( (char*)w_real, 0, sizeof(w_real) );
memset( (char*)w_imag, 0, sizeof(w_imag) );
/*
* 计算旋转因子
* 旋转因子, 需要优化...
* Wn=cos(2*pi*n/N)+j*sin(2*pi*n/N)
*
* tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));
* tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));
*/
// 长窗FFT要使用的旋转因子, 1024点FFT.
M = LOGBLKSIZE; // 10, 分成10个Layer
for(L=0; L
{
le = 1 << (M-L); // (M-L)*2
le1 = le >> 1; // le1 = pow(2, cur_layer)/(2*(p+step))
// 旋转因子.
w_real[0][L] = cos(PI/le1);
w_imag[0][L] = -sin(PI/le1);
}
// 短窗FFT要使用的旋转因子, 256点FFT.
M = LOGBLKSIZE_S; //8
for(L=0; L
{
le = 1 << (M-L);
le1 = le >> 1;
w_real[1][L] = cos(PI/le1);
w_imag[1][L] = -sin(PI/le1);
}
init ++;
}
switch( N )
{
// 注意到pow(2,10)=1024
case BLKSIZE : //1024
M = LOGBLKSIZE; //10
MP = 0;
break;
// 注意到pow(2,8)=256
case BLKSIZE_S ://256
M = LOGBLKSIZE_S;//8
MP = 1;
break;
default : //
//printf( "Error: Bad FFT Size in subs.c/n" );
//exit( -1 );
break;
}
MM1 = M - 1;
NV2 = N >> 1;
NM1 = N - 1;
/* 这里就是FFT了, 结构是
* for(layer)
* for()
* for()
*/
for(L=0; L
{
le = 1 << (M-L);
le1 = le >> 1;
u_real = 1;
u_imag = 0;
for(j=0; j
{
for(i=j; i
{
ip = i + le1;
t_real = x_real[i] + x_real[ip];
t_imag = x_imag[i] + x_imag[ip];
x_real[ip] = x_real[i] - x_real[ip];
x_imag[ip] = x_imag[i] - x_imag[ip];
x_real[i] = t_real;
x_imag[i] = t_imag;
t_real = x_real[ip];
x_real[ip] = x_real[ip]*u_real - x_imag[ip]*u_imag;
x_imag[ip] = x_imag[ip]*u_real + t_real*u_imag;
}
t_real = u_real;
u_real = u_real*w_real[MP][L] - u_imag*w_imag[MP][L];
u_imag = u_imag*w_real[MP][L] + t_real*w_imag[MP][L];
}
}
/*
* special case: L = M-1; all Wn = 1
* 求各点的能量和夹角
*/
for(i=0; i
{
// i为0, 2, 4, 6..., ip为1, 3, 5...
ip = i + 1;
/* 为什么要做一下这样的处理? 没搞明白哦! 如果这里这样做, 那么上面一定
* 是已经做好了二进制反转工作或下面要做二进制反转工作 */
t_real = x_real[i] + x_real[ip];
t_imag = x_imag[i] + x_imag[ip];
x_real[ip] = x_real[i] - x_real[ip];// real[i] = real[i] - real[ip]
x_imag[ip] = x_imag[i] - x_imag[ip];
x_real[i] = t_real; // real[i] = real[i] + real[ip]
x_imag[i] = t_imag;
/* 求能量和夹角(-PI/2 ~ PI/2 ) */
energy[i] = x_real[i]*x_real[i] + x_imag[i]*x_imag[i];
// 0.0005是否是静音门槛曲线上规定的? 还是作者根据经验得到?
if(energy[i] <= 0.0005)
{
phi[i] = 0;
energy[i] = 0.0005;
}
else
{
phi[i] = atan2( (double)x_imag[i], (double)x_real[i] );
}
/* 求能量和夹角(-PI/2 ~ PI/2 ) */
energy[ip] = x_real[ip]*x_real[ip] + x_imag[ip]*x_imag[ip];
// 这里为什么不和0.0005比较?
if(energy[ip] == 0)
{
phi[ip] = 0;
}
else
{
phi[ip] = atan2((double) x_imag[ip],(double) x_real[ip]);
}
}
// this section reorders the data to the correct ordering 重新排序. 二进制反转
j = 0;
for(i=0; i
{
if(i < j)
{
// use this section only if you need the FFT in complex
// number form (and in the correct ordering)
t_real = x_real[j];
t_imag = x_imag[j];
x_real[j] = x_real[i];
x_imag[j] = x_imag[i];
x_real[i] = t_real;
x_imag[i] = t_imag;
// reorder the energy and phase, phi
t_real = energy[j];
energy[j] = energy[i];
energy[i] = t_real;
t_real = phi[j];
phi[j] = phi[i];
phi[i] = t_real;
}
k = NV2;
while(k <= j)
{
j = j - k;
k = k >> 1;
}
j = j + k;
}
}