c语言实现FIR(窗函数设计法)


前言

现在大多教程都是matlab的教程,那我用C语言实现一下FIR


此博客为个人学习

一、FIR滤波器

        FIR有限长滤波器,有限长指的是滤波器的脉冲响应为有限长的序列

输入X进过滤波器H得到滤波后的输出Y

表达成差分方程形式就是:

                y[n]=\sum_{m=0}^{N-1}h[m]x[n-m]  

也可以写成卷鸡形式

                y[n]=h[n]*x[n]

窗函数法

        由于理想滤波器在时域上是无线长序列,所以要对理想滤波器加窗截断变成有限信号。

                

                                                        理想低通滤波器时域

常用窗函数:            

        使用不同的窗函数会有不同的滤波性能(衰减程度和过渡带大小的不一样)

窗函数的介绍以及画出常见窗函数(汉宁窗,矩形窗,汉明窗,布莱克曼窗)的时域图和频谱图-CSDN博客

设计步骤

构造理想滤波器

hl[n]

理想离散低通滤波器公式\frac{sin(wc(n-\tau ))}{\pi (n-\tau )}

低通可构成其他高通带通等

构造窗函数         

w[n]

相乘得到FIR滤波器

h[n]=w[n]hl[n]

最后让输出

y[n]=\sum_{m=0}^{N-1}h[m]x[n-m] 

得到滤波数据

二、代码

0.头文件和宏定义

#include<stdio.h>
#include <stdlib.h>
#include <math.h>


#define pi  3.1415926535897932

/*----窗类型-----*/ 
//三角形窗未完成,所以其实三角形和矩形的一样 
#define Rectangle  1			//矩形 
#define triangle   2			//三角 
#define	Hanning    3			//汉宁
#define	Hamming    4			//海明 
#define	Blackman   5			//布拉克曼

/*----滤波类型-----*/ 
#define LOWPASSFILTER	 	1      //低通 
#define HIGEPASSFILTER  	2
#define	BANDPASSFILTER   	3	  //带通	
#define	BANDSTOPFILTER    	4

1.构造滤波器1函数

这个函数是按阶数设计滤波器,(N为偶数时,窗函数法无法设计高通和带组)

//已知阶数,求fir 的 传递函数 值 
/*----------------------- 
* 函数名  	FIR_Filter_Transfer_functions_param
* 输入  	@Filter_h  	:	用于返回传递函数 数据数组 长度为N
 			@Filter_type  :滤波器类型  低通高通带通带阻  参数可以是[LOWPASSFILTER	, HIGEPASSFILTER  ,BANDPASSFILTER  , BANDSTOPFILTER] 
  			@Wc1:			滤波器的截止频率 
  			@Wc2:			BPF和BSF的第二个截止频率  
  			@N				阶数 
 			@window			窗函数类型:参数可以是[Rectangle,  triangle ,  	Hanning ,Hamming ,Blackman] 
* 功能      按阶数设计滤波器 ,注意设计高通和带阻时  N必须为奇数 
* 返回 		1成功  0失败 
----------------------*/ 
char FIR_Filter_Transfer_functions_param(double *Filter_h,char Filter_type,double Wc1 ,double Wc2 ,unsigned int N,int window)
{
 
	int n;
	//偶数点无法设计高通和带阻 // 
	if(((Filter_type==HIGEPASSFILTER)||(Filter_type==BANDSTOPFILTER))&&(N%2==0))
	{
		return 0;	
	} 
	/*窗函数******-------------------------------*/ 
	int const const_N=N;
 	double win_param[const_N];			//存放窗函数数据 
	switch(window)
	{
	  	case Rectangle:
	  		for(n=0;n<N;n++)
	  		{
	  			win_param[n]=1;  			
			}
	  		break;
		case triangle:
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=1; //2部分,懒得打了 ,直接用矩形窗游览			
			}
	  		break;
		case Hanning: 
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.5*(1-cos(2*pi*n/(N-1))); 			
			}
	  		break;
	  	case Hamming :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.54-0.46*cos(2*pi*n/(N-1));
