FIR数字滤波器 C语言频域实现 matlab设计FIR参数
本文主要介绍用C语言实现频域FIR。
一、FIR实现步骤
1、FIR参数做FFT
2、输入数据做FFT
3、FIR做复数乘积
4、将复数乘积结果做IFFT输出
二、FIR代码实现
1、FIR参数的生成
FIR的系数用matlab的FDA工具生成,设计参数:
FS:48000Hz
Fpass:2000Hz
Fstop:2500Hz
滤波器:低通 FIR
FIR阶数:511
Density Factor:20
参数设置如下图:
2、FIR系数做FFT计算
void FIRCoffesCal(void *processor)
{
FFT_ELEM *fft = (FFT_ELEM *)processor;
int i = 0,j = 0;
memset(fft->overlap ,0,sizeof(float)*(FFT_LENGTH<<1));
memset(fft->FIR_CoffesIn,0,sizeof(float)*(FFT_LENGTH<<1));
for(i=0; i< FIR_ORDER; i++)
{
fft->FIR_CoffesIn[i<<1] = FIR_COFFES[i] ;//* fft->win[i]; //实部
}
DSPF_sp_fftSPxSP_cn(FFT_LENGTH, fft->FIR_CoffesIn, fft->tw , fft->FIR_CoffesOut,fft->base, 0,FFT_LENGTH);
}
3、输入数据做overlap
for(i=0; i< FFT_LENGTH-FRAME_LEN; i++)
{
fft->frameIn[i] = fft->frameIn[i+FRAME_LEN] ;
}
for(i=0; i< FRAME_LEN; i++)
{
fft->frameIn[FFT_LENGTH-FRAME_LEN+i] = x[i] ;
}
4、输入数据做FFT
for(i=0; i< FFT_LENGTH; i++)
{
fft->FFT_InData[i<<1] = fft->frameIn[i] ;//* fft->win[i]; //实部
fft->FFT_InData[(i<<1)+1] = 0 ; //虚部赋0
}
DSPF_sp_fftSPxSP_cn(FFT_LENGTH, fft->FFT_InData, fft->tw , fft->FFT_outData,fft->base, 0,FFT_LENGTH);
5、数据做复数乘积
/*
struct Complex MUL(struct Complex a,struct Complex b)//定义复乘
{
struct Complex c;
c.real=a.real*b.real-a.imag*b.imag;
c.imag=a.real*b.imag+a.imag*b.real;
return(c);
}
*/
fft->FIR_InData[0] = fft->FFT_outData[0]*fft->FIR_CoffesOut[0] - fft->FFT_outData[1]*fft->FIR_CoffesOut[1];//8.569;//
fft->FIR_InData[1] = fft->FFT_outData[0]*fft->FIR_CoffesOut[1] + fft->FFT_outData[1]*fft->FIR_CoffesOut[0];
fft->FIR_InData[FFT_LENGTH] = fft->FFT_outData[FFT_LENGTH]*fft->FIR_CoffesOut[FFT_LENGTH] - fft->FFT_outData[FFT_LENGTH+1]*fft->FIR_CoffesOut[FFT_LENGTH+1];
fft->FIR_InData[FFT_LENGTH+1] = fft->FFT_outData[FFT_LENGTH]*fft->FIR_CoffesOut[FFT_LENGTH+1] + fft->FFT_outData[FFT_LENGTH+1]*fft->FIR_CoffesOut[FFT_LENGTH];
for(i=2;i<FFT_LENGTH;i+=2)
{
fft->FIR_InData[i] = fft->FFT_outData[i]*fft->FIR_CoffesOut[i] - fft->FFT_outData[i+1]*fft->FIR_CoffesOut[i+1];
fft->FIR_InData[i+1] = fft->FFT_outData[i]*fft->FIR_CoffesOut[i+1] + fft->FFT_outData[i+1]*fft->FIR_CoffesOut[i];
fft->FIR_InData[FFT_LENGTH*2-i] = fft->FIR_InData[i];
fft->FIR_InData[FFT_LENGTH*2-i+1] = -fft->FIR_InData[i+1];
}
6、数据做IFFT并输出
DSPF_sp_ifftSPxSP_cn(FFT_LENGTH, fft->FIR_InData, fft->tw , fft->FIR_OutData,fft->base, 0,FFT_LENGTH);
for(j=0;j<FRAME_LEN;j++)
{
y[j] = fft->FIR_OutData[(FFT_LENGTH>>1)+j<<1];//取后半部分
}
三、代码说明以及待完善
1、说明
代码实现了频域FIR,针对overlap有两种方案,一种是FFT前做,一种是IFFT后做。代码未贴出,读写文件操作,以
及FFT和IFFT的实现,这个实现网上应该有大把。其中最关键的地方就是FIR复数乘积计算。尤其注意数据对称问题。
2、待完善
代码暂时支持的滤波器阶数必须小于FFT的长度,所以FFT长度做了一个特殊处理。后续完成滤波器长度大于FFT长度的实现。