zwj512 发表于 2014-4-20 15:55:40

WAV 文件做FFT变换

本帖最后由 zwj512 于 2014-4-20 19:25 编辑

平台:ARM9QT4.5
小弟现在可以解析WAV文件
采样率是44Khz16bit双声道PCM编码
我现在想做FFT 变换    我是直接把WAV的16bit数据作为一个点 进行FFT变换呢还是需要别的步骤?
我只做一个声道的FFT   PCM存储数据的时候是高低字节反着存储我用不用 变换一下再做FFT ?
而且16bit的数据有点大运算有点慢我现在是只读取 低字节进行FFT 变换   这样可取不 ?
我现在FFT变换后 频谱有些乱我进行的256点变换   一般正常的话 是低频到高频逐渐降低
而且我的FFT点数 低于256时程序运行时 就会出现内存错误不懂。。。
我的不是这样的    有做过这方面的大神吗   谢谢指点

下面是FFT程序 有懂的大神帮看看

#ifndef FILTER_H
#define FILTER_H


/*********************************************************************
                       快速福利叶变换C函数
函数简介:此函数是通用的快速傅里叶变换C语言函数,移植性强,以下部分不依
          赖硬件。此函数采用联合体的形式表示一个复数,输入为自然顺序的复
          数(输入实数是可令复数虚部为0),输出为经过FFT变换的自然顺序的
          复数
使用说明:使用此函数只需更改宏定义FFT_N的值即可实现点数的改变,FFT_N的
          应该为2的N次方,不满足此条件时应在后面补0
函数调用:FFT(s);
时    间:2010-2-20
版    本:Ver1.0
参考文献:

**********************************************************************/
#include<math.h>

#define PI 3.1415926535897932384626433832795028841971               //定义圆周率值
#define FFT_N 128                                                   //定义福利叶变换的点数

struct compx {float real,imag;};                                    //定义一个复数结构
struct compx s;
//FFT输入和输出:从S开始存放,根据大小自己定义


/*******************************************************************
函数原型:struct compx EE(struct compx b1,struct compx b2)
函数功能:对两个复数进行乘法运算
输入参数:两个以联合体定义的复数a,b
输出参数:a和b的乘积,以联合体的形式输出
*******************************************************************/
struct compx EE(struct compx a,struct compx b)
{
struct compx c;
c.real=a.real*b.real-a.imag*b.imag;
c.imag=a.real*b.imag+a.imag*b.real;
return(c);
}

/*******************************************************************
//定义复数求模


********************************************************************/

float cmplxabs(struct compx a)
{
float b;
b=sqrt(a.real*a.real+a.imag*a.imag);
return(b);
}

/*****************************************************************
函数原型:void FFT(struct compx *xin,int N)
函数功能:对输入的复数组进行快速傅里叶变换(FFT)
输入参数:*xin复数结构体组的首地址指针,struct型
*****************************************************************/
void FFT(struct compx *xin)
{
int f,m,nv2,nm1,i,k,l,j=0;
struct compx u,w,t;

   nv2=FFT_N/2;                  //变址运算,即把自然顺序变成倒位序,采用雷德算法
   nm1=FFT_N-1;
   for(i=0;i<nm1;i++)
   {
    if(i<j)                  //如果i<j,即进行变址
   {
      t=xin;
      xin=xin;
      xin=t;
   }
    k=nv2;                  //求j的下一个倒位序
    while(k<=j)               //如果k<=j,表示j的最高位为1
   {
      j=j-k;               //把最高位变成0
      k=k/2;               //k/2,比较次高位,依次类推,逐个比较,直到某个位为0
   }
   j=j+k;                   //把0改为1
}

{
   int le,lei,ip;                            //FFT运算核,使用蝶形运算完成FFT运算
    f=FFT_N;
   for(l=1;(f=f/2)!=1;l++)                  //计算l的值,即计算蝶形级数
           ;
for(m=1;m<=l;m++)                         // 控制蝶形结级数
   {                                        //m表示第m级蝶形,l为蝶形级总数l=log(2)N
    le=2<<(m-1);                            //le蝶形结距离,即第m级蝶形的蝶形结相距le点
    lei=le/2;                               //同一蝶形结中参加运算的两点的距离
    u.real=1.0;                           //u为蝶形结运算系数,初始值为1
    u.imag=0.0;
    w.real=cos(PI/lei);                     //w为系数商,即当前系数与前一个系数的商
    w.imag=-sin(PI/lei);
    for(j=0;j<=lei-1;j++)                   //控制计算不同种蝶形结,即计算系数不同的蝶形结
   {
      for(i=j;i<=FFT_N-1;i=i+le)            //控制同一蝶形结运算,即计算系数相同蝶形结
       {
        ip=i+lei;                           //i,ip分别表示参加蝶形运算的两个节点
        t=EE(xin,u);                  //蝶形运算,详见公式
        xin.real=xin.real-t.real;
        xin.imag=xin.imag-t.imag;
        xin.real=xin.real+t.real;
        xin.imag=xin.imag+t.imag;
       }
      u=EE(u,w);                           //改变系数,进行下一个蝶形运算
   }
   }
}

}
#endif // FILTER_H

