基带BPSKQPSKQAMOFDM仿真C实现_第1页
基带BPSKQPSKQAMOFDM仿真C实现_第2页
基带BPSKQPSKQAMOFDM仿真C实现_第3页
基带BPSKQPSKQAMOFDM仿真C实现_第4页
基带BPSKQPSKQAMOFDM仿真C实现_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

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

文档简介

1、移动通信系统仿真标准C实现的利与弊http:/28 摘 要本文介绍采用标准C语言搭建BPSK、QPSK、16QAM、OFDM基带移动通信仿真系统的原理和实现,深刻揭示了使用标准C语言进行移动通信系统仿真的优势和弊端,认为虽然标准C具有运行速度快和占用内存小的优点,但是缺乏科学计算库,抽象层次低,内存管理复杂,并发严重依赖操作系统,在语言层面和标准库没有对多线程的直接支持,不适合进行模型的快速构建和理论验证。本系统除C语言标准库外仅仅依赖第三方库FFTW3,程序采用高内聚、低耦合的模块化程序设计思想进行设计,代码重用率高,具有较强的可扩展性和可重用性。本文所有仿真系统模仿香农经典通

2、信系统模型,即点对点通信,不涉及网络通信。信道模型包含高斯噪声信道和瑞利信道。系统仿真的结果是误比特率曲线,通过比较不同调制方法的误比特率曲线,分析其抗噪声、抗衰落性能。关键字:BPSK QPSK 16QAM OFDM 标准C一、 简介1. 各种调制方法简介BPSKBPSK即二进制相移键控,采用相位相反的正弦载波表示0和1。St=Acos(ct), &an=1Asin(ct), &an=0QPSKBPSK的一个符号代表一个比特,即Rs=Rb,在QPSK中,一个符号代表两个比特,即Rs=2Rb。QPSK的编码采用格雷码,在星座图中某点与距离其最近的点的汉明距离最小。16QAM对于

3、BPSK和QPSK,每种信号的能量或者振幅是相同的,对于16QAM可以有三种能量或振幅的信号。OFDM星座图中的点也采用格雷码表示,某点与距离其最近的点的汉明距离最小。OFDMBPSK、QPSK、16QAM都只有一路载波,而OFDM采用多路相互正交的子载波,子载波的频率间隔f=1/Ts,Ts为OFDM信号的符号周期,其调制解调框图如下所示。2. BER、SNR和Eb/N0BER:误比特率,即 错误比特数发送比特数SNR:信噪比SNR=PsignalPnoise=signal2noise2SNRdb:信噪比的分贝形式:SNRdb=10lgsignal2noise2EbN0 : 功率效率RbB :

4、带宽效率PsignalPnoise=EbN0RbBEbN0db : EbN0 的分贝形式:EbN0db=10lg(EbN0)在编程实现中,假设各种调制系统的发送信号平均每比特能量相同且为Eb,假设码元发送速率已知且Rb=2B,通过改变EbN0db的值测试不同功率效率下的误比特率,待求变量是noise,由上述方程和假设已知条件可得,noise2=EbRb2×10EbN0db10假设Eb=1,Rb=1,则noise2=12×10EbN0db103. 标准C回顾为使用C语言进行系统仿真,必须深入理解C语言语法,其中最重要的是数组与指针。在C的世界里,数组和指针都是基本数据类型。指

5、针变量中存放的是某段内存空间的起始地址,指针的类型暗示指针做自加运算时偏移的字节数。当数组作为函数参数或者函数返回值或者赋值给指针时,数组被隐式转换为指针,丢失数组大小信息。局部变量存储在栈上,局部变量离开其作用域时,内存不能再被访问。举例,函数体内不加static关键字定义的数组作为返回值返回,此返回值赋值给指针,试图使用指针访问之前在函数体内定义的数组将会发生错误,因为此数组在栈上分配,栈上内存在函数结束时被计算机回收。为使函数体内分配的内存具有跨函数的生命周期,采用动态内存分配或者static关键字修饰,前者灵活但不易编程,后者编程方便但所分配内存直到程序结束才释放。二、 系统模型对于B

6、PSK、QPSK、16QAM、OFDM仿真系统,编程实现由易到难,但简单仿真系统的子模块经常可以复用到复杂仿真系统,并且简单仿真系统可以为复杂仿真系统提供设计思路。本文从最简单的BPSK仿真系统开始,规定各种仿真系统平均每比特能量Eb=1。首先生成0/1伪随机序列,对于基带仿真系统,不考虑高频正弦载波,因此使用1表示比特1,使用-1表示比特0。然后模拟信道传输,添加噪声(和衰落),如果发送x,噪声,则接收y=x+,如果衰落,则接收 y=x+。最后判决,计算误码率。对于QPSK仿真系统,由于QPSK系统的星座图有四个点,每个点离原点距离相同,故能量相同,又因为Es=2Eb, Eb=1,因此星座图

