课设-基于MATLAB的BPSK调制-(完本)_第1页
课设-基于MATLAB的BPSK调制-(完本)_第2页
课设-基于MATLAB的BPSK调制-(完本)_第3页
课设-基于MATLAB的BPSK调制-(完本)_第4页
课设-基于MATLAB的BPSK调制-(完本)_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

沈阳理工大学装备工程学院课程设计说明书

PAGE

79

摘要

本次课程设计为基于MATLAB的BPSK原理电路仿真。本次课设着重介绍了算法的实现,并采用MATLAB程序仿真测试了BPSK过程中单极性不归零编码、脉冲成形、PSK调制、信号通过AWGN信道、载波恢复、解调、解码等过程。

关键词:BPSK;2PSK;MATLAB;数字频带通信;

目录

绪论

1

1BPSK数字调制原理

2

1.1数字带通传输分类

2

1.2BPSK调制原理分析

2

1.2.1调制原理分析

2

1.2.2解调原理分析

4

2MATLAB软件

6

2.1MATLAB软件介绍

6

3基于的MATLAB的BPSK调制分析和仿真

7

3.1基于MATLAB的BPSK调制系统总述

7

3.2编码过程的MATLAB实现

8

3.3BPSK调制的MATLAB的实现

11

3.4AWGN信道MATLAB的实现

13

3.5载波恢复的MATLAB实现

16

3.5.1接收端带通滤波器

16

3.5.2通过FFT实现载波的直接频率估计

20

3.5.3自适应(迭代)算法验证恢复频率

22

3.6BPSK解调

25

4总结

30

附录

31

致谢

32

参考文献

33

绪论

数字信号传输方式分为数字带通传输和数字基带传输。对于本次课程设计二进制相移键控BPSK(BinaryPhaseShiftKey)是利用载波的相位变化来传递数字信息,而振幅和频率保持不变的一种数字带通调制方式。在实际应用中,PSK具有恒包络特性,频带利用率比FSK高,在相同信噪比的条件下误码率也较低,同时PSK调制实现相对简单,故卫星通信,遥测遥控中用得最多的是BPSK方式调制。

1BPSK数字调制原理

1.1数字带通传输分类

数字带通传输中一般利用数字信号的离散取值特点通过开关键控载波,从而实现数字调制,比如对载波的振幅、频率和相位进行键控可获得振幅键控(ASK)、频移键控(FSK)和相移键控(PSK)。

1.2BPSK调制原理分析

1.2.1调制原理分析

相移键控是利用载波的相位变化来传递数字信息,而振幅和频率保持不变。在BPSK中,通常用初始相位0或分别表示二进制的‘0’和‘1’。因此,BPSK信号的时域表达式为:

1-1

其中,表示第n个符号的绝对相位:

1-2

因此,式(1-1)可以改写为:

1-3

由于表示信号的两种码元的波形相同,极性相反,故BPSK信号一般可以表述为一个双极性全占空(100%dutyratio)矩形脉冲序列于一个正弦载波的相乘,即

1-4

其中,

1-5

这里,g(t)脉冲宽度为的单个矩形脉冲,而得统计特性为

1-6

即发送二进制符号位‘0’时(取+1),取0相位;发送二进制符号为‘1’时(取-1),取相位。这种以载波的不同相位直接去表示响应的二进制数字信号的调制方式,称为二进制绝对相移调制(BPSK)。

调制原理框图如图1.1所示:

图1.1BPSK调制原理图

典型波形如图1.2所示:

图1.2发送码元为10011的BPSK波形

1.2.2解调原理分析

BPSK信号的解调方法是相干解调法。由于PSK信号本身就是用相位传递信息的,所以在接受端必须利用信号的相位信息,故采用相干解调法来解调信号。

BPSK解调原理框图如1.3所示:

抽样判决

低通滤波器

相乘器

带通滤波器

图1.3BPSK解调原理框图

给出了一种BPSK信号想干接受设备原理框图。图中经过带通滤波的信号在相乘器与本地载波相乘,在相干解调中,如何得到与接收的BPSK信号同频同相的相干载波是关键,然后用低通滤波器去除高频分量,再进行抽样判决,判决器是按极性进行判决,得到最终的二进制信息。图中,假设相干载波的基准相位于BPSK信号的调制载波的基准相位一致。但是,由于在BPSK信号的载波恢复过程中存在º的相位迷糊(phaseambiguity),即恢复的本地载波与所需的相干载波可能同相,也可能反相,这种相位关系的不确定性将会造成解调出数字基带信号与发送的数字基带信号正好相反,即‘1’变为‘0’,‘0’变为‘1’,判决器输出数字信号全部出错。这种现象称为BPSK方式的‘倒’现象。

具体波形如图1.4所示

图1.4解调信号示意图

2MATLAB软件

2.1MATLAB软件介绍

MATLAB简介MATLAB的名称源自MatrixLaboratory,它是一种科学计算软件,专门以矩阵的形式处理数据。MATLAB将高性能的数值计算和可视化集成在一起,并提供了大量的内置函数,从而被广泛地应用于科学计算、控制系统、信息处理等领域的分析、仿真和设计工作,而且利用MATLAB产品的开放式结构,可以非常容易地对MATLAB的功能进行扩充,从而在不断深化对问题认识的同时,不断完善MATLAB产品以提高产品自身的竞争能力。

在通信仿真中,欲将寄载消息的信号保质保量的传送给接收者,就必须对它们进行加工处理,对相应的部件进行分析和研究,而这种研讨过程中会用到大量的数学计算。它是以矩阵,数组为基本处理对象,矩阵的维数不需要预先指定,且随时可变,具有丰富的矩阵运算功能。仿真功能我们采用MATLAB语言编程,以Windows和MATLAB为软件运行环境。将通信原理中的知识点用MATLAB来实现。通过灵活的菜单和界面设计使某些参数可调。同时运用Simulink软件包,使波形在仿真的同时显示系统。更加有利于在课堂上使用。

