基于PLUTO和MATLAB的QPSK无线调制解调系统

**实验介绍:**本次实验应用软件无线电模块ADALM-PLUTO和MATLAB软件,并结合现代无线数字通信原理,利用MATLAB设计出完整的 QPSK无线通信系统,利用ADALM-PLUTO实现完整的QPSK无线通信系统端到端通信,并对实际的QPSK无线通信系统进行分析。
一、QPSK调制解调原理

(一)QPSK信号
一个MPSK信号码元可以表示为:
S_k (t)=A cos⁡(ω_0 t+θ_k ),k=1,2,…,M
式中:A为常数;θ_k为一组间隔均匀的受调制相位;通常M取2的某次幂
不失一般性,我们可以令A=1,然后将上式MPSK信号码元表达式展开写成:
S_k (t)=A cos⁡(ω_0 t+θ_k )=a_k cos⁡〖ω_0 t〗-b_k sin⁡〖ω_0 t〗
式中:a_k=cosθ_k,b_k=〖sinθ〗_k
令M=4,对4PSK信号作进一步分析。4PSK常称为正交相移键控(Quadrature Phase Shift Keying,QPSK)。他的每个码元含有2比特的信息,现用ab表示这两个比特。发送码元序列在编码时需要先将每两个比特分成一个双比特组ab。ab有4种排列,即00、01、10、11。然后用4种相位之一去表示每种排列。各种排列的相位之间的关系通常按格雷码安排。

在这里插入图片描述

图1 QPSK信号的矢量图
(二)QPSK调制
QPSK信号的产生方法有两种方法。第一种是用相乘电路,如图2所示。图中输入基带信号A(t)是二进制不归零双极性码元,它被“串/并变换”电路变成两路码元a和b。变成并行码元a和b后,其每个码元的持续时间是输入码元的2倍。这两路并行码元序列分别用以和两路正交载波相乘。
在这里插入图片描述

图2 QPSK信号产生方法
(三)QPSK解调
QPSK信号的解调原理方框图示于图3中。由于QPSK信号可以看作是两个正交2PSK信号的叠加,所以用两路正交的相干载波去解调,可以很容易地分离这两路正交的2PSK信号。相干解调后的两路并行码元a和b,经过并/串变换后,成为串行数据输出。
三、使用MATLAB编程实现QPSK相位映射原理及过程
(一)相位映射原理
实际编程里选择的角度对应关系为
角度-3π/4 、 3π/4、π/4 、-π/4分别对应格雷码向量00、01、11、10
在这里插入图片描述
二进制码元 00 01 11 10
映射相位 -3π/4 3π/4 -π/4 -π/4
图4表1 QPSK相位映射关系
(二)实现步骤
①创建一个大小为4的一维数组table,储存QPSK向量:ⅇ^jθ,
其中θ=-3π/4 、 3π/4、π/4 、-π/4
代码:table=exp(j*[-3/4pi 3/4pi 1/4pi -1/4pi]);
table=table([0 1 3 2]+1); % 实现格雷码的对应
②将输入数据进行串并转换,原大小为1×length的数据,变成2×(length/2)的二维数组
代码:inp=reshape(bits_in,2,full_len/2);
%这一步是为了后面将格雷码变换成数组下标的数组运算符合矩阵乘法
③将格雷码变换成数组下标,根据table的规则进行相位映射
代码:mod_symbols=table([2 1]*inp+1); % 根据对应的table进行相位映射
实际代码效果检验:
在这里插入图片描述
(三)完整matlab代码

~isempty(findstr(modulation, 'QPSK'))
table=exp(j*[-3/4*pi 3/4*pi 1/4*pi -1/4*pi]);  
% generates QPSK symbols
table=table([0 1 3 2]+1); 
% Gray code mapping pattern for QPSK symbols
   inp=reshape(bits_in,2,full_len/2);
mod_symbols=table([2 1]*inp+1);  
% maps transmitted bits into QPSK symbols

四、通信过程及协议分析
(一)通信过程
总体功能描述:发送一定长度内任意长度文本内容(汉字、英文),接收端显示发送内容。适当改动程序,可自发自收,也可两个用户进行相互通信。
在这里插入图片描述

(127位)帧同步信息 数据部分 (32位)CRC校验码
图5 帧结构图
本程序代码里一帧的长度固定为703位,这里的数据部分指的是经过处理之后的数据.