//					printf("%lf\n",win_param[n]);			
			}  		
	  		break;
		case Blackman :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.42-0.5*cos((4*pi*n/(N-1))-0.08*(4*pi*n/(N-1))); 			
			}  		
	  		break;
		default: 
			return 0;	
	}
	  

	  /*---------------构造理想滤波器-------------------------*/ 
	double tao;   //群延迟 

	double h_lixiang[const_N];  //理想滤波器 
	tao=(N-1)/2.0;
 
	switch(Filter_type)
	{
	  	case LOWPASSFILTER:
	  		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)       //如果 (n-tao)==0则分子分母为0   取极限 
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=sin(Wc1*(n-tao))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case HIGEPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case BANDPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(Wc2*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		  
		case BANDSTOPFILTER:
		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc2*(n-tao))+sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
	  	
		default: 
			return 0;	
	}
	/*--------求h[n]-----------*/ 
	for(n=0;n<N;n++)
	  	{
	  		
				Filter_h[n]=h_lixiang[n]*win_param[n];
				  					  			
		}
	return 1;	
}

2.构造滤波器2函数

这个是按照模拟指标设计滤波器

配套结构体


typedef struct{
	double(*Hn)[];            // 指向一个 传递函数的指针 
	int N;					//传递函数的阶数 
	
}H_Struct;            /*传递函数结构体------第二种函数实现用到 */ 


typedef struct {
	int fs;                                          //采样率 
	int fp1;                                		 //通带截止频率 1  靠近w=0这边的 
	int fst1;                                		 //通带截止频率 1 	靠近w=0这边的 
	int fp2;                                		 //通带截止频率 2   如果为低通和高通则 不用关 2 
	int fst2;                                		 //阻带截止频率 2 
	int ast;                                		 //阻带最小衰减		
}Transfer_functions_struct; /*模拟指标结构体  */ 

 


/*----------------------- 
* 函数名  	FIR_Filter_Transfer_functions_param2
* 输入  	
 			@Filter_type  :		滤波器类型  低通高通带通带阻  参数可以是[LOWPASSFILTER	, HIGEPASSFILTER  ,BANDPASSFILTER  , BANDSTOPFILTER] 
  			@Transfer_param:		滤波器的模拟指标,   
  		
* 功能      按照模拟指标设计滤波器 
* 返回 		H_Struct包含 滤波器传递函数 和 阶数 的结构体 , 
----------------------*/ 
H_Struct* FIR_Filter_Transfer_functions_param2(char Filter_type,Transfer_functions_struct*Transfer_param) 
{
	/*------------数字指标-------------------*/ 
  	double 	Wc1=2*pi*((Transfer_param->fp1+Transfer_param->fst1)/2)/Transfer_param->fs;
  	double	Wc2=2*pi*((Transfer_param->fp2+Transfer_param->fst2)/2)/Transfer_param->fs;
  	double  det_W1=2*pi*abs(Transfer_param->fst1-Transfer_param->fp1)/Transfer_param->fs;           //过度带带宽 
  	double  det_W2=2*pi*abs(Transfer_param->fst2-Transfer_param->fp2)/Transfer_param->fs;			//过度带带宽 2 
  	double 	det_W=det_W1;
  	if((Filter_type==BANDPASSFILTER)||(Filter_type==BANDSTOPFILTER)) 				 //如果是带通或者带阻,选择窄的指标 
  	{
  		det_W=det_W1>det_W2?det_W2:det_W1;
	}
	
	
	int n;
	int N;
	int window; 
	/*窗函数选择--------------------------------------------------------------------------- */ 
	// 根据衰as减选择窗 
	switch((int)(Transfer_param->ast/10))
	{
	  	case 2:   //20db 
	  		N=(int)1.8*pi/det_W;
	  		if(N!=1.8*pi/det_W)N++;
	  		window=Rectangle;
	  		break;	
		case 3://30db 
			N=(int)6.1*pi/det_W;
	  		if(N!=6.1*pi/det_W)N++;
	  		window=triangle;
	  		break;
		case 4: //40db 
			N=(int)(6.2*pi/det_W);
	  		if(N!=6.2*pi/det_W)N++;
	  		window=Hanning;
	  		break;
	  	case 5 ://50db 
	  		N=(int)(6.6*pi/det_W);
	  		if(N!=6.6*pi/det_W)N++;
	  		window=Hamming;
	  		break;
		case 7 ://70db
			N=(int)11*pi/det_W;
	  		if(N!=11*pi/det_W)N++;
	  		window=Blackman;
	  		break;
		default: 
			return 0;	
	}

	int const const_N=N;
 	double win_param[const_N]; //存放窗函数数据 
	switch(window)
	{
	  	case Rectangle:        //矩形 
	  		for(n=0;n<N;n++)
	  		{
	  			win_param[n]=1;  			
			}
	  		break;
		case triangle:
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=1; //三角形窗未实现			
			}
	  		break;
		case Hanning:  
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.5*(1-cos(2*pi*n/(N-1))); 			
			}
	  		break;
	  	case Hamming :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.54-0.46*cos(2*pi*n/(N-1));