7、中每个点的模均为2。本系统使用的映射如下00-1-1, 01-11, 101-1, 1111并且采用格雷编码使汉明距离最小的码相邻。对于16QAM仿真系统,Rs=4Rb,星座图包括十六个点,离远点距离有三类,分别用a,b,c表示 a<b<c,令 Eb=1则 Es=4Eb=4,所以a2+2b2+c24=4由方形QAM系统星座图的特点易得 a=25, b=2, c=65,因此x轴和y轴的投影长度只有25 和325 两种。本系统采用映射如下,依然采用格雷编码:0, 0, 0, 0->x1, y1 0, 0, 0, 1->x2, y1 0, 0, 1, 0->x1, y2

8、 0, 0, 1, 1->x2, y20, 1, 0, 0->x1, -y1 0, 1, 1, 0->x1, -y2 0, 1, 0, 1->x2, -y1 0, 1, 1, 1->x2, -y21, 0, 0, 0->-x1, y1 1, 0, 1, 0->-x1, y2 1, 0, 0, 1->-x2, y1 1, 0, 1, 1->-x2, y21, 1, 0, 0->-x1,-y1 1, 1, 0, 1->-x2,-y1 1, 1, 1, 0->-x1,-y2 1, 1, 1, 1->-x2,-y2其中x1=

9、y1=25,x2=y2=325。对于OFDM系统,本次仿真产生伪随机0/1序列后立刻做16QAM映射,然后串并变换,快速傅里叶反变换,添加循环前缀,并串变换,模拟噪声(和衰落)信道,接收端采用与发送端相逆的过程,最后统计误码率。各种调制系统流程图如下图所示:三、 编程实现1. 瑞利随机数与高斯随机数的产生瑞利随机数的分布函数为:Fxx=1-e-x222, x0在概率论中,根据给定的随机变量x的分布和函数g(x)容易得到y=g(x)的分布。其逆问题是已知随机变量x的分布和y的分布,确定g(x),使得g(x)服从y的分布。根据概率论理论:Ø if u=Fxx, then Fuu=u 0u

10、1Ø if y=Fy-1u, then PYy=Fy(y)Ø if y=Fy-1Fxx, then PYy=Fy(y)产生瑞利随机数的思想是由0-1均匀分布的随机变量u和瑞利分布函数Fx(x)求解g(u),令:u=1-e-x222解得x=-2lnu根据概率论理论,如果x和y是相互独立的零均值方差为2的正太随机变量,那么z=x2+y2服从瑞利分布,=archtan(yx)服从(-22)的均匀分布。因此,可以由x=zcos产生零均值,方差为2的高斯随机数。2. 动态分配m×n二维矩阵的两种方法方法一: 方法二: 方法一的优点是需要调整数组维数只需realloc,缺点是

11、malloc和free的复杂度都是o(n),并且访问每一个元素需要两次寻址;方法二的优点是malloc和free的复杂度都是o(1),访问每个元素只需要一次寻址,缺点是调整数组维数非常不便,比如OFDM仿真系统需要添加循环前缀,使用第二种方法需要对整个数组做拷贝。3. 内存管理使用MatLab、Java等带有垃圾回收机制的编程语言很少操心内存管理,但是在C语言给予用户直接操纵内存的自由,而用户需要为这种自由承担内存管理的责任,为此需要深刻理解操作系统内存布局。一种典型的操作系统内存由低字节到高字节包括:文本段(代码段)、已初始化数据段、未初始化数据段、栈、堆。文本段存储将要执行的代码,多个程序

12、实例可以共享文本段,当多个程序实例链接相同动态库时,内存只载入一份此库的副本。文本段还是只读的,程序不能改变自身。已初始化数据段存储已经初始化的全局变量。未初始化数据段存储尚未初始化的全局变量,存储在此段中的变量,即所有未初始化的全局变量在程序执行前自动被初始化为0或者NULL。栈是栈帧的集合,每当一个函数被调用时会为它分配一个栈帧,栈帧中存放被调用函数所有局部变量,传递给被调用函数的参数,被调用函数返回后将要执行的下一条指令的地址。堆,是C调用malloc或者C+调用new分配内存的区域。堆和栈的生长方向相反。C语言的内存管理是一项极易犯错的编程任务,培养好的编程习惯可以降低错误发生率l 为

