ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

16-APSK DVB-S2发射器在BladeRF上的FPGA实现与调试

16-APSK DVB-S2发射器在BladeRF上的FPGA实现与调试 简介面向BladeRF软件无线电平台的16-APSK DVB-S2发射器完整工程专为FPGA与SDR开发者设计实现DVB-S2标准下的16-APSK高阶调制相比传统QPSK、8PSK能更高效利用带宽资源。压缩包共741个文件、5.32MB核心包括114个VHDL文件、61个Verilog文件及31个SystemVerilog源文件配合C语言驱动、Tcl脚本、QIP工程配置和MIF初始化文件覆盖从逻辑综合、仿真验证到编译下载的完整流程其中vhd与v为硬件描述源码mif存放调制映射与波形数据tcl和qip负责自动化工程构建另有编译报告、时序约束和部分PDF/Markdown文档辅助理解。已有90人学习适合正在学习硬件描述语言、希望深入理解DVB-S2调制映射与成形滤波或需要在BladeRF上快速搭建发射验证环境的工程师。解压后可获得16-APSK调制解调算法源码、BladeRF接口控制逻辑、仿真与编译脚本、配置约束文件以及演示用的比特流与ELF固件便于对照工程结构进行二次开发与调试。1. 拿到这个BladeRF的16-APSK DVB-S2发射器工程先确认自己能改什么很多做卫星通信验证的工程师手里都有BladeRF但搜遍开源SDR项目会发现DVB-S2发射器不是跑到QPSK就是只实现8PSK遇到16-APSK就开始含糊。这个标题里的“适用于BladeRF的16-APSK DVB-S2发射器”正好补上这种需求用Verilog和VHDL在FPGA内部完成从TS流加扰、BCH/LDPC编码到16-APSK符号映射再到射频发射的完整链路。拿到这样一个zip源码包你不只是需要它“能跑”更需要知道哪里改符号率、哪里改IDE、哪里改滤波器系数尤其是当你要接入自己的传输流时状态机和FIFO往往才是真正的修改主战场。下面从调制原理开始逐步拆到BladeRF板级调试。2. DVB-S2与16-APSKFPGA实现前必须权衡的链路预算与调制结构2.1 DVB-S2物理层中16-APSK的工作位置DVB-S2是第二代卫星数字广播标准物理层采用恒包络或近恒包络调制传输链路包含传输流加扰、外码BCH、内码LDPC、比特交织、符号映射、物理层组帧、脉冲成型和正交调制。16-APSK(Amplitude Phase Shift Keying)是DVB-S2规定的四种调制之一星座点分布在两个同心圆上内环4点、外环12点所以也常被写成“412 APSK”。相比8PSK16-APSK每个符号多携带1比特频谱效率更高相比32APSK它对线性功放的峰均比要求更低。实用中选择16-APSK一般对应码率从2/3到5/6的典型配置用于转发器带宽有限但SNR较高的下行或上行链路。从FPGA实现角度看16-APSK不是简单的查表映射就完事它需要和物理层帧结构一起考虑。DVB-S2一帧由一个PLHEADER90符号和可选择导频块的数据构成接收端锁帧高度依赖PLHEADER中已知的SOF和PLS码。所以实现时发射状态机必须严格按照帧节奏在数据符号和导频符号之间切换映射模块也要知道当前是数据还是导频否则接收端无法完成帧同步。2.2 Verilog和VHDL选型为什么这个工程会两头都有看到标题同时出现Verilog和VHDL最重要的原因是为了复用IP。BladeRF使用的Cyclone V FPGA来自Altera现已并入Intel官方参考设计和部分通信IP核有VHDL版本而社区里的符号映射、FIFO、状态机控制往往更习惯用Verilog写。很多已有的DVB-S2发射器例如从欧洲MMIC项目或学术代码流传出来的版本普遍用VHDL写LDPC编码器但工程顶层和BladeRF的接口部分常被改成Verilog因为Quartus平台下的Qsys、Avalon总线接口用Verilog连接更直观。这两种语言的边界并不难定。实际处理时有一个“verilog计数器”和“vhdl中常量的定义”经常混用的场景例如需要在VHDL顶层中例化Verilog脉冲成型滤波器那么信号的位宽映射必须显式写出不能靠Quartus推断。我一般推荐把控制路径状态机、帧计数、使能生成、调度器放在Verilog里把运算密集的LDPC/BCH编码器保留VHDL原封不动这样改动面最小。一个容易踩的坑是变量类型匹配VHDL的std_logic_vector与Verilog的wire/reg在无符号/有符号解释上并不天然一致。端口表中尽量统一使用logic或等宽的std_logic_vector不要使用integer穿过模块边界。2.3 链路预算参数符号率、滚降系数和DAC采样率的匹配DVB-S2规定滚降系数可选0.35、0.25和0.20发射端必须使用根升余弦(RRC)脉冲滤波器。BladeRF的DAC最高采样率取决于具体型号rx2/x40可配置Fs达到61.44 MSps但实际可用带宽受到USB3.0传输速率和板载时钟PLL的约束通常不会跑到极限。在布板级工程中FPGA内部插值倍数固定后Fs 符号率 × 插值倍数。常用的配置是采样率40MSps、符号率20Mbaud、插值因子2这时滚降系数0.25的信号带宽大约是25MHz刚好在BladeRF x40的40MHz射频带宽范围内。下面这组参数直接决定FPGA内部时钟和滤波器阶数符号率(Mbaud)DAC采样率(MSps)插值因子RRC滚降信号带宽(MHz)适用场景2.540160.353.375窄带测试54080.256.25典型链路104040.2012高吞吐信号204020.2024极限宽带从参数表可见符号率越低插值因子越高RRC滤波器在FPGA里消耗的资源也越大因为数据通路的并行抽头数乘上插值倍数。工程中要用到“verilog分频器”生成各种使能时钟但建议不要用分频后的时钟作为采样时钟而是用高倍时钟加数据有效脉冲这样时序约束会简单很多。3. 发射器核心模块用Verilog拆解加扰、FEC、16-APSK映射和脉冲成型3.1 顶层状态机与数据通路控制发射器顶层本质上是一个长流水线输入TS包为188字节经过加扰、BCH、LDPC、交织后变成固定长度的FEC帧再映射到星座符号最后插入物理层头。很多初学者把注意力放到16-APSK查表上实际最容易失控的是帧节奏状态机因为LDPC编码器是长块流水线而符号映射器需要连续符号输入两者之间必须用“生产-消费”握手信号。下面这个顶层端口片断展示了信号约定它可以在Verilog里作为整个发射器骨架module dvb_s2_tx #( parameter DATA_BITS 8, parameter FF_BITS 16 )( input wire clk, input wire rst_n, // TS流输入FIFO读侧 input wire [DATA_BITS-1:0] ts_data_in, input wire ts_valid_in, output reg ts_ready, // IQ输出到DAC或插值模块 output reg [FF_BITS-1:0] i_out, output reg [FF_BITS-1:0] q_out, output reg iq_valid, // 配置端口 input wire [1:0] modulation, input wire [2:0] code_rate ); localparam S_WAIT_TS 3d0; localparam S_SCRAMBLE 3d1; localparam S_BCH_LDPC 3d2; localparam S_MAP 3d3; localparam S_PLHEADER 3d4; localparam S_PAD 3d5; reg [2:0] state, next_state;这里的关键状态在S_SCRAMBLE和S_BCH_LDPC之间切换时要拉高ts_ready给上级FIFO继续送数据。modulation参数可以使用2b10代表16-APSK但建议在顶层通过宏定义常量例如localparam MOD_16APSK 2b10;方便和VHDL封装的LDPC编码器保持一致。3.2 16-APSK映射查表实现如何写星座点常量DVB-S2标准中16-APSK星座由外圆半径R2和内圆半径R1定义比值gamma R2/R1根据码率不同有固定推荐值。比如码率3/4时gamma约2.575/6时约2.85。映射器只需要在FIFO中读取已经交织好的比特按表查出I、Q量化值。用Verilog实现查表最简单的方式是casez或case下面代码演示了量化到12bit后的4个坐标方向完整32点可以写成function// 16-APSK映射查表输入分组后4比特输出量化IQ function [23:0] apsk16_map; input [3:0] sym; begin case (sym) 4b0000: apsk16_map {12sd0, 12sd-1870}; // 内环点 4b0001: apsk16_map {12sd1870, 12sd0}; 4b0010: apsk16_map {12sd0, 12sd1870}; 4b0011: apsk16_map {12sd-1870,12sd0}; // 外环12点根据旋转角预计算后填入常量 default: apsk16_map {12sd0, 12sd0}; endcase end endfunction wire [3:0] sym_4b; assign i_out apsk16_map(sym_4b)[23:12]; assign q_out apsk16_map(sym_4b)[11:0];这种function写法会在每次调用时生成组合逻辑没有额外寄存器。要注意常量定义用有符号数12sd避免代入16位乘法器后符号扩展错误。如果你的工程风格要求常量集中管理可以写成localparam数组但Quartus对二维数组的支持不如VHDL完整少量星座点直接写在function里可读性更好。实际中不建议把整个DVB-S2映射表全部手工计算推荐用MATLAB或Python生成Verilog常量然后嵌入到模块里。这里的坐标量化位宽需要和后面的RRC滤波器输入位宽匹配12比特量化通常已经足够过多位宽只增加DSP乘法器用量并不会明显改善EVM。3.3 异步FIFO缓冲跨时钟域的实用写法BladeRF上的数据来源常常是USB控制器写入的TS数据FPGA处理时钟与USB接口时钟不是同一个时钟源异步FIFO是绕不开的。工程里不要自己写一套亚稳态处理逻辑直接例化Quartus提供的FIFO IP核比较稳。但IP例化代码比较冗长这里给出一个可综合的同步FIFO作为缓冲层的替代方案// 异步FIFO通常由IP完成这里演示同步FIFO的写读指针逻辑 module sync_fifo #( parameter DATA_WIDTH 8, parameter DEPTH 512 )( input wire wr_clk, input wire wr_en, input wire [DATA_WIDTH-1:0] din, input wire rd_clk, input wire rd_en, output reg [DATA_WIDTH-1:0] dout ); localparam ADDR_W $clog2(DEPTH); reg [ADDR_W-1:0] wr_ptr 0, rd_ptr 0; reg [DATA_WIDTH-1:0] mem [0:DEPTH-1]; always (posedge wr_clk) begin if (wr_en) begin mem[wr_ptr] din; wr_ptr wr_ptr 1b1; end end always (posedge rd_clk) begin if (rd_en) begin dout mem[rd_ptr]; rd_ptr rd_ptr 1b1; end end assign fifo_empty (wr_ptr rd_ptr); assign fifo_full (wr_ptr - rd_ptr DEPTH); endmodule这段代码直接用于异步时钟域是不安全的它只展示指针回退和读写侧独立的写法。实际在BladeRF工程中读侧时钟由LMK62xx或板载VCXO产生写侧时钟来自USB接收FIFO两边时钟频率可能相差几个ppm到几十ppm长期运行必须用异步FIFO或DPRAM方式。FIFO深度怎么设计是有讲究的。DVB-S2的LDPC编码器是块式工作一帧FEC在输入阶段要一次性接收足够比特然后开始计算计算期间输入数据不能中断。若LDPC编码一个FEC块需要K个符号时间而输入符号率为Rs则FIFO深度至少为K * Rs / RcRc为编码码率实际再加两倍余量。在代码中可以用宏定义预留深度例如// 根据码率和FEC长度估算FIFO深度 localparam FEC_FRAME_BITS 16200; // DVB-S2普通FEC帧 localparam RATE 3; localparam FIFO_DEPTH_LOG2 $clog2((FEC_FRAME_BITS * 8 * RATE) / 2);如果代码里已经用到$clog2要注意Quartus和Vivado都支持这一系统函数但综合后的寄存器数量会呈2的幂增长不要盲目放大到10万深度。3.4 根升余弦滤波器与脉冲成型参数RRC滤波器决定了发射信号的带外辐射DVB-S2接收端会搭配相同滚降系数的匹配滤波器。FPGA实现RRC可以采用两种方式直接FIR结构和多相插值结构。对于符号率5Mbaud、DAC采样率40MSps、插值因子8的情况滤波器长度通常选择48阶到64阶每符号输出8个样点。可以用MATLAB的firrcos或rcosdesign产生系数然后导出成.coe或.mif文件。下面是一个在Quartus FIR II IP中实例化的概念性参数参数设定值说明滤波器类型Interpolating FIR每符号产生8个点抽头数49阶数48群延迟24个符号系数位宽16 bit防止通带纹波过大输入位宽14 bit常用DAC数据位宽插值倍数8与DAC采样率对应输出位宽16 bit截断后送入DAC这里要注意的是滤波器系数要按“插值因子”做多相分解Quartus的FIR II IP会自动处理但系数文件必须是按多相顺序排列的否则时域波形会出现周期重复的错误。验证方法很简单输入恒定直流观察滤波器输出是否稳定恢复为直流增益乘输入幅度。如果出现周期性抖动多半是系数索引没按多相排序。另外一个容易被忽略的是时延对齐。LDPC编码器会产生几十个周期的流水线延迟而导频符号插入模块如果只是按计数器对齐就会在帧头位置出现偏移。正确做法是在控制状态机里用使能信号而非绝对时钟计数去对齐符号边界。也就是说前端所有模块都用valid打拍后端用valid驱动状态转移不建议计数器在FEC块完成前预置到某固定值。4. 把DVB-S2发射器移植到BladeRF的最小可运行方案4.1 BladeRF的Cyclone V与Quartus工程适配BladeRF第一代x40/x115使用了Altera Cyclone V SoC系列FPGA具体型号是5CSEMA4U23C6Nx40或5CSEMC4U23C6N。Xilinx的工程移植过来需要先做pin assignment。常见的BladeRF参考设计顶层语言是VHDL因此如果你手上的原始代码是Verilog需要做顶层封装。适配步骤通常是这样新建Quartus工程器件选择Cyclone V 5CSEMA4U23C6N。将解压zip得到的.v和.vhd文件全部加入工程。若原始代码有Xilinx原语例如BUFG、DSP48E、IDDR替换为Cyclone V对应原语PLL用Altera PLL IP核DDR输入用ALTDDIO_IN。引脚约束参考Nuand官方bladerf-fpga工程的bladerf.qsf关闭不用的外设把需要发射的SMA连接器对应引脚引出。综合后生成.rbf文件。加载.rbf到BladeRF可以通过命令行工具# 加载FPGA配置到BladeRF bladeRF-cli -f bladerf_16apsk.rbf # 查看加载状态 bladeRF-cli -i关于bladeRF-cli命令-f参数指定镜像文件执行后FPGA逻辑会被重新配置。镜像文件需要注意版本BladeRF的硬件版本是2.x的话需要确认.rbf编译目标与板卡匹配否则可能出现USB枚举失败。加载成功后还要用bladeRF-cli -e firmware查看固件版本FPGA镜像和固件版本之间如果差距过大部分API功能会失效建议先升级到官方最新的稳定版本库。4.2 配置采样率和本振频率BladeRF内部有RX和TX两个通道发射链路通过XCVR芯片和AD9361类似器件实际是AD9361的变体处理IQ信号。DAC采样率和中心频率都由API配置而不是在FPGA内部硬编码。FPGA内部只做基带速率到DAC速率的插值因此你需要在跑通前先确定采样率。常见的做法是通过bladeRF-cli直接设置# 发送频率925MHz采样率40MSps发射增益30dB bladeRF-cli -e set frequency tx 925M -e set samplerate tx 40M -e set gain tx 30需要注意BladeRF的TX增益设置是相对值不是绝对功率。DAC满幅对应的射频功率约为0 dBm量级但具体值会随频率和温度漂移。在接天线或功放之前最好在射频输出端加衰减器避免过载损坏后级设备。FPGA内部16-APSK星座点如果满幅输出DAC会削峰一般发射端会加约1.5到2 dB回退。4.3 用pyBladeRF联动FPGA镜像与参数调整如果你的实验需要自动化扫描建议用Python而不是反复敲命令。下面是一个最小整合脚本它先加载FPGA镜像再设置发射参数import time import bladeRF # 打开设备 dev bladeRF.BladeRF() dev.set_frequency(TX, 925e6) dev.set_sample_rate(TX, 40e6) dev.set_gain(TX, 25) # 打开TX通道 dev.enable_module(TX, True) time.sleep(1) # 检查FPGA版本 print(dev.fpga_version) # 开始发射持续10秒后关闭 time.sleep(10) dev.enable_module(TX, False)这段代码比较粗糙bladeRF库的实际接口可能因版本而异常见会看到BladeRF()无参构造失败的情况这时需要传入设备序列号。推荐做法是先直接用bladeRF-cli -i交互确认设备可用再进入Python调试。FPGA中的iq_valid输出会直接送给BladeRF内部的数据通路。若你的Verilog发射器输出IQ是并行多路比如4路并行需要改成单路串行格式否则需要调整接口位宽匹配。BladeRF在FPGA内部使用两个各自独立的16位IQ数据寄存器顺序是先I后Q发射时由采样使能驱动。5. 最后一步用频谱仪、星座图和EVM确认16-APSK发射成功5.1 先用SignalTap抓IQ再做FPGA闭环上板之后不要立刻接频谱仪先在Quartus SignalTap II里观察i_out和q_out是否有数据流动。针对Altera Cyclone VSignalTap可以挂在顶层任意wire上但信号名千万不能被综合器优化掉Verilog中要写(* keep *)或(* preserve *)。比如(* keep *) wire [15:0] debug_i; (* keep *) wire [15:0] debug_q; assign debug_i i_out; assign debug_q q_out;SignalTap触发条件可以设为帧头标识信号拉高采样存储深度设为4096采样时钟设为DAC采样时钟的2倍以上。如果在捕获数据中看到周期性幅度跳变说明PLHEADER插入成功如果IQ轨迹为一条光滑圆环簇说明16-APSK映射正常。这里需要注意SignalTap会占用片上RAM对于已经使用了大量LDPC编码器的工程RAM可能会不够。建议保留深度1024即可用于观察一帧内的星座点数量是否足够。5.2 用回环IQ数据计算EVM验证是否真的“16-APSK”比肉眼观察更严格的做法是把BladeRF发射口的信号送入接收端或者直接抓取算法仿真IQ数据离线计算误差矢量幅度EVM。下面是一段MATLAB脚本用于计算接收星座点与理想16-APSK参考点的距离% 假设rx_symbols是解调后的复数星座点ref_symbols是16-APSK理想星座 % 先最佳匹配忽略幅度偏移和相位旋转 rx_normalized rx_symbols / sqrt(mean(abs(rx_symbols).^2)); ref_normalized ref_symbols / sqrt(mean(abs(ref_symbols).^2)); % 计算每个接收点距离最近的参考点 dist abs(rx_normalized - ref_normalized.); min_dist min(dist, [], 2); evm_rms sqrt(mean(min_dist.^2)) / sqrt(mean(abs(ref_normalized).^2)) * 100; fprintf(RMS EVM %.2f%%\n, evm_rms);如果设备完好且滤波器参数正确16-APSK在中等符号率下的EVM通常在5%到8%之间如果EVM超过12%先检查相位噪声BladeRF的内置本振在5G以下仍可能出现相位跳动。一个容易混淆的问题是DVB-S2的16-APSK星座不是标准正方形因此计算EVM时不能简单用所有理想点平均功率要分别归一化内环和外环。上面代码里用全体星点平均功率做归一化能减少整体功率缩放的影响但无法校正外环周期旋转带来的相位偏移。5.3 常见陷阱与调试顺序先检查频谱是否出现“倒锥形”——即信号带宽变宽且底部抬高这通常是RRC滤波器系数顺序反了或者插值滤波器多相分组错误。再检查星座中心是否偏移到四个象限意味着DAC直流偏置没有校准需要在BladeRF的TX增益里加入直流校正寄存器。相位噪声问题会导致星座图外环旋转模糊内环相对清晰此时回退发射功率可以减少非线性但大概率是由本振锁定环路带宽过窄造成应通过软件调整本振锁相环环路带宽。还有一个常见坑是LDPC编码器输出比特序和16-APSK映射表的输入要求不一致。DVB-S2标准里交织后的比特序是MSB在前而芯片内部FIFO读出可能默认LSB在前这时需要在映射器前加一个字节翻转模块。这个错误很难从时域波形看出来但会直接导致接收端LDPC译码失败。所以推荐的调试顺序是先单音验证RRC滤波器再观察PLHEADER相关峰再调16-APSK星座最后做LDPC误码块统计。这套路径走通后你再把发射器接到真实卫星信道模拟器或功放级联才有意义。本文还有配套的精品资源点击获取
返回列表