//					printf("%lf\n",win_param[n]);			
			}  		
	  		break;
		case Blackman :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.42-0.5*cos((4*pi*n/(N-1))-0.08*(4*pi*n/(N-1))); 			
			}  		
	  		break;
		default: //只设计了几个常用的,衰减超出这些则返回失败 
			return 0;	
	}
  

	  /*构造理想滤波器-----------------------------------------------------------------------------*/
	   
	double tao;				//H的群延迟
	double h_lixiang[const_N];	//存放理想滤波器 数据 
	tao=(N-1)/2.0;			//求出中心点 
 
	switch(Filter_type)
	{
	  	case LOWPASSFILTER:
	  		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)		//n-tao=0时分子分母为零  取极限 
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=sin(Wc1*(n-tao))/(pi*(n-tao));                //理想低通滤波器表达式 
				}	  					  			
			}
	  		break;
		case HIGEPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)		//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case BANDPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)	//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(Wc2*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		  
		case BANDSTOPFILTER:
		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)	//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc2*(n-tao))+sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
	  	
		default:      //如果不是这些则返回失败 
			return 0;		
	}
	
	/*计算FIR的传递函数*/ 
	H_Struct *Filter_h=NULL;
	Filter_h=(H_Struct*)malloc(sizeof(H_Struct));
	Filter_h->Hn=(double(*)[])malloc(sizeof(double)*N);                //申请 跟阶数相等的内存空间 
	Filter_h->N=N;
	
	for(n=0;n<N;n++) //将窗函数和理想低通相乘得到 h 
	{
	  		
		(*(Filter_h->Hn))[n]=h_lixiang[n]*win_param[n];
				  					  			
	}
	return Filter_h;	   
}

3滤波函数

配套结构体和初始化函数


typedef struct {
	double(*input_Xbuff)[];       //指向一个缓存区用于存放历史数据 ,长度为N的数组 
	int Data_input;      		 
	int Data_output	;			
}FIR_struct;          /*一个存历史输入和当前输入的 环形数组  */ 
*----------------------- 
* 函数名  	FIR_Struct_Init
* 输入  	@Fir_variable  :一个 历史输入 环形数组指针 
* 功能      初始化数组
* 返回 		无 
----------------------*/ 
void FIR_Struct_Init(FIR_struct *Fir_variable)
{
	int i;
	Fir_variable->Data_input=0;
	Fir_variable->Data_output=0;
	
	Fir_variable->input_Xbuff=NULL;

}

函数 


/*----------------------- 
* 函数名  	Fir_filter
* 输入  	@Xdata:	包含这一时刻的 历史数据数组 
 			@hn  :		滤波器的传递函数 
  			@N			阶数 
* 功能      求出滤波后的输出  
* 返回 		这一时刻滤波后的输出 
----------------------*/ 
double Fir_filter(FIR_struct*Xdata,double*hn,unsigned int N)
{
	double y=0;
	int i=0,j=0; 

	for(i=0;i<N;i++)
	{
		  //寻找历史输入的数组 下标  X[n-i] 
		if((Xdata->Data_output-i)<0)
		{
			//越界 
			j=N+Xdata->Data_output-i;
		}else
		{
			j=Xdata->Data_output-i;
		}
		/*Fir的差分方程形式-->卷积*/ 
		y+=hn[i]*(*(Xdata->input_Xbuff))[j];	
	}
	/*延时数据,此刻变成上一时刻*/ 
	Xdata->Data_output++;  
	if(Xdata->Data_output>=N)
	{
		Xdata->Data_output=0;
	}
	
	return y;
	
}