1.发送
①输入信息:根据UTF-8编码原则,汉字编码按两个字节计算,字符按一个字节,该实验代码限制了数据部分转为bit的位数最大为992bit。
即如果发送的是纯汉字的话,最多发送的个数为992/8/2=64个,如果发送纯字符的话,最多发送的个数为992/8=124个
②由于固定了一帧的长度,原始数据也就固定是992bit,如果输入的数据长度不足992,那么在后面补零到992位。
③生成帧同步的帧头并进行相位映射,最终长度为127bit
④crc32校验(CRC校验码长度32 bits)
⑤加扰(不改变数据位数)
⑥QPSK调制,相位映射(数据经过QPSK映射后会减半,(992bit+32bit)变为512bit)
⑦插入导频,每64bits插入8位导频信息(前面的数据映射后是512bit,则512/64=8,即会插入8次导频信息,共64bits,最终输出512+64=576bits)
⑧插入帧同步(帧同步是127bits,则一帧的长度变为(576+127=703)bits)
⑨上采样和滚降滤波
⑩将数据乘以2^14,增大DAC输出,根据DAC数据总长度为10万bits,将DAC数据多次复制,将数据长度变为DAC数据长度在10万bits内最大倍数,再通过补零将数据变为10万bits,将10万bits数据传给ADALM-PLUTO模块
程序流程图如下:
在这里插入图片描述

2.接收
匹配滤波->数据归一化->时钟同步->搜索帧同步,获取有效帧信息->三次频率同步->相位估计->删除帧同步(导频+信息码元+CRC码)->相位追踪->删除导频(只剩信息码元+循环校验码)->时域均衡->信号解调->循环码校验,同时除去循环校验码->将二进制转换为文本信息,显示接收到的信息。
(二)通信协议分析

  1. UTF-8编码
    汉字2个字符,英文1个字符(将文本内容转换为二进制数,然后预留32位的crc校验码位置,计算现在的数据是否可以被128整除(为了满足QPSK后插入导频的要求),如果不可以,通过补零使得转换之后数据bit位数为128的倍数此时数据长度为N bit,N可被128整除)。
    2.导频
    (1)插入导频
    每64bits插入8bits经过QPSK调制的导频信息。
    二进制导频信息:pilot=[1 0 1 0 0 1 0 1];
    (2)删除导频
    运用MATLAB方便的矩阵运算,插入导频的逆向操作:将除去帧同步信号的信息按64+8=72bits一份进行均分,只取后面64位即可删除导频。
    3.帧同步
    (1)插入帧同步
    插入的帧同步信号为伪随机序列,采用n=7的移位寄存器,移位寄存器的结构为(1 0 0 0 0 0 1),7级移位寄存器有2^7=128个状态,除去不能用的全零状态,故能产生最长周期为127的伪随机序列,帧同步信息长度为127bits。帧同步信号采用BPSK调制解调。
    (2)删除帧同步
    由于帧同步信号的长度固定(127bits),因此只要找到帧同步信号之后,删除127bits数据即可。
    4.差错控制—循环冗余校验CRC码
    采用32bits的循环冗余校验码。如果校验成功,将解调之后的传输信息送往下一步处理。如果校验失败,则丢弃该帧。
    (三)利用定时器实现全双工通信
    初始化一个定时器定时接收信息,这样可以在input等待输入的时候可以继续接收数据.
    代码如下:
%%%%%%%%%
timer_id = timer;
timer_id.StartDelay = 1.0;
timer_id.Period = 0.1;
timer_id.ExecutionMode = 'fixedSpacing';
timer_id.TimerFcn = @timer_handler;
%
start(timer_id);
function timer_handler(~,~)
    global s
    output=readRxData(s);
    I = output{1};
    Q = output{2};
    Rx = I+1i*Q;
    bpsk_rx_func(Rx(end/2:end));
end

五、实验中遇到的困难和解决方法
(1)如何实现任意长度的信息发送?
答: 因为每一次发送的数据长度设为固定的,所以如果长度小于设定值,可以通过补0到指定长度,如果长度大于设定值,可以采取分组发送的方式,分几次发送数据.
(2)如何发送中文信息?
答:我们小组通过查找资料发现,采用UTF-8编码,汉字就能被编码成两个字节的二进制数据。
(3)如何实现双机通信?
答:改动硬件初始化,实现
(4)QPSK的帧同步信号
答:未解决。本系统采用QPSK的帧同步信号
(5)如何实现全双工?
答:因为发送模式需要调用input函数占用程序进程,使程序停在这一句,而且matlab没有多线程的实现,解决办法是调用matlab的定时器,固定时间去接收解调信号,以此实现全双工
六、参考代码

1、产生帧同步信号:
tx_gen_m_seq([1 0 0 0 0 0 1]);
2、调制函数与解调函数
tx_modulate(seq_sync, 'BPSK');
rx_qpsk_demod(out_signal8);
mod_symbols=tx_modulate(sym_bits, 'QPSK');
QPSK调制:
if ~isempty(findstr(modulation, 'QPSK'))
   % Angle [pi/4 3*pi/4 -3*pi/4 -pi/4] corresponds to 
   % Gray code vector [00 10 11 01], respectively.
   table=exp(j*[-3/4*pi 3/4*pi 1/4*pi -1/4*pi]);  % generates QPSK symbols
   table=table([0 1 3 2]+1); % Gray code mapping pattern for QPSK symbols
   inp=reshape(bits_in,2,full_len/2);
   mod_symbols=table([2 1]*inp+1);  % maps transmitted bits into QPSK symbols
