ARTICLE DETAIL

资讯详情

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

AD9361与GNU Radio实战:QPSK收发链路调试与优化

AD9361与GNU Radio实战:QPSK收发链路调试与优化 1. 项目缘起与整体链路设计1.1 为什么选择 P201Pro 搭配 GNU Radio 这套组合最早动念做这条收发链路是因为手头正好有一块 P201Pro。这块板子的核心是 AD9361 射频捷变收发器覆盖 70 MHz 到 6 GHz 的频段瞬时带宽可以做到 56 MHz2 发 2 收通道用来做 QPSK 这种中等复杂度的调制解调验证绰绰有余。选它而不是更便宜的 RTL-SDR 或者 PlutoSDR理由很直接AD9361 的收发通道是真正意义上的全双工发射和接收共用同一套本振和时钟树做闭环自测的时候相位关系稳定不会出现两块独立设备之间那种频率偏移和采样时钟漂移的问题。GNU Radio 这边我用的还是 3.10 版本。选它而不是纯 C 或者 MATLAB核心考量是开发迭代速度。QPSK 链路的每个环节——星座映射、脉冲成型、匹配滤波、定时同步、载波恢复——在 GNU Radio 里都有现成的模块可以调用我可以把精力集中在参数调优和问题排查上而不是从头写一个 Gardner 定时误差检测器。当然代价是运行时的调度开销比纯 C 大但在 1 MSps 到 5 MSps 这个量级上普通 x86 主机完全扛得住。提示如果你手头是 AD9361 方案的板子务必先确认固件和 FPGA 镜像的版本匹配。我遇到过因为 FPGA 镜像太老导致采样率切换后 IQ 数据错位的情况排查了大半天才发现是镜像问题。1.2 整条链路的分层结构这条链路我把它拆成四层来看这样排查问题的时候可以快速定位是哪一层出了状况。第一层是射频前端层也就是 AD9361 内部的混频器、放大器、滤波器和 ADC/DAC。这一层的配置通过板子的驱动接口完成主要涉及采样率、本振频率、增益模式和模拟滤波器带宽。第二层是数字基带层在 FPGA 里完成数字上下变频、抽取和插值。P201Pro 的 FPGA 镜像决定了这一层的抽取因子和插值因子最终送到主机的是已经降采样到目标速率的 IQ 流。第三层是主机处理层也就是 GNU Radio 里跑的流图。这一层负责调制解调、同步、滤波和判决。第四层是分析与可视化层包括星座图、眼图、频谱图和误码率统计。这一层不是链路的功能部分但它是调试的眼睛没有这一层基本没法干活。这四层里第一层和第二层是硬件相关的配置错了后面怎么调都白搭第三层是算法相关的参数需要根据实际信号质量反复微调第四层是辅助的但工具选对了能省一半时间。1.3 阶段性目标设定我没有一上来就追求高速率或者高灵敏度而是设定了三个阶段性目标逐个击破。第一阶段的目标是打通闭环。用一根 SMA 线缆把发射口直接接到接收口衰减器加上 30 dB确认从 bit 流进去到 bit 流出来误码率在可接受范围内。这个阶段不追求性能只验证链路通畅。第二阶段的目标是优化星座和眼图。通过调整脉冲成型滤波器的滚降系数、匹配滤波器的参数、定时同步环路的增益让星座点簇尽可能收敛眼图张开度尽可能大。第三阶段的目标是加入信道损伤。在闭环里插入噪声、频偏和衰落测试链路的鲁棒性为后续的空口测试打基础。这三个阶段走下来大概花了三周左右的业余时间。下面我把每个阶段的关键细节和踩过的坑逐一展开。2. AD9361 射频前端配置与关键参数解析2.1 采样率与带宽的匹配计算AD9361 的采样率配置是整条链路的地基。这里有一个容易混淆的点AD9361 内部有两个采样率概念一个是 ADC/DAC 的采样时钟频率另一个是经过抽取/插值后送到主机的数据速率。前者决定了模拟带宽后者决定了数字基带的带宽。我的目标符号率是 500 kspsQPSK 调制每个符号 2 bit所以理论比特率是 1 Mbps。为了留出足够的余量给脉冲成型滤波器的滚降系数我选择 2 倍过采样也就是采样率设为 1 MSps。滚降系数取 0.35那么信号占用的带宽大约是 500k × (1 0.35) 675 kHz。AD9361 的模拟滤波器带宽需要覆盖这个信号带宽同时又要尽量滤掉带外噪声。我把它设在 1 MHz 左右比信号带宽略宽保证信号不被削掉同时又能抑制一部分带外干扰。具体到寄存器配置AD9361 的采样率是通过一个复杂的时钟分频链实现的。核心公式是ADC 采样率 参考时钟频率 / (分频因子链的乘积)P201Pro 板载的参考时钟通常是 40 MHz。为了得到 1 MSps 的基带速率同时让 ADC 工作在合适的过采样状态我实际配置的 ADC 采样率是 30.72 MSps然后通过 FPGA 里的抽取滤波器降到 1 MSps。抽取因子是 30.72 / 1 30.72不是整数所以实际配置中会做一些近似最终得到的实际采样率会有微小偏差这个偏差在后续的定时同步环节会被补偿掉。参数设定值说明参考时钟40 MHz板载晶振ADC 采样率30.72 MSps经过时钟分频链得到抽取因子32FPGA 内 CIC FIR 抽取基带采样率960 ksps30.72M / 32符号率480 ksps2 倍过采样滚降系数0.35根升余弦模拟带宽1 MHzRX/TX 模拟滤波器这张表里的数值是我最终稳定运行的一套配置。注意基带采样率 960 ksps 和最初设想的 1 MSps 有细微差别这是因为抽取因子必须是整数而 30.72M 除以 32 正好是 960k。这个差别对 QPSK 解调没有实质影响只要收发两端用同样的参数就行。2.2 增益模式的选择与陷阱AD9361 的增益控制有两种模式手动增益和自动增益控制。在闭环自测阶段我强烈建议用手动增益因为自动增益控制会引入额外的环路动态干扰你对链路其他环节的判断。手动增益模式下接收链路的增益由几个部分组成LNA 增益、混频器增益、TIA 增益和 ADC 前的 PGA 增益。这些增益不是随便设的需要根据输入信号功率来算。我的闭环测试中发射端输出功率大约 -10 dBm经过 30 dB 衰减器后到达接收端是 -40 dBm。AD9361 的 ADC 满量程大约是 1V 峰峰值对应 50 欧姆负载上的功率大约是 10 dBm 左右。所以从 -40 dBm 到 10 dBm需要大约 50 dB 的增益。这 50 dB 的增益分配是有讲究的。LNA 增益放在最前面对噪声系数影响最大但增益太高会导致后级饱和。我的经验是 LNA 给 20 dB 左右混频器和 TIA 给 20 dBPGA 给 10 dB。这样分配下来噪声系数和线性度比较平衡。注意AD9361 的增益表不是线性的每个增益档位对应的实际增益值需要查芯片手册里的增益表。我一开始按线性去估算结果实际增益比预期高了 6 dB导致 ADC 饱和星座图完全糊成一团。2.3 滤波器设置的实操要点AD9361 的滤波器设置是很多人容易忽略但又极其关键的一环。芯片内部有三级滤波器TIA 低通滤波器、BBP基带低通滤波器和 ADC 前的抗混叠滤波器。这三级的带宽需要逐级配合不能随便设。TIA 低通滤波器的带宽应该设得比信号带宽宽一些我一般设成信号带宽的 1.5 到 2 倍。BBP 低通滤波器的带宽可以设得紧一些接近信号带宽用来做主要的带外抑制。ADC 抗混叠滤波器的带宽由采样率决定通常是采样率的 0.4 到 0.45 倍。具体到我的配置信号带宽 675 kHzTIA 滤波器设 1.2 MHzBBP 滤波器设 800 kHzADC 抗混叠滤波器在 30.72 MSps 采样率下自动设为约 13 MHz。这个配置实测下来带外抑制足够信号带内平坦度也在 1 dB 以内。如果你手头有 AD9361 的滤波器设置工具可以直接输入采样率和信号带宽它会自动算出各级滤波器的系数。但要注意工具算出来的系数是理想值实际板子上的时钟抖动和寄生电容会导致频率响应有偏差最好用扫频信号实测一下滤波器的实际带宽。3. GNU Radio 流图搭建与 QPSK 调制解调实现3.1 发射链路从 bit 流到基带 IQ发射链路的流图我拆成几个模块来搭。最前面是信源我用的是随机 bit 源每帧 1000 个 bit帧头插入一个 32 bit 的巴克码用于帧同步。巴克码的好处是自相关特性好接收端做滑动相关的时候峰值尖锐不容易误判。接下来是 QPSK 星座映射。GNU Radio 自带的 Constellation QPSK 模块可以直接用它把每两个 bit 映射成一个复数符号。映射规则是格雷码相邻星座点之间只差一个 bit这样在信噪比不高的时候误码率会低一些。映射完之后是脉冲成型。我用的是根升余弦滤波器滚降系数 0.35每符号 2 个采样点。根升余弦的好处是收发两端各用一个级联起来就是一个完整的升余弦响应满足奈奎斯特第一准则符号间干扰在采样时刻为零。脉冲成型之后是上变频。因为我的基带信号是零中频的直接送到 AD9361 的 DAC 就行不需要数字上变频。AD9361 内部的混频器会把零中频信号搬到射频载波上。提示GNU Radio 里的根升余弦滤波器模块有一个“ excess bandwidth ”参数就是滚降系数。还有一个“ samples per symbol ”参数必须和后续的采样率匹配。我一开始把这两个参数搞反了结果出来的星座图是一个圆环完全没法解调。3.2 接收链路同步与判决的关键环节接收链路比发射链路复杂得多因为要处理各种非理想因素。我把接收链路分成五个环节匹配滤波、定时同步、载波恢复、信道均衡和判决。匹配滤波和发射端的脉冲成型是对称的也是根升余弦参数完全一样。匹配滤波之后信号的信噪比达到最大。定时同步我用的是 Gardner 算法。这个算法的好处是不需要先验的符号定时信息而且对载波频偏不敏感。Gardner 算法的核心是一个定时误差检测器它利用相邻两个符号的采样点来估计定时误差然后通过一个环路滤波器去调整采样时刻。环路滤波器的带宽需要仔细调太宽了会引入噪声太窄了收敛速度慢。我一般设在符号率的 0.5% 到 1% 左右。载波恢复我用的是 Costas 环。QPSK 的 Costas 环有一个四象限的鉴相器它把接收信号和本地振荡器的相位差提取出来然后通过环路滤波器去调整本地振荡器的频率和相位。Costas 环的环路带宽也需要调我一般设在符号率的 0.1% 到 0.5% 左右。信道均衡这一步在闭环测试里其实可以省略因为闭环信道是理想的。但为了后续的空口测试我还是加了一个简单的 LMS 均衡器抽头数设了 8 个步长设了 0.01。实测下来在闭环里均衡器几乎不起作用但在加入多径之后效果明显。判决就是找离接收符号最近的星座点然后输出对应的 bit。GNU Radio 的 Constellation Decoder 模块可以直接做这件事。3.3 流图的采样率匹配与缓冲区设置GNU Radio 的流图里每个模块的输入输出采样率必须匹配否则会报错或者数据错乱。我的流图里发射端从 bit 源到星座映射是 1 倍采样从星座映射到脉冲成型是 2 倍过采样从脉冲成型到 SDR sink 是 2 倍采样。接收端从 SDR source 出来是 2 倍采样经过匹配滤波还是 2 倍采样经过定时同步降到 1 倍采样然后送到载波恢复和判决。采样率的匹配靠的是模块内部的插值和抽取。GNU Radio 会自动处理这些但你需要确保每个模块的“ samples per symbol ”参数设对了。缓冲区设置是另一个容易忽略的点。GNU Radio 的默认缓冲区大小是 8192 个样本在高采样率下这个值可能太小导致频繁的缓冲区切换和 CPU 占用率飙升。我一般把缓冲区调到 32768 或者 65536实测下来 CPU 占用率能降 20% 左右。模块输入采样率输出采样率关键参数bit 源-1 bit/样本帧长 1000星座映射1 bit/样本0.5 符号/样本QPSK 格雷码脉冲成型0.5 符号/样本2 样本/符号滚降 0.35SDR sink2 样本/符号-960 kspsSDR source-2 样本/符号960 ksps匹配滤波2 样本/符号2 样本/符号滚降 0.35定时同步2 样本/符号1 样本/符号Gardner载波恢复1 样本/符号1 样本/符号Costas判决1 样本/符号1 bit/样本最近星座点4. 星座图与眼图的调试实录4.1 星座点簇收敛的四个阶段星座图是 QPSK 调试中最直观的工具。我把星座图的收敛过程分成四个阶段每个阶段对应不同的链路状态。第一个阶段是完全散开。星座点像一团雾四个象限分不清。这个阶段通常是射频前端配置错了比如增益太低导致信噪比不够或者本振频率偏了导致星座图旋转。第二个阶段是四个模糊的团。能看出四个象限但每个团很大点很散。这个阶段通常是定时同步没收敛或者匹配滤波器的参数不对。第三个阶段是四个收敛的团。每个团明显收紧了但团与团之间还有重叠。这个阶段通常是载波恢复的环路带宽太宽引入了额外的相位噪声。第四个阶段是四个清晰的点簇。每个团收得很紧团与团之间完全分开。这个阶段说明整条链路都调好了。我实测下来从第一阶段到第四阶段主要调了三个参数定时同步的环路带宽、载波恢复的环路带宽、以及 AD9361 的增益分配。其中影响最大的是增益分配增益不对的话后面怎么调都白搭。4.2 眼图张开度与符号间干扰眼图是另一个重要的调试工具。QPSK 的眼图有两路I 路和 Q 路各一个。眼图的张开度直接反映了符号间干扰的大小。理想情况下眼图的张开度应该等于信号幅度的两倍。实际中由于脉冲成型滤波器的滚降系数不是零眼图的张开度会略小一些。滚降系数越小频带利用率越高但眼图张开度越小对定时误差越敏感。这是一个权衡。我试过滚降系数从 0.2 到 0.5 的几个值。0.2 的时候频带利用率最高但眼图几乎闭合定时同步稍微偏一点就误码。0.5 的时候眼图张开得很好但占用的带宽多了 30%。最后我选了 0.35在频带利用率和鲁棒性之间取了个平衡。注意眼图的观测需要触发同步。GNU Radio 里可以用“ Eye Diagram ”模块但它的触发是基于符号时钟的如果定时同步没收敛眼图会是一片模糊。所以调眼图之前先确保定时同步已经收敛。4.3 误码率统计与信噪比估算误码率是最终的评判标准。我在接收端加了一个误码率统计模块把发射端的 bit 流和接收端的 bit 流做对比统计误码率。闭环测试中我实测的误码率在 10^-5 到 10^-6 之间。这个值已经相当好了因为闭环信道几乎没有噪声主要的误码来源是定时同步的残余误差和载波恢复的残余相位噪声。信噪比的估算我用的是 EVM误差矢量幅度。EVM 的定义是接收符号和理想符号之间的误差矢量的均方根值除以理想符号的幅度。EVM 越小信噪比越高。我实测的 EVM 大约在 5% 到 8% 之间对应的信噪比大约是 22 dB 到 26 dB。指标实测值说明误码率10^-5 ~ 10^-6闭环无噪声EVM5% ~ 8%对应信噪比 22~26 dB星座点簇半径约 0.1归一化幅度眼图张开度约 1.6归一化幅度5. 常见问题排查与避坑经验5.1 星座图旋转但点簇收敛这个问题我遇到过两次。星座图四个团很清晰但整体在旋转转速还不固定。第一次是因为发射端和接收端的本振频率不一致。AD9361 的收发共用同一个本振理论上不应该有频偏但如果你用的是两块独立的板子或者板子上的参考时钟有偏差就会出现这个问题。解决办法是确保收发共用同一个参考时钟或者在接收端加一个频率估计和补偿模块。第二次是因为 Costas 环的环路带宽设得太宽把噪声当成了频偏去跟踪。把环路带宽从符号率的 1% 降到 0.2% 之后旋转就消失了。5.2 星座图四个团大小不一致这个问题比较隐蔽。四个团里有一两个明显比其他的大说明 I 路和 Q 路的增益不平衡或者 ADC 的 I 路和 Q 路存在偏置。AD9361 内部有 I/Q 校准功能可以在初始化的时候自动校准增益和偏置。但如果校准没做好或者温度变化导致校准漂移就会出现这个问题。解决办法是重新跑一遍 I/Q 校准或者在 GNU Radio 里加一个 I/Q 不平衡补偿模块。我实测下来AD9361 的 I/Q 校准在开机后半小时内比较稳定时间长了会有漂移。如果做长时间测试建议每隔一小时重新校准一次。5.3 误码率突然恶化这个问题通常和缓冲区溢出有关。GNU Radio 的流图在运行时如果某个模块的处理速度跟不上采样率缓冲区就会溢出导致数据丢失。表现就是误码率突然从 10^-5 跳到 10^-2 甚至更高。排查方法是看 GNU Radio 的控制台输出有没有“ buffer overflow ”或者“ buffer underflow ”的警告。如果有说明某个模块的处理速度不够。解决办法是降低采样率或者优化流图把计算量大的模块换成更高效的实现。我遇到过一次是因为星座图的显示模块拖慢了整个流图。把星座图的刷新率从每秒 10 次降到每秒 2 次之后误码率就恢复正常了。5.4 常见问题速查表现象可能原因排查方法解决办法星座图完全散开增益太低或本振偏了检查接收功率和本振频率调整增益校准本振星座图旋转频偏或 Costas 环带宽太宽看旋转速度是否恒定共用参考时钟降低环路带宽四个团大小不一I/Q 增益不平衡检查 I/Q 校准状态重新校准加补偿模块误码率突然恶化缓冲区溢出看控制台警告降低采样率优化流图眼图闭合定时同步没收敛检查定时误差检测器输出调整环路带宽检查匹配滤波频谱有杂散时钟泄漏或谐波看频谱图上的离散峰检查时钟屏蔽加滤波器6. 后续扩展方向与个人体会6.1 从闭环到空口的跨越闭环测试跑通之后下一步自然是空口测试。空口测试和闭环最大的区别是信道不再是理想的有多径、衰落、干扰和频偏。我目前正在做的几件事一是加一个信道模拟器在 GNU Radio 里用信道模型模块模拟多径和衰落二是把发射端和接收端分开到两块板子上测试真实的频偏和时钟漂移三是加前向纠错编码提高链路的鲁棒性。前向纠错我打算用卷积码或者 LDPC 码。卷积码实现简单GNU Radio 里有现成的模块但编码增益有限。LDPC 码编码增益高但实现复杂需要自己写编解码器。我还在权衡。6.2 一些个人体会这条链路做下来我最大的体会是射频前端的配置比基带算法的调优重要得多。很多人一上来就调星座图、调环路带宽但忽略了 AD9361 的增益分配和滤波器设置。实际上如果射频前端配置对了基带算法用默认参数都能跑出不错的星座图如果射频前端配置错了基带算法怎么调都是白费劲。另一个体会是调试工具的选择很关键。GNU Radio 自带的星座图和眼图模块够用但不够好用。我后来用 Python 写了一个自定义的星座图显示工具可以实时显示 EVM 和误码率比 GNU Radio 自带的模块方便很多。如果你打算长期做 SDR 开发建议花点时间搭一套自己的调试工具链。最后不要怕慢。我一开始追求高速率把采样率设得很高结果 CPU 扛不住缓冲区频繁溢出调试起来非常痛苦。后来把采样率降到 960 ksps一切都顺畅了。速率低一点没关系先把链路调通再逐步提速。6.3 一个实用小技巧如果你也在用 AD9361 方案的板子建议在初始化之后先跑一个自环测试发射一个单音信号接收端看频谱。如果频谱干净说明射频前端配置没问题如果频谱有杂散或者谐波说明滤波器或者时钟配置有问题。这个测试只需要几分钟但能帮你排除掉一大半的射频前端问题。另外AD9361 的增益表建议打印出来贴在工位上。调试的时候经常需要查某个增益档位对应的实际增益值翻手册太慢了。我把它整理成了一个表格放在手边效率高很多。
返回列表