MATLAB界面:

图2.1MATLAB界面

3基于的MATLAB的BPSK调制分析和仿真

3.1基于MATLAB的BPSK调制系统总述

基于MATLAB的BPSK调制解调系统流程框图如3.1所示:

道信

调制

成形冲脉

编码

文本

信息

决判样抽

载波恢复

解码

解调

图3.1BPSK调制解调系统流程框图

通信过程分析:

整个发送与接收过程仿真了实际中的通信过程,输入一段信息如‘ph’经过编码过程,变换为一串二进制字符,再加载矩形窗进行脉冲成形,生成原始的数字基带信号,为了发送信息,通过BPSK调制成数字带通信号发射,发射信号进入模拟的AWGN信道,被接收机所接受,BPSK解调采用的是相干解调,故需要进行载波恢复,恢复载波的频率,用已恢复的载波对接受信号进行相乘,再对其进行抽样判决,恢复最原始的二进制字符,再进行解码恢复原始的信息内容。

仿真过程的要求:

本次课设使用MATLAB进行BPSK通信过程仿真,要求不仅能将原始信息转换成二进制字符信息,解调后也能很好的恢复成原来的信息,过程中对信号观察不仅需要从时域上进行观察分析,也需要再频域上进行观察分析,以分析通过AWGN信道对信号的影响。

3.2编码过程的MATLAB实现

对于输入的文本信息,如果要进行调制发送,必然而且也可以将其转换成由‘0’与‘1’二进制字符,这个过程是信源编码过程。

算法原理:

对于输入的文本信息,在MATLAB中有对于的ASCII编码,MATLAB会自动的任意一行文档表示为一列ASCII码。再将十进制的ASCII码转换为二进制的的字符。

对于数字形式的信息,必须转化成模拟形式,也就是脉冲成形过程,它将数字形式的每个字符转换成合适的模拟脉冲,经过传输后,接受端可以从接受到的信号中恢复出原来的二进制字符。本次课设采用矩形窗加载,即为矩形脉冲。

算法原理框图如3.2所示:

基带信号

脉冲成形

二进制信息

文本信息

图3.2算法框图

MATLAB代码:

%编码和脉冲成形

%采样率100

decimalvalue=real(str);%使用自带real函数读取字符串的ASCII码

binaryvalue=dec2base(decimalvalue,2,8);%dec2base函数转成8位二进制形式字符

%因为使用dec2base函数转换出的二进制字符是使用char型的数组

%进行将char型转换成int型二进制字符

matrix1=size(binaryvalue);

a=matrix1(1,1);

b=matrix1(1,2);

bv=[];

fori=1:1:a;

forj=1:1:b;

bv1=binaryvalue(i,j);

bv1=bv1*1;

bv1=bv1-48;

bv=[bvbv1];

end

end

%为了能使编码后的二进制可以进行脉冲成形需要对其进行过采样

M=100;

N=length(bv);

bsignal=zeros(1,N*M);

bsignal(1:M:end)=bv;

%使用矩形窗进行脉冲成形

p=ones(1,M);

s=conv(p,bsignal);

%因为使用卷积,加载后的信号需要剔除后续多余部分

k1=length(s);

k1=k1-99;

signal=zeros(1,k1);

fori=1:1:k1;

signal(i)=s(i);

end

%画图语句

k=1;%第一幅图

x=signal;Ts=1/100;

plotspec(x,Ts,k);%调用自编子函数

运行程序输入str=‘ph’,输出二进制字符的基带信号signal,时域图如3.3所示:

图3.3基带信号时域图

基带信号频域图如3.4所示:

图3.4基带信号频域图

由MATLAB的工作空间可知‘ph’转换成的二进制字符为:011000001101000.

3.3BPSK调制的MATLAB的实现

数字基带信号一般不直接进行发射,需经过调制,本次课设要求使用BPSK调制方式进行调制。

算法原理:

在MATLAB中,可以采取脉冲成形的方式对原始信号进行调制,先将信号进行过采样插值,将1s内取100k个有相同幅值的点,以便使用载波进行脉冲成形,过采样后直接使用载波对信号进行相乘,以达到调制的目的。

算法原理框图如3.5所示:

图3.5算法原理框图

MATLAB代码:

%BPSK调制

%采样率100kHZ

t2=0:(2*pi)/100000:2*pi-0.00001;%载波一周期内采样点数

fc=300;%载波频率

m1=[];

c1=[];

b1=[];

%进行过采样插值

forn=1:1:length(bv);

ifbv(n)==0;

m=-ones(1,100000);

b=zeros(1,100000);

elsebv(n)==1;

m=ones(1,100000);

b=ones(1,100000);

end

c=cos(fc*t2);%生成相应载波

%过采样后插值的信号

m1=[m1,m];

c1=[c1,c];

b1=[b1,b];

end

psk=c1.*m1;%生成BPSK信号

Ts=1/100000;%采样周期

x=psk;%画图

k=2;%第二幅图

plotspec(x,Ts,k);%调用自编函数文件

运行程序得到BPSK已调信号psk,时域图如3.6所示:

图3.6BPSK信号时域图(部分)

BPSK的频域图如3.7所示:

图3.7BPSK信号频域图

从图观察,在HZ处附近有值,说明已用频率300HZ的载波调制数字基带信号。

3.4AWGN信道MATLAB的实现

加性高斯白噪声AWGN(AdditiveWhiteGaussianNoise)是最基本的噪声与干扰模型。它的幅度分布服从高斯分布,而功率谱密度是均匀分布的,它意味着除了加性高斯白噪声外,r(t)与s(t)没有任何失真。即H(f)失真的

