Vivado 实现 pi/4 QPSK仿真 及 使用MATLAB 进行仿真过程分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文讲述了使用Vivado 仿真FPGA实现pi/4 QPSK 调制解调的过程,并将调制过程中的信号导出至matlab进行分析。

一、 π / 4 \pi/4 π/4 QPSK 调制解调原理

1 π / 4 \pi/4 π/4 QPSK 信号介绍

相移键控(PSK)的解调原理为通过数字码字控制载波信号(正弦信号)相位。其相对于ASK具有能量稳定的优先,相对于FSK,具有频带窄的优势。

QPSK指的是共有4种相位,通过数字码元{00,01,10,11},进行控制,通常其相位为{ 0 , π / 2 , π , 3 π / 2 0,\pi/2,\pi,3\pi/2 0,π/2,π,3π/2}。

为了解决载波同步的问题,引入了差分编码技术DQPSK,差分编码指的是码字不是直接控制载波信号相位,而是控制当前码元和上一码元的相位差。

为了解决相邻码字相位差可能出现 π \pi π跳变的情况(这在实际的通信系统中会引入高频分量),引入了 π / 4 \pi/4 π/4 QPSK调制。其信号有8个相位,分为两组,每次信号会从其中一组跳到另外一组,导致最大相位差为 3 π / 4 3\pi/4 3π/4
在这里插入图片描述
如图所示,上下左右为一组,左上右上左下右下为一组,码字控制的相位跳变为
00 ( π / 4 ) 01 ( 3 π / 4 ) 10 ( − π / 4 ) 11 ( − 3 π / 4 ) 00 ( \pi/4) \quad 01 (3\pi/4) \quad 10 (-\pi/4)\quad 11 (-3\pi/4) 00(π/4)01(3π/4)10(π/4)11(3π/4)

2 π / 4 \pi/4 π/4 QPSK 调制原理

在这里插入图片描述
如图所示,主流的调制方法是方法二,因为控制幅度比控制相位差来的简单,本文中由于DDSip核可以直接控制相位输入,因此使用方法1 进行调制。

3 π / 4 \pi/4 π/4 QPSK 解调原理

在这里插入图片描述

二、Vivado 和 Matlab实现

主体流程图如下

在这里插入图片描述

1 发送码字生成

matlab 码字写入文件

a1 = 0.4;
a2 = 0.7;
a3 = 0.9;
len = 1e4;     % 码字长度以及各个码字出现的概率
close all
fid=fopen('A2.txt','wb');%写入文件路径
for ii  = 1:len 
    c = rand(1);%           按不同概率生成码字
    if(c>a3)
        fprintf(fid,'%d\n',1);  
        fprintf(fid,'%d\n',1);   %11
    elseif(c>a2)
        fprintf(fid,'%d\n',1);  
        fprintf(fid,'%d\n',0);  % 10
    elseif(c>a1)
        fprintf(fid,'%d\n',0);  
        fprintf(fid,'%d\n',1);   %01
    else
        fprintf(fid,'%d\n',0);  
        fprintf(fid,'%d\n',0);  %00
    end
end
    
fclose(fid)
;

teshbench 读取码字

integer file ;
file = $fopen("E:\\qpsk_src\\qpsk1\\A2.txt","r");    // 读取文件

always  //读取码字
begin  
    # 1600;
    if(bit_in_clk)
        bit_in_clk = !bit_in_clk;//生成时钟,
    else begin
        bit_in_clk = !bit_in_clk;
        if(bit_idx<bit_len)
        begin
         $fscanf(file,"%b",bit_in); //读取码字输入比特流
         bit_idx=bit_idx+1;
         end
         else
         begin
         $fclose(file);
     end
    end
    
end

2. π / 4 \pi/4 π/4 QPSK 调制

串并变换

 always @(posedge bit_clk) begin  
   bit_buffer_inter <= {bit_buffer_inter[0], bit_in}; // 移位寄存器  
            idx = !idx;
            if (idx) begin     
                bit_ready <= 1'b1;      //存储2位后完成后   发出可以调制相位的信号
                bit_buffer_out<=bit_buffer_inter;
            end  
 end            //串并变换   将输入比特流存储至两位qpsk码元的缓存区

本地载波信号

  dds_compiler_0 dds0 (
  .aclk(clk),                               
  .s_axis_phase_tvalid(high),  
  .s_axis_phase_tdata(phase_in_reg),    //输入相位!!!!!!!!!!!!!
  //也是本程序控制的相位
  .m_axis_data_tvalid(a2),   
  .m_axis_data_tdata(dds_out)      // 本地载波
);

