⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filterdesigndlg.cpp

📁 无限脉冲数字滤波器的设计系列。本程序为高通滤波器。欢迎切磋。
💻 CPP
字号:
// filterDesignDlg.cpp : implementation file
//

#include "stdafx.h"
#include "filterDesign.h"
#include "filterDesignDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//yyyyyyyyyyyyyyyyyyyy 复数结构及复数运算 yyyyyyyyyyyyyyyyyyyyy
#include "math.h"
double PI = atan(1)*4;

struct complexNumber//定义复数结构z=a+bi
{
	double a;
	double b;
};

complexNumber complexAdd(complexNumber z1, complexNumber z2)//复数加法
{
	complexNumber z;
	z.a=z1.a + z2.a;
	z.b=z1.b + z2.b;
	return z;
}

complexNumber complexSub(complexNumber z1, complexNumber z2)//复数减法
{
	complexNumber z;
	z.a=z1.a - z2.a;
	z.b=z1.b - z2.b;
	return z;
}

complexNumber complexMultiply(complexNumber z1, complexNumber z2)//复数乘法
{
	complexNumber z;
	z.a=z1.a*z2.a - z1.b*z2.b;
	z.b=z1.a*z2.b + z1.b*z2.a;
	return z;
}

complexNumber complexGonge(complexNumber z1)//共轭复数
{
	complexNumber z;
	z.a=  z1.a;
	z.b= -z1.b;
	return z;
}

double complexModule2(complexNumber z)//求复数模的平方
{
	return (z.a*z.a + z.b*z.b);
}

complexNumber complexDivide(complexNumber z1, complexNumber z2)//复数除法
{
	complexNumber z=complexMultiply(z1,complexGonge(z2));
	double module=complexModule2(z2);

	z.a/=module;
	z.b/=module;
	return z;
}

complexNumber complexInvert(complexNumber z1)//复数倒法
{
	complexNumber z=complexGonge(z1);
	double module=complexModule2(z1);

	z.a/=module;
	z.b/=module;
	return z;
}
//yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

//yyyyyyyyyyyyyyyy 多项式运算 yyyyyyyyyyyyyyyyyyyyyyyyyy
void polyAdd(double* a, int m, double* b, int n, double* p, int* np)//多项式加法
{	//a、b代表两个多项式序列的系数, m、n分别是它们的自变量最高/最低次数, 它们比多项式的项数少1
	//p代表乘积多项式的系数, N是其自变量最高/最低次数, 它们比多项式的项数少1

	int k;

	*np=max(m,n);//和的长度等于长序列的长度

	if (m>n)//如果a序列更长
	{
		for (k=0; k<=n; k++)
			*(p+k)=*(a+k) + *(b+k);//前半截取a、b序列之和
		for (k=n+1; k<=*np; k++)
			*(p+k)=*(a+k);//后半截取a序列
	}
	else
	{
		for (k=0; k<=m; k++)
			*(p+k)=*(a+k) + *(b+k);//前半截取a、b序列之和
		for (k=m+1; k<=*np; k++)
			*(p+k)=*(b+k);//后半截取b序列
	}
}

void polyMultiplyNumber(double* a, int m, double c, double* p, int* np)//多项式乘以系数c
{
	for (int k=0; k<=m; k++)
		*(p+k)=*(a+k) * c;//各项都乘以系数c
	*np=m;//项数不变
}

void polyMultiplyPoly(double* a, int m, double* b, int n, double* p, int* np)//多项式乘法
{
	int k;
	double aa[100], bb[100];

	*np=m+n;//积的长度等于两序列长度之和

	for (k=0; k<=*np; k++)//分别延长序列a、b成aa、bb, 使其长度都达到m+n, 延长部份补0
		{aa[k]=0;  bb[k]=0;}
	for (k=0; k<=m; k++)//将序列a复制进aa的前半截
		aa[k]=*(a+k);
	for (k=0; k<=n; k++)//将序列b复制进bb的前半截
		bb[k]=*(b+k);

	for (k=0;k<=*np;k++)//计算各次项的系数
	{
		double sum=0;
		for (int i=0;i<=k;i++)//第k次项的系数由k+1个a[i]*b[k-i]相加而成
			sum=sum + aa[i] * bb[k-i];
		*(p+k)=sum;
	}
}

