第1章(2):QPSK调制解调器仿真 您所在的位置:网站首页 gmsk误码率仿真代码 第1章(2):QPSK调制解调器仿真

第1章(2):QPSK调制解调器仿真

2024-04-13 04:46| 来源: 网络整理| 查看: 265

在写完《第1章(1):BPSK调制解调器仿真》的学习总结后,便有读者问什么时候出QPSK的内容,今天便来了。

20211129推荐文章和代码:

带通信号与等效低通信号,SNR与EbN0的换算关系,下面这几篇文章讲解非常清楚。

通信原理与matlab仿真v2 第六章 什么是误码率(5)

通信原理与matlab仿真v2 第六章 什么是误码率(6)

通信原理与matlab仿真v2 第六章 什么是误码率(7)

通信原理与matlab仿真v2 第六章 什么是误码率(8)

本章主要内容如下:

一、QPSK调制解调器流程

二、噪声怎么加?

三、BPSK和QPSK的误码率一样吗?

四、总结

一、QPSK调制解调器流程

在《第1章(1):BPSK调制解调器仿真》中已经介绍了不少关于BPSK调制解调的知识,比如匹配滤波器、最佳采样点、S/N 与\[{E_b}/{N_0}\]的换算关系、频谱图和眼图怎么看等等,而这些知识在本章中还会用到

尤其是S/N(信噪比)和Eb/N0(比特信噪比)的换算关系,这一点非常容易搞混,从而会导致与理论误码率曲线存在3dB的性能误差,接下来会重点讲到这一点。

本章最重要便注意三点:建立I路和Q路正交调制的概念、噪声怎么加、SNR与\[{E_b}/{N_0}\]换算关系。

典型数字通信系统的方框图

不管对于MPSK还是MQAM来说,首先画出星座图,一般采用格雷码映射,即相邻星座点只有1比特不同,这样误码率性能较好。(至于为什么格雷码映射误码率比特性能会更好一点,相同误码率情况下好多少个dB,这个也可以单独仿真,作为一个小实验,哈哈哈哈)。

当然,MATLAB的文档已经给出了相关仿真如下:

接下来介绍用复数概念来表示调制解调,进而理解调制器的正交实现。看到斯克拉的《数字通信第二版》

如果代码中没有滚降成型滤波器这一步,那么g(t)就是星座图的四个点,比如 \[\frac{{\sqrt 2 }}{2} + \frac{{\sqrt 2 }}{2}j\] (对应00)、 \[\frac{{\sqrt 2 }}{2} - \frac{{\sqrt 2 }}{2}j\] (对应01)、\[ - \frac{{\sqrt 2 }}{2} + \frac{{\sqrt 2 }}{2}j\] (对应10)、和 \[ - \frac{{\sqrt 2 }}{2} - \frac{{\sqrt 2 }}{2}j\] (对应11)。

如果代码中有滚降成型这一步,就用星座点经过成型滤波器后的值即可,并且经过成型滤波器前后的每个符号功率不变,从后面的代码也将看到这一点。

尤其要注意的是发送端是 \[I\cos wt - Q\sin wt\] ,接收端的I路乘以 \[\cos wt\] ,Q路是乘以 \[ - \sin wt\] 。(如果这里没有对应,误码率曲线总是和理论曲线对应不上)

二、噪声怎么加?

有了复数形式、正交调制的概念,加上可以直接在基带仿真(即不上载波,没有乘coswt或者sinwt的过程),因此对于QPSK便提供了三种仿真思路。

值得注意的是,不管以上三种仿真思路,得出来的误码率曲线,都是和理论误码率曲线相差不大。如果出现了不一样的情况,说明是代码中某个地方出错了。

(1)复数形式

在发送端基带成型出来的I路和Q路数据合并成(a+bj)的复数形式,上载波的过程直接采用exp(j*2pi*fc*t),由于在计算机里面是离散的,因此需要将t = nT进行代换。

发送端如下:

time = 1:length(r_msg_source_I); rcos_msg_source_carrier = (r_msg_source_I + 1j*r_msg_source_Q).*exp(1j*2*pi*fc.*time/fs); spow1 = sum(rcos_msg_source_carrier*rcos_msg_source_carrier')/length(Transmit_code_I);

接收端如下:

%%%线性高斯白噪声信道 %**加噪声 r_msg_source_carrier_addnoise = awgn(rcos_msg_source_carrier,snr(1,k),'measured'); spow4 = sum(r_msg_source_carrier_addnoise*r_msg_source_carrier_addnoise')/length(Transmit_code_I); noise_temp = r_msg_source_carrier_addnoise - rcos_msg_source_carrier; spow5 = sum(noise_temp*noise_temp')/length(Transmit_code_I); snr_temp = 10*log10(spow1/spow5);

由于awgn函数本身支持复数输入,这可以在awgn函数自带说明文档中看出,因此加噪声时,rcos_msg_source_carrier作为输入可以直接是复数形式。

当然,如果还想验证一下awgn函数加的信噪比和想加的信噪比是否一致,可以采用上面代码中snr_temp = 10*log10(spow1/spow5),即用加完噪声出来后的信号,对其进行信噪比计算,发现和snr(1,k)一致。

即也验证了awgn函数在复数输入情况下,对输入信号进行加噪声,和我们想加的信噪比是一致。

接收端的下载波过程如下:

%%%相干解调 r_msg_source_addnoise = r_msg_source_carrier_addnoise.*exp(-1j*2*pi*fc.*time/fs);

如果采用这种复数的形式下载波,那么低通滤波器都可以省了,因为这种复数下载波的形式并不会产生2fc的分量。

再其后就是下载波、匹配滤波、抽样判决,与发送数据比对,从而统计出误码率,并与QPSK理论曲线进行对比,这个过程和上一章《第1章(1):BPSK调制解调器仿真?》是一样的过程。

参考MATLAB关于 AWGN Channel的说明

值得注意的是,误码率曲线横坐标是EbN0,因此需要进行SNR与EbN0的换算。

此时采用的换算公式,是对应复数输入的信号,即 \[{E_s}/{N_0}\left( {{\rm{dB}}} \right) = 10{\log _{10}}({T_{sym}}/{T_{samp}}) + SNR\left( {{\rm{dB}}} \right)\]

对应QPSK调制来说,1个符号是2个比特,所以k=2。

综合以上两点,得到 \[{E_b}/{N_0}\left( {{\rm{dB}}} \right) = SNR\left( {{\rm{dB}}} \right) + 10{\log _{10}}({T_{sym}}/{T_{samp}}) - 10{\log _{10}}(2)\]

我设置的符号速率sr = 1000,采样频率fs=16000,因此 \[10{\log _{10}}({T_{sym}}/{T_{samp}}) - 10{\log _{10}}(2)\] =9dB,对应代码中这句:

ebn0 = snr+9;

对应画误码率曲线前的准备代码中如下:

ebn0 = snr+9; berbpsk_th = berawgn(ebn0,'psk',2,'nondiff'); berqpsk_th = berawgn(ebn0,'psk',4,'nondiff'); semilogy(ebn0,berbpsk_th,'-o',ebn0,berqpsk_th,'-*',ebn0,bit_err_ratio,'->'); xlabel('比特信噪比'); xlabel('误码率'); title('QPSK调制不同信噪比下误码率仿真曲线'); legend('BPSK理论线','QPSK理论线','QPSK实验曲线'); grid on;复数形式下QPSK的误码率曲线

结论:复数形式下仿真QPSK仿真误码率曲线和理论是一样的。

(2)正交调制

显然,在上面这种复数上、下载波方式下,仿真过程比较好理解,更像是一个纯理论的验证过程。没有用到正交调制的这种方法,而实际信号时,还是要分开I路和Q路。

因此,来说一下采用正交调制的情况下,应当怎么样加入噪声。

对于正交调制来说,以前面的图4.24为例, 对应代码如下:

%%%%%载波发送 time = 1:length(r_msg_source_I); tra_IFsignal = r_msg_source_I.*cos(2*pi*fc.*time/fs) - r_msg_source_Q.*sin(2*pi*fc.*time/fs);

其中r_msg_source_I是I路数据经过成型滤波器出来的结果,r_msg_source_Q同理。

前面已经讲过用固定SNR来推导EbN0,这里,不妨采用固定EbN0来推导SNR,旨在熟练推导两者之间的关系。

除了用awgn函数来加噪声,另外一种常见的加噪声方式是对信号加入一个随机序列,可将之理解成噪声对信号的一种随机扰动。

%****************************** 线性高斯白噪声信道 % *******方式一 %代码参考《simulation and software Radio for mobile communication》,书中是基带,这里是中频 spow = sum(tra_IFsignal.^2)/length(Transmit_code_I);%中频信号功率 attn_pow = 0.5*spow*sr/br*10.^(-EbN0(1,k)/10); %这个0.5是必须的 attn = sqrt(attn_pow); inoise = attn*randn(1,length(tra_IFsignal)); qnoise = attn*randn(1,length(tra_IFsignal)); IFsignal = tra_IFsignal+ inoise.*cos(2*pi*fc.*time/fs) - qnoise.*sin(2*pi*fc.*time/fs); %这句最关键 spow4 = sum(IFsignal*IFsignal')/length(Transmit_code_I); noise_temp = IFsignal - tra_IFsignal; spow5 = sum(noise_temp*noise_temp')/length(Transmit_code_I); snr_temp1 = 10*log10(spow/spow5); %仿真代码中的信噪比 snr_temp2 = EbN0(1,k)+10*log10(br/sr)-10*log10(0.5*fs/sr); %按照MATLAB的EbNO与SNR换算关系得到

为了下面阐述方便,不妨令 n_temp = inoise.*cos(2*pi*fc.*time/fs) - qnoise.*sin(2*pi*fc.*time/fs);

有一位读者朋友问我,为什么 attn_pow = 0.5*spow*sr/br*10.^(-EbN0(1,k)/10); 这一句有0.5这个系数,我当时很自然的回答噪声功率要分成I路和Q路,各占总噪声功率的一半。

而在《simulation and software Radio for mobile communication》的P87也是类似说法,“Gaussian noise is normally distributed equally in in-phase and quadrature-phase channels.

原书中这里是基带仿真,没有上载波

可是注意到 \[E\left( {n\_tem{p^2}} \right) = E\left( {inois{e^2}} \right) = E\left( {qnois{e^2}} \right)\] 。如果需要深入了解、完全搞懂这个等式,需要用到随机过程和通信原理的一些知识。

比如樊昌信老师的《通信原理》第3.6节正弦波加窄带高斯白噪声,《通信系统仿真原理与无线应用》的第4章带通信号与系统的低通仿真模型,这两个地方有详解介绍。

回到正题,采用 inoise.*cos(2*pi*fc.*time/fs) - qnoise.*sin(2*pi*fc.*time/fs) 这种加噪声方式下,也即往信号中加入的噪声实际是算出来的总噪声功率的一半,但此时误码率曲线是正确的。

加噪声功率的时候,为什么加一半得出来的却是正确的误码率曲线呢?这和我们之前理解的信噪比有什么不同呢?这种矛盾如何解释呢?

这个问题,想了我一天。

直到我和微信公众号通信工程师专辑的作者蔡老师说起此事,老师马上便知道是差3dB的这个问题,推荐我去看该公众号上《什么是误码率》系列文章。

下面这几篇推荐文章,值得反复学习,从理论分析,到仿真实验,以及不同书籍、论文、代码的相互交叉验证,已经说得非常清楚了。

通信原理与matlab仿真v2 第六章 什么是误码率(5)

通信原理与matlab仿真v2 第六章 什么是误码率(6)

通信原理与matlab仿真v2 第六章 什么是误码率(7)

通信原理与matlab仿真v2 第六章 什么是误码率(8)

我简单记录如下,回到MATLAB中对AWGN Channel的说明如下:

此时中频信号仿真对应的实数信号输入的这种形式,即

\[SNR\left( {{\rm{dB}}} \right) = {E_b}/{N_0}\left( {{\rm{dB}}} \right) + 10{\log _{10}}(2) - 10{\log _{10}}(0.5 \times {T_{sym}}/{T_{samp}})\]

代入数值: \[SNR\left( {{\rm{dB}}} \right) = {E_b}/{N_0}\left( {{\rm{dB}}} \right) - 6\]

%%%%%%%%%%%%%%%%%%%%%%%% 信道 %%%%%%%%%%%%%%%%%%% %设置比特信噪比,单位dB % EbN0 = 3:8; EbN0 = 3; err_number = zeros(1,length(EbN0)); bit_err_ratio = zeros(1,length(EbN0)); for k =1:length(EbN0) %****************************** 线性高斯白噪声信道 % *******方式一 %代码参考《simulation and software Radio for mobile communication》,书中是基带,这里是中频 spow = sum(tra_IFsignal.^2)/length(Transmit_code_I);%中频信号功率 attn_pow = 0.5*spow*sr/br*10.^(-EbN0(1,k)/10); %这个0.5是必须的 attn = sqrt(attn_pow); inoise = attn*randn(1,length(tra_IFsignal)); qnoise = attn*randn(1,length(tra_IFsignal)); IFsignal = tra_IFsignal+ inoise.*cos(2*pi*fc.*time/fs) - qnoise.*sin(2*pi*fc.*time/fs); %这句最关键 spow4 = sum(IFsignal*IFsignal')/length(Transmit_code_I); noise_temp = IFsignal - tra_IFsignal; spow5 = sum(noise_temp*noise_temp')/length(Transmit_code_I); snr_temp1 = 10*log10(spow/spow5); %仿真代码中的信噪比 snr_temp2 = EbN0(1,k)+10*log10(br/sr)-10*log10(0.5*fs/sr); %按照MATLAB的EbNO与SNR换算关系得到 aaa = 1; %仅用于调试

当EbN0 = 3时,得到的snr_temp1 = -3.006049375201079,snr_temp2= -3.020599913279623,可认为 snr_temp1 = snr_temp2。

当我令 attn_pow = spow*sr/br*10.^(-EbN0(1,k)/10); 即没有0.5时,此时snr_temp1 = -6.028571258253274,snr_temp2=-3.020599913279623,即snr_temp1 不等于 snr_temp2,且是差3dB。

因此,attn_pow = 0.5*spow*sr/br*10.^(-EbN0(1,k)/10)中这个0.5是非常必要的。

这是从仿真中直接去验证可以得出来的结论,回到对于实信号的换算关系上来,表达如下:

\[SNR\left( {{\rm{dB}}} \right) = {E_b}/{N_0}\left( {{\rm{dB}}} \right) + 10{\log _{10}}(2) - 10{\log _{10}}({T_{sym}}/{T_{samp}}) - 10{\log _{10}}(0.5)\]

\[ - 10{\log _{10}}(0.5)\] 是+3dB,也就是说 \[{E_b}/{N_0}\left( {{\rm{dB}}} \right) + 10{\log _{10}}(2) - 10{\log _{10}}({T_{sym}}/{T_{samp}})\] 需要再加上3dB才是信噪比,因此需要在给信号加入的噪声功率少一半,便是对应加上3dB这个过程了。

同理,也可以对信号功率乘2倍,即幅度前面乘以 \[\sqrt 2 \] ,那么此时attn_pow = spow*sr/br*10.^(-EbN0(1,k)/10),就可以应用了。

如果想使用awgn函数进行加噪,代码如下:

% %*****方式二 % % measured'使信噪比更加准确,对实验结果关键影响tra_IFsignal IFsignal = awgn(tra_IFsignal,snr_temp2,'measured'); % %结论:和理论误码率曲线比对,正确

至此,换算问题已经说完了。

三、BPSK和QPSK的误码率一样吗?

这个问题我之前在《陈老湿:问答交流1:采用过采样的原因》说过一次。由于我觉得这个结论对于通信原理的基础学习过于重要,强调一下也是值得的。

尤其是本章已经有QPSK调制解调的仿真代码,这样可以和BPSK的仿真代码、BPSK的理论误码率曲线、QPSK的理论误码率曲线进行对比,这样的结果非常直观。

复数形式下QPSK的误码率曲线

看到斯克拉的《数字通信——基础与应用》。

你也可以在MATLAB使用berawgn函数,进行验证。

%%%%%%%%%%%%%%%%%%%%% MPSK误码率曲线 %%%%%%%%% %%%%%%%%%%%%%%%%%%%%% mpsk_ber.m %%%%%%%%% %%%%%%%%%%%%%%% data:2020年10月6日 作者:飞蓬大将军 %%%%%%%%%%%%%%%%%%% EbNo = 0:1:10; ber_2psk = berawgn(EbNo,'psk',2,'nondiff'); ber_4psk = berawgn(EbNo,'psk',4,'nondiff'); ber_8psk = berawgn(EbNo,'psk',8,'nondiff'); semilogy(EbNo,ber_2psk,'-*',EbNo,ber_4psk,'-+',EbNo,ber_8psk,'-o'); xlabel('比特信噪比'); ylabel('误码率'); title('不同信噪比下误码率仿真曲线'); legend('2psk','qpsk','8psk'); grid on; %%%%%%%%%%%%%%%%% 结论 %%%%%%%%%%%%%%%%%%%% %BPSK和QPSK的理论误比特率是一样的 %没有包含编译码内容 %2020-10-6四、总结(1)基础

不积跬步,无以至千里。

通信仿真可简单可复杂,但是越接近实际时,所用到的模块便越多,涉及的知识也越来越多。然而,后面的工作往往都要前面打下的基础,尤其是理论与仿真均验证过正确,个人理解也算正确的基础知识。

这样的基础知识,便成为自己看待专业问题的准绳,亦或者叫参考点。

不然,等到后期做实验时,一旦仿真出现错误时,便不知道从哪些模块查起,因为自己没有把握哪些模块是一定正确的,哪些模块可能出现错误。

因此,如果是这样排查错误,那么找到错误并纠正错误的效率便会很低。

举个例子,加入我这次写的QPSK调制解调器实验,如果加上了捕获和同步模块,那么此时出现错误,我可能都不知道是捕获还是同步、还是SNR与EbN0的换算出问题,然后得逐一排查。

另外一种思路,我先把捕获模块、同步模块、SNR与EbN0的换算关系,均仿真正确,再加入到一个大程序中,这样仿真正确性便有一定程序的保证了。

(2)经验

由于我们碰到的问题,绝大多数,前辈们已经思考过,并可能已经有解决方法。有时候真的是有经验的前辈一点拨 ,胜过自己瞎捉摸几个小时甚至几天半个月。

就拿这次中频信号的仿真中存在3dB误差时,出现问题后,我也是查网上是否有资料专门阐述这个问题,我是想了一天。

恰好得到公众号"通信工程师专辑"作者蔡老师的点拨,公众号上《什么是误码率》这系列文章已经将SNR与EbN0换算关系,从理论和仿真把这个问题讲得非常清楚了。

在这里,感谢前辈蔡老师对我本人的指点,也推荐读者去微信公众号“通信工程师专辑”中学习更多的通信知识。

欢迎你双击屏幕、点赞、收藏、转发和分享,关注我的知乎号,也欢迎读者朋友就相关技术问题与我交流,一起学习,共同进步。请你也别忘了把这篇文章分享给你身边正在学习通信专业的同学们,也许能够帮到Ta。

这是《陈老湿·通信MATLAB仿真》的第1章,下次更新见!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有