码字控制相位

always @(posedge clk) begin      //根据二位码元进行相位累加  改变ddsip核生成正弦波的相位
    if (bit_ready) begin         
        case (bit_buffer_out)  
         2'b00: phase_in_reg = phase_in_reg+PHASE_SHIFT_PI_4; // 相位45度      对应00
         2'b01: phase_in_reg  = phase_in_reg+PHASE_SHIFT_fuPI_4;  // 相位-45度   对应01
         2'b10: phase_in_reg = phase_in_reg+PHASE_SHIFT_3PI_4; // 相位135度   对应10
         2'b11: phase_in_reg = phase_in_reg+PHASE_SHIFT_fu3PI_4;// 相位-135度   对应11

            default: phase_in_reg = phase_in_reg+PHASE_SHIFT_PI_4; // 默认输出0  
        endcase  
        phase_pre = phase_in_reg;
        bit_ready = 1'b0;   //调制完相位后准备接收下一码字
    end  
end  

加噪
matlab生成噪声rom核系数

close all;
clear all;
clc;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%          
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fc=3e6;         
fs=65e6;       
L=1024;          
ADC_bit=10;     

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
t=0:1/fs:(L-1)/fs;
noise=randn(1,length(t));

st=noise;
y=st/4;%max(abs(st));               
yt=round(y*(2^(ADC_bit-1)-1));    
figure(1);
plot(st);hold on;
figure(2);
plot(y);hold on;
figure(3);
plot(yt);hold on;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%            MATLAB
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fid=fopen('WN.coe','w');
fprintf(fid,'Memory_Initialization_Radix = 2;\r\n'); 
fprintf(fid,'Memory_Initialization_Vector = \r\n');
for p=1:L
    B_s=dec2bin(yt(p)+(yt(p)<0)*2^ADC_bit,ADC_bit);
    for q=1:ADC_bit  
        if B_s(q)=='1'
            data=1;
        else
            data=0;
        end
        fprintf(fid,'%d',data);
    end
    
    if (p<L)
        fprintf(fid,',\r\n'); 
    else
        fprintf(fid,';\r\n');  
    end
   
end
fclose(fid);

fpga通过rom核加噪

   blk_mem_gen_0 noise_rom (
  .clka(clk),    // input wire clka
  .addra(addra),  // input wire [9 : 0] addra
  .douta(noise)  // output wire [7 : 0] douta
);          //噪声生成rom核,噪声

mult_gen_1 noise_mul (
  .CLK(clk),  // input wire CLK
  .A(noise),      // input wire [9 : 0] A
  .B(noise_factor),      // input wire [7 : 0] B  //信噪比输入
  .P(noise1)      // output wire [16 : 0] P
);               //噪声乘法ip核  进行噪声缩小,

c_addsub_2 noise_add (
  .A(noise2),      // input wire [9 : 0] A
  .B(dds_out),      // input wire [7 : 0] B
  .CLK(clk),  // input wire CLK
  .CE(high),    // input wire CE
  .S(noised_sig1)      // 信号与噪声相加

调制模块接口定义

module qpsk_mod(

    input clk,                // 时钟信号  
    input rst_n,              // 异步复位信号,低电平有效  
    input bit_in,             // 串行输入比特  
    input bit_clk,            // 输入比特时钟  
    input wire [7:0] noise_factor,   //  SNR 控制 44 0dB   14 10dB
    output  wire [7:0] sin_out,  // QPSK信号
    output  wire [1:0] qpsk_code_out  // QPSK码字

);  

3. π / 4 \pi/4 π/4 QPSK 解调

本地载波信号

dds_compiler_0 dds1 (     //cos
    .aclk(clk),                                // input wire aclk
    .s_axis_phase_tvalid(high),  // input wire s_axis_phase_tvalid
    .s_axis_phase_tdata(phase_in_reg),    // input wire [15 : 0] s_axis_phase_tdata
    .m_axis_data_tvalid(a2),    // output wire m_axis_data_tvalid
    .m_axis_data_tdata(cos_out)      // output wire [7 : 0] m_axis_data_tdata
    );

    dds_compiler_0 dds2 (        //sin
  .aclk(clk),                                // input wire aclk
  .s_axis_phase_tvalid(high),  // input wire s_axis_phase_tvalid
  .s_axis_phase_tdata(PHASE_SHIFT_fu90),    // input wire [15 : 0] s_axis_phase_tdata
  .m_axis_data_tvalid(a1),    // output wire m_axis_data_tvalid
  .m_axis_data_tdata(sin_out)      // output wire [7 : 0] m_axis_data_tdata
);

相乘,低通

//首先将输入信号分别和两路本地载波信号相乘
  mult_gen_0 mul1 (
  .CLK(clk),  // input wire CLK
  .A(cos_out),      // input wire [7 : 0] A
  .B(sin_in),      // input wire [7 : 0] B
  .P(cos_mul)      // output wire [15 : 0] P
);

 
  mult_gen_0 mul2 (
  .CLK(clk),  // input wire CLK
  .A(sin_out),      // input wire [7 : 0] A
  .B(sin_in),      // input wire [7 : 0] B
  .P(sin_mul)      // output wire [15 : 0] P
);
   
     
    //随后分别对两路相乘后信号进行滤波  滤除高频分量,剩余相位信息
  fir_compiler_0 cos_lpf (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(high),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),  // output wire s_axis_data_tready
  .s_axis_data_tdata({cos_mul}),    // input wire [15 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(lpf_out1)    // output wire [39 : 0] m_axis_data_tdata
);
  
    fir_compiler_0 sin_lpf (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(high),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),  // output wire s_axis_data_tready
  .s_axis_data_tdata(sin_mul),    // input wire [15 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(lpf_out2)    // output wire [39 : 0] m_axis_data_tdata
);
   