加性噪声:叠加在信号上的一种噪声,通常记为n(t),而且无论有无信号,噪声n(t)都是始终存在的。因此通常称它为加性噪声或者加性干扰。

白噪声:噪声的功率谱密度在所有的频率上均为一常数,则称这样的噪声为白噪声。如果白噪声取值的概率分布服从高斯分布,则称这样的噪声为高斯白噪声。

在MATLAB中有模拟AWGN信道可直接使用awgn函数,y=awgn(x,SNR)

在信号x中加入高斯白噪声。信噪比SNR以dB为单位。x的强度假定为0dBW。如果x是复数,就加入复噪声。

y=awgn(x,SNR,SIGPOWER)

如果SIGPOWER是数值,则其代表以dBW为单位的信号强度;如果SIGPOWER为'measured',则函数将在加入噪声之前测定信号强度。

y=awgn(x,SNR,SIGPOWER,STATE)

重置RANDN的状态。

y=awgn(…,POWERTYPE)

指定SNR和SIGPOWER的单位。POWERTYPE可以是'dB'或'linear'。如果POWERTYPE是'dB',那么SNR以dB为单位,而SIGPOWER以dBW为单位。如果POWERTYPE是'linear',那么SNR作为比值来度量,而SIGPOWER以瓦特为单位。

MATLAB代码:

%模拟AWGN信道

e2psk=awgn(psk,100);%调用awgn

%画图

x=e2psk;

Ts=1/100000;%采样率

k=3;

plotspec(x,Ts,k);

运行程序,经过AWGN信道后的信号e2psk,其时域图如3.8所示:

图3.8经过AWGN信道后的信号e2psk

信号局部放大图如3.9所示:

图3.9e2psk信号时域图(部分)

可见信号经过AWGN信道后,受到噪声污染,时域上有失真。

e2psk信号频谱图如3.10所示:

图3.10e2psk信号频谱图

300HZ左右处放大图如3.11所示:

图3.11e2psk信号300Hz左右处频谱

分析图可知,由于信号经过了AWGN信号,收到噪声干扰,频谱图在整个频域上有加性白噪声污染,都有不同程度的失真,不利于信号的解调。

3.5载波恢复的MATLAB实现

从接收端接收到信号后,为了进行相干解调,需要从本地恢复载波。对本次课设BPSK调制方式是一种没有抑制载波的调制方式,但是在通常情况下,载波很容易的被隐藏在接收信号中,而且需要很多额外的处理过程来恢复载波。对于刚接收到的信号可先通过FFT实现载波的频率估测,得出一个频率之后,再使用自适应算法的方式,准确定位和验证载波频率值。

3.5.1接收端带通滤波器

在接收器接受到调制信号后,由于调制信号被AWGN信道“污染”,在整个频带上增加了加性高斯白噪声,故为了过滤信号需要在接受端加上一个带通滤波器,以滤除带外信号。

本次课设调用remez函数以使用雷米兹算法,雷米兹算法提供了求解切比雪夫逼近问题的有效方法。切比雪夫滤波器是在通带或阻带上频率响应幅度等波纹波动的滤波器。

MATLAB代码:

%带通滤波器生成及其频率响应

f1=500;%滤波器阶数

fs=1000;%滤波器显示频率最大值的两倍

ff=[0.51.52.68.691];%归一化的截止频率

fa=[001100];

h=remez(f1,ff,fa);%生成带通滤波器

figure(4),

freqz(h,1,512,fs);%绘出滤波器的频率响应

r=filter(h,1,e2psk);%信号通过带通滤波器

k=5;

plotspec(r,Ts,k)

带通滤波器的幅频响应如图3.12所示:

图3.12带通滤波器幅频响应

带通滤波器的相频响应如图3.13所示:

图3.13带通滤波器的相频响应

分析可知在通带或阻带上频率响应幅度等波纹波动的切比雪夫滤波器,带通滤波器的频率响应可知带通滤波器的中心频率为300Hz,通带为260Hz至340Hz,群延时为179.85度。

信号通过带通滤波器后时域图如3.14所示:

图3.14信号通过带通滤波器

通过带通滤波后信号的局部图如3.15所示:

图3.15接收信号通过带通滤波(部分)

可知经过带通滤波后,时域图中信号有一定成度的改善,波形突刺减少,一定程度的恢复成原来的波形。

信号通过带通滤波后的幅频响应如3.16所示:

图3.16接受信号通过带通滤波后的幅频响应

分析频域图,在频带中多余的加性白噪声得到一定的抑制,而很好的保留了载频附近的频率信息。

3.5.2通过FFT实现载波的直接频率估计

对于没有抑制载波的调制信号来说,使用FFT变换后通常载波频率幅度是最大值,可以通过检测已调信号的整个频率范围最大值来确定最大值。但是,一般情况下,由于已调信号经过信道后,频谱受到损伤,出现一定程度的失真,降低了用最大值来确定载波频率的方法的可靠性,此时需要使用另外的方法来恢复载波频率。

载波恢复流程框图如3.17所示:

图3.17载波恢复流程图

如图3.17所示,一般可以在带通滤波器后使用非线性模块平方器,是接受信号,由基带信号和载波相乘组成,平方器的输出项为

3.1

又根据等式,改写3.1为

3.2

将用其平均值和偏移量的和来表示

3.3

因此3.4

以为中心的窄带带通滤波器只能让中的纯余弦项通过,而且还会抑制当中的直流成分,低频部分和向上边频了的也不能通过。带通滤波器的输出约为

3.5

式中,是相位偏移,是带通滤波器引入的。对于接受机来说,值是已知的,故可用来估算出载波的频率。