13、函数编写清晰的注释,尤其涉及内存分配与释放的函数l 尽力把内存分配逻辑和释放逻辑写到同一作用域内l 代码检查,调用malloc的次数等于调用free的次数l 检查malloc返回值,判断内存是否分配成功l free指针指向的内存后,将指针赋值为NULLl 浅复制时,当内存被释放后所有指向此处内存区的指针应赋值为NULL;深复制时,复制后的内存也要释放。4. 头文件一览#ifndef SIMULAT_H#define SIMULAT_H#include <stdbool.h>#include <fftw3.h>#include <math.h>typedef

14、unsigned long ulong;typedef struct Point double SNR_db; double BER; Point;/*串行序列*/typedef struct Serial double * signal; ulong N; Serial;/*串行序列, but存储的是复数*/typedef struct Serial_C fftw_complex * signal; ulong N; Serial_C;/*m路并行*/typedef struct Parallel double * signal; ulong M; ulong N; Parallel;/*m

15、路并行, but存储的是复数*/typedef struct Parallel_C fftw_complex * signal; ulong M; ulong N; Parallel_C;double gen_uniform_random(void);double gen_rayleigh_random(double sigma);double gen_standard_normal_random(void);double gen_normal_random(double mean, double sigma);int gen_binomial_random(double p);Serial*

16、 gen_signal(ulong N);void bipolar(Serial* serial, double scale);void add_noise(Serial * serial, double mean, double sigma);void add_noise_c(Serial_C * serial_c, double mean, double sigma);void add_noise_and_fading(Serial * serial, double n_mean, double n_sigma, double r_sigma);void add_noise_and_fad

17、ing_c(Serial_C * serial, double n_mean, double n_sigma, double r_sigma);Parallel* serial_to_parallel(Serial * serial, ulong M);Parallel_C* serial_to_parallel_c(Serial_C* serial, ulong M);Serial_C* parallel_to_serial_c(Parallel_C* parallel_c);void add_cycle_prefix(Parallel_C* parallel_c);void del_cyc

18、le_prefix(Parallel_C* parallel_c);Serial* BPSK(Serial* serial);Serial* rBPSK(Serial* serial);Serial_C* QPSK(Serial* serial);Serial* rQPSK(Serial_C* serial_c);Serial_C* QAM16(Serial* serial);Serial* rQAM16(Serial_C* serial_c);void judge4QAM16(Serial_C* serial_c);void judge4QPSK(Serial_C* serial_c);vo

19、id judge4BPSK(Serial* serial);void fft(Parallel_C* parallel_c);void ifft(Parallel_C* parallel_c);void transpose_array(Parallel* parallel);#endif5. 绘图脚本"""绘出误码率/信噪比曲线"""import sysimport csvimport matplotlib.pyplot as pltimport matplotlib.pylab as plbfrom collections impo

20、rt namedtupledef get_x_y(result_file): """ 绘出误码率/信噪比曲线 """ with open(file=result_file, mode='r') as data: data_csv = csv.reader(data) headings = next(data) SNR_BER = namedtuple("SNR_BER", headings) SNR_db, BER = , for line in data_csv: row = SNR_BER(*l

21、ine) SNR_db.append(float(row.SNR_db) BER.append(float(row.BER) return SNR_db, BERif _name_ = '_main_': files = sys.argv1: for file in files: SNR_db, BER = get_x_y(file) plt.title("") plt.yscale("log") plt.plot(SNR_db, BER, 'r-') plt.grid(True)plt.show()四、 仿真结果及讨论所

22、有仿真系统的产生一千万个伪随机序比特,噪声服从零均值,方差为1的高斯分布,瑞利衰落的参数取0.5,OFDM为16路复用。仿真系统的所有误码率数据保存为.csv格式的文件,读者可以使用最擅长的绘图工具绘制误码率曲线对比研究。笔者使用Python作图,命令行参数为需要比较的误码率文件。1. BPSK右上方的曲线是加了衰落和噪声的曲线,下面的曲线是只添加噪声的曲线。由图可知添加衰落比无衰落误码率高,并且信噪比越高,衰落影响越大。2. QPSKQPSK的误码率曲线与BPSK的误码率曲线完全相同。3. 16QAM4. OFDMOFDM和16QAM在瑞利信道下误码率都非常高,16QAM是OFDM的子过程,对16QAM的分析适用于OFDM。在16QAM中将四元组(取值集合为0,1)映射为二元组(取值集合为-325,-25,25,325),不同于BPSK或者QPSK的将二元组(取值集合为0,1)映射为二元组(取值集合为-1,1),16QAM映射后包括两种振幅,这两种振幅乘以衰落小于2/3或者大于2的衰落因子(门限值比发送值)就会发生误码,而BPSK或者QPSK无论乘以怎样的衰落因子(正数)都不会误码,同符号数相乘不会改

温馨提示

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

最新文档

评论

0/150

提交评论