dellric 发表于 2014-4-20 16:43:02

1)WAV文件的16bitPCM有两种存储方式,即大端方式和小端方式,通过你的描述,估计是小端方式。如果是小端方式而且在X86系统中使用C语言进行数据处理,可用采用一个short int指针来进行读取。
2)对于X86系统,16bit数据不大,运算也不慢。如果是ARM,在运算的时候,要充分利用移位指令计算。如果是DSP,我就不多说了,一般TI、ADI或飞思卡尔都会提供一些标准算法库,自己写也不难。如果你是在8位机上实现FFT,则要充分考虑机器的运算能力,一般情况下256点FFT在44K下实时变换这样的运算负荷,对于一般的8位机基本完不成,除非外部配合FPGA或DSP来完成。
3)对于16bit数据,只取低字节是不对的,如果声音数据有超过-128~+127范围的,则计算完全错误,同时降低了分析的动态范围,不可取。
4)使用FFT的蝶形变换后,输出的复数是倒位序,你需要重新对虚实部进行排列。
5)以后问算法的时候,最好告知大家你的运算平台,否则很难回答你的提问。

90999 发表于 2014-4-20 16:49:18

你自己生成一个1K正弦波来做FFT不就知道了。

Jordan?? 发表于 2014-4-20 16:50:07

MARK
正在做这方面的东西

zwj512 发表于 2014-4-20 18:16:15

dellric 发表于 2014-4-20 16:43
1)WAV文件的16bitPCM有两种存储方式,即大端方式和小端方式,通过你的描述,估计是小端方式。如果是小端方 ...

谢谢我在ARM9上跑用QT4.5写的程序    我开始也是用的 short int 读取数据 进行FFT变换 256点速度跟不上来    而且我求出的复数取模后 还会有负数出现的情况(我用16bit数据)
我用FFT的时候点数如果低于 256点 比如128点 系统就会出现内存错误   我也不知道怎么回事

zwj512 发表于 2014-4-20 18:16:56

Jordan?? 发表于 2014-4-20 16:50
MARK
正在做这方面的东西

做的怎么样啦   指点一下啊

Jordan?? 发表于 2014-4-20 19:52:11

zwj512 发表于 2014-4-20 18:16
做的怎么样啦   指点一下啊

我用的是fftw库
自己写的效果没这么好

zwj512 发表于 2014-4-20 20:33:14

Jordan?? 发表于 2014-4-20 19:52
我用的是fftw库
自己写的效果没这么好

fftw库qt下可以用吗

Jordan?? 发表于 2014-4-20 21:26:52

zwj512 发表于 2014-4-20 20:33
fftw库qt下可以用吗

我就是用在qt下......

zwj512 发表于 2014-4-21 00:30:36

Jordan?? 发表于 2014-4-20 21:26
我就是用在qt下......

我已安装好啦明天试试有问题请教你啊