MATLAB代码:

rsc=r;

q=rsc.^2;%通过平方器

fl=500;ff=[0.0100.0104.0136.01401];

fa=[001100];

h=remez(fl,ff,fa);%生成带通滤波器

rp=filter(h,1,q);%再通过带通滤波

fftrBPF=fft(rp);%对rp信号进行FFT变换

[m,imax]=max(abs(fftrBPF(1:end/2)));%找到最大值,返回最大值和最大值所在数组点

ssf=(0:length(rp))/(Ts*length(rp));%建立储存频率的数组

freqS=ssf(imax);%找出存储频率数组对应最大幅度的频率

运行程序结果:

freqS=

600

由结果可知估测频率fc=300Hz。

3.5.3自适应(迭代)算法验证恢复频率

对于前面已经估测处了载波的频率,此时可以由freqS为假设值,利用自适应算法对恢复的载波频率进行再估测和验证。

在通信中的许多问题能够被设计成最优化问题要解决这种问题需要三个基本的步骤:

(1)设定一个目标-选择一个目标函数

(2)选择一个实现目标的方法-最大化或最大化这个目标函数

(3)检验以确定这个方法能达到预期效果

“设定一个目标函数”通常包括寻找一个可以最大化或可以最小化的函数,定位最大和最小值为所要解决问题提供了有用的信息。这个函数的选择必须使它和它的导数的值能基于一些信息计算出来。

有很多的方法可以用来实现最大化或最小化过程。有的时候是可以使用直接的方法,如,如果为了找到多项式达到最小值的点,只要直接找到它的导数并置零就可以得到解答。但是很多时候,不可能有如此简单的解决方法,递归方法(自适应方法)通常在信号运算中有很好的应用。

自适应算法通常以最陡下降为目的,也可以称之为最陡下降法,最陡下降自适应算法从最初猜测的位置开始,算出从估计值开始哪个是最陡下降的方向,并沿着这条下降方向做出最新的估算,为了运用最陡下降法来最小化多项式,假设在时间处的的当前估算是可以得到的,表示为在时间的估算可以用下式:

3.6

式中,是很小正数,称为步长,而的梯度是当前点计算出来的,当重复计算,依次迭代运算,最终接近最小值

对于接受信号为,设freqS为,合理的算法为尝试最小化下式:

3.7

利用梯度算法重写3.6式,得:

3.8

将平方项展开整理为:

3.9

此式即为其误差表面函数,可以用来分析性能函数。

MATLAB代码:

%自适应算法估测频率

%预先恢复频率2fc=freqS=600Hz

%本次算法初始值为300Hz,采用步长mu=0.003

Ts=1/100000;

time=5;

t=0:Ts:time-Ts;%建立时间向量

fl=300;

ff=[0.005.011];

fa=[1100];

h=remez(fl,ff,fa);%低通滤波生成

mu=.003;%步长fc=300;%freqS估测出频率

fest=zeros(1,length(t));

fest(1)=fc+3;%起始运算的频率303Hz

z=zeros(1,fl+1);

%进行循环运算迭代运算有3.8式得出

fork=1:length(t)-1

z=[(r(k)-cos(2*pi*fest(k)*t(k)))*sin(2*pi*fest(k)*t(k)),z(1:fl)];

update=fliplr(h)*z';

fest(k+1)=fest(k)-mu*update;

end

%画图

figure(6),

plot(t,fest);

title('FrequencyTrackingviatheDirectmethod')

xlabel('time');

ylabel('phaseoffset');

运行程序后,自适应算法结果如3.18所示:

图3.18自适应算法结果图

由图可知,在一段区域内由假定的303Hz趋近于300Hz,与之前直接频率估计的结果相符,故可知载波的频率为300Hz。

3.6BPSK解调

对于BPSK解调,本次课设采用匹配滤波接收,匹配滤波器可使输出信噪比达最大,有利于判决抽样。

设接受滤波器传输函数为,冲击函数为,滤波器输入码元的持续时间为匹配滤波器的特性可以用其冲激响应函数来描述:

3.10

由式可知匹配滤波器的冲激响应就是的镜像,但在时间轴上平移了。

一个实际的匹配滤波器应该是物理可实现的,其冲激响应必须符合因果关系,在输入冲激脉冲加入前不应有冲激响应出现,即必须有:

3.11

既要求满足条件:

3.12

或满足条件:

3.13

式3.13的条件说明,接受滤波器输入端的信号码元在抽样时刻之后必须为零。一般不希望在码元结束之后很久才抽样,故通常选择在码元末尾抽样,即选。故匹配滤波器冲激响应可以写为:

3.14

这时,若匹配滤波器的输入电压为,则输出信号码元的波形,可以求出为:

3.15

式3.15表明,匹配滤波器输出信号码元波形是输入信号码元波形的自相关函数。为任意一常数,通常取。

MATLAB代码:

%匹配滤波

tm=0:1/100000:1-(1/100000);

ps=cos(2*pi*300*tm);

dm=conv(ps,r);

%画图

figure(7),

plot(dm);gridon

运行程序图如3.19所示:

图3.19匹配滤波后信号

信号局部放大图如3.20所示:

图3.20信号通过匹配滤波后局部方法图

对信号匹配滤波后,则可以进行抽样判决以恢复原始二进制信息。对于匹配滤波后的信号采样点为nTs。

MATLAB代码:

%抽样赋值1和-1

dmbv=[];

fori=1:1:length(r)/100000;

dmbv1=dm(i*100000);

dmbv=[dmbvdmbv1];

end

%将双极性不归零码变为单极性不归零码,赋值0和1

fori=1:1:length(dmbv);

ifdmbv(i)>0;dmbv(i)=0;

elsedmbv(i)=1;

end

end

