ARTICLE DETAIL

资讯详情

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

基于P201Pro与GNU Radio的QPSK全链路SDR收发系统设计与实现

基于P201Pro与GNU Radio的QPSK全链路SDR收发系统设计与实现 1. 项目缘起与整体链路设计思路1.1 为什么选 P201Pro 加 GNU Radio 这套组合手头这个项目最初的动机很朴素想把基带里的一串 bit 真正“变成”空口上的电磁波再从另一端把它收回来中间每一个环节都能看得见、摸得着、改得动。市面上能跑 QPSK 的 SDR 平台不少但真正适合做教学级全链路验证的其实就那么几类。P201Pro 这块板子用的是 AD9361 射频捷变收发器覆盖 70MHz 到 6GHz瞬时带宽最高能到 56MHz通道是 2T2R配合 FPGA 做数字接口本质上就是一个可以完全由软件定义的射频前端。选它而不是选更便宜的 RTL-SDR核心原因是 RTL-SDR 只能收不能发做不了闭环选它而不是选更高端的 USRP是因为预算和体积摆在那里P201Pro 在性价比和便携性上更平衡。GNU Radio 这边则是整个链路的“大脑”。它把调制、滤波、同步、解调这些环节全部拆成独立的 block用流图的方式串起来。你可以把它理解成一套射频领域的乐高每个 block 干一件事block 之间用数据流连接改一个参数就能立刻看到输出变化。对于 QPSK 这种既涉及数字信号处理又涉及射频前端配置的场景GNU Radio 的可视化调试能力几乎是不可替代的。我试过用纯 Python 加 numpy 手搓整条链路光是符号同步那一段就调了整整两天换成 GNU Radio 之后同样的逻辑用现成的 Polyphase Clock Sync 加 Costas Loop半小时就跑通了。1.2 整条收发链路的模块划分整条链路我把它拆成四个大块发射侧基带处理、发射侧射频上变频、接收侧射频下变频、接收侧基带处理。发射侧基带负责把 bit 流做差分编码、星座映射、脉冲成型输出复数基带样本发射侧射频负责把基带样本通过 AD9361 的 DAC 变成模拟信号再上变频到载波频率发射出去。接收侧反过来AD9361 先把空口信号下变频到基带ADC 采样后交给 GNU Radio 做匹配滤波、定时同步、载波同步、判决最后还原出 bit 流。这个划分方式的好处是每一段都可以独立验证。比如你怀疑是射频前端的问题可以直接在 AD9361 的环回模式下测试不经过空口你怀疑是同步算法的问题可以把发射侧和接收侧基带在同一个流图里对接跳过射频。这种分段排查的思路在后面调 AD9361 寄存器的时候救了我好几次。1.3 为什么最终锁定 QPSK 而不是更高阶调制QPSK 每个符号携带 2 bit频谱效率是 BPSK 的两倍但星座点之间的欧氏距离仍然足够大对相位噪声和幅度不平衡的容忍度比 16QAM 高不少。对于第一次搭全链路的人来说QPSK 是一个“跳一跳够得着”的目标它足够复杂能让你把差分编码、格雷映射、脉冲成型、定时同步、载波同步这些环节全部走一遍但它又没有复杂到让你在星座图上一眼看不出问题出在哪。16QAM 的星座点更密一旦有轻微的 IQ 不平衡或者相位噪声星座点就会糊成一团排查起来非常痛苦。所以我的建议是先把 QPSK 跑通眼图和星座图都干净了再往上加阶数。2. 发射侧基带从 bit 到复数样本的完整实现2.1 差分编码与格雷映射的取舍QPSK 有一个经典的坑相位模糊。接收端恢复出来的载波可能和发射端差 90 度、180 度甚至 270 度导致整个星座图旋转解出来的 bit 全错。解决办法有两种一是用差分编码把信息承载在相邻符号的相位变化上而不是绝对相位上二是在接收端用独特的同步序列做绝对相位估计。我选的是差分编码因为实现简单而且不需要在帧结构里额外插入导频。具体做法是把输入的 bit 流每两个一组映射成 00、01、10、11 四个状态然后对相位做差分。格雷映射的作用是让相邻星座点之间只差一个 bit这样即使判决时偏到了相邻点也只会错一个 bit而不是两个 bit 同时错。GNU Radio 里可以用Differential Encoder这个 block 直接做参数里把 modulus 设成 4 就行。2.2 脉冲成型滤波器的参数计算基带符号如果直接送出去频谱会无限延展邻道干扰会非常严重。所以必须做脉冲成型把每个符号的能量限制在一定的带宽内。我用的是根升余弦滤波器滚降系数设成 0.35。这个值的选择有讲究滚降系数越小频谱效率越高但时域拖尾越长对定时同步的要求越高滚降系数越大频谱越宽但时域波形越干净。0.35 是一个比较折中的值既不会让带宽膨胀太多也不会让同步变得太困难。具体参数是这样算的假设符号率是 100k symbol/s每个符号 2 bit那么比特率就是 200kbps。根升余弦滤波器的带宽是符号率乘以1 加滚降系数也就是 100k 乘以 1.35等于 135kHz。在 GNU Radio 里Root Raised Cosine Filter这个 block 需要设置三个关键参数Gain 设成 1.0Sample Rate 设成符号率的整数倍比如 4 倍就是 400kSymbol Rate 设成 100kAlpha 设成 0.35Num Taps 设成 11 的奇数倍我一般用 33。注意Num Taps 必须是奇数否则滤波器的群延迟不是整数个采样点会给后续的定时同步带来额外的相位偏移。2.3 帧结构与训练序列的插入为了让接收端知道一帧从哪里开始我在每帧数据前面插入了一段训练序列。训练序列用的是 32 个符号的伪随机序列接收端用滑动相关做帧同步。这个序列的选择也有讲究自相关峰要尖锐互相关要低。我直接用 GNU Radio 里PN Sequence生成的 m 序列周期设成 31前面补一个符号凑成 32。帧结构是这样的训练序列 32 符号接着是帧头 8 符号用来标识帧类型和长度然后是有效载荷最后是 4 个符号的尾比特。整个帧长我设成 256 个符号这样一帧能带 512 个 bit 的有效载荷。训练序列和帧头都不参与差分编码接收端在同步完成后再对有效载荷做差分解码。3. 射频前端AD9361 的初始化与关键寄存器调试3.1 AD9361 初始化流程与常见卡点AD9361 这块芯片功能很强但初始化流程也比较繁琐。上电之后它需要经过一系列寄存器配置才能进入正常工作状态。整个初始化流程大致是先配置时钟和 PLL再配置收发通道的滤波器然后校准 ADC 和 DAC最后使能收发链路。我用的是 P201Pro 官方提供的初始化脚本但实际跑的时候还是遇到了几个卡点。第一个卡点是RX PLL 没有锁定。现象是读 0x247 寄存器一直返回 0x80说明 PLL 的锁定状态位没有置起来。排查下来发现是参考时钟的频率设错了。AD9361 的参考时钟可以是外部晶振也可以是内部产生的但不管哪种都要保证在 10MHz 到 80MHz 之间。我一开始把参考时钟设成了 40MHz但实际板子上的晶振是 38.4MHz导致 PLL 分频比算错自然锁不上。改成 38.4MHz 之后0x247 立刻变成了 0x00PLL 锁定正常。第二个卡点是CP OVRG HIGH 被置位。这个位在 0x247 寄存器里表示电荷泵过压。出现这个问题的原因通常是环路滤波器的参数和当前的参考时钟、VCO 频率不匹配。我的解决办法是重新计算环路滤波器的电阻和电容值。AD9361 的环路滤波器是片外元件P201Pro 板子上已经焊好了但如果你用的参考时钟和官方默认值差太多就需要换元件。我最后是把参考时钟调到和官方默认值接近的 40MHzCP OVRG 才不再置位。3.2 滤波器配置工具的使用与参数导入AD9361 的收发通道里各有一组数字滤波器包括 HB1、HB2、HB3 和 FIR 滤波器。这些滤波器的系数需要通过 SPI 写入芯片。手动算系数非常麻烦所以 ADI 官方提供了一个滤波器配置工具你输入采样率、带宽、滚降系数这些参数它自动生成系数并导出成寄存器配置脚本。我用的参数是这样的RX 采样率设成 4MHz带宽设成 2MHz滚降系数 0.35TX 采样率也设成 4MHz带宽 2MHz。工具生成的脚本里包含了一长串寄存器写入命令直接通过 GNU Radio 的IIO Device Sink或者FMComms2 Sink下发就行。这里有一个细节滤波器的使能顺序很重要必须先配 FIR 再配 HB否则会出现滤波器状态机卡死的情况。我一开始顺序搞反了结果 RX 通道一直输出全零查了半天才发现是滤波器没使能。3.3 收发通道增益与 AGC 模式选择AD9361 的收发通道都有独立的增益控制。发射侧我用手动增益设成 -10dB因为 P201Pro 的输出功率在 0dBm 左右如果增益太高近端接收会饱和。接收侧我用的是 AGC 模式但 AGC 的响应速度设得比较慢避免在帧同步的时候增益突变导致训练序列失真。AGC 的模式选择也有讲究。AD9361 支持快速 AGC、慢速 AGC 和混合 AGC。快速 AGC 适合突发信号但增益抖动大慢速 AGC 适合连续信号但遇到强干扰时恢复慢。我最后选的是慢速 AGC因为我的帧是连续发送的而且训练序列本身就有一定的幅度信息不需要 AGC 快速响应。4. 接收侧基带同步、解调与判决的完整流程4.1 匹配滤波与定时同步的实现细节接收侧第一步是匹配滤波用的滤波器和发射侧的根升余弦完全一样这样收发合起来就是一个完整的升余弦响应满足无码间干扰条件。GNU Radio 里直接用Root Raised Cosine Filter参数和发射侧保持一致。匹配滤波之后是定时同步。我用的是Polyphase Clock Sync这个 block它通过多相滤波器组估计最佳采样时刻。关键参数是 Samples per Symbol设成 4和发射侧的过采样倍数一致Loop Bandwidth 设成 0.01这个值越小同步越稳但收敛越慢。我试过 0.05收敛快但抖动大星座图上的点会散开0.01 收敛慢一点但星座点非常集中。实操心得Polyphase Clock Sync 的 Loop Bandwidth 不要设得太大尤其是当你的采样时钟和符号时钟不是同源的时候。我一开始用 0.1结果星座图一直在旋转后来降到 0.01 才稳定下来。4.2 载波同步与 Costas 环的参数整定定时同步之后是载波同步。QPSK 的载波同步通常用 Costas 环GNU Radio 里对应的是Costas Loopblock。关键参数也是 Loop Bandwidth我设成 0.005。这个值比定时同步的环路带宽还要小因为载波频偏通常比定时偏差变化更慢。Costas 环的 Order 参数要设成 4因为 QPSK 的相位误差检测需要四次方运算。这里有一个容易忽略的点Costas 环的输出是经过相位旋转的复数样本但它的相位是模糊的可能差 90 度的整数倍。所以后面还需要一个绝对相位判决或者用差分编码来消除模糊。我用的是差分编码所以 Costas 环输出直接送判决就行。4.3 星座图与眼图的判读方法星座图和眼图是调 QPSK 时最重要的两个可视化工具。星座图看的是符号判决点的分布理想情况下四个点应该集中在四个象限的中心如果点散开或者偏移说明有噪声、相位噪声或者 IQ 不平衡。眼图看的是时域波形的张开程度眼睛张得越开说明码间干扰越小定时同步越准。我调的时候遇到过星座图整体旋转 45 度的情况排查下来是 Costas 环的初始相位没有收敛。解决办法是在 Costas 环前面加一个Phase Mod做初始相位校正或者把 Costas 环的 Loop Bandwidth 调大一点让它快速收敛。眼图这边如果眼睛闭合通常是匹配滤波器的滚降系数和发射侧不一致或者定时同步的采样点偏了。5. 常见问题排查与避坑经验实录5.1 AD9361 初始化失败速查表现象可能原因排查方法解决办法0x247 读出 0x80RX PLL 未锁定检查参考时钟频率确保参考时钟在 10-80MHz 且与板子晶振一致CP OVRG HIGH 置位环路滤波器参数不匹配检查参考时钟和 VCO 频率调整参考时钟或更换环路滤波器元件RX 通道输出全零滤波器使能顺序错误检查 FIR 和 HB 的配置顺序先配 FIR 再配 HBTX 无输出DAC 未校准读校准状态寄存器重新执行 DAC 校准流程星座图旋转Costas 环未收敛观察 Costas 环输出相位增大 Loop Bandwidth 或加初始相位校正5.2 GNU Radio 流图卡死与性能优化GNU Radio 的流图在采样率较高的时候容易卡死尤其是当你的电脑 CPU 性能一般的时候。我一开始把采样率设成 10MHz结果流图跑几秒钟就卡住CPU 占用率直接飙到 100%。后来把采样率降到 4MHz同时把一些不必要的可视化 block 关掉才稳定下来。性能优化的几个技巧第一把QT GUI的刷新率调低比如从 30fps 降到 10fps第二把不需要实时显示的 block 的Update Period调大第三如果用的是 USB 接口的 SDR确保 USB 控制器是独立通道不要和其他高速设备共享。我试过把 P201Pro 插在 USB Hub 上结果采样数据经常丢包直接插在主板后置 USB 口就没事了。5.3 收发闭环测试的步骤与验证方法在正式做空口测试之前一定要先做闭环测试。闭环测试有两种方式一种是基带闭环把发射侧基带的输出直接接到接收侧基带的输入跳过射频另一种是射频闭环用一根同轴电缆把 TX 口和 RX 口直接连起来中间加一个 30dB 的衰减器。基带闭环主要验证调制解调算法是否正确如果基带闭环都跑不通那肯定是算法有问题。射频闭环主要验证 AD9361 的收发通道是否正常如果基带闭环通了但射频闭环不通那问题就在射频前端。我建议先做基带闭环再做射频闭环最后做空口测试。每一步都确认无误后再进行下一步这样排查问题的时候范围会小很多。6. 阶段性成果与后续扩展方向6.1 当前链路的性能指标目前整条链路在 4MHz 采样率、100k 符号率下的误码率在 10 的负 5 次方左右星座图四个点非常集中眼图张开度良好。发射功率在 0dBm 左右接收灵敏度在 -60dBm 左右空口距离在视距条件下能到 10 米左右。这个性能对于教学验证来说已经足够了但离实用还有距离。6.2 可以继续深挖的几个方向第一个方向是提高频谱效率把 QPSK 换成 16QAM 甚至 64QAM但这需要更精细的 IQ 不平衡校正和相位噪声抑制。第二个方向是加入信道编码比如卷积码或者 LDPC把误码率再降一两个数量级。第三个方向是做真正的双向通信现在只是单向发射接收如果要做双向需要处理收发切换的时序和冲突避免。我个人在实际操作中的体会是SDR 全链路调试最耗时的部分往往不是算法本身而是射频前端的配置和硬件接口的稳定性。算法可以用仿真快速验证但射频前端的问题必须上板子才能发现。所以我的建议是先把基带算法在仿真里跑通再上板子调射频这样能省下大量时间。另外AD9361 的寄存器手册一定要放在手边遇到问题先查寄存器状态比盲目改代码有效得多。
返回列表