三、使用步骤和matlab验证

输入信号是320 、1200 、2400hz叠加的波形

    double X[500];
	double y;
	/*---*/ 
	double old[Nd];      			 //历史输入数组 
	FIR_struct X_old;
	FIR_Struct_Init(&X_old);
	X_old.input_Xbuff=&old;
	
	int t=500;
	/*---输入信号*/ 
	for(k=0;k<t;k++)
	{
		X[k]=sin(2*pi*320*k/fs)+sin(2*pi*1200*k/fs)+sin(2*pi*2400*k/fs); 
	}
	

1.用阶数设计滤波器

设计一个通带Nd=42阶 的低通滤波  截止频率fc在1000 到1400hz之间的低通滤波

	double hn[Nd]={0};        //fir滤波器数组 
 	double fs=5000;
 	double fp=1000; 	
 	double fst=1400; 	
 	double wc=2*pi*((fst+fp)/2)/fs;          //3db频率
	int i=0,k;

	/*---*/ 
	double old[Nd];      			 //历史输入数组 
	FIR_struct X_old;
	FIR_Struct_Init(&X_old);
	X_old.input_Xbuff=&old;
	

 	FIR_Filter_Transfer_functions_param(hn,LOWPASSFILTER,wc,0,Nd,Hamming);
 	
 	FILE*H_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/H_pm.txt", "w");  //输出H的数据文件让matlab调用绘图 
 	for(i=0;i<Nd;i++)
 	{
 		
 		fprintf(H_fp, "%lf\n",hn[i]);
	}
 	FILE*Y_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/Y_pm.txt", "w");   //输出Y的数据文件让matlab调用绘图
 	for(i=0;i<t;i++)
 	{
 		(*(X_old.input_Xbuff))[X_old.Data_input]=X[i];
 		X_old.Data_input++;
 		X_old.Data_input%=Nd;
 		y=Fir_filter(&X_old,hn,Nd);
 		fprintf(Y_fp, "%lf\n",y); //写入数据到输出文件数据 
 		
	}
	fclose(Y_fp);//关闭文件 

matlab绘制数据图形,可以看出滤波效果不错

                                                        (滤波前后对比)

                                                  (滤波器幅频响应)

2.用指标设计滤波器

设计一个带通滤波器

指标:

采样频率=5000

指标as=50 

通带截止为800 和1500

阻带截止为400 和2000

    

	Transfer_functions_struct H;
	H.ast=50;
	H.fp1=800;
	H.fst1=400;
	H.fp2=1500;
	H.fst2=2000;
	H.fs=5000;
	H_Struct *hk=NULL;
	hk=FIR_Filter_Transfer_functions_param2(BANDSTOPFILTER,&H);
	
	FILE*H_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/H_pm.txt", "w");  //输出H的数据文件让matlab调用 
	for(i=0;i<hk->N;i++)
 	{ 	
   		fprintf(H_fp, "%lf\n",(*(hk->Hn))[i]);	
	}
	
	fclose(H_fp);
	
	FILE*Y_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/Y_pm.txt", "w");  //输出Y的数据文件让matlab调用 
	for(i=0;i<t;i++)
 	{
 		
 		(*(X_old.input_Xbuff))[X_old.Data_input]=X[i];  //将 输入放入历史输入数组
 		X_old.Data_input++;
 		X_old.Data_input%=hk->N;
 		y=Fir_filter(&X_old,(*(hk->Hn)),hk->N);
 		//printf("%lf\n",y);
 		
 		fprintf(Y_fp, "%lf\n",y);	
	}
	
	fclose(Y_fp);
	printf("%d\n",hk->N);

matlab

                                                        

                                                (滤波器幅频响应)

四、个人实验的完整代码

#include<stdio.h>
#include <stdlib.h>
#include <math.h>


#define pi  3.1415926535897932