%画图

tm1=0:1:length(dmbv)-1;

figure(8),

stem(tm1,dmbv);

gridon;

axis([-0.515.5-12]);

xlabel('时间');

ylabel('幅度')

title('解调后的单极性不归零二进制信号')

运行程序后得结果如3.21所示:

图3.21解调后的单极性不归零二进制信号

由图可读出恢复数据为0111000001101000

MATLAB代码:

%解码

dmbv1=dmbv(1:end/2);%8位

dmbv2=dmbv(end/2+1:end);

dmstr1=num2str(dmbv1);%数值型变成字符型

dmstr2=num2str(dmbv2);

dms1=bin2dec(dmstr1);%由二进制转成十进制

dms2=bin2dec(dmstr2);

运行程序后,由工作空间可知都dms1为112,dms2为104。

再有代码:char(112);char(104);

得结果为:ph

故解调出了原始的文本信息。

4总结

本次课设基于MATLAB仿真了BPSK调制方式的通信传输,发送端将文本信息转换成二进制基带信号,进行BPSK调制发送,信道为AWGN信道产生加性高斯白噪声,接收端接收信号,进行载波恢复,将恢复的载波对接受信号进行匹配滤波,并解调,再进行抽样判决,恢复出原始的二进制字符,在解码成文本信息。本次课设进行了相对实际的BPSK调制通信仿真,初步验证了BPSK调制的可行性,并对通信系统中遇到的问题进行了一定的探索研究。

通过本次课设,使我对已掌握专业知识有了更深一层次的把握,也学到了很多新的知识并很好的掌握了这些知识,同时整个过程充分理解了理论指导实践,实践验证理论这句话。我不仅书本上得理论知识有了进一步的理解,也同时熟练的掌握了MATLAB的仿真,使自己脑海中的理论不再只是理论而得到了实践的验证。

这次课设使我能很好的综合运用自己所学的知识解决一些问题,在面对自己不懂的问题时能逐步分析并最后解决这些问题,对我以后的学习起到了抛砖引玉的作用,促使以后能不断的进步。

附录

%为调用的plotspec函数

functionplotspec(x,Ts,k)

%函数功能是画出信号的时域图和频域图

%x为输入信号,Ts为抽样率,k为图的序号

N=length(x);

t=Ts*(1:N);

ssf=(-N/2:N/2-1)/(Ts*N);

fx=fft(x(1:N));

fxs=fftshift(fx);

figure(k)

subplot(2,1,1),plot(t,x);gridon,

xlabel('秒');ylabel('幅度');

subplot(2,1,2),plot(ssf,abs(fxs));gridon,

xlabel('频率');ylabel('幅度')

end

致谢

感谢这次课程设计的指导老师李宏达老师、刘庆泉老师和伍彩云老师,也感谢指导过我的教研室老师和同学们。

参考文献

[1]C.RichardJohnsonJr.等著.潘甦译.软件无线电机械工业出版社

[2]樊昌信等编著.通信原理.国防工业出版社

[3]郭文彬等编.通信原理-基于MATLAB的计算机仿真.北京邮电大学出版社

[4]赵鸿图等编.通信原理MATLAB仿真教程.人民邮电出版社

附录资料:不需要的可以自行删除

C语言编程规范(仅供参考)

1.基本要求

1.1程序结构清析,简单易懂,单个函数的程序行数不得超过100行。

1.2打算干什么,要简单,直接了当,代码精简,避免垃圾程序。

1.3尽量使用标准库函数和公共函数。

1.4不要随意定义全局变量,尽量使用局部变量。

1.5使用括号以避免二义性。

2.可读性要求

2.1可读性第一,效率第二。

2.2保持注释与代码完全一致。

2.3每个源程序文件,都有文件头说明,说明规格见规范。

2.4每个函数,都有函数头说明,说明规格见规范。

2.5主要变量(结构、联合、类或对象)定义或引用时,注释能反映其含义。

2.7常量定义(DEFINE)有相应说明。

2.8处理过程的每个阶段都有相关注释说明。

2.9在典型算法前都有注释。

2.10利用缩进来显示程序的逻辑结构,缩进量一致并以Tab键为单位,定义Tab为6个

字节。

2.11循环、分支层次不要超过五层。

2.12注释可以与语句在同一行,也可以在上行。

2.13空行和空白字符也是一种特殊注释。

2.14一目了然的语句不加注释。

2.15注释的作用范围可以为:定义、引用、条件分支以及一段代码。

2.16注释行数(不包括程序头和函数头说明部份)应占总行数的1/5到1/3。

3.结构化要求

3.1禁止出现两条等价的支路。

3.2禁止GOTO语句。

3.3用IF语句来强调只执行两组语句中的一组。禁止ELSEGOTO和ELSERETURN。

3.4用CASE实现多路分支。

3.5避免从循环引出多个出口。

3.6函数只有一个出口。

3.7不使用条件赋值语句。

3.8避免不必要的分支。

3.9不要轻易用条件分支去替换逻辑表达式。

4.正确性与容错性要求

4.1程序首先是正确,其次是优美

4.2无法证明你的程序没有错误,因此在编写完一段程序后,应先回头检查。

4.3改一个错误时可能产生新的错误,因此在修改前首先考虑对其它程序的影响。

4.4所有变量在调用前必须被初始化。

4.5对所有的用户输入,必须进行合法性检查。

4.6不要比较浮点数的相等,

如:10.0*0.1==1.0,不可靠

4.7程序与环境或状态发生关系时,必须主动去处理发生的意外事件,如文件能否

逻辑锁定、打印机是否联机等。

4.8单元测试也是编程的一部份,提交联调测试的程序必须通过单元测试。

5.可重用性要求

5.1重复使用的完成相对独立功能的算法或代码应抽象为公共控件或类。

