【FPGA、maltab】基于FPGA的SOQPSK调制解调技术的设计与实现

基于FPGA的SOQPSK调制解调技术的设计与实现

SOQPSK

一、QPSK、OQPSK、SOQPSK之间的关系

SOQPSK(Shaped Offset Quadrature Phase Shift Keying),整形偏移四相相移键控。其中,S(shaped)指的是信号的波形经过特殊设计,以优化传输性能,O(offset)表示信号的相位被偏移以改善调制方案的性能。

SOQPSK是一种基于QPSK调制方式的改进版本,通过特殊的波形设计和相位调整来改善性能。在QPSK中,将基带码元分成I、Q两路,相邻码元的最大相位差为180°,这样的相位突变在频带受限的系统中会引起信号包络的很大起伏,为了减小此相位突变,在OQPSK中,将I、Q两路在时间上错开半个码元,使之不可能同时改变,此时相邻码元的相位差的最大值为90°,从而减小了信号振幅的起伏,包络恒定,相对于传统的QPSK,它具有更好的抗多径衰落和功率放大器非线性的性能,其频谱旁瓣要低于QPSK信号的旁瓣,且有较高的功率利用率。

然而,OQPSK依旧具有90°的相位跳变,并且变化并不连续,使得OQPSK的高频滚降变慢,频带变宽。从OQPSK到SOQPSK的实现方式是通过改变附加相位中的频率成形函数,以保证相位的连续变化。在OQPSK中频率成形函数是冲激函数,对应的相位成形函数是矩形函数,因此相位不连续。若要相位成形函数连续,可采用矩形函数或升余弦函数作为频率成形函数,由此得到的相位成形函数是连续的,因而频谱较窄,频谱利用率较高。是连续相位调制(CPM)中的一种特殊调制方式,适用于功率受限且频带受限的通信信道中。

QPSK、OQPSK、SOQPSK的相位曲线

二、SOQPSK调制原理

SOQPSK作为一种特殊的CPM调制方式,区别于传统CPM的一个明显特征是,实际传输的三元符号集{ }为{-1,0,1}。

SOQPSK调制的时域表达式为:

代表一个码元的持续时间, 代表 时间内码元的能量, 代表SOQPSK时域信号的载波频率, 为相位函数, 为初始相位 。其中,

频率脉冲函数为
相位函数q(t)为频率脉冲函数的积分,即

因此,可得到相位信息

为原始输入的二进制数据 ,取值为{0,1},经过预编码

得到,取值为{0,+1,-1}。经过与编码的 ,1和-1不相邻,保证了SOQPSK相邻码元的相位变化最大为 。

matlab 仿真

根据以上SOQPSK的基本原理,对SOQPSK在基带上调制解调过程进行matlab仿真。基本参数设置如下

对随机产生的二进制码元进行turbo编码后,对其进行预编码,转化为三进制码元,并进行四倍采样,得到的采样序列如图所示

I路和Q路以及SOQPSK调制后的的基带调制波形如下


可以看出SOQPSK为恒包络信号

其相位曲线为
星座图

当采样率足够大时,该星座图为一个连续的圆,即SOQPSK相位连续;采样率为1时,SOQPSK星座图与QPSK的星座图相同。

信号频谱如下

可以看出,经过SOQPSK调制后的信号频谱较窄,频谱利用率高。

在信道内加入高斯白噪声,信噪比为20db

加入噪声后的相位曲线:

星座图

频谱

硬判决:

对加噪后的相位曲线每隔一个码元周期对其进行最小二乘拟合,得到的斜率为

以+0.5和-0.5作为判决门限,得到的判决结果为

与原二进制编码后的输入数据几乎相同

matlab 代码如下(仅仅显示核心代码)

c 复制代码
clear ;                  % 清除所有变量
close all;                  % 关闭所有窗口
clc;                        % 清屏

%% 基本参数
M=224*8;                       % 产生码元数    
Ns=4;                      % 每码元复制L次,每个码元采样次数4
Tb=1;                   % 每个比特的持续时间1
Rb=1/Tb;                    % 码元速率1
dt=Tb/Ns;                    % 采样间隔0.25
Fs=1/dt;                    % 采样间隔的倒数即采样频率4