/*----窗类型-----*/ 
//三角形窗未完成,所以其实三角形和矩形的一样 
#define Rectangle  1			//矩形 
#define triangle   2			//三角 
#define	Hanning    3			//汉宁
#define	Hamming    4			//海明 
#define	Blackman   5			//布拉克曼

/*----滤波类型-----*/ 
#define LOWPASSFILTER	 	1      //低通 
#define HIGEPASSFILTER  	2
#define	BANDPASSFILTER   	3	  //带通	
#define	BANDSTOPFILTER    	4

typedef struct {
	double(*input_Xbuff)[];       //指向一个缓存区用于存放历史数据 ,长度为N的数组 
	int Data_input;      		 
	int Data_output	;			
}FIR_struct;          /*一个存历史输入和当前输入的 环形数组  */ 

typedef struct{
	double(*Hn)[];            // 指向一个 传递函数的指针 
	int N;					//传递函数的阶数 
	
}H_Struct;            /*传递函数结构体------第二种函数实现用到 */ 


typedef struct {
	int fs;                                          //采样率 
	int fp1;                                		 //通带截止频率 1  靠近w=0这边的 
	int fst1;                                		 //通带截止频率 1 	靠近w=0这边的 
	int fp2;                                		 //通带截止频率 2   如果为低通和高通则 不用关 2 
	int fst2;                                		 //阻带截止频率 2 
	int ast;                                		 //阻带最小衰减		
}Transfer_functions_struct; /*模拟指标结构体  */ 

void FIR_Struct_Init(FIR_struct *Fir_variable); 
H_Struct* FIR_Filter_Transfer_functions_param2(char Filter_type,Transfer_functions_struct*Transfer_param);
char FIR_Filter_Transfer_functions_param(double *Filter_h,char Filter_type,double Wc1 ,double Wc2 ,unsigned int N,int window); 
double Fir_filter(FIR_struct*Xdata,double*hn,unsigned int N);