5.2公共控件或类应考虑OO思想,减少外界联系,考虑独立性或封装性。

5.3公共控件或类应建立使用模板。

附:C++编程规范,delphi作相应的参考

1适用范围

本标准适用于利用VisulC++,BorlandC++进行软件程序开发的人员.。

.2变量命名

命名必须具有一定的实际意义,形式为xAbcFgh,x由变量类型确定,Abc、Fgh表示连续意

义字符串,如果连续意义字符串仅两个,可都大写.如OK.

具体例程:

BOOL类型bEnable;

ch*charchText

c*类对象cMain(对象实例)

h*Handle(句柄)hWnd

i*int

n*无符号整型

p*指针

sz,str*字符串

wWORD

x,y坐标

Char或者TCHAR类型与WindowsAPI有直接联系的用szAppName[10]形式否则用

FileName[10]形式,单个字符也可用小写字母表示;

Int类型nCmdShow;

LONG类型lParam;

UINT类型uNotify;

DWORD类型dwStart;

PSTR类型pszTip;

LPSTR类型lpCmdLine

LPTSTR类型lpszClassName;

LPVOID类型lpReserved

WPARAM类型wParam,

LPARAM类型lParam

HWND类型hDlg;

HDC类型hDC;

HINSTANCE类型hInstance

HANDLE类型hInstance,

HICON类型hIcon;

intiTmp

floatfTmp

DWORDdw*

String,AnsiStringstr*

m_类成员变量m_nVal,m_bFlag

g_全局变量g_nMsg,g_bFlag

局部变量中可采用如下几个通用变量:nTemp,nResult,I,J(一般用于循环变量)。

其他资源句柄同上

.3常量命名和宏定义

常量和宏定义必须具有一定的实际意义;

常量和宏定义在#include和函数定义之间;

常量和宏定义必须全部以大写字母来撰写,中间可根据意义的连续性用下划线连接,每一

条定义的右侧必须有一简单的注释,说明其作用;

资源名字定义格式:

菜单:IDM_XX或者CM_XX

位图:IDB_XX

对话框:IDD_XX

字符串:IDS_XX

DLGINIT:DIALOG_XX

ICON:IDR_XX

.4函数命名

函数原型说明包括引用外来函数及内部函数,外部引用必须在右侧注明函数来源:模

块名及文件名,如是内部函数,只要注释其定义文件名;

第一个字母必须使用大写字母,要求用大小写字母组合规范函数命名,必要时可用下划线

间隔,示例如下:

voidUpdateDB_Tfgd(TRACK_NAME);file://ModuleName:r01/sdw.c

voidPrintTrackData(TRACK_NAME);file://ModuleName:r04/tern.c

voidImportantPoint(void);file://ModuleName:r01/sdw.c

voidShowChar(int,int,chtype);file://LocalModule

voidScrollUp_V(int,int);file://LocalModule

.5结构体命名

结构体类型命名必须全部用大写字母,原则上前面以下划线开始;结构体变量命名必须用

大小写字母组合,第一个字母必须使用大写字母,必要时可用下划线间隔。对于私有数

据区,必须注明其所属的进程。全局数据定义只需注意其用途。

示例如下:

typedefstruct

{

charszProductName[20];

charszAuthor[20];

charszReleaseDate[16];

charszVersion[10];

unsignedlongMaxTables;

unsignedlongUsedTables;

}DBS_DATABASE;

DBS_DATABASEGdataBase;

6控件的命名:

用小写前缀表示类别

用小写前缀表示类别:

fm窗口

cmd按钮

cobcombo,下拉式列表框

txt文本输入框

lablabal,标签

imgimage,图象

picpicture

grdGrid,网格

scr滚动条

lst列表框

frmfram

7注释

原则上注释要求使用中文;

文件开始注释内容包括:公司名称、版权、作者名称、时间、模块用途、背景介绍等,复

杂的算法需要加上流程说明;

函数注释包括:输入、输出、函数描述、流程处理、全局变量、调用样例等,复杂的函数

需要加上变量用途说明;

程序中注释包括:修改时间和作者、方便理解的注释等;

引用一:文件开头的注释模板

/******************************************************************

**文件名:

**Copyright(c)1998-1999*********公司技术开发部

**创建人:

**日期:

**修改人:

**日期:

**描述:

**

**版本:

**

******************************************************************/

引用二:函数开头的注释模板

/*****************************************************************

**函数名:

**输入:a,b,c

**a

**b

**c

**输出:x

**x为1,表示...

**x为0,表示...

**功能描述:

**全局变量:

**调用模块:

**作者:

**日期:

**修改:

**日期:

**版本

****************************************************************/

引用三:程序中的注释模板

/**/

/*注释内容*/

/**/

8程序

a.程序编码力求简洁,结构清晰,避免太多的分支结构及太过于技巧性的程序,

尽量不采用递归模式。

b.编写程序时,亦必须想好测试的方法,换句话说,”单元测试”的测试方案应

在程序编写时一并拟好。

c.注释一定要与程序一致。

d.版本封存以后的修改一定要将老语句用/**/封闭,不能自行删除或修改,并要

在文件及函数的修改记录中加以记录。

e.程序中每个block的开头”{"及"}”必须对齐,嵌套的block每进一套,

缩进一个tab,TAB为4个空格,block类型包括if、for、while、do等关键字引出的。

f.对于比较大的函数,每个block和特殊的函数调用,都必须注明其功能,举例如下

count.divisor=1193280/freq;//computethepropercount

OutByte((unsignedshort)67,(unsignedchar)182);//tell8253thata

countiscoming

OutByte((unsignedshort)66,count.c[0]);//sendlow-orderbyte