利用和差化积计算相位差

   
  //以下四个乘法和两个加减法是根据和差化积公式算出当前码元和上一码元的相位差,这代表着两位qpsk码字信息
  mult_gen_0 coscos (
  .CLK(clk),  // input wire CLK
  .A(cos_mul_lpf),      // input wire [7 : 0] A
  .B(cos_mul_lpf_old),      // input wire [7 : 0] B
  .P(cc1)      // output wire [15 : 0] P
);
  mult_gen_0 sinsin (
  .CLK(clk),  // input wire CLK
  .A(q),      // input wire [7 : 0] A
  .B(sin_mul_lpf_old),      // input wire [7 : 0] B
  .P(ss1)      // output wire [15 : 0] P
);
  mult_gen_0 cossin (
  .CLK(clk),  // input wire CLK
  .A(cos_mul_lpf),      // input wire [7 : 0] A
  .B(sin_mul_lpf_old),      // input wire [7 : 0] B
  .P(cs1)      // output wire [15 : 0] P
);
  mult_gen_0 sincos (
  .CLK(clk),  // input wire CLK
  .A(q),      // input wire [7 : 0] A
  .B(cos_mul_lpf_old),      // input wire [7 : 0] B
  .P(sc1)      // output wire [15 : 0] P
);
c_addsub_0 csub (
  .A(cc),      // input wire [7 : 0] A
  .B(ss),      // input wire [7 : 0] B
  .CLK(clk),  // input wire CLK
  .CE(high),    // input wire CE
  .S(cossub1)      // output wire [8 : 0] S
);
 
c_addsub_1 ssub (
  .A(sc),      // input wire [7 : 0] A
  .B(cs),      // input wire [7 : 0] B
  .CLK(clk),  // input wire CLK
  .CE(high),    // input wire CE
  .S(sinsub1)      // output wire [7 : 0] S
);

与QPSK码字判决

always @(posedge clk or negedge rst_n) begin  
    if (!rst_n) 
    begin  
        bit_buffer_out <= 2'b00;  
        bit_buffer_inter <= 2'b00;  
        bit_ready <= 1'b0;  
    end 
    else 
    begin  
        q<=-sin_mul_lpf;  //sin项的正负变换

    end 
     
    if(code_clk_idx>=clk_rto)
    begin
        code_clk_idx<=8'd0;
        inter_clk1<=!inter_clk1;
    end
    else
    begin
        code_clk_idx<=code_clk_idx+1;
    end
    if((pre_idx>0)||(bit_ready==1))
    begin
        if(pre_idx>=pretect_len)
        begin
            latency_idx<=0;
            pre_idx<=0;
        end
        else
        begin
            pre_idx=pre_idx+1;
            latency_idx=latency_idx+1;
        end
    end
    
    if(latency_idx==latency)            //根据cos和sin的值进行判决
    begin
        if(cossub[7]==0)
        if(sinsub[7]==0)
        bit_buffer_inter=2'b00;
        else 
        bit_buffer_inter=2'b01;
        else
        if(sinsub[7]==0)
        bit_buffer_inter=2'b10;
        else 
        bit_buffer_inter=2'b11;
    end
