摘 要
音频放大器可以用来话音扩音、音乐欣赏、卡拉OK伴唱,其中的电子混响器使声音听起来具有一定深度感和空间立体感。
音频放大器可以用来话音扩音、音乐欣赏、卡拉OK伴唱,其中的电子混响器使声音听起来具有一定深度感和空间立体感。
音频放大器可以用来话音扩音、音乐欣赏、卡拉OK伴唱,其中的电子混响器使声音听起来具有一定深度感和空间立体感。
关键词:
目 录
1 设计目的与要求... 1
2 电路原理分析与设计... 1
2.1 **电路原理简介... 1
2.2 **电路分析... 2
2.3 **电路原理图... 2
3 Protel 99SE绘制图... 3
3.1 元件库的调用... 3
3.2 放置元件... 4
3.3 原理图的布线... 5
4 PCB设计... 10
4.1 图形界面设计... 10
4.2 程序代码设计... 12
4.3 运行结果及分析... 17
结 论... 19
参考文献... 20
很多自然科学和工程技术中的问题的解决最终都归结到线性方程组的求解,高斯消去法是线性方程组解法中很经典的算法,由它改进、变形得到的全选主元消去法,是一种效率很高、较为常用的线性方程组解法。
线性方程组的一般形式为Ax=b,其中A是线性方程组的系数矩阵,x是列向量,是方程组的解,b也是列向量,这里假定A是非奇异矩阵。
程序测试数据来自徐士良先生编著的《C常用算法程序集》中,所选的方程是:
(1)
设有n元线性方程组:
(2)
将(2)写成矩阵形式,其中:
(3)
将系数矩阵A和向量b放在一起,形成增广矩阵B:
(4)
全选主元消去就在这个B矩阵上进行,整个过程分为两个步骤:
第一步消去过程。
对于k从0开始到n-2结束,进行以下三步:
(1)首先,从系数矩阵A的第k行、k列开始的子矩阵中选取绝对值最大的元素作为主元素,例如:
(5)
然后交换B的第k行与第i1行,第k行与第j1列,这样,这个子矩阵中的具有最大绝对值的元素被交换到第k行、k列的位置。
(2)其次,进行归一化计算。计算方法为:
(6)
(3)最后,进行消去运算:
(7)
第二步,回代过程。
(8)
在这里,只是列出简要地给出了全选主元高斯消去法的算法步骤,具体推导及详细过程可参考数值分析方面的有关资料。
当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。这个过程可用下式描述:
采用这种方法时,首先计算出元素的直接哈希地址,如果该存储单元已被其他元素占用,则继续查看地址为的存储单元,如此重复直至找到某个存储单元为空时,将关键字为 key 的数据元素存放到该单元。增量 d 可以有不同的取法,并根据其取法有不同的称呼。
类模板就是设计一种类的框架,可以适用不同的数据类型,只是一种类的抽象,因此,利用类模板可以针对不同的数据类型定义出具有共性的一组类。
定义形式如下:
template <类型名参数名1,类型名参数名2,…>
class 类名
{
类声明体;
};
与函数模板类似,通过使用类模板可以使得所定义的类中的某些数据成员某些成员函数的参数某些成员函数的返回值都可以是任意的数据类型(包括基本类型和自定义类型)。所以,可以通过类模板将程序所处理的对象的类型参数化,从而使得同一段程序可用于处理多种不同类型的对象,提高了程序的抽象层次和可重用性。由于哈希表中的数据元素可以是char, int, float等多种数据类型,因此可以使用类模板来构造本程序的实现框架。
本设计面临的计算问题的关键是矩阵运算。可以定义一个矩阵类Matrix作为基类,然后由矩阵类派生出线性方程组类Linequ。矩阵类Matrix只处理n×n类型的方阵,方阵用一个一维数组来存放,矩阵类Matrix的数据成员包括数组的首地址和n,矩阵类Matrix的功能有设置矩阵的值SetMatrix( )和显示矩阵PrintM( )等。
从问题的需要来看,线性方程组类Linequ的数据除了由矩阵类Matrix继承过来用于存放系数矩阵A的成员外,还应该包括存放解向量x和方程右端向量b的数组首地址。线性方程组类Linequ的主要操作有设置SetLinequ( )、显示PrintL( )、求解Solve( )及输出方程的解showX( )。可以通过定义线性方程组类Linequ的新增成员函数来实现这些针对方程组求解的功能。
在线性方程组的求解过程中,在线性方程组类Linequ的成员函数Solve中需要访问基类矩阵类Matrix的数据成员,利用公有继承方式派生,同时将Matrix类中的数据成员的访问控制设置为保护类型。这样,经过公有派生之后,基类的保护成员在派生类中依然是保护成员,可以被派生类的成员函数访问。
整个类分别使用了insert(t1 key,t2 data)实现哈希表元素的插入,remove(t1 key)实现哈希表元素的删除,query(t1 key)实现哈希表元素的查找,display()实现哈希表元素的显示。
//Linequ.h文件,实现类的声明
#include <iostream>
#include <cmath>
using namespace std;
class Matrix //基类Matrix声明
{
public: //外部接口
Matrix(int dims=2); //构造函数
~Matrix(); //析构函数
void SetMatrix(double *rmax); //矩阵赋初值
void PrintM(); //显示矩阵
protected:
int index; //方阵的行数
double* MatrixA; //矩阵存放数组首地址
};
class Linequ:public Matrix //公有派生类Linequ声明
{
public: //外部接口
Linequ(int dims=2); //构造函数
~Linequ(); //析构函数
void SetLinequ(double *a, double *b); //方程赋值
void PrintL(); //显示方程
int Solve(); //全选主元高斯消去法求解方程
void ShowX(); //显示方程的解
private: //私有数据
double *sums; //方程右端项
double *solu; //方程的解
};
经过公有派生,Linequ类获得了除构造函数、析构函数之外的Matrix类的全部成员,由于基类的成员是公有和保护类型,因此在派生类中的成员函数中,基类继承来的成员全部可以访问,而对于建立Linequ类对象的外部模块来讲,基类的保护成员是无法访问的。通过保护访问类型和公有的继承方式,实现了基类Matrix的数据的有效共享和可靠保护。在程序中,方程的系数矩阵、解以及右端项全部采用了动态内存分配技术,这些工作都是在基类、派生类的构造函数中完成,它们的清理工作在析构函数中完成。
template<class t1,class t2>//构造函数的实现
hash<t1,t2>::hash(){
array=new linknode[7];
for(int i=0;i<7;i++){
array[i]=NULL;
}
}
template<class t1,class t2>
hash<t1,t2>::~hash(){
for(int i=0;i<7;i++){
if(array[i]!=NULL){
linknode n=array[i];
while(n!=NULL){
linknode n1=n;
n=n->next;
delete n1;
}
}
}
}
template<class t1,class t2>//插入元素的函数
void hash<t1,t2>::insert(t1 key,t2 data){
int sum=func(key)%7;
//派生类Linequ的实现
Linequ::Linequ(int dims):Matrix(dims) //派生类Linequ的构造函数
{ //使用参数调用基类构造函数
sums=new double[dims]; //动态内存分配
solu=new double[dims];
}
Linequ::~Linequ() //派生类Linequ的析构函数
{
delete[] sums; //释放内存
delete[] solu;
}
}else{
ln *n=new ln;
n->key=key;
n->data=data;
n->next=NULL;
array[sum]=n;
}
}
template<class t1,class t2>//查询元素的函数实现
t2 hash<t1,t2>::query(t1 key){
int sum=func(key)%7;
linknode p=array[sum];
while(p){
if(type=="char*"){
if(stricmp((char*)(int)p->key,(char*)(int)key)==0){ cout<<"关键字"<<key<<"的data值为:"<<endl;
return p->data;
}else{
p=p->next;
}
}else if(type=="void*"){
if((int)p->key==(int)key){ cout<<"关键字"<<key<<"的data值为:"<<endl;
return p->data;
}else{
p=p->next;
}
}else{
if(p->key==key){ cout<<"关键字"<<key<<"的data值为:"<<endl;
return p->data;
}else{
p=p->next;
}
}
}
return "您所查询的关键字在该哈希表中不存在!";
}
template<class t1,class t2>
void hash<t1,t2>::display()//显示哈希表元素的函数实现
{
for(int i=0;i<7;i++)
{ if(array[i]!=NULL)
{
ln *n=array[i];
while(n!=NULL)
{
cout<<"array["<<i<<"]"<<"为"<<n->key<<endl;
n=n->next;
}
}else cout<<"array["<<i<<"]"<<"为空!"<<endl;
}
}
template<class t1,class t2>//整型关键字哈希函数实现
int hash<t1,t2>::func(int i){
type="int";
return i;
}
template<class t1,class t2>//浮点型模板
int hash<t1,t2>::func(float i){
type="float";
int s=i*100;
return s;
}
template<class t1,class t2>//指向字符型指针关键字哈希函数实现
int hash<t1,t2>::func(char *i){
type="char*";
int s=strlen(i)*i[0];
return s;
}
template<class t1,class t2>//字符型模板
int hash<t1,t2>::func(char i){
type="char";
int s=(int)i;
return s;
} }
template<class t1,class t2>
void hash<t1,t2>::remove(t1 key)//删除元素的哈希函数实现
{
int sum=func(key)%7;
linknode p=array[sum];
if(p!=NULL)
{ if(p->next!=NULL)
{if(p->key==key)
{array[sum]=p->next;delete p;cout<<"关键字"<<key<<"已被删除!"<<endl;}
else
{ while(p->next!=NULL&&p->next->key!=key)
p=p->next;
linknode p2=p->next;
p->next=p2->next;
delete p2;
cout<<"关键字"<<key<<"已被删除!"<<endl;
}
}
else {array[sum]=NULL;delete p;cout<<"关键字"<<key<<"已被删除!"<<endl;}
}
else {cout<<"对不起!您删除的关键字"<<key<<"在本哈希表中不存在!"<<endl; }
}
MFC的图形界面程序设计可在上述类设计的基础上进行改造,MFC的图形界面程序与DOS界面程序的主要不同点是:MFC图形界面程序与DOS界面程序的输入输出方式不同,DOS界面程序采用字符交互式实现数据输入输出,主要通过cin,cout等I/O流实现,而MFC的图形程序界面采用标准Windows窗口和控件实现输入输出,因此必须在MFC类的框架下加入上面所设计的矩阵和方程组类,并通过图形界面的输入输出改造来完成。
首先在VC中建立MFC AppWizard(exe)工程,名称为GassineGU,并在向导的Step1中选择Dialog based,即建立基于对话框的应用程序,如下图5~6所示。
图5 建立MFC AppWizard(exe)工程
图6 建立基于对话框的应用程序
将对话框资源中的默认对话框利用工具箱改造成如下界面,如图7所示。
图7 方程组求解程序界面设计
图7所示的界面中包含了3个Static Text控件,3个Button控件,和2个Edit Box控件,控件的基本信息列表如下表1所示。
表1 控件基本信息
为了能够将对话框界面上的控件能够与代码联系起来,需要为24个Edit Box控件建立Member Variables,按Ctrl+w键进入MFC ClassWizard界面,选择Member Variables选项卡,可显示成员变量设置界面,如图8所示。
图8 成员变量设置界面
下面是编写代码的重要阶段,可以借鉴在设计基于DOS界面的控制台应用程序的代码,并将其作必要的改写,具体改写的步骤与内容如下。
// Haxibiao.cpp : implementation file
//
类
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
hash<char *,char *> h;//将实例化的hash类对象声明为全局的以便以下函数使用
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DE
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWANGDlg dialog
CWANGDlg::CWANGDlg(CWnd* pParent /*=NULL*/)
: CDialog(CWANGDlg::IDD, pParent)
{xGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CWANGDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CWANGDlg)
DDX_Text(pDX, IDC_EDIT1, m_HX);
DDX_Text(pDX, IDC_EDIT2, m_key);
DDX_Text(pDX, IDC_EDIT3, m_data);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CWANGDlg, CDialog)
//{{AFX_MSG_MAP(CWANGDlg)
ON_WM_SYSCOMMAND()
ON_W/////////////////////////////////////////////////////////////////////////////
// CWANGDlg message handlers
BOOL CWANGDlg::OnInitDialog()
{
CDialog::OnInitDialog();
h.insert("sds","etew");//初始化哈希表
h.insert("n25","45");//初始化哈希表
h.insert("4.5765k","2");//初始化哈希表
h.insert("$345","6");//初始化哈希表
h.insert("43.r","55");//初始化哈希表
h.insert("yan","24");//初始化哈希表
h.display();//h对象调用display()函数以显示哈希表元素
m_HX=h.str;
UpdateData(0);//在编辑框处显示哈希表元素
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
Menu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CWANGDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CWANGDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CWANGDlg::Oninsert() //“插入”按钮的响应函数
{
// TODO: Add your control notification handler code here
char a[10]="",b[10]="";
UpOnquery() //“查询”按钮的响应函数
{
// TODO: Add your control notification handler code here
char c[10]="";
UpdateData();
memcpy(c,m_key,m_key.GetLength());
h.query(c);
MessageBox((LPCTSTR)h.str);
}
void CWANGDlg::Onremove() //“删除”按钮的响应函数
{
// TODO: Add your control notification handler code here
char d[10]="";
UpdateData();
memcpy(d,m_key,m_key.GetLength());
h.remove(d);
MessageBox(h.str);
h.display();
m_HX=" ";
UpdateData(0);
m_HX=h.str;
UpdateData(0);
}
运行程序后,首先出现的界面如图9所示。
图9 程序初始运行界面
单击读入数据按钮后,可将系数矩阵A和方程组右端项b的数据在界面上显示出来,如图10所示。
图10 读入数据后的界面
单击计算求解按钮,实现求解并将解显示出来,如图11所示。
图11 求解方程组后的界面
单击退出按钮后,程序能够正常实现退出。
[1] 谭浩强.C++基础入门大全.北京:清华大学出版社,2012:100-102
[2] 郑莉,董渊,张瑞丰.C++语言程序设计(第3版).北京:清华大学出版社,2007:25-60
[3] 钱能.C++程序设计教程(第2版).北京:清华大学出版社,2007:100-130
电子信息与电气工程系课程设计报告题目系别专业班级学号姓名指导教师成绩20xx年9月13日课程设计任务书目录AD转换电路的PCB板设…
Protel课程设计报告学院中原工学院信息商务学院专业班级自动化071学号20xx81824132学生姓名王涛指导教师乔卫杰20x…
PROTEL课程设计报告专业电气工程及其自动化学号姓名班级教师电气与电子工程学院20xx62摘要Protel99SE是一种基于Wi…
天津工业大学理学院电子线路课程设计报告书班级姓名学号同组成员指导老师20xx114目录一课程设计的目的3二技术参数和设计要求3三电…
Protel99SE课程设计报告题目编号127姓名班级学号原理图印制电路板图总结通过为期两周的protel学习从刚开始对PROTE…
protel实训报告题目基于protel单片机最小系统电路的设计专业班级电子1002学生姓名辛威指导教师洪建勋武汉理工大学信息工程…
单片机最小系统PCB设计一实验目的1熟悉PROTEL的基本操作2掌握用PROTEL绘制原理图的基本方法3掌握用PROTEL制作PC…
电子信息与电气工程系课程设计报告题目系别专业班级学号姓名指导教师成绩20xx年9月13日课程设计任务书目录AD转换电路的PCB板设…
Protel课程设计报告学院中原工学院信息商务学院专业班级自动化071学号20xx81824132学生姓名王涛指导教师乔卫杰20x…
PROTEL课程设计报告专业电气工程及其自动化学号姓名班级教师电气与电子工程学院20xx62摘要Protel99SE是一种基于Wi…