void polyPower(double* a, int m, int k, double* p, int* np)//多项式的幂(a的k次幂)
{
	int i=1, N1;
	double p1[100];
	
	if (k<=0)
	{ AfxMessageBox("多项式的幂不可求, 因为幂指数k<=0 !"); exit(0);}

	polyMultiplyNumber(a, m, 1, p1, &N1);//p1=a

	do//循环累乘a(共乘k-1个a)
	{
		polyMultiplyNumber(p1, N1, 1, p, np);//p1→p

		i++;
		if (i>k) break;

		polyMultiplyPoly(p, *np, a, m, p1, &N1);//p1=p*a
	}while(1);
}
//yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

/////////////////////////////////////////////////////////////////////////////
// CFilterDesignDlg dialog

CFilterDesignDlg::CFilterDesignDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFilterDesignDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CFilterDesignDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFilterDesignDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CFilterDesignDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CFilterDesignDlg, CDialog)
	//{{AFX_MSG_MAP(CFilterDesignDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_Button_Calculate, OnButtonCalculate)
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFilterDesignDlg message handlers

BOOL CFilterDesignDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here
	ShowWindow(SW_MAXIMIZE);//yyyyyyyyyyyyyyyy
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFilterDesignDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	CDialog::OnSysCommand(nID, lParam);
}

void CFilterDesignDlg::OnPaint() 
{
	CDialog::OnPaint();
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFilterDesignDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CFilterDesignDlg::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	exit(0);//yyyyyyyyyyyy

	CDialog::OnLButtonDblClk(nFlags, point);
}