//    bit_clk_old<=bit_clk;

end  

并串变换


//两位码字解调结束后,串行输出比特流
always @(posedge inter_clk1) begin
    cos_mul_lpf_old <= cos_mul_lpf;
    sin_mul_lpf_old <= q;

    if(bit_ready)
    begin
        if(idx==0)
            bit_ready<=0;
        begin
        end
        idx<= idx-1;
        out_reg <= bit_buffer_out[idx];
        
        
    end

    
end



本文系统中解调模块无须比特始终,只需qpsk信号进行输入,其中配备了位同步模块

    //位同步模块,通过捕捉相位差信息在码字来临时的变化,提取码元同步信息
bit_sync my_sync(
.clk(clk),
.cos(cossub),
.sin(sinsub),
.bit_sync_pluse(qpsk_sync)
);
//位同步信息来临时,开始解调
always @(posedge qpsk_sync) begin

        if(pre_idx==0)
        begin                
            latency_idx<=0;
            bit_ready=1;    
            code_clk_idx<=0;
            inter_clk1<=0;
            bit_buffer_out <= bit_buffer_inter;
            
        end


//    end

end  

位同步模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/09/09 20:59:18
// Design Name: 
// Module Name: bit_sync
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module bit_sync(
    input wire clk,
    input wire [7:0]  cos,
    input wire [7:0] sin,
    output bit_sync_pluse
    );
    // 提取位同步的思想是当输入余弦项或正弦项持续五个时钟朝同一方向变化时,认为码元发生了变化,输出位同步信号
    wire[7:0] cosand;
    wire[7:0] sinand;
    wire[7:0] cosor;
    wire[7:0] sinor;
    wire cos_same; 
    wire sin_same;
     reg [7:0] cosold_1;
     reg [7:0] cosold_2;
     reg [7:0] cosold_3;
     reg [7:0] cosold_4; 
     reg [7:0] cosold_5;
reg [7:0] cossub1;
          
reg [7:0] cossub2;
reg [7:0] cossub3;
reg [7:0] cossub4;
reg [7:0] cossub5;
reg [7:0] sinsub1;  
reg [7:0] sinsub2;  
reg [7:0] sinsub3;  
reg [7:0] sinsub4;    
reg [7:0] sinsub5; 
          reg [7:0] sinold_1;
     reg [7:0] sinold_2;
     reg [7:0] sinold_3;
     reg [7:0] sinold_4; 
     reg [7:0] sinold_5;   
     wire cos_eq_0 ;
     wire sin_eq_0;
     assign cos_eq_0=cossub1||cossub2||cossub3||cossub4||cossub5;
     assign sin_eq_0=sinsub1||sinsub2||sinsub3||sinsub4||sinsub5;
     assign cosand = cossub1&cossub2&cossub3&cossub4&cossub5;
     assign sinand = sinsub1&sinsub2&sinsub3&sinsub4&sinsub5;
     assign cosor = cossub1|cossub2|cossub3|cossub4|cossub5;
     assign sinor = sinsub1|sinsub2|sinsub3|sinsub4|sinsub5;
     assign cos_same = cosand[7]|(!cosor[7]);
     assign sin_same = sinand[7]|(!sinor[7]);
     assign bit_sync_pluse = (cos_same|sin_same)&cos_eq_0&sin_eq_0;
  
 //对输入的正弦项或余弦项进行差分,        
    always @(posedge clk) begin
        cosold_1<=cos;
        cosold_2<=cosold_1;
        cosold_3<=cosold_2;
        cosold_4<=cosold_3;
        cosold_5<=cosold_4;
        sinold_1<=sin;
        sinold_2<=sinold_1;
        sinold_3<=sinold_2 ;       
        sinold_4<=sinold_3 ;  
        sinold_5<=sinold_4 ;   
        cossub1<=cos-cosold_1;
        cossub2<=cosold_1-cosold_2;
        cossub3<=cosold_2-cosold_3;
        cossub4<=cosold_3-cosold_4;
        cossub5<=cosold_4-cosold_5;
        sinsub1<=sin-sinold_1;
        sinsub2<=sinold_1-sinold_2;
        sinsub3<=sinold_2-sinold_3;
        sinsub4<=sinold_3-sinold_4;        
        sinsub5<=sinold_4-sinold_5;
   
        
                
    end
    
    