OutByte((unsignedshort)66,count.c[1]);//sendhigh-orderbyte

×××××××××××××××××××××××××××××××××××××××

bcb,delphi中的变量命名:

遵循匈牙利命名法,命

名必须有意义,制定如下规定

窗体:以大写的W开始,如About版权窗体,命名为WAbout

文件:以大写的F开始,如About版权窗体,文件命名为FAbout.cpp

按钮(Button):如退出按钮,命名为btnExit

……

基类:加base标记,如报表基类,窗体命名为:WBaseRep,文件命名为FBaseRep.cpp

转贴

>1.在.h/.cpp的开头应有一段格式统一的说明,内容包括:

>a.文件名(FileName);

>b.创建人(Creater);

>c.文件创建时间(Date);

>d.简短说明文件功能、用途(Comment)。

好习惯

>2.除非极其简单,否则对函数应有注释说明。内容包括:功能、入口/出口参数,必

>时还可有备注或补充说明。

还是好习惯

>3.每列代码的长度推荐为80列,最长不得超过120列;折行以对齐为准。

太宽了,我的限制是60列,因为文本方式下屏幕一共80列,如果你用BC这一类的编辑

器,窗口边框等又要占据一定空间,所以80列太宽

>4.循环、分支代码,判断条件与执行代码不得在同一行上。

很对

>5.指针的定义,*号既可以紧接类型,也可以在变量名之前。

>

>例:可写做:int*pnsize;

>

>也可写做:int*pnsize;

>

>但不得写做:int*pnsize;

建议采用第二种,除非附加另外一条规定:一次只声明一个变量,否则就会让人混淆,

比如:

int*a,b;

看起来b好像也是个指针,其实不是。

>6.在类的成员函数内调用非成员函数时,在非成员函数名前必须加上"::"。

这一条我倒觉得并不是必需的,我的看法是决不要让你的类成员函数和全局函数的名称

相同(或类似)

>7.函数入口参数有缺省值时,应注释说明。

>

