如何来做声音波形的频谱分析

时间:2023-01-09 10:23:55
我现在正在做一个小东东:
  要检测声卡是否发出“嘟”这个声音,我有们这个声音的波形(比如440HZ,持续0.1s),而且也已经得到了声卡出来的数据。现在的问题是:如果对捕捉到的声卡数据进行分析??
  在网上翻了一下,好像是要对得到的声卡数据进行FFT,得到声音波形的频谱。但我不知道这个到底该怎么来实现,还请各位DX指点指点。

对这个问题,现存在下面两个疑问:

问题1:如何对现有数据进行FFT变换,得到相应的频谱数据
问题2:如何对得到的频谱数据进行分析,检测其是否匹配(是否为440HZ,持续0.1s

10 个解决方案

#1


up

#2


http://www.codeproject.com/audio/waveInFFT.asp

#3


TO:Zhymax(蓝点)
那第二个问题又如何来解决呢!!
如何进行匹配

#4


呵呵,从你的问题来看,你要解决这个问题关键还在于基础知识
不论你是通过何种方法进行分析都需要针对数据的某个特征,即使是频谱特征你也需要明确你自己的目标,你有一个样本,你取出来的特征和样本特征要如何比较或运算才能达到匹配,这是从代码中找不出来的,建议多用 google

#5


对FFT不大明白
根据网上的算法,经过FFT后得到两组数据Real[]、Img[].
这两组数据都表示着什么呢
在我的匹配中,只要能取到在440HZ频率下持续0.1s的声音波形,这又该如何做呢??
用得到的两组数据,如何来画出一个频谱图呢??

请指教....

#6


其实第二个问题是比较简单的信号检测匹配问题.
以http://www.codeproject.com/audio/waveInFFT.asp的FFT算法说明:

参数说明:
FFT_LEN  FFT的长度 这里假定为512点
p_nSamples(Hz/s) 声卡采样速率 这里假定为11025Hz/s
FFT频域分辨率(Hz/点): Freq=p_nSamples/FFT_LEN
FFT时域分辨率(s):Timeq=FFT_LEN/p_nSamples;表示一次FFT所代表的时间长度

从这里看出FFT的时域和频域分辨率成反比,也就是说如果要得到较好的频域分辨效果就要增大
FFT点数,但会导致时域分辨率下降,反之亦然。

原理说明:
FFT算法是将信号从时域变化到频域的一种算法
输出值分为虚部foutimg和实部fout,
foutimg和fout的平方和代表一个频率的功率

某一频率出是否有信号的判断:
该例中,频域分辨率为(11025/512)Hz=21.5Hz;
FFT频域分辨率也就代表了FFT输出的相邻一对虚部和实部值表示的频率间的差值
第i对FFT输出值所代表的频率:Fre[i]=(p_nSamples/FFT_LEN)*i;//i=0...FFT_LEN/2-1;
440Hz所在的点为:440/Freq=440/21.5=20.4,也就是说第20和21点处的值就代表了440Hz,
所以只需将第20和21点处的功率值与其他点的功率值相比就可以判断当前在440Hz处是否有信号。

持续时间的判断:
时域分辨率Timeq=512/11025=0.046s=46ms
例:若判断持续时间为0.1s,那么只需判断0.1/0.046=2次就可以了

注意:以上算法仅适用于简单的频谱估计,如果要求比较精确,那么可以采用短时FFT算法或者时域滤波法会更精确
不过时域滤波算法设计数字滤波器和相关匹配等专业知识,这里就不多说了,有兴趣的可以和我联系。

int frec=0;
DWORD nCount = 0;
    for (DWORD dw = 0; dw < FFT_LEN; dw++)
    {
        {
            //将声卡数据拷贝到FFT算法缓冲区
            finleft[nCount++] = (double)((short*)pwh->lpData)[dw++];
       }
    }
    //左声道的512点FFT
    fft_double(FFT_LEN/2,0,finleft,NULL,fout,foutimg);
    //输出值分为虚部foutimg和实部fout,
    float re,im;
    float power0=0,power;
    int fremax;
    
    //检测16到25点(244Hz----537Hz)处的最大频率点
    for(int i=16;i < 25;i++)
    {
        re = fout[i];//实部
        im = foutimg[i];//虚部
        //get frequency intensity and scale to 0..256 range
        power=GetFrequencyIntensity(re,im);
        if(power>power0) fremax=i;
    }
    //判断440Hz处是否有信号
    if(fremax==20 || fremax==21) frec++;
    if(frec>=2) 
    {
     //持续时间>=0.1s
     ............
    }

#7


补充一点:
在检测时,不要把检测范围设的太大,否则容易误判,具体设置要在实际测试中设置

//检测16到25点(244Hz----537Hz)处的最大频率点
   for(int i=16;i < 25;i++)
    {
        re = fout[i];//实部
        im = foutimg[i];//虚部
        //get frequency intensity and scale to 0..256 range
        power=GetFrequencyIntensity(re,im);
        if(power>power0) fremax=i;
    }

#8


TO:  bbbleo() 
能给我发一份相关的材料吗??谢谢
ww51xh@163.com

#9


TO:  bbbleo() 
画出来的频谱好像不对!!
for (DWORD i=0; i<FFT_LEN/2;i++)
{
    LineTo(i, GetFrequencyIntensity(re, im);
}

当我用一个恒定频率的声音时,其产生的频谱并不能在这一频率上固定,而是在周围不停地跳跃的。

#10


怎么我做完FFT后,得到的频率的值猣峰值达到了3万多,这符合吗??
而且当产生一固定频率的声音的时候,频谱图并不稳定,

#1


up

#2


http://www.codeproject.com/audio/waveInFFT.asp

#3


TO:Zhymax(蓝点)
那第二个问题又如何来解决呢!!
如何进行匹配

#4


呵呵,从你的问题来看,你要解决这个问题关键还在于基础知识
不论你是通过何种方法进行分析都需要针对数据的某个特征,即使是频谱特征你也需要明确你自己的目标,你有一个样本,你取出来的特征和样本特征要如何比较或运算才能达到匹配,这是从代码中找不出来的,建议多用 google

#5


对FFT不大明白
根据网上的算法,经过FFT后得到两组数据Real[]、Img[].
这两组数据都表示着什么呢
在我的匹配中,只要能取到在440HZ频率下持续0.1s的声音波形,这又该如何做呢??
用得到的两组数据,如何来画出一个频谱图呢??

请指教....

#6


其实第二个问题是比较简单的信号检测匹配问题.
以http://www.codeproject.com/audio/waveInFFT.asp的FFT算法说明:

参数说明:
FFT_LEN  FFT的长度 这里假定为512点
p_nSamples(Hz/s) 声卡采样速率 这里假定为11025Hz/s
FFT频域分辨率(Hz/点): Freq=p_nSamples/FFT_LEN
FFT时域分辨率(s):Timeq=FFT_LEN/p_nSamples;表示一次FFT所代表的时间长度

从这里看出FFT的时域和频域分辨率成反比,也就是说如果要得到较好的频域分辨效果就要增大
FFT点数,但会导致时域分辨率下降,反之亦然。

原理说明:
FFT算法是将信号从时域变化到频域的一种算法
输出值分为虚部foutimg和实部fout,
foutimg和fout的平方和代表一个频率的功率

某一频率出是否有信号的判断:
该例中,频域分辨率为(11025/512)Hz=21.5Hz;
FFT频域分辨率也就代表了FFT输出的相邻一对虚部和实部值表示的频率间的差值
第i对FFT输出值所代表的频率:Fre[i]=(p_nSamples/FFT_LEN)*i;//i=0...FFT_LEN/2-1;
440Hz所在的点为:440/Freq=440/21.5=20.4,也就是说第20和21点处的值就代表了440Hz,
所以只需将第20和21点处的功率值与其他点的功率值相比就可以判断当前在440Hz处是否有信号。

持续时间的判断:
时域分辨率Timeq=512/11025=0.046s=46ms
例:若判断持续时间为0.1s,那么只需判断0.1/0.046=2次就可以了

注意:以上算法仅适用于简单的频谱估计,如果要求比较精确,那么可以采用短时FFT算法或者时域滤波法会更精确
不过时域滤波算法设计数字滤波器和相关匹配等专业知识,这里就不多说了,有兴趣的可以和我联系。

int frec=0;
DWORD nCount = 0;
    for (DWORD dw = 0; dw < FFT_LEN; dw++)
    {
        {
            //将声卡数据拷贝到FFT算法缓冲区
            finleft[nCount++] = (double)((short*)pwh->lpData)[dw++];
       }
    }
    //左声道的512点FFT
    fft_double(FFT_LEN/2,0,finleft,NULL,fout,foutimg);
    //输出值分为虚部foutimg和实部fout,
    float re,im;
    float power0=0,power;
    int fremax;
    
    //检测16到25点(244Hz----537Hz)处的最大频率点
    for(int i=16;i < 25;i++)
    {
        re = fout[i];//实部
        im = foutimg[i];//虚部
        //get frequency intensity and scale to 0..256 range
        power=GetFrequencyIntensity(re,im);
        if(power>power0) fremax=i;
    }
    //判断440Hz处是否有信号
    if(fremax==20 || fremax==21) frec++;
    if(frec>=2) 
    {
     //持续时间>=0.1s
     ............
    }

#7


补充一点:
在检测时,不要把检测范围设的太大,否则容易误判,具体设置要在实际测试中设置

//检测16到25点(244Hz----537Hz)处的最大频率点
   for(int i=16;i < 25;i++)
    {
        re = fout[i];//实部
        im = foutimg[i];//虚部
        //get frequency intensity and scale to 0..256 range
        power=GetFrequencyIntensity(re,im);
        if(power>power0) fremax=i;
    }

#8


TO:  bbbleo() 
能给我发一份相关的材料吗??谢谢
ww51xh@163.com

#9


TO:  bbbleo() 
画出来的频谱好像不对!!
for (DWORD i=0; i<FFT_LEN/2;i++)
{
    LineTo(i, GetFrequencyIntensity(re, im);
}

当我用一个恒定频率的声音时,其产生的频谱并不能在这一频率上固定,而是在周围不停地跳跃的。

#10


怎么我做完FFT后,得到的频率的值猣峰值达到了3万多,这符合吗??
而且当产生一固定频率的声音的时候,频谱图并不稳定,