endmodule


解调模块接口

module qpsk_demod(

    input clk,                // 时钟信号  
    input rst_n,              // 异步复位信号,低电平有效  
//    input bit_in,             // 串行输入比特  
//    input bit_clk,            // 输入比特时钟     //取消输入   加入位同步
    
    input  wire [7:0] sin_in,  // 输入的加噪后的qpsk信号
    output  wire  out , // 输出比特流 
    output wire inter_clk_out // 输出比特流时钟  
)

4 仿真信号写入

file2 = $fopen("E:\\qpsk_src\\qpsk1\\B2.txt","w");//输出比特流
f_qpsk_in = $fopen("E:\\qpsk_src\\qpsk1\\qpsk_in.txt","w");//  qpsk调制码字
f_qpsk_out = $fopen("E:\\qpsk_src\\qpsk1\\qpsk_out.txt","w");// qpsk解调码字
f_sin = $fopen("E:\\qpsk_src\\qpsk1\\sin.txt","w");//  纯qpsk信号
f_noise = $fopen("E:\\qpsk_src\\qpsk1\\noise.txt","w");  //噪声
f_nsin = $fopen("E:\\qpsk_src\\qpsk1\\nsin.txt","w");//  加噪信号

 always @(negedge bit_out_clk) begin  
     $fwrite(file2,"%b\n",bit_out);
   	 $fwrite(f_qpsk_in,"%b\n",qpsk_code_out);//将o_Ifir_R的值以整数形式写入It.txt文件,并换行
   	 $fwrite(f_qpsk_out,"%b\n",qpsk_demod_out);
   	 $fwrite(f_sin,"%b\n",qpsk_signal);//将o_Ifir_R的值以整数形式写入It.txt文件,并换行
   	 $fwrite(f_noise,"%b\n",G_noise);//将o_Ifir_R的值以整数形式写入It.txt文件,并换行
   	 $fwrite(f_nsin,"%b\n",noised_signal);//将o_Ifir_R的值以整数形式写入It.txt文件,并换行
     end

5 主模块及调用

主模块接口

module main(
    input clk,                // 主时钟信号  
    input rst_n,              // 异步复位信号,低电平有效  
    input bit_in,             // 串行输入比特  
    input bit_in_clk,            // 输入比特时钟  
    input wire [7:0] noise_factor,   //噪声因子 取8'd44代表0dB   14代表0dB

    output  wire  bit_out,  //      输出比特流
    output wire [1:0] qpsk_demod_out,   //串并变化后调制前的两位qpsk码元
    output wire [1:0]qpsk_code_out,         //解调后的两位qpsk码元
    output wire bit_out_clk   ,     // 输出比特流时钟
       output  wire [7:0] sin_out,    //加噪信号
        output  wire [7:0] dds_sin,//纯qpsk信号
        output  wire [9:0] Gnoise//纯噪声

    );

testbench 调用主模块

 main main_module(
    .clk(clk),                // 时钟信号  
    .rst_n(rst_n),              // 异步复位信号,低电平有效  
    .bit_in(bit_in),             // 串行输入比特  
    .bit_in_clk (bit_in_clk),            // 输入比特时钟  
    .noise_factor(noise_factor),   //噪声因子控制信噪比取8'd44代表0dB   14代表0dB
    .bit_out(bit_out),  //  输出比特流
    .qpsk_demod_out(qpsk_demod_out), // 输出qpsk码字
//    .inter_clk_out(inter_clk_out),  //输出qpsk码字时钟
    .qpsk_code_out(qpsk_code_out),   //输入qpsk码字
    .bit_out_clk(bit_out_clk),  //输出比特时钟
    .sin_out(noised_signal), //加噪信号
    .dds_sin(qpsk_signal), //纯qpsk信号
    .Gnoise(G_noise) //噪声

    );

6 matlab 分析仿真过程

clear
 close all

% ??????  
clear; clc;  
  
% ??????  
clear; clc;  
  
% ?????  
EbN0_dB = 0:1:10; % ???????0dB?10dB  
  
% QPSK?BER??  
berQPSK = 0.5 * erfc(sqrt(10.^(EbN0_dB/10)));  
  
% 8PSK?BER??????????????????  
EsN0_dB = EbN0_dB + 10*log10(log2(8)); % ???Es/N0  
% sinPi8 = sin(pi/8)^2;  
% ber8PSK = 2/3 * qfunc(sqrt(2 * 10.^(EsN0_dB/10) * sinPi8));  
  