QPSK解调:
rx_symbols=rx_symbols./sqrt(2);
soft_bits = zeros(2,length(rx_symbols));
 
evm_real=zeros(1,length(rx_symbols));
evm_image=zeros(1,length(rx_symbols));
 
bit0 = real(rx_symbols); 
for i=1:length(rx_symbols)
    if(bit0(i)>0)
        evm_real(i)=bit0(i)-1/sqrt(2);
        bit0(i)=1;
    else 
        evm_real(i)=bit0(i)-(-1/sqrt(2));
        bit0(i)=0;
    end
end
bit1 = imag(rx_symbols);
for j=1:length(rx_symbols)
    if(bit1(j)>0)
        evm_image(j)=bit1(j)-1/sqrt(2);
        bit1(j)=1;
    else
        evm_image(j)=bit1(j)-(-1/sqrt(2));
        bit1(j)=0;
    end
end
evm=(evm_real.^2+evm_image.^2).^0.5;
evm=sum(evm)/length(evm);
soft_bits(1,:) = bit0;
soft_bits(2,:) = bit1;
soft_bits_out = soft_bits(:)';

2、实现中文编码函数
function msg_bits = str_to_bits(msgStr)
msgBin = de2bi(int8(msgStr),8,'left-msb');
len = size(msgBin,1).*size(msgBin,2);
msg_bits = reshape(double(msgBin).',len,1).';
end
3、crc校验函数
crc32(mst_bits);
4、白噪声化函数与去白噪声化
scramble([1,1,0,1,1,0,0], inf_bits); 
descramble(soft_bits_out(i),Si)  
5、插入导频函数和删除导频
insert_pilot(mod_symbols);
rx_delete_pilot(out_signal6) 
6、滚降滤波,上采函数
rcosdesign(1,128,4);
upfirdn(trans_symbols,fir,4);
7、将传输数据复制多份,补零,达到10万位长度
txdata = bpsk_tx_func; 
txdata = round(txdata .* 2^15);
txdata=repmat(txdata, floor(send_and_receive_length/length(txdata)),1);
if length(txdata)<send_and_receive_length
    txdata=[txdata;zeros(send_and_receive_length-length(txdata),1)];
end
8、发送、接受数据
output = stepImpl(s, input);
9、处理接收数据函数
bpsk_rx_func(Rx(end/2:end))
13、归一化代码
c1=max([abs(real(rx_sig_filter.')),abs(imag(rx_sig_filter.'))]);
rx_sig_norm=rx_sig_filter ./c1;
14、位同步
rx_timing_recovery(rx_sig_norm.');
15、频率同步函数
rx_freq_sync(coarse_sync_seq,4,rx_frame)
16、相位估计
rx_phase_sync(out_signal3,local_sync)
17、删除帧同步信号和相位跟踪
out_signal4(length(local_sync)+1:end);
 rx_phase_track(rx_no_syn_seq); 
18、时域均衡
rx_time_equalize(out_signal7)
19、显示接收字符
disp(native2unicode(b,'UTF-8'));

20.主函数
while(flag==1)
% if(partern=='1')
    disp('ÊäÈë¿ò×î¶à124¸öÎı¾');
    msgStr=input('ÇëÊäÈë´«Ë͵ÄÐÅÏ¢£º','s');%ÊäÈëÐÅÏ¢
%     mst_bits_first=str_to_bits(msgStr);
    mst_bits_first=chinese_to_bits(msgStr);
     o=length(mst_bits_first);
     k=o/max_bits;
     % %% string to bits
     if k<1||k==1
        mst_bits=[mst_bits_first zeros(1,max_bits-o)];
     end
     txdata = bpsk_tx_func(mst_bits);
    txdata = round(txdata .* 2^14);
    txdata=repmat(txdata, 8,1);
   % fprintf('Transmitting Data Block %i ...\n',i);
    Input{1} = real(txdata);
    Input{2} = imag(txdata);
    writeTxData(s, Input);
    
    prompt = 'Do you want continue? Y/N [Y]: ';
    str = input(prompt,'s');
    if str == 'Y'|| str == 'y'
        flag=1;  
    else
        flag=0;
    end
end
21.定时器部分
%%%%%%%%%
timer_id = timer;
timer_id.StartDelay = 1.0;
timer_id.Period = 0.1;
timer_id.ExecutionMode = 'fixedSpacing';
timer_id.TimerFcn = @timer_handler;
%
start(timer_id);
function timer_handler(~,~)
    global s
    output=readRxData(s);
    I = output{1};
    Q = output{2};
    Rx = I+1i*Q;
    bpsk_rx_func(Rx(end/2:end));
end

希望获得整个工程代码的同学也可以私信联系我!!

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

237工作室

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值