zwj512 发表于 2014-4-21 09:30:50

Jordan?? 发表于 2014-4-20 16:50
MARK
正在做这方面的东西

我交叉编译器 4.3.3编译时 有这个错误   怎么解决啊我试试了 FFTW3    FFTW2  一样的效果

Jordan?? 发表于 2014-4-21 09:36:33

zwj512 发表于 2014-4-21 09:30
我交叉编译器 4.3.3编译时 有这个错误   怎么解决啊我试试了 FFTW3    FFTW2  一样的效果
...

静态链接?加上-static 看看吧

zwj512 发表于 2014-4-21 09:41:36

Jordan?? 发表于 2014-4-21 09:36
静态链接?加上-static 看看吧

我生成的库文件 没有.so文件 是不这个问题你有吗给我传一个 谢谢

Jordan?? 发表于 2014-4-21 09:46:48

zwj512 发表于 2014-4-21 09:41
我生成的库文件 没有.so文件 是不这个问题你有吗给我传一个 谢谢

会不会是你编译选项错了?
我的是在BBB上直接本地编译的,静态库库和动态库都有
要不你在pro文件里加上
TEMPLATE = lib
CONFIG   += staticlib

zwj512 发表于 2014-4-21 09:53:59

Jordan?? 发表于 2014-4-21 09:46
会不会是你编译选项错了?
我的是在BBB上直接本地编译的,静态库库和动态库都有
要不你在pro文件里加上


照你的办法成功啦没错啦但是我只有静态库我也是 ./configmake make install啊   不知怎么回事 我这样做 不会影响程序运行结果吧

Jordan?? 发表于 2014-4-21 09:57:09

zwj512 发表于 2014-4-21 09:53
照你的办法成功啦没错啦但是我只有静态库我也是 ./configmake make install啊   不知怎么回事...

不会,静态链接理论上还快一些呢{:lol:}

zwj512 发表于 2014-4-21 10:00:47

Jordan?? 发表于 2014-4-21 09:57
不会,静态链接理论上还快一些呢

哈哈谢谢你啦 你不是在linux下安装的吧在linux下好像就没有 动态库啊   

Jordan?? 发表于 2014-4-21 10:04:43

zwj512 发表于 2014-4-21 10:00
哈哈谢谢你啦 你不是在linux下安装的吧在linux下好像就没有 动态库啊

/usr/lib下一大堆动态库

xuanfong1 发表于 2014-4-21 10:08:39

路过学习学习。

zwj512 发表于 2014-4-21 12:48:20

Jordan?? 发表于 2014-4-21 10:04
/usr/lib下一大堆动态库

大侠有几个问题
1. 我的是16bit的 我用short int读回来的数据   用高低字节互换吗然后再FFT
2. FFTW里面的数据类型可以是float,那我读回来的数据 还用别的处理吗还是直接强制类型转换然后FFT

Jordan?? 发表于 2014-4-21 13:11:14

zwj512 发表于 2014-4-21 12:48
大侠有几个问题
1. 我的是16bit的 我用short int读回来的数据   用高低字节互换吗然后再FFT
2. FF ...

{:lol:} 我不是什么大侠。。。
应该是要高低字节互换的..
我也在折腾这些

zwj512 发表于 2014-4-21 14:35:01

Jordan?? 发表于 2014-4-21 13:11
我不是什么大侠。。。
应该是要高低字节互换的..
我也在折腾这些

按你的方式 生成的是 .a 文件没有可执行文件求助   

Jordan?? 发表于 2014-4-21 15:05:12

zwj512 发表于 2014-4-21 14:35
按你的方式 生成的是 .a 文件没有可执行文件求助

将库添加到工程中即可。。
不会添加的话我也没办法了

zwj512 发表于 2014-4-21 15:10:37

Jordan?? 发表于 2014-4-21 15:05
将库添加到工程中即可。。
不会添加的话我也没办法了

好吧我解决啦生成动态库啦
页: [1]
查看完整版本: WAV 文件做FFT变换