% ??QPSK?8PSK?BER??  
figure;  
semilogy(EbN0_dB, berQPSK, 'b-o');  
% hold on;  
% semilogy(EbN0_dB, ber8PSK, 'r-x');  
grid on;  
xlabel('Eb/N0 (dB)');  
ylabel('Bit Error Rate (BER)');  
title('BER vs. Eb/N0 for QPSK');  
legend('QPSK BER');  
  

fprintf('err rate in theory in 0dB:%f\n', berQPSK(1));

fprintf('err rate in theory in 10dB:%f\n', berQPSK(end));

bit_in = textread('A2.txt','%s');
bit_out = textread('B2.txt','%s');
code_in = textread('qpsk_in.txt','%s');%????

code_out = textread('qpsk_out.txt','%s');%????
psk8_sin = textread('sin.txt','%s');%????

Gnoise = textread('noise.txt','%s');%????
noised_sin = textread('nsin.txt','%s');%????

len = length(code_in);
cd_in = zeros(1,len);
cd_out = zeros(1,len);

sin_d =  zeros(1,len);;
n_d =  zeros(1,len);;
nsin_d =  zeros(1,len);;
blen = length(bit_out);

bi = zeros(1,blen);
bo = zeros(1,blen);
for ii = 1:len
    cd_in(ii)=b2d(code_in{ii});
    cd_out(ii)=b2d(code_out{ii});
    sin_d(ii)=b2d(psk8_sin{ii});
    n_d(ii)=b2d(Gnoise{ii});
    nsin_d(ii)=b2d(noised_sin{ii});
    
end
for ii = 1:blen
    bi(ii)=b2d(bit_in{ii});
    bo(ii)=b2d(bit_out{ii});
end
xcorr_len = 300;
a1 = cd_in(1:xcorr_len);
a2 = cd_out(1:xcorr_len);
figure(2)
stairs(a1);
hold on 
stairs(a2-5)
axis([0 xcorr_len -10 10])

title('qpsk code input/output');  
legend('input code', 'output code')

a3 = xcorr(a1,a2);
figure(3)
title('input and output corelation')
plot(a3)
[~,delay] = max(a3);
delay = xcorr_len-delay;
% delay=6;
bit_len = len-delay;
right = zeros(1,bit_len);
right2=0;
bit_right_sum = 0;
for ii = 4:bit_len
    right(ii) = cd_out(ii+delay)-cd_in(ii);
    if(right(ii)~=0)
        right2=right2+1;
    end
    

end
a1 = bi(1:xcorr_len);
a2 = bo(1:xcorr_len);
figure(2)
stairs(a1);
hold on 
stairs(a2-5)
axis([0 xcorr_len -10 10])

title('qpsk code input/output');  
legend('input code', 'output code')

a3 = xcorr(a1,a2);
figure(3)
title('input and output corelation')
plot(a3)
[~,delayb] = max(a3);
delayb = xcorr_len-delayb;
% delay=6;
bit_len = len-delayb;
right = zeros(1,bit_len);

for ii = 4:bit_len

    
    bit_right = bo(ii+delayb)-bi(ii);
    
    if(bit_right~=0)
        bit_right_sum=bit_right_sum+1;
    end
end

right3 = bit_len-right2;
err = 1-right3/bit_len;
fprintf('symbol error rate:%f\n', err);

right6 = bit_len-bit_right_sum;
berr = 1-right6/bit_len;
fprintf('bit error rate:%f\n', berr);
figure(4)
plot(sin_d)
title('pure qpsk signal')
figure(5)
plot(n_d)
title('pure guassian noise')
figure(6)
plot(nsin_d)
title('noised signal')
sig_pwr = sum(nsin_d.^2);
n_pwr = sum(n_d.^2);
snr = sig_pwr/n_pwr;
fprintf('SNR:%fdB', 10*log10(snr));

三、仿真结果

1 Vivado 仿真结果

在这里插入图片描述在这里插入图片描述

图中注意高斯噪声是窄带的,也就是每个码元周期噪声是个恒定值,码元切换时噪声变化,这符合信噪比的确切定义。

可以看到 输出比特流和输入比特流形状一致,只是有延迟。QPSK解调的码字和发送的码字也一致。

2 MATLAB分析结果

在这里插入图片描述

可以看到,实际的误码率低于理论误码率。图中为10dB仿真。Vivado中设计的信噪比通过MATLAB分析也是正确的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值