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

news2024/11/14 13:56:08

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

  • SOQPSK
    • 一、QPSK、OQPSK、SOQPSK之间的关系
    • 二、SOQPSK调制原理
  • matlab 仿真
  • FPGA 实现
    • 顶层设计
    • 发射模块
    • 接收模块
    • 顶层调制解调FPGA代码

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 代码如下(仅仅显示核心代码)

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代码


// 生成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
);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680343.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fl studio试用版文件保存无法打开??一个方法教你免费打开!

前言 当下,各款编曲软件五花八门,而这其中最有声誉的必为FL Studio莫属 这个软件呢国人习惯叫他水果,拥有强大的录音、编曲、混音等功能,所以广受音乐圈欢迎。如今,大部分水果一旦有编曲所需,一般都要使用…

一文搞懂CPU是如何进行计算的?

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…

优秀测试的核心能力!2招高效定位分析BUG!

之所以写这一篇文章,是突然想起来曾经在测试过程中被开发嘲讽过,事情是这样的,当时发现了一个疑似前端的Bug就草草提交到了禅道,结果刚来的女前端看到了就有点生气地问我为啥不查清到底是前后端问题就直接派给她前端了&#xff0c…

React框架-Next 学习-1

创建一个 Next.js 应用,node版本要高,16.5以上 npm淘宝镜像切为https://registry.npmmirror.com npm config set registry https://registry.npmmirror.com npx create-next-applatest//安装后 使用npm run dev 启动 Next.js 是围绕着 页面(pages&am…

uac驱动之const修饰的变量和const修饰的指针

const int*p // p所指向的空间是常量 不可修改 ,但p可以修改 int*const p // p所指向的空间是可以修改 ,p不可以修改 #include <stdio.h> #include <string.h>struct usb_string {char id;const char *s; };enum {STR_ASSOC,STR_AC_IF,STR_USB_OUT_IT,STR_USB_O…

单位个人怎样向报社的报纸投稿?

作为一名单位的信息宣传员,我肩负着每月定期在媒体上投稿发表文章的重任。然而,在投稿的道路上,我经历了不少波折和挫折。 一开始,我天真地以为只要将稿件发送到报社的投稿邮箱,就能轻松完成任务。然而,现实却远比我想象的复杂。邮箱投稿的竞争异常激烈,编辑们会在众多稿件中挑…

ROS2系统与px4通信测试

参考文章&#xff1a; No communication with ROS2 using MicroXRCEAgent with px4 board ROS2官方安装及测试程序 概要 新安装的ROS2与PixHawk开发板进行通信。 操作步骤 启动示例程序&#xff0c;在&#xff5e;/ws_sensor_combined/src路径下执行&#xff1a; ros2 l…

MYSQL-9.问题排查

问题排查的思路与方向 问题排查思路 分析问题&#xff1a;根据理论知识经验分析问题&#xff0c;判断问题可能出现的位置或可能引起问题的原因&#xff0c;将目标缩小到一定范围&#xff1b;排查问题&#xff1a;基于上一步的结果&#xff0c;从引发问题的“可疑性”角度出发…

【C++ 高阶数据结构 Test】AVL ~ 二叉搜索树

文章目录 1. AVL 树概念2. AVL 树节点的定义3. AVL树的插入4. AVL树的旋转4.1 新节点插入较高左子树的左侧---左左&#xff1a;右单旋4.2 新节点插入较高右子树的右侧---右右&#xff1a;左单旋4.3 新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋4.4 新节点插…

【计算机毕业设计】springboot房地产销售管理系统的设计与实现

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低房地产公司的运营人员成本&#xff0c;实现了房地产销售的 标准化、制度化、程序化的管理&#xff0c;有效地防止了房地产销售的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、…

九游娱乐携手云达不莱梅共谋跨界新发展!

近日&#xff0c;九游娱乐正式宣布&#xff0c;成为德国著名足球俱乐部云达不莱梅俱乐部的亚洲官方合作伙伴。此次跨界合作将携手开创体育与娱乐融合的新篇章&#xff0c;不仅彰显九游娱乐在全球体育和娱乐领域的影响力&#xff0c;也为云达不莱梅俱乐部在亚洲市场带来了新的机…

js之选项卡制作实例

大家好&#xff0c;今天给大家书写选项卡实例&#xff0c;话不多说&#xff0c;直接上干货 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, in…

UVM寄存器模型——手写Ralf问题debug

寄存器模型是UVM中至关重要的一部分&#xff0c;如果没有寄存器模型&#xff0c;那么验证平台对于DUT内寄存器的访问方式将十分有限&#xff0c;对DUT运行状态的把控也会变得更为复杂。 在验证过程中&#xff0c;scoreboard或者其他验证组件经常需要了解当前时间某个寄存器的值…

c++20---std::erase----std::erase_if

问题&#xff1a;如何删除满足条件的所有元素。 erase #include <iostream> #include <algorithm> #include <vector>int main(){std::vector<int> vec{1,2,3,1,1,1,1,1};std::erase(vec,1);for(int v:vec) std::cout<<v<<" "…

详细分析Vue3中的reactive(附Demo)

目录 1. 基本知识2. 用法3. Demo 1. 基本知识 reactive 是一个函数&#xff0c;用于将一个普通的 JavaScript 对象转换为响应式对象 当对象的属性发生变化时&#xff0c;Vue 会自动追踪这些变化&#xff0c;并触发相应的更新 Vue2没有&#xff0c;而Vue3中有&#xff0c;为啥…

[AI智能摄像头]RV1126部署yolov5并加速

导出onnx模型 yolov5官方地址 git clone https://github.com/ultralytics/yolov5 利用官方命令导出python export.py --weights yolov5n.pt --include onnx 利用代码导出 import os import sys os.chdir(sys.path[0]) import onnx import torch sys.path.append(..) from m…

如何使用JMeter测试导入接口/导出接口?

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 今天上班&#xff0c;被开发问了一个问题&#xff1a;JM…

怎样恢复E盘里删了的文件夹,2024让EasyRecovery来帮你轻松恢复

使用EasyRecovery易恢复进行数据恢复非常简单。首先&#xff0c;用户需要选择需要恢复的数据类型&#xff0c;如文档、图片、视频等。然后&#xff0c;软件会对选定的存储设备进行全面扫描&#xff0c;以寻找可恢复的数据。在扫描过程中&#xff0c;用户可以预览部分已找到的文…

一周学习总结:数组与链表

学习内容&#xff1a;数组与链表、计算机网络知识 数组&#xff1a; 从数组的基础知识到相关应用 数组的基础知识&#xff1a;数组在内存中的存储、数组的相关操作&#xff08;获取与更新&#xff09;、数组的相关应用&#xff1a; 二分查找法⭐⭐⭐⭐⭐ ● 掌握左闭右闭的…

matlab使用教程(71)—控制坐标区布局

1.与位置相关的属性和函数 有几个属性和函数可用于获取和设置坐标区的大小与位置。下表摘要显示了这些属性和函数。 函数或属性描述 OuterPosition 属性 使用此属性可以查询或更改坐标区的外边界&#xff0c;包括标题、标签和边距。要更改外边界&#xff0c;请将此属性指定为…