%% 产生二进制数据 %%
M_data = 0x1:0xE0;
binStr = dec2bin(M_data);
binData = binStr - '0';
data = reshape(binData',M,1)';

%% turbo编码
encoded_data=TurboEncode(data); 

%% SOQPSK 调制
s = soqpsk_mod(encoded_data);

%% 信道
s_n=awgn(s,-20,'measured');%加入高斯白噪声20db


% 度量
L=length(DI);

%分支度量
gammaI_0 = zeros(1,length(DI));
gammaI_1 = zeros(1,length(DI));
gammaI_2 = zeros(1,length(DI));
gammaI_3 = zeros(1,length(DI));
gammaQ_0 = zeros(1,length(DI));
gammaQ_1 = zeros(1,length(DI));
gammaQ_2 = zeros(1,length(DI));
gammaQ_3 = zeros(1,length(DI));

%前向度量
%初始化前向度量
alphaI_0 = zeros(1, L+1);
alphaI_1 = zeros(1, L+1);
alphaQ_0 = zeros(1, L+1);
alphaQ_1 = zeros(1, L+1);

%前向度量的递推

%后向度量
%初始化后向度量
betaI_0 = zeros(1, L+1);
betaI_1 = zeros(1, L+1);
betaQ_0 = zeros(1, L+1);
betaQ_1 = zeros(1, L+1);

%后向度量的递推

% 计算软信息
decoded_data = [llrQ,llrI];

%Turbo译码
turbodecoded_data=lteTurboDecode(decoded_data');

% 计算误码比特数
num_errors = sum(turbodecoded_data' ~= data);

% 计算总比特数
total_bits = length(data);

% 计算误码率
BER = num_errors / total_bits

得出的误码率为零。代码是示意代码。

FPGA 实现

上文已经描述了详细的原理和matlab仿真,下一步就是用FPGA进行实现;

顶层设计

包含了完整的信源和信宿、误码率比较;

包含有加扰和解扰;

包含有soqpsk调制和解调;

包含有turbo编译码;

发射模块


接收模块


最终输出的数据和发射的数据保持一致;

顶层调制解调FPGA代码

c 复制代码
// 生成224 8Bit数据;
gen_Incremental_223 gen_Incremental_224(
    .clk        (clk        ),
    .rst        (rst        ),
    .start      (start_data ),
    .dout       (din        ),
    .dout_clk_p (           ),
    .dout_en    (din_clk_p  )
);

// turbo  编码
//  1/3Turbo Encode
Turbo_Encode_1_3(
    .clk                (clk            ),
    .rst                (rst            ),
    
    .din_dout           (din_dout       ),
    .before_sc_dat_en   (before_sc_dat_en),
    .before_sc_dat_p    (before_sc_dat_p),
    
    .dat_choose         (dat_choose     ),
    .src_din_p          (src_din_p      ),
    .all_dat_clk_p      (all_dat_clk_p  )
);

Scrambler
#( .FRAME_LENGTH(ALL_DAT-1) )     // 1792*3+12-1 = 5387
Scrambler (
    .clk(clk					),//系统时钟
    .rst(rst				    ),//系统复位,高有效
    .din(dat_choose				),//待加扰数据
    .din_p(src_din_p		    ),//待加扰数据帧头,脉冲型
    .din_en(all_dat_clk_p		),//帧同步后的使能信号,便于写入FIFO

    .dout(scr_dat				),//加扰后数据
    .dout_en(scr_en			    ),//加扰后数据使能信号
    .dout_p( 				    ) //加扰后数据帧头指示信号,脉冲型
);

// tb:判断是否完成调制
soqpsk_mod(
    .clk            (clk            ),
    .rst            (rst            ),
    .scr_dat        (scr_dat        ),
    .scr_en         (scr_en         ),
    
    .is_End_SOQPSK_Mod(is_End_SOQPSK_Mod),
    .pulses_dout_i  (pulses_dout_i),
    .pulses_dout_q  (pulses_dout_q),
    .pulses_dout_clk_p(),
    .ram_cnts_write (ram_cnts_write)
);

// 组帧
blk_mem_24_32768 blk_mem_24_32768 (
  .clka(clk),    // input wire clka
  .ena(1'b1),      // input wire ena
  .wea(1'b1),      // input wire [0 : 0] wea
  .addra(ram_cnts_write ),  // input wire [14 : 0] addra_write
  .dina({pulses_dout_i,pulses_dout_q}),    // input wire [23 : 0] dina
  
  .clkb(clk),    // input wire clkb
  .enb(1'b1),      // input wire enb
  .addrb(addrb_read),  // input wire [14 : 0] addrb_read
  .doutb({lut_dout_i,lut_dout_q})  // output wire [23 : 0] doutb
);

soqpsk_demod_gamma(
    .clk                 (clk               ),
    .rst                 (rst               ),
    .start               (is_End_SOQPSK_Mod ),
    
    .addrb_read          (addrb_read        ),
    .lut_dout_i          (lut_dout_i        ),
    .lut_dout_q          (lut_dout_q        ),
    
    .is_End_SOQPSK_gamma (is_End_SOQPSK_gamma),
    
    .gammaI_0_ram        (gammaI_0_ram      ),
    .gammaI_1_ram        (gammaI_1_ram      ),
    .gammaI_2_ram        (gammaI_2_ram      ),
    .gammaI_3_ram        (gammaI_3_ram      ),
    .gammaQ_0_ram        (gammaQ_0_ram      ),
    .gammaQ_1_ram        (gammaQ_1_ram      ),
    .gammaQ_2_ram        (gammaQ_2_ram      ),
    .gammaQ_3_ram        (gammaQ_3_ram      ), // Q28.22
    .read_gamma_addrb    (read_gamma_addrb  )

);

// 解调第四步: 前向度量
soqpsk_demod_alpha (
    .clk                 (clk                   ),
    .rst                 (rst                   ),
    .start               (is_End_SOQPSK_gamma   ),
    
    .gammaI_0_ram        (gammaI_0_ram          ),
    .gammaI_1_ram        (gammaI_1_ram          ),
    .gammaI_2_ram        (gammaI_2_ram          ),
    .gammaI_3_ram        (gammaI_3_ram          ),
    .gammaQ_0_ram        (gammaQ_0_ram          ),
    .gammaQ_1_ram        (gammaQ_1_ram          ),
    .gammaQ_2_ram        (gammaQ_2_ram          ),
    .gammaQ_3_ram        (gammaQ_3_ram          ), 
    .read_gamma_addrb    (read_gamma_addrb_forward),
    
    .is_End_SOQPSK_alpha (is_End_SOQPSK_alpha   ),
    
    .alphaI_0_ram        (alphaI_0_ram          ), 
    .alphaI_1_ram        (alphaI_1_ram          ), 
    .alphaQ_0_ram        (alphaQ_0_ram          ), 
    .alphaQ_1_ram        (alphaQ_1_ram          ),
    .read_alpha_addrb    (read_gamma_addrb_IIr  )
);

// 解调第五步: 后向度量
soqpsk_demod_beta(
    .clk                 (clk                   ),
    .rst                 (rst                   ),
    .start               (is_End_SOQPSK_alpha   ),
    
    .gammaI_0_ram        (gammaI_0_ram          ),
    .gammaI_1_ram        (gammaI_1_ram          ),
    .gammaI_2_ram        (gammaI_2_ram          ),
    .gammaI_3_ram        (gammaI_3_ram          ),
    .gammaQ_0_ram        (gammaQ_0_ram          ),
    .gammaQ_1_ram        (gammaQ_1_ram          ),
    .gammaQ_2_ram        (gammaQ_2_ram          ),
    .gammaQ_3_ram        (gammaQ_3_ram          ), 
    .read_gamma_addrb    (read_gamma_addrb_backward),
    
    .is_End_SOQPSK_beta  (is_End_SOQPSK_beta    ),
    
    .betaI_0_ram         (betaI_0_ram), 
    .betaI_1_ram         (betaI_1_ram), 
    .betaQ_0_ram         (betaQ_0_ram), 
    .betaQ_1_ram         (betaQ_1_ram),
    .read_beta_addrb     (read_gamma_addrb_IIr + 1)
);

// 解调第六步: 计算软信息
soqpsk_demod_llr(
    .clk                 (clk                   ),
    .rst                 (rst                   ),
    .start               (is_End_SOQPSK_beta    ),
    
    .gammaI_0_ram        (gammaI_0_ram),
    .gammaI_1_ram        (gammaI_1_ram),
    .gammaI_2_ram        (gammaI_2_ram),
    .gammaI_3_ram        (gammaI_3_ram),
    .gammaQ_0_ram        (gammaQ_0_ram),
    .gammaQ_1_ram        (gammaQ_1_ram),
    .gammaQ_2_ram        (gammaQ_2_ram),
    .gammaQ_3_ram        (gammaQ_3_ram), 
    .read_gamma_addrb    (read_gamma_addrb_IIr),
    
    .betaI_0_ram         (betaI_0_ram), 
    .betaI_1_ram         (betaI_1_ram), 
    .betaQ_0_ram         (betaQ_0_ram), 
    .betaQ_1_ram         (betaQ_1_ram),
    .read_beta_addrb     (),
    
    .alphaI_0_ram        (alphaI_0_ram), 
    .alphaI_1_ram        (alphaI_1_ram), 
    .alphaQ_0_ram        (alphaQ_0_ram), 
    .alphaQ_1_ram        (alphaQ_1_ram),
    .read_alpha_addrb    (),
    
    .is_End_SOQPSK_llr   (is_End_SOQPSK_llr),
    
    .llrI                (llrI          ),
    .llrQ                (llrQ          ),
    .llr_clk_p           (llr_clk_p     )
);

// 转化为串行的数据流
soqpsk_demod_2p1s 
# ( .ALL_DAT        (ALL_DAT        ),
    .ALL_DAT_PADDING(ALL_DAT_PADDING) )
soqpsk_demod_2p1s(
    .clk                 (clk),
    .rst                 (rst),
    
    .bs_cut_i            (llrI[26:19]),
    .bs_cut_q            (llrQ[26:19]),
    .dout_cut_en         (llr_clk_p),
    
    .bs_din              (bs_din),
    .bs_din_p            (bs_din_p),
    .bs_din_en           (bs_din_en)
);

/*-----------------------------------------------------------------------
    下面是进入解扰的模块
-----------------------------------------------------------------------*/    
    
Descrambler
# ( .ALL_DAT(ALL_DAT) )
Descrambler(
    .clk                 (clk       ),
    .rst                 (rst       ),
    .bs_din              (bs_din    ),
    .bs_din_p            (bs_din_p  ),
    .bs_din_en           (bs_din_en ),
    
    .soft_din            (soft_din),
    .soft_din_clk_p      (soft_din_clk_p)
);   

//准备送入Turbo 译码器
Turbo_Decode_1_3 Turbo_Decode_1_3(
    .clk(clk),
    .rst(rst),
    
    .soft_din(soft_din),
    .soft_din_clk_p(soft_din_clk_p),
    
    .dout(turbo_dout),
    .dout_clk_p(turbo_dout_clk_p)
);

// 解调第八步: turbo译码

// tb: 误码率统计
 fifo_1_8 FIFOS (
  .clk(clk            ),                      // input wire clk
  .srst(rst           ),                    // input wire srst
  .din(turbo_dout        ),                      // input wire [0 : 0] din
  .wr_en(turbo_dout_clk_p),                  // input wire wr_en
  .rd_en(  rd_en11       ),                  // input wire rd_en
  .dout( fifo_dout11     ),                    // output wire [7 : 0] dout
  .full(           ),                    // output wire full
  .empty(         ),                  // output wire empty
  .rd_data_count(rd_data_count )  // output wire [9 : 0] rd_data_count
);
相关推荐
EasyDSS3 小时前
视频监控从安装到优化的技术指南,视频汇聚系统EasyCVR智能安防系统构建之道
大数据·网络·网络协议·音视频
rufeike3 小时前
UDP协议理解
网络·网络协议·udp
江理不变情4 小时前
海思ISP调试记录
网络·接口隔离原则
程高兴4 小时前
基于Matlab的车牌识别系统
开发语言·matlab
世界尽头与你4 小时前
【安全扫描器原理】网络扫描算法
网络·安全
GKoSon4 小时前
加入RPC shell指令 温箱长时间监控
网络·网络协议·rpc
hgdlip5 小时前
关闭IP属地显示会影响账号的正常使用吗
网络·网络协议·tcp/ip·ip属地
Zz_waiting.6 小时前
网络原理 - 7(TCP - 4)
网络·网络协议·tcp/ip
RECRUITGUY6 小时前
用交换机连接两台电脑,电脑A读取/写电脑B的数据
服务器·网络·负载均衡
zheshiyangyang6 小时前
HTTP相关
网络·网络协议·http