#define Nd 42         //阶数 
#define Typ 3        //当 1 2 不同函数设计低通   否则用第二种函数设计 带通 
int main()
{
	
 	double hn[Nd]={0};        //fir滤波器数组 
 	double fs=5000;
 	double fp=1000; 	
 	double fst=1400; 	
 	double wc=2*pi*((fst+fp)/2)/fs;          //3db频率
	int i=0,k;

	double X[500];
	double y;
	/*---*/ 
	double old[Nd];      			 //历史输入数组 
	FIR_struct X_old;
	FIR_Struct_Init(&X_old);
	X_old.input_Xbuff=&old;
	
	int t=500;
	/*---输入信号*/ 
	for(k=0;k<t;k++)
	{
		X[k]=sin(2*pi*320*k/fs)+sin(2*pi*1200*k/fs)+sin(2*pi*2400*k/fs); 
	}
	#if Typ==1   /*用第一种函数设计低通滤波器*/ 

 	FIR_Filter_Transfer_functions_param(hn,LOWPASSFILTER,wc,0,Nd,Hamming);
 	
 	FILE*H_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/H_pm.txt", "w");  //输出H的数据文件让matlab调用绘图 
 	for(i=0;i<Nd;i++)
 	{
 		
 		fprintf(H_fp, "%lf\n",hn[i]);
	}
 	FILE*Y_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/Y_pm.txt", "w");   //输出Y的数据文件让matlab调用绘图
 	for(i=0;i<t;i++)
 	{
 		(*(X_old.input_Xbuff))[X_old.Data_input]=X[i];
 		X_old.Data_input++;
 		X_old.Data_input%=Nd;
 		y=Fir_filter(&X_old,hn,Nd);
 		fprintf(Y_fp, "%lf\n",y); //写入数据到输出文件数据 
 		
	}
	fclose(Y_fp);//关闭文件 


	
#elif Typ==2    /*用第二种函数设计低通滤波器*/ 
	Transfer_functions_struct H;
	H.ast=50;
	H.fp1=1000;
	H.fst1=1400;
	H.fs=5000;
	H_Struct *hk=NULL;
	hk=FIR_Filter_Transfer_functions_param2(LOWPASSFILTER,&H);

	FILE*H_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/H_pm.txt", "w");  //输出H的数据文件让matlab调用 
	for(i=0;i<hk->N;i++)
 	{
 		
   		
   		fprintf(H_fp, "%lf\n",(*(hk->Hn))[i]);
   		
 		
	}
	fclose(H_fp);
	
	FILE*Y_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/Y_pm.txt", "w");  //输出Y的数据文件让matlab调用 
	for(i=0;i<t;i++)
 	{
 		(*(X_old.input_Xbuff))[X_old.Data_input]=X[i];
 		X_old.Data_input++;
 		X_old.Data_input%=hk->N;
 		y=Fir_filter(&X_old,(*(hk->Hn)),hk->N);
 		fprintf(Y_fp, "%lf\n",y);
 		
	}
	fclose(Y_fp);
	printf("%d\n",hk->N);
	
	
	
	
#else      /*设计一个带通滤波器*/ 
	Transfer_functions_struct H;
	H.ast=50;
	H.fp1=800;
	H.fst1=400;
	H.fp2=1500;
	H.fst2=2000;
	H.fs=5000;
	H_Struct *hk=NULL;
	hk=FIR_Filter_Transfer_functions_param2(BANDSTOPFILTER,&H);     
	
	FILE*H_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/H_pm.txt", "w");  //输出H的数据文件让matlab调用 
	for(i=0;i<hk->N;i++)
 	{ 	
   		fprintf(H_fp, "%lf\n",(*(hk->Hn))[i]);	
	}
	
	fclose(H_fp);
	
	FILE*Y_fp = fopen("E:/Matlab1/bin/DSP_poj/Fir_filter/Y_pm.txt", "w");  //输出Y的数据文件让matlab调用 
	for(i=0;i<t;i++)
 	{
 		
 		(*(X_old.input_Xbuff))[X_old.Data_input]=X[i];      //将 输入放入历史输入数组 
 		X_old.Data_input++;
 		X_old.Data_input%=hk->N;
 		y=Fir_filter(&X_old,(*(hk->Hn)),hk->N);
 		//printf("%lf\n",y);
 		
 		fprintf(Y_fp, "%lf\n",y);	
	}
	
	fclose(Y_fp);
	printf("%d\n",hk->N);
		
#endif
 	return 0;	
} 


/*----------------------- 
* 函数名  	FIR_Struct_Init
* 输入  	@Fir_variable  :一个 历史输入 环形数组指针 
* 功能      初始化数组
* 返回 		无 
----------------------*/ 
void FIR_Struct_Init(FIR_struct *Fir_variable)
{
	int i;
	Fir_variable->Data_input=0;
	Fir_variable->Data_output=0;
	
	Fir_variable->input_Xbuff=NULL;

}