>例:BOOLCWpsDib::PaintDIB(CDC*pDC,CRect&rc,

>intnBrightness,file://*=0*//

>BOOLbGrayScalefile://*=FALSE*//)

每个变量写一行,必要时加上/*in,out*/注释

>8.elseif必须写在一行。

应该尽量避免elseif这样的结构

>9.与‘{’、‘}’有关的各项规定:

>

>9.1‘{’、‘}’应独占一行。在该行内可有注释。

>9.2‘{’必须另起一行,‘{’之后的代码必须缩进一个Tab。‘{’与‘}’必须在

>一列上。

>9.3在循环、分支之后若只有一行代码,虽然可省略‘{’、‘}’,但不推荐这么

>做。若省略后可能引起歧义,则必须加上‘{’、‘}’。

持保留意见,因为GNU的代码规范是这样的:

if(NULL==ptr)

{

//dosomethinghere

}

或者

if(NULL==ptr){

//dosomethinghere

}

争论哪个更好并没有意义,关键是统一,如果用VC当然你的办法最方便,可是如果你用

emacs或者vi,就不是这样了。

>10.与空格有关的各项规定。

>

>10.1在所有两目、三目运算符的两边都必须有空格。在单目运算符两端不必空格。

>在‘—>’、‘::’、‘.’、‘[’、‘]’等运算符前后,及‘&’(取地址)、‘*

>’(取值)等运算符之后不得有空格。

>10.2for、while、if等关键词之后应有1个空格,再接‘(’,之后无空格;在结

>的‘)’前不得有空格。

我认为在括号两端加空格并不是什么错误,尤其是在一个条件十分复杂的if语句里

>10.3调用函数、宏时,‘(’、‘)’前后不得有空格。

>10.4类型强制转换时,‘(’‘)’前后不得有空格

同上

>11.与缩进有关的各项规定

>

>11.1缩进以Tab为单位。1个Tab为4个空格

我认为这个值应该更大,我自己使用8个空格,如果你的代码因为缩进幅度太大而导致

折行,那么几乎可以肯定你的程序设计方案有问题。

>11.2下列情况,代码缩进一个Tab:

>1.函数体相对函数名及'{'、'}'。

>2.if、else、for、while、do等之后的代码。

>3.一行之内写不下,折行之后的代码,应在合理的位置进行折行。若有+-*/等

>算符,则运算符应在上一行末尾,而不应在下一行的行首。

这一条我反对,运算符应该放在下一行行首,以使人能清楚的知道这一行是续上一行

的,比如

if(something

&&somethingelse

&&otherthings)

如果写做

if(something&&

somethingelse&&

otherthings)

反而看不清楚

>11.3下列情况,不必缩进:switch之后的case、default。

编程规范与范例

目录

1排版6

2注释11

3标识符命名18

4可读性20

5变量、结构22

6函数、过程28

7可测性36

8程序效率40

9质量保证44

10代码编辑、编译、审查50

11代码测试、维护52

12宏53

1排版

1-1:程序块要采用缩进风格编写,缩进的空格数为4个。

说明:对于由开发工具自动生成的代码可以有不一致。

1-2:相对独立的程序块之间、变量说明之后必须加空行。

示例:如下例子不符合规范。

if(!valid_ni(ni))

{

...//programcode

}

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

应如下书写

if(!valid_ni(ni))

{

...//programcode

}

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

1-3:较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。

示例:

perm_count_msg.head.len=NO7_TO_STAT_PERM_COUNT_LEN

+STAT_SIZE_PER_FRAM*sizeof(_UL);

act_task_table[frame_id*STAT_TASK_CHECK_NUMBER+index].occupied

=stat_poi[index].occupied;

act_task_table[taskno].duration_true_or_false

=SYS_get_sccp_statistic_state(stat_item);

report_or_not_flag=((taskno<MAX_ACT_TASK_NUMBER)

&&(n7stat_stat_item_valid(stat_item))

&&(act_task_table[taskno].result_data!=0));

1-4:循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。

示例:

if((taskno<max_act_task_number)

&&(n7stat_stat_item_valid(stat_item)))

{

...//programcode

}

for(i=0,j=0;(i<BufferKeyword[word_index].word_length)

&&(j<NewKeyword.word_length);i++,j++)

{

...//programcode

}

for(i=0,j=0;

(i<first_word_length)&&(j<second_word_length);

i++,j++)

{

...//programcode

}

¹1-5:若函数或过程中的参数较长,则要进行适当的划分。

示例:

n7stat_str_compare((BYTE*)&stat_object,

(BYTE*)&(act_task_table[taskno].stat_object),

sizeof(_STAT_OBJECT));

n7stat_flash_act_duration(stat_item,frame_id*STAT_TASK_CHECK_NUMBER

+index,stat_object);

¹1-6:不允许把多个短语句写在一行中,即一行只写一条语句。

示例:如下例子不符合规范。

rect.length=0;rect.width=0;

应如下书写

rect.length=0;

rect.width=0;

1-7:if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}。

示例:如下例子不符合规范。

if(pUserCR==NULL)return;

应如下书写:

if(pUserCR==NULL)

{

return;

}

1-8:对齐只使用空格键,不使用TAB键。

说明:以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐,不要使用BC作为编辑器合版本,因为BC会自动将8个空格变为一个TAB键,因此使用BC合入的版本大多会将缩进变乱。

1-9:函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。

1-10:程序块的分界符(如C/C++语言的大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。

示例:如下例子不符合规范。

for(...){

...//programcode

}

if(...)

{

...//programcode

}

voidexample_fun(void)

{

...//programcode

}

应如下书写。

for(...)

{

...//programcode

}

if(...)

{

...//programcode

}

voidexample_fun(void)

{

...//programcode

}

1-11:在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格。

说明:采用这种松散方式编写代码的目的是使代码更加清晰。

由于留空格所产生的清晰性是相对的,所以,在已经非常清晰的语句中没有必要再留空格,如果语句已足够清晰则括号内侧(即左括号后面和右括号前面)不需要加空格,多重括号间不必加空格,因为在C/C++语言中括号已经是最清晰的标志了。

在长语句中,如果需要加的空格非常多,那么应该保持整体清晰,而在局部不加空格。给操作符留空格时不要连续留两个以上空格。

示例:

(1)逗号、分号只在后面加空格。

inta,b,c;

(2)比较操作符,赋值操作符"="、"+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。

if(current_time>=MAX_TIME_VALUE)

a=b+c;

a*=2;

a=b^2;

(3)"!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。

*p='a';//内容操作"*"与内容之间

flag=!isEmpty;//非操作"!"与内容之间

p=&mem;//地址操作"&"与内容之间

i++;//"++","--"与内容之间

(4)"->"、"."前后不加空格。

p->id=pid;//"->"指针前后不加空格

(5)if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。

if(a>=b&&c>d)

1-1:一行程序以小于80字符为宜,不要写得过长。

2注释

2-1:一般情况下,源程序有效注释量必须在20%以上。

说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。

2-2:说明性文件(如头文件.h文件、.inc文件、.def文件、编译说明文件.cfg等)头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。

示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

/*************************************************

Copyright(C),1988-1999,HuaweiTech.Co.,Ltd.

Filename://文件名

Author:Version:Date://作者、版本及完成日期

Description://用于详细说明此程序文件完成的主要功能,与其他模块

//或函数的接口,输出值、取值范围、含义及参数间的控

//制、顺序、独立或依赖等关系

Others://其它内容的说明

FunctionList://主要函数列表,每条记录应包括函数名及功能简要说明

1.

History://修改历史记录列表,每条修改记录应包括修改日期、修改

//者及修改内容简述

1.Date:

Author:

Modification:

2....

*************************************************/

2-3:源文件头部应进行注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。

示例:下面这段源文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

/************************************************************

Copyright(C),1988-1999,HuaweiTech.Co.,Ltd.

FileName:test.cpp

Author:Version:Date:

Description://模块描述

Version://版本信息

FunctionList://主要函数及其功能

1.

History://历史修改记录

<author><time><version><desc>

David96/10/121.0buildthismoudle

***********************************************************/

说明:Description一项描述本文件的内容、功能、内部各部分之间的关系及本文件与其它文件关系等。History是修改历史记录列表,每条修改记录应包括修改日期、修改者及修改内容简述。

2-4:函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等。

示例:下面这段函数的注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

/*************************************************

Function://函数名称

Description://函数功能、性能等的描述

Calls://被本函数调用的函数清单

CalledBy://调用本函数的函数清单

TableAccessed://被访问的表(此项仅对于牵扯到数据库操作的程序)

TableUpdated://被修改的表(此项仅对于牵扯到数据库操作的程序)

Input://输入参数说明,包括每个参数的作

//用、取值说明及参数间关系。

Output://对输出参数的说明。

Return://函数返回值的说明

Others://其它说明

*************************************************/

2-5:边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。

2-6:注释的内容要清楚、明了,含义准确,防止注释二义性。

说明:错误的注释不但无益反而有害。

规则2-7:避免在注释中使用缩写,特别是非常用缩写。

说明:在使用缩写时或之前,应对缩写进行必要的说明。

2-8:注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。

示例:如下例子不符合规范。

例1:

/*getreplicatesubsystemindexandnetindicator*/

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

例2:

repssn_ind=ssn_data[index].repssn_index;

repssn_ni=ssn_data[index].ni;

/*getreplicatesubsystemindexandnetindicator*/

应如下书写

/*getrepli

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论