实验一利用GNU-Radio和USRP搭建OFDM通信系统图1,基于GNU-Radio和USRP的OFDM通信系统示意图1实验设备设备清单设备型号数量1EttusUSRPN21022SBX-40子板23VERT245024计算机2开发环境操作系统:Ubuntu14.0464bit软件平台:GNU-Radiov3.7.8UHDrelease_003_009_0012实验目的理解OFDM信号的调制和解调原理;熟悉使用GNU-Radio软件并对信号进行处理;学会使用软件GNU-Radio和硬件USRP来完成点对点设备的通信。3实验内容本实验是在Linux桌面应用系统Ubuntu上进行的,使用到的包括一款免费的无线电和信号处理开发软件—GNU-Radio,和通用软件无线电外设硬件—USRPN210。实验的任务是在GUN-Radio和USRP组成的软硬件平台,搭建了基于OFDM调制的无线通信环境,以便更好的了解OFDM通信原理和信号在无线信道中传播的特点。实验主要包括三部分:发送端、信道和接收端。其中发送端主要包括信源、符号映射、子载波分配、IFFT并加CP、USRPTX;无线信道所处的是室内环境,也被称为准静态信道环境(这也为接收端的均衡提供了思想);接收端主要包括USRPRX、同步、去CPFFT、信道估计和均衡、解符号映射、信宿。4实验步骤4.1发送端在OFDM通信系统中,发送端需要完成以下几个功能:信源编码、数据打包、符号映射、子载波分配、IFFT变换、加CP、USRP发送射频信号等。除USRP模块外其它几个模块中的信号处理都是在GNR-Radio中完成的,也即在主机中完成。USRP模块拥有单独的DSP和FPGA模块,因此可以独立对输入数据进行处理。在USRP模块里面需要完成很多的功能,比如抽取、数字上变频、A/D转换、混频等功能都是在其中完成的。发送端的主要目的是完成信号的调制、上变频、功放,最后通过专用天线将其发送到无线信道中去。考虑到若上变频后的信号幅度过大,在经过功放后可能导致信号失真,因此需要在USRP模块前增加一个限幅器模块。图2,OFDM通信系统的发送端实验流程图4.1.1数据帧结构实验开始时一帧数据的长度规定为96个字节,其中每个字节包含8个比特。信源不断地产生0和1的比特序列,经过数据打包模块(B模块)后变成上述固定长度的帧数据。数据流经过CRC校验后,会在一帧数据的末尾增加4个字节,这时一帧数据便变成了100字节。这些有用的信息称为payload,其采用的是QPSK调制方式,注意经过QPSK映射后一帧数据的长度变成了100*8/2=400个QPSK符号。接着,针对每一帧数据需要生成一个帧头,用来记录当前帧的一些信息,比如帧长、这是第几帧等信息。实验中帧头信息长度为6个字节共48个比特,帧头中的信息称为Header,采用BPSK方式调制,故其长度不变。Payload和Header需要复合在一起才能进行传输,一般将Header置于Payload之前形成新的帧结构,这时一帧数据的长度又发生了变化,变成了400+48=448个符号。在实验中一个OFDM符号的长度设定为64(即总载波个数为64),除去虚拟载波、直流子载波和射频子载波还有48个有效数据子载波。因此,一个OFDM符号可以负载48个Payload的符号,也就是这是一帧数据需要10(448/48=9.333)个OFDM符号。另外,根据文献【1】为了接收端能正常解调信号,需要在一帧数据前加上两个OFDM符号的同步字。所以,一帧数据中包含12个OFDM符号。图3数据帧结构示意图4.1.2发送端各模块功能的介绍A.VectorSource:实现的功能是循环产生同一组向量,并将该向量转化成无符号整形变量(即uchar型变量),所以其输出是一连串的0和1的数据流。输入变量:1,Vector,range(packet_len)。其中packet_len是个变量指一帧数据的长度,单位字节,试验中该变量的值设为96。所以,根据python语法规则range(Packet_len)就是产生一组0到95的向量。2,Veclength,1。产生一个向量。可选变量:是否循环:Yes。输出:一串0和1的数据流,数据类型byte。图3,向量信源模块B.StreamtoTaggedStream:该模块实现的功能是将输入数据流进行打包,形成一定长度的帧数据流,并给数据贴上标签。因此,试验中设定一帧数据长度为96个字节,则该模块按该长度输出打包好的帧数据流,共96个字节96*8个比特。输入变量:1,Vectorlength:1,输入向量的个数,默认为1个;2,2,packetlength:packet_len,定义一帧数据的长度,在流程图的变量模块中packet_len设定为96;3,3,LengthTagKey:length_tag_key,给输出数据打上标签,其标签名为length_tag_key,值为96.输出:带标签的帧数据流,数据类型byte.图4,数据打包模块C.StreamCRC32:该模块实现的功能是对输入的每帧数据进行校验,并将形成的4个字节的校验字附在每帧数据的末尾。注意:经过该模块后输出的一帧数据长度较输入之前增加了4个字节,所以一帧数据长度变成100个字节共100*8个比特。输入变量:1,Lengthtagname:length_tag_key,输入的标签名,该模块需要知道一帧数据的长度是多少;可选变量:Mode:GenerateCRC。这里是发送端,所以选产生CRC校验码,而不是校验接收到的数据。Packed:Yes。告诉模块输入的数据是否是打包好的数据。输出:带标签的帧数据流,数据类型byte.图5,CRC校验模块D.PackerHeaderGenerator:该模块用来记录一帧数据中的信息,即形成帧头,共6个字节6*8个比特,其中字节1代表一帧数据的长度,字节2和3一起表示当前帧的帧号,字节2每16个加一帧,到255字节3便加1;其它三个字节还不知道具体表示什么。输入变量:1,FormatterObject:header_formatter.formatter().指定形成的帧头格式;2,LengthTagName:packet_len.标签名。该模块在对数据进行处理时需要知道一帧数据的长度。输出:帧头数据流,数据类型byte,暂存到HeaderBits模块中.图6,帧头生成模块E.RepackBits:该模块实现的功能是将8比特一组的数据变成2比特一组,由最低位到最高位依次转换。因此,在解码的时候需要特别注意每个比特在一个字节中的位置。输入变量:1,Bitsperinputbyte:8,输入端口每个字节中包含的比特数,指定为8;2,Bitsperoutputbyte:payload_mod.bits_per_symbol(),输出端口每个字节中所包含的比特数,payload_mod.bits_per_symbol中的payload_mod在流图的变量模块中设定为QPSK,因此每个符号应包含2个比特数。3,LengthTagKey:length_tag_key.标签名。该模块在对数据进行处理时需要知道帧长。可选变量:PacketAlignment:input.选择需要进行该操作的端口,这里只有一个input端口可选。Endianness:LSB.从一个字节的最低位开始操作。输出:带标签的帧数据流,数据类型byte,但每个byte包含2个字节.图7,字节重生成模块F.ChunkstoSymbols:符号映射模块,完成数据块到符号流的转换。这里可选的符号参数为-1+0j和1+0j,因此该模块的功能是实现BPSK映射。输入变量:1,SymbolTable:header_mod.points(),该值在变量模块中已定义,其映射规则是输入0时输出-1+0j,输入1时输出1+0j;2,Dimension:1,整个流图始终处理的都是一维数据,所以这里同样是1维。3,NumPorts:1.端口数,同样这里选1。可选变量:InputType:Byte:输入数据类型与前一模块的数据类型相同。OutputType:Complex.输出数据类型为复数。输出:带标签的帧数据流,数据类型complex。图8,BPSK映射模块G.ChunkstoSymbols:符号映射模块,完成数据块到符号流的转换。这里可选符号参数包括-0.707+0.707j,-0.707-0.707j,0.707-0.707j和0.707+0.707j,因此该模块实现的功能是QPSK映射。输入变量:1,SymbolTable:payloas_mod.points(),该值在变量模块中已定义,其映射规则是输入10时输出-0.707+0.707j,输入00时输出-0.707-0.707j,输入01时输出0.707-0.707j,输入11时输出0.707+0.707j。2,Dimension:1,整个流图始终处理的都是一维数据,所以这里同样是1维。3,NumPorts:1.端口数,同样这里选1。可选变量:InputType:Byte:输入数据类型与前一模块的数据类型相同。OutputType:Complex.输出数据类型为复数。输出:带标签的帧数据流,数据类型complex。图9,QPSK映射模块H.TaggedStreamMux:该模块的功能是增大或减小数据流标签中值的大小,从而达到增加或缩减一帧数据长度的目的。这里需要将两路信号合并,因此需要增加数据帧的长度。之前我们分析过数据帧长为100个字节共100*8个比特,经QPSK映射后为100*4个符号;同样针头有6个字节共48个比特,经BPSK映射后变成48个符号。因此,将这两路信号进行合并后得到的一帧数据长度为100*4+48=448个符号。输入变量:1,NumberofInput:2,输入端口数,有两路信号输入,因此这里应填。2,Lengthtagnames:length_tag_key,输入数据帧的长度,96。3,VectorLength:1.和信源保持一致;可选变量:IOType:complex,端口输入数据类型。输出:带标签的帧数据流,数据类型complex。图10,信号合成模块I.OFDMCarrierAllocator:OFDM子载波分配模块,也即串并转换模块。该模块的作用是给每个子载波分配相应的值,数据相应地实现串并转换。这里设总载波个数为64,载波类型包括以下几种:数据子载波(Occupiedcarriers)、导频子载波(Pilotcarriers)、虚拟子载波(Virtualcarriers,VC)和直流子载波(DCcarrier)。其中占用载波可以用来携带数据和同步字,导频载波用于发射特定符号数据,空载波的值默认为0.在试验中发送端OFDM子载波的编号规则是:为了保持左右对称,将64个子载波编号为[-32,31]。其中,最左边6个子载波[-32,-27]和最右边的5个子载波[26,31]称为虚拟载波,即不使用的载波它的值默认为0,其作用是为了减少带外功率和抑制ACI。编号为[-26,-22]、[-20,-8]、[-6,-1]、[1,6]、[8,20]、[22,26]都是数据子载波;编号为-21、-7、7、21为射频子载波;编号为0为直流子载波,作用是降低OFDM信号的峰值信噪比以及硬件电路的复杂度【3】。由此可知,64个子载波中有效子载波只有48个。这样我们便可以计算出承载一帧有效数据(包括帧头和负载共448个符号)所需要的OFDM符号数(将64个子载波组成的并行数据称为一个OFDM符号),即448/48=9.33个OFDM符号,也就是说传输一帧有效数据需要10个OFDM符号。另外,为了接收端解调方便,本实验中的OFDM信号需要加入2个符号的同步字置于一帧有效数据的开头。所以,最后传输的一帧数据中包含了12个OFDM字符,2个同步字和10个有效数据。输入变量:1,FFTlength:fft_len,傅里叶变换的长度,fft_l