/*----------------------- 
* 函数名  	FIR_Filter_Transfer_functions_param2
* 输入  	
 			@Filter_type  :		滤波器类型  低通高通带通带阻  参数可以是[LOWPASSFILTER	, HIGEPASSFILTER  ,BANDPASSFILTER  , BANDSTOPFILTER] 
  			@Transfer_param:		滤波器的模拟指标,   
  		
* 功能      按照模拟指标设计滤波器 
* 返回 		H_Struct包含 滤波器传递函数 和 阶数 的结构体 , 
----------------------*/ 
H_Struct* FIR_Filter_Transfer_functions_param2(char Filter_type,Transfer_functions_struct*Transfer_param) 
{
	/*------------数字指标-------------------*/ 
  	double 	Wc1=2*pi*((Transfer_param->fp1+Transfer_param->fst1)/2)/Transfer_param->fs;
  	double	Wc2=2*pi*((Transfer_param->fp2+Transfer_param->fst2)/2)/Transfer_param->fs;
  	double  det_W1=2*pi*abs(Transfer_param->fst1-Transfer_param->fp1)/Transfer_param->fs;           //过度带带宽 
  	double  det_W2=2*pi*abs(Transfer_param->fst2-Transfer_param->fp2)/Transfer_param->fs;			//过度带带宽 2 
  	double 	det_W=det_W1;
  	if((Filter_type==BANDPASSFILTER)||(Filter_type==BANDSTOPFILTER)) 				 //如果是带通或者带阻,选择窄的指标 
  	{
  		det_W=det_W1>det_W2?det_W2:det_W1;
	}
	
	
	int n;
	int N;
	int window; 
	/*窗函数选择--------------------------------------------------------------------------- */ 
	// 根据衰as减选择窗 
	switch((int)(Transfer_param->ast/10))
	{
	  	case 2:   //20db 
	  		N=(int)1.8*pi/det_W;
	  		if(N!=1.8*pi/det_W)N++;
	  		window=Rectangle;
	  		break;	
		case 3://30db 
			N=(int)6.1*pi/det_W;
	  		if(N!=6.1*pi/det_W)N++;
	  		window=triangle;
	  		break;
		case 4: //40db 
			N=(int)(6.2*pi/det_W);
	  		if(N!=6.2*pi/det_W)N++;
	  		window=Hanning;
	  		break;
	  	case 5 ://50db 
	  		N=(int)(6.6*pi/det_W);
	  		if(N!=6.6*pi/det_W)N++;
	  		window=Hamming;
	  		break;
		case 7 ://70db
			N=(int)11*pi/det_W;
	  		if(N!=11*pi/det_W)N++;
	  		window=Blackman;
	  		break;
		default: 
			return 0;	
	}

	int const const_N=N;
 	double win_param[const_N]; //存放窗函数数据 
	switch(window)
	{
	  	case Rectangle:        //矩形 
	  		for(n=0;n<N;n++)
	  		{
	  			win_param[n]=1;  			
			}
	  		break;
		case triangle:
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=1; //三角形窗未实现			
			}
	  		break;
		case Hanning:  
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.5*(1-cos(2*pi*n/(N-1))); 			
			}
	  		break;
	  	case Hamming :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.54-0.46*cos(2*pi*n/(N-1));
//					printf("%lf\n",win_param[n]);			
			}  		
	  		break;
		case Blackman :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.42-0.5*cos((4*pi*n/(N-1))-0.08*(4*pi*n/(N-1))); 			
			}  		
	  		break;
		default: //只设计了几个常用的,衰减超出这些则返回失败 
			return 0;	
	}
  

	  /*构造理想滤波器-----------------------------------------------------------------------------*/
	   
	double tao;				//H的群延迟
	double h_lixiang[const_N];	//存放理想滤波器 数据 
	tao=(N-1)/2.0;			//求出中心点 
 
	switch(Filter_type)
	{
	  	case LOWPASSFILTER:
	  		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)		//n-tao=0时分子分母为零  取极限 
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=sin(Wc1*(n-tao))/(pi*(n-tao));                //理想低通滤波器表达式 
				}	  					  			
			}
	  		break;
		case HIGEPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)		//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case BANDPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)	//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(Wc2*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		  
		case BANDSTOPFILTER:
		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)	//n-tao=0时分子分母为零  取极限
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc2*(n-tao))+sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
	  	
		default:      //如果不是这些则返回失败 
			return 0;		
	}
	
	/*计算FIR的传递函数*/ 
	H_Struct *Filter_h=NULL;
	Filter_h=(H_Struct*)malloc(sizeof(H_Struct));
	Filter_h->Hn=(double(*)[])malloc(sizeof(double)*N);                //申请 跟阶数相等的内存空间 
	Filter_h->N=N;
	
	for(n=0;n<N;n++) //将窗函数和理想低通相乘得到 h 
	{
	  		
		(*(Filter_h->Hn))[n]=h_lixiang[n]*win_param[n];
				  					  			
	}
	return Filter_h;	   
}

/*----------------------- 
* 函数名  	Fir_filter
* 输入  	@Xdata:	包含这一时刻的 历史数据数组 
 			@hn  :		滤波器的传递函数 
  			@N			阶数 
* 功能      求出滤波后的输出  
* 返回 		这一时刻滤波后的输出 
----------------------*/ 
double Fir_filter(FIR_struct*Xdata,double*hn,unsigned int N)
{
	double y=0;
	int i=0,j=0; 

	for(i=0;i<N;i++)
	{
		  //寻找历史输入的数组 下标  X[n-i] 
		if((Xdata->Data_output-i)<0)
		{
			//越界 
			j=N+Xdata->Data_output-i;
		}else
		{
			j=Xdata->Data_output-i;
		}
		/*Fir的差分方程形式-->卷积*/ 
		y+=hn[i]*(*(Xdata->input_Xbuff))[j];	
	}
	/*延时数据,此刻变成上一时刻*/ 
	Xdata->Data_output++;  
	if(Xdata->Data_output>=N)
	{
		Xdata->Data_output=0;
	}
	
	return y;
	
}
//已知阶数,求fir 的 传递函数 值 
/*----------------------- 
* 函数名  	FIR_Filter_Transfer_functions_param
* 输入  	@Filter_h  	:	用于返回传递函数 数据数组 长度为N
 			@Filter_type  :滤波器类型  低通高通带通带阻  参数可以是[LOWPASSFILTER	, HIGEPASSFILTER  ,BANDPASSFILTER  , BANDSTOPFILTER] 
  			@Wc1:			滤波器的截止频率 
  			@Wc2:			BPF和BSF的第二个截止频率  
  			@N				阶数 
 			@window			窗函数类型:参数可以是[Rectangle,  triangle ,  	Hanning ,Hamming ,Blackman] 
* 功能      按阶数设计滤波器 ,注意设计高通和带阻时  N必须为奇数 
* 返回 		1成功  0失败 
----------------------*/ 
char FIR_Filter_Transfer_functions_param(double *Filter_h,char Filter_type,double Wc1 ,double Wc2 ,unsigned int N,int window)
{
 
	int n;
	//偶数点无法设计高通和带阻 // 
	if(((Filter_type==HIGEPASSFILTER)||(Filter_type==BANDSTOPFILTER))&&(N%2==0))
	{
		return 0;	
	} 
	/*窗函数******-------------------------------*/ 
	int const const_N=N;
 	double win_param[const_N];			//存放窗函数数据 
	switch(window)
	{
	  	case Rectangle:
	  		for(n=0;n<N;n++)
	  		{
	  			win_param[n]=1;  			
			}
	  		break;
		case triangle:
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=1; //2部分,懒得打了 ,直接用矩形窗游览			
			}
	  		break;
		case Hanning: 
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.5*(1-cos(2*pi*n/(N-1))); 			
			}
	  		break;
	  	case Hamming :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.54-0.46*cos(2*pi*n/(N-1));
//					printf("%lf\n",win_param[n]);			
			}  		
	  		break;
		case Blackman :
			for(n=0;n<N;n++)
	  		{
	  				win_param[n]=0.42-0.5*cos((4*pi*n/(N-1))-0.08*(4*pi*n/(N-1))); 			
			}  		
	  		break;
		default: 
			return 0;	
	}
	  

	  /*---------------构造理想滤波器-------------------------*/ 
	double tao;   //群延迟 

	double h_lixiang[const_N];  //理想滤波器 
	tao=(N-1)/2.0;
 
	switch(Filter_type)
	{
	  	case LOWPASSFILTER:
	  		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)       //如果 (n-tao)==0则分子分母为0   取极限 
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=sin(Wc1*(n-tao))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case HIGEPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		case BANDPASSFILTER:
			for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(Wc2*(n-tao))-sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
		  
		case BANDSTOPFILTER:
		for(n=0;n<N;n++)
	  		{
	  			if((n-tao)==0)
				{
					h_lixiang[n]=Wc1/pi;
				}
				else
				{
					h_lixiang[n]=(sin(pi*(n-tao))-sin(Wc2*(n-tao))+sin(Wc1*(n-tao)))/(pi*(n-tao));
				}	  					  			
			}
	  		break;
	  	
		default: 
			return 0;	
	}
	/*--------求h[n]-----------*/ 
	for(n=0;n<N;n++)
	  	{
	  		
				Filter_h[n]=h_lixiang[n]*win_param[n];
				  					  			
		}
	return 1;	
}

总结

        写一半时按一下撤销文章变回半小时小时前的气死我了

这里三角窗是为实现的,用了矩形代替,可自己修改,

可能有bug我没有测试带阻等设计

  • 13
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值