void CFilterDesignDlg::OnButtonCalculate() 
{
	CDC* pDC=GetDC();
	pDC->SetBkMode(TRANSPARENT);
	CString astr;
	int positionY=10;
	int x0=200, y0=500;
	pDC->MoveTo(x0-50, y0);
	pDC->LineTo(x0+700, y0);
	pDC->MoveTo(x0, y0-200);
	pDC->LineTo(x0, y0+200);


	//巴特沃思多项式的系数
	double a[11][11];
	a[1][0]=1;	a[1][1]=1;
	a[2][0]=1;	a[2][1]=1.4142136;	a[2][2]=1;
	a[3][0]=1;	a[3][1]=2.0000000;	a[3][2]=2.0000000;	 a[3][3]=1;
	a[4][0]=1;	a[4][1]=2.6131259;	a[4][2]=3.4142136;	 a[4][3]=2.6131259;	  a[4][4]=1;
	a[5][0]=1;	a[5][1]=3.2360680;	a[5][2]=5.2360680;	 a[5][3]=5.2360680;	  a[5][4]=3.2360680;	a[5][5]=1;
	a[6][0]=1;	a[6][1]=3.8637033;	a[6][2]=7.4641016;	 a[6][3]=9.1416202;	  a[6][4]=7.4641016;	a[6][5]=3.8637033;	  a[6][6]=1;
	a[7][0]=1;	a[7][1]=4.4939592;	a[7][2]=10.0978347;	 a[7][3]=14.5917939;  a[7][4]=14.5917939;	a[7][5]=10.0978347;	  a[7][6]=4.4939592;	a[7][7]=1;
	a[8][0]=1;	a[8][1]=5.1258909;	a[8][2]=13.1370712;	 a[8][3]=21.8461510;  a[8][4]=25.6883559;	a[8][5]=21.8461510;	  a[8][6]=13.1370712;	a[8][7]=5.1258309;	  a[8][8]=1;
	a[9][0]=1;	a[9][1]=5.7587705;	a[9][2]=16.5817187;	 a[9][3]=31.1634375;  a[9][4]=41.9863857;	a[9][5]=41.9863857;	  a[9][6]=31.1634375;	a[9][7]=16.5817187;	  a[9][8]=5.7587705;	a[9][9]=1;
	a[10][0]=1;	a[10][1]=6.3924532;	a[10][2]=20.4317291; a[10][3]=42.8020611; a[10][4]=64.8823963;	a[10][5]=74.2334292;  a[10][6]=64.8823963;	a[10][7]=42.8020611;  a[10][8]=20.4317291;	a[10][9]=6.3924532;	a[10][10]=1;

	//输入参数. 主要是截止频率和衰减分贝(根据所需要的滤波器进行人为设定)
	int N=10;//巴特沃思滤波器的阶数
	double fs=50;//10*1000;//采样频率(Hz)
	double fc=9;//3*1000;//2*1000;//高通3DB的截止频率(Hz)

	//计算周期和截止处数字角频率
	double T, wc;
	T=1/fs;//采样周期(即采样时间间隔)
	wc=2*PI*fc*T;

	//计算c1
	double aumigapc=1;//原型滤波器的截止频率. 此值总是取为常数1(rad/s)
	double c1=aumigapc*tan(wc/2);

	if (N>10)
		{AfxMessageBox("滤波器的阶数要求太高(>10), 请调整设计要示, 重新设计!"); exit(0);}
	astr.Format("        N = %d", N);
	pDC->TextOut(20,10, astr);

	//求数字高通滤波器的传递函数H(z)
	double fenzi[2], fenmu[2];//p=f(z)表达式中的分子多项式(1 + Z^-1)
	                                          //分母多项式(1 - Z^-1)
	double p[12][11], pSum[11];//H(z)分子多项式(1个)、分母中的多项式(1+N个)及它们的和. 
							   //由于只有N<=10的滤波器有设计数据可查, 所以此处最多有12
	                           //个多项式, 每个多项式最多有1+N<=11项
	int Np[12], Nsum;//各式项式p[k]所含的项数及它们和所含的项数
	double fenziPower[11], fenmuPower[11];//分子幂和分母幂. 最多1+10=11项
	int Nfenzi, Nfenmu;//分子幂的项数和分母幂的项数
	int k;

	fenzi[0]=c1;	fenzi[1]=c1;
	fenmu[0]=1;		fenmu[1]=-1;

	polyPower(fenmu, 1, N, p[0], &Np[0]);//计算H(z)分子多项式(=p(z)分母的N次幂)
	for (k=1; k<=N+1; k++)//计算H(z)分母中的N+1个多项式.(按H(p)中按p的降序排列)
	{
		if (k==1)//第一个多项式p[1](=p(z)分子的N 次幂)
			polyPower(fenzi, 1, N, p[k], &Np[k]);
		else if(k==N+1)//最后一个多项式p[N+1](=p(z)分母的N 次幂)
			polyPower(fenmu, 1, N, p[k], &Np[k]);
		else//中间各个多项式p[k](=p(z)分子的N-k+1次幂 * 分母的k-1次幂)
		{
			polyPower(fenzi, 1, N-k+1, fenziPower, &Nfenzi);//分子的N-k+1次幂
			polyPower(fenmu, 1, k-1, fenmuPower, &Nfenmu);//分母的k-1次幂
			polyMultiplyPoly(fenziPower, Nfenzi, fenmuPower, Nfenmu, p[k], &Np[k]);//两者相乘

					if (Np[k] != N)
						{AfxMessageBox("多项式计算有误(阶次不符), 请检查!");  exit(0);}
		}
		
		polyMultiplyNumber(p[k], Np[k], a[N][k-1], p[k], &Np[k]);//各多项式乘以对应的巴特沃思多项式系数
	}

	polyMultiplyNumber(p[1], Np[1], 1, pSum, &Nsum);//把各多项式加起来(同类项合并)
	for (k=2; k<=N+1; k++)
		polyAdd(pSum, Nsum, p[k], Np[k], pSum, &Nsum);

					if (Np[0] != N || Nsum != N)
						{AfxMessageBox("多项式计算有误(阶次不符), 请检查!");  exit(0);}

					astr.Format("%15.8f", p[0][0]/pSum[0]);
					pDC->TextOut(20,50, astr);
					
					for (k=0; k<=N; k++)//将H(z)的分母多项式系数写成串
					{
						astr.Format("%15.8f", pSum[k]/pSum[0]);	
						pDC->TextOut(20,80+k*30, astr);
					}

	//将H(z)用z=exp(jw)化成H(jw),以便画频率响应图
	double w, moduleHw;
	complexNumber z1, z2, Hw;
	double ratioX=150, ratioY=100;

	for (w=0; w<=PI; w+=0.002)
	{
		z1.a=0;		z1.b=0;//H(jw)的分子
		for (k=0; k<=N; k++)//将分子按exp(-jw)=cos(w)-jsin(w)展开后, 进行实部和虚部的合并
		{
			z1.a+= p[0][k]*cos(k*w);
			z1.b+=-p[0][k]*sin(k*w);
		}
		
		z2.a=0;		z2.b=0;//H(jw)的分母
		for (k=0; k<=N; k++)//将分母按exp(-jw)=cos(w)-jsin(w)展开后, 进行实部和虚部的合并
		{
			z2.a+= pSum[k]*cos(k*w);
			z2.b+=-pSum[k]*sin(k*w);
		}

		Hw=complexDivide(z1,z2);//分子除分母,得H(jw)

		moduleHw=sqrt(complexModule2(Hw));//求|H(jw)|
		
		//画幅度曲线|H(jw)|=f(w)
		pDC->SetPixel(x0+w*ratioX, y0-moduleHw*ratioY, RGB(255,0,0));

		//画高通段起始频率竖线
		pDC->SetPixel(x0+wc*ratioX, y0-moduleHw*ratioY, RGB(0,0,255));
			astr.Format("%.1fHz", fc+1);
			pDC->TextOut(x0+wc*ratioX-20, y0+5, astr);
	}


	//将设计所得滤波器的参数输出成数据文件
	CStdioFile toFile;
	CString fileName="E:\\VC程序集\\工作\\滤波器设计\\滤波器设计.txt";

	if(!toFile.Open(fileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite))//打开输出文件. 
		    //如该文件不存在, 则modeCreate使之被创建; 如果已经存在, 则modeNoTruncate使其内容不被清空
		{MessageBox("文件打开失败,请检查!"); exit(0);}

	toFile.SeekToEnd();//定位到文件尾继续写
	toFile.WriteString("\n\n---------------------------------------------------------------------------------------------------------\n");
	toFile.WriteString("高通滤波器: \n");

	CString astrPart;
	astr="    分子:";
	for (k=0; k<=N; k++)//将H(z)的分子多项式系数写成串
		{astrPart.Format("%15.10f", p[0][k]/pSum[0]);	astr+=astrPart;}
	astr+="  //\n";
	toFile.WriteString(astr);
	
	astr="    分母:";
	for (k=0; k<=N; k++)//将H(z)的分母多项式系数写成串
		{astrPart.Format("%15.10f", pSum[k]/pSum[0]);	astr+=astrPart;}
	astr+="  //\n";
	toFile.WriteString(astr);

	//将传递函数的分子分母组合成差分方程的形式
	toFile.WriteString("    差分方程: \n");
	astr="        y[n]=";
	for (k=0; k<=N; k++)//组合分子,即Σbr*x[n-r]项
	{
		astrPart.Format("%+15.10f*x[n-%d]", p[0][k]/pSum[0], k);
		astr+=astrPart;
	}
	
	for (k=1; k<=N; k++)//组合分母,即Σak*y[n-k]项
	{
		astrPart.Format("%+15.10f*y[n-%d]", -pSum[k]/pSum[0],k);
		astr+=astrPart;
	}
	
	toFile.WriteString(astr);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -