1. 为什么是AD9361和DPSK:一次并不"理所当然"的选型
很多人一听说DPSK,第一反应往往是"这不就是PSK加了个差分编码嘛,简单"。等真把这套东西搬到AD9361上做完整的收发链路,才会慢慢意识到,简单背后全是工程权衡。DPSK选择用一点点灵敏度和实现复杂度,换取解调端对载波相位模糊的天然免疫力;AD9361选择把射频前端做成高集成度的通用收发通道,让你把精力集中在基带算法上。这两者放到一起,恰好是低成本可靠数传里很常见的一种组合:想要快速实现一套能用的点对点通信系统,又不想在载波同步算法上投入太多研发时间。
这篇文章把整个项目从选型、调制解调实现、AD9361配置到实测排障的过程串起来讲一遍。内容围绕一个核心场景:以FPGA为基带处理器,AD9361做射频收发,实现DQPSK(差分四相相移键控)调制解调,并在此基础上补齐突发检测、AGC策略、帧结构设计等"让它真正能用"的功能。适合正在做SDR基带开发、刚接触AD9361、或者准备从仿真走向射频联调的工程师和学生参考。
1.1 DPSK真正的优势:把相位模糊踢出解调回路
先说一个很多人忽略的问题:PSK类调制的天然敌人不是噪声,而是相位模糊。
BPSK还好解,载波恢复出来只有0度和180度两种状态,反正判决边界对称。到了QPSK就麻烦了,接收端的载波恢复环路锁定之后,恢复出来的参考相位可能停在任意一个90度的整数倍上。发送端不知道接收端锁定在哪一档,接收端自己也不知道。于是会出现一种特别难受的现象:信号质量明明很好,星座点清清楚楚,但解出来的数据全部按象限整体搬移,误码率接近一半。这就是相位模糊。
差分编码的思路非常朴素:不去猜这个绝对相位具体是多少,我只关心相邻两个符号之间相对转了多少。发送端把信息编码到相位差上,接收端也拿前后两个符号的相位差来判决,载波的固定相位偏置在作差这一步直接被消掉了。
代价当然也有。差分检测等效于拿两个时刻的信号做延迟相乘,噪声电压变成了两个时刻噪声的乘积,低信噪比时误码平台会明显抬高。工程经验上,相比绝对相干解调大概要损失2到3dB的等效信噪比。但换来的是突发通信里最宝贵的"开机即收"能力,不需要十几毫秒的训练序列、不需要锁相环慢慢牵引到稳定状态,信号一到,下一个符号就能开始解调。对低速数传、无人机测控、移动车载这类链路距离和信道环境一直在变的场景,这笔账非常划算。
1.2 AD9361在这套系统里到底扮演什么角色
AD9361不是解调器,它是射频通道。
它的核心任务是把基带处理器算出来的IQ采样搬上射频发出去,再把天线收到的射频信号搬回基带IQ。接收和发射路径上集成了混频器、可编程滤波器、增益控制,以及12位的ADC和DAC,频率覆盖从几十兆到6GHz量级,带宽从窄带一路到几十兆。硬件上它把整个射频前端收敛成一片芯片,需要你决定的问题是:基带采样率多少、滤波器带宽配多少、增益用自动还是手动,以及最容易被忽略的那些校准项。
我习惯用一个比喻:AD9361是水管,DPSK信号是水管里流动的声音。水管负责把声音从一头送到另一头,但你在另一端听得清不清楚,取决于水管的材质、杂质、压力波动,也取决于说话的人吐字清不清楚。基带算法和射频通道必须联调着看,各管各的永远做不出稳定链路。
1.3 系统模块划分:哪些活归基带,哪些活归射频
我这个项目里基带用的是FPGA,因为后面还要挂扩频、前向纠错和跳频,纯软件无线电框架跑实时性不够稳。如果你只是想验证算法,用PC加软件无线电平台也完全够,差别只是接口延迟和吞吐余量。
整个收发链路按信号流分是这么几块:
- 基带发送端:比特组帧、差分编码、符号映射、根升余弦成形,输出基带IQ采样
- AD9361发射路径:数字上变频、内插滤波、DAC、模拟低通、混频到射频、功率放大
- 射频信道:天线发射、空间传播、天线接收
- AD9361接收路径:低噪声放大、混频到基带、模拟低通、ADC、数字下变频、输出基带IQ
- 基带接收端:匹配滤波、定时同步、粗频偏补偿、差分解调、符号判决、比特解帧
AD9361采用零中频架构,也就是说接收端直接把射频信号下变频到基带,中间没有高中频。这种架构的好处是简单、便宜、集成度高,坏处是IQ不平衡、本振泄漏、直流偏置这些问题会直接影响基带接收质量。这三个问题不是靠算法就能完全抹掉的,必须在射频配置和校准层面解决。后面第三章我会详细讲。
2. DQPSK调制解调实现:映射表、延迟相乘和同步
2.1 差分编码:一张映射表加一次复乘
DQPSK是对QPSK做差分,每个符号携带2比特信息,两比特组合成四种相位变化量。映射表可以有很多种变体,我用的是格雷编码形式,相邻相位状态只差1个比特,这样判决出错时大概率只引入一个比特错误,对误码性能友好。
| 输入比特 | 相位变化Δφ | 复数旋转因子 |
|---|---|---|
| 00 | 0 | 1+j0 |
| 01 | π/2 | 0+j1 |
| 11 | π | -1+j0 |
| 10 | 3π/2 | 0-j1 |
调制端的实现就是一个复乘:s[k] = s[k-1]·exp(jΔφ[k])。上一符号是复平面上的某个点,乘上一个单位幅度复数,就等于把这个点旋转了Δφ角度。初始参考相位随便给一个值就行,因为接收端只关心相对转角。
import numpy as np def dqpsk_mod(bits): # bits: 0/1序列,长度为偶数 symbols = np.zeros(len(bits) // 2, dtype=complex) phase = 0.0 mapping = {0: 0, 1: np.pi / 2, 2: np.pi, 3: 3 * np.pi / 2} for i in range(len(bits) // 2): two_bits = bits[2 * i] * 2 + bits[2 * i + 1] phase = (phase + mapping[two_bits]) % (2 * np.pi) symbols[i] = np.exp(1j * phase) return symbols这里有个容易写错的点:差分编码里的"相位变化"指的是绝对相位在复平面上的旋转角,不是直接把比特映射到某个固定星座点的坐标。很多人自测不过,根源就在这一步把差分编码和普通符号映射混在了一起。
2.2 解调策略:延迟共轭相乘比绝对恢复省心得多
接收端最直接的差分解调做法是延迟共轭相乘:
d[k] = r[k] · conj(r[k-1])
d[k]的辐角就是当前符号相对上一符号的相位差,也就是我们要的信息。实现上只需要一个延迟单元、一个共轭运算、一个复乘,FPGA里消耗的乘法器资源很少。这也是DPSK在低端硬件上特别受欢迎的原因。
和"先恢复绝对载波相位再做相干解调"的方案相比,延迟共轭相乘对固定频偏天然不敏感。只要一个符号周期内的相对相位差没有被频偏破坏,解调照样能工作。但它也有明显软肋:相邻两个时刻的噪声在相乘时不是简单叠加,而是相关相乘,信号越差,误码平台抬得越狠。所以实际链路里还是要留一个粗频偏估计模块,把残余频偏压到符号率的百分之几以内,否则星座图整体旋转会让判决边界慢慢失配。
还有一个实操小坑:延迟一个符号周期,必须在定时同步和匹配滤波完成之后做。你延迟的是符号序列,不是ADC的原始采样点。如果直接用采样点延迟一整个符号周期,而采样率又不是符号率的整数倍,误差会慢慢累积起来,最后星座图糊成一团。
2.3 让信号能判决:成形滤波、匹配滤波和定时同步
发送端加根升余弦成形,接收端再放一个根升余弦匹配滤波器。两个根升余弦串联起来构成升余弦响应,符号点上的干扰为零,满足奈奎斯特无码间串扰准则。滚降系数α越大,带外衰减越快、对定时误差越宽容,但占用带宽也越大。我习惯先在仿真里对不同α各跑一遍误码率,再结合占用带宽需求取值,一般落在0.3到0.4之间。
滚降系数和带宽的关系是工程里天天要算的一笔账。符号率Rs=1Msps,α=0.35,双边带宽就是(1+0.35)×1MHz=1.35MHz。这个数值会直接关系到AD9361接收滤波器的带宽设置,你在射频端配置的带宽必须比这个值宽一点点,但又不能宽太多,否则把带外噪声也放进来了。
差分检测对带外噪声特别敏感。延迟相乘之后,带外高频噪声会通过镜像叠加到低频段,如果前端滤波不够干净,实测误码率曲线和理论仿真差上三四分贝一点都不奇怪。
符号定时同步方面,我用的方案是早迟门。原因是FPGA实现比Gardner算法还省乘法器,性能在DPSK这种调制方式下足够用。如果你有充足的训练序列,也可以直接在FPGA里做相关峰插值来估计定时误差。这些算法都要求信号经过匹配滤波后有足够高的过采样倍数,一般每符号4个采样点起步。低于这个数,定时抖动就会开始吃掉误码性能。
3. AD9361的工程配置:从波形能出来到链路能稳住
3.1 最小可用初始化顺序:先跑通参考配置,再动单项参数
配置AD9361的顺序比参数本身更容易让人翻车。我不建议一开始就对着寄存器手册一条条改。稳妥的路径是:先按芯片原厂提供的参考驱动和默认配置把整个链路跑通,再逐步改成自己需要的参数。
为什么这么谨慎?因为AD9361内部有大量状态机互相牵扯。数字上变频/下变频的抽取率、基带接口速率、滤波器带宽、AGC攻击时间,这些参数不是独立变量。参考配置是原厂验证过的组合,先跑通,再动单项参数,出问题也好隔离排查。
初始化的大致顺序可以归纳成:SPI和复位时序 → 时钟树和接口模式 → DDC/DUC抽取倍率 → 本振频率和基带带宽 → 增益模式 → 校准 → 使能发射和接收。校准放在使能之前做是有讲究的,换了频点、改了带宽、动了增益策略之后不重新校准,校准表的内容就是废纸。
3.2 采样率、抽取率和数据率:最容易算错的一笔账
我见过太多人把射频端配置带宽和基带采样率当作一回事来填参数。实际上,从AD9361的ADC出来到基带接口,中间还隔着数字下变频和抽取滤波器,基带采样率是由ADC采样率和抽取率共同决定的,不是想当然填一个值。
举一个具体例子。符号率1Msps,滚降0.35,射频双边带宽1.35MHz。AD9361内部ADC运行在很高的采样率上,假设是61.44MHz,抽取8倍后基带采样率是7.68Msps,对应每个符号7.68个采样点;如果抽取16倍,就是3.84Msps,每符号3.84个采样点,仍然够用。这里的关键计算是:ADC采样率除以抽取率,结果必须大于等于符号率乘以过采样倍数。有的项目配置完才发现基带采样率只有符号率的2倍,定时同步算法性能大幅劣化,源头就是这笔账没算清楚。
另外一个容易出问题的地方是基带接口的数据吞吐。12比特IQ各一路、基带采样率4Msps,单通道数据率就是4M×2×12=96Mbps。CMOS并行接口跑这个速率没问题,但如果你用的是串行或LVDS模式,时序余量就要重新核算。我的习惯是把基带数据率控制在接口理论带宽的70%以内,剩下的余量留给控制命令、校准流程和调试抓数用。
3.3 增益控制:AGV参数和帧结构必须一起设计
手动增益的好处是链路行为完全可预期,适合距离基本不变的固定点对点。坏处是一旦天线环境变化,比如移动载体的姿态遮挡、远近链路切换,信号可能一下子掉到ADC噪声底附近,也可能直接把接收链路打饱和。动态应用场景还是得开自动增益控制。
AD9361的AGC支持峰值检测模式,攻击时间设短、释放时间设长是比较合理的起点。攻击时间短,面对突发信号能尽快收敛;释放时间长,遇到短暂遮挡不会立刻把增益拉飞,恢复通信更快。但要注意,AGC的动作是阶梯式的,增益切换的一瞬间,幅度和相位都会有扰动。如果帧头恰好落在增益切换点上,这一帧基本就废了。所以AGC参数从来不是孤立配置的,它必须和突发帧结构一起设计。我最后采用的帧结构细节在第四章会展开讲。
3.4 校准:IQ不平衡、本振泄漏与直流偏置
零中频射频收发器最怕的几件事,IQ幅度不平衡、IQ相位不平衡、本振泄漏和直流偏置。IQ幅度不平衡会让星座图变成椭圆,相位不平衡会让椭圆旋转,本振泄漏会在频谱中心出现一根不该有的谱线,直流偏置会在解调结果里加一个固定偏移。
解决办法不是去买更贵的器件,而是用芯片自带的校准机制。发射端做发射正交校准和本振泄漏校准,接收端做接收正交校准和直流偏置校准。ADC也有自己的校准流程。关键点是,校准必须在工作频点、工作带宽、目标增益状态下执行,换任何一个条件,校准结果就不准了。
温度漂移也值得单独提醒。实验室环境和外场长时间工作,芯片温度能差出十几度,校准参数会慢慢过期。我的做法是在系统设计里加一个定时校准任务,在通信空闲的间隙静默跑一次短校准,避免外场设备开机时间长了性能悄悄变差。
4. 实测排障记录:三个让我折腾到半夜的问题
4.1 三层回环定位法
联调第一天我就吃了大亏。当时射频自环误码率测出来是零,我差点以为整套系统一次就通了。后来把固定衰减器换掉才发现,之前那个"完美表现"纯粹是接收电平碰巧落在极佳的工作点上,稍微改变功率,误码率立刻恶化。
从那以后我养成了一个习惯:任何链路问题,先用三层回环做故障隔离。
| 回环层级 | 信号路径 | 能排查的问题 |
|---|---|---|
| 数字基带回环 | 调制输出直接接解调输入,不经过任何射频器件 | 编码映射、差分状态、定时同步逻辑 |
| 模拟IQ回环 | 发射IQ测试点短接接收IQ测试点,绕过混频和天线 | ADC/DAC、模拟滤波器、基带接口时序 |
| 射频自环 | 发射射频经衰减器接回接收射频 | 混频、本振、增益控制、射频前端整体链路 |
排查顺序永远是先数字、再IQ、最后射频。一次只引入一类硬件,别让多个变量互相干扰。哪一层出现问题,故障域就锁定在哪一层。
4.2 频谱很干净,误码率却一直下不来
有一个很典型的案例:发射频谱看着非常漂亮,带外泄漏也满足要求,可接收端误码率死活压不到1e-4以下。频谱干净只能说明发射机没问题,不能说明接收链路没问题。
这种场景的第一步是看频偏。AD9361发射和接收各自用一套锁相环,中心频率不可能绝对一致,标称10ppm的参考晶振在2.4GHz频段就对应约24kHz的偏差。对1Msps符号率来说,24kHz大约是2.4%的符号率,粗频偏估计能压住。但如果符号率降到了10ksps,24kHz就是2.4倍的符号率,星座图转得像风扇一样,延迟共轭相乘在两次旋转之后做差,误码率直接崩盘。所以低速率场景必须加基于训练序列的粗频偏估计,或者重新设计符号率和链路预算。
第二步看定时。把接收端采样点和符号点一一对齐,差分检测对定时误差没那么敏感,但匹配滤波器旁瓣会放大邻近符号干扰。我的经验是定时误差控制在0.1个符号周期以内,再宽就会有可感知的性能损失。
第三步才是看IQ不平衡补偿和校准是否过期。大多数时候,走到这一步问题早就解决了。
4.3 环路全过,两台样机互发就翻车
信号源接到AD9361接收端,链路表现良好;可两台样机互相收发,误码率就高到没法用。这种问题我在实验室里遇到不止一次,罪魁祸首多半是收发两端的参考时钟不共源。
之前手头一个低速链路,符号率只有10ksps。两边的晶振标称10ppm,2.4GHz下频偏能到24kHz,是符号率的2.4倍。我后来在帧头里加了一段已知的训练序列,接收端先把这段训练序列的相关结果做FFT,估计出残余频偏,再在前面那个延迟共轭相乘的差分解调流程里把频偏补偿掉。补偿精度不需要太高,只要把剩余频偏压到符号率的0.5%以内,差分解调就能正常工作。
另外,多径也是环路自测永远测不出来的。外场一发一收之间反射物很多,每个符号都变成前面几个符号的叠加,差分检测在这个场景下会额外放大噪声。我在接收链路里加了一个最简单的单抽头均衡器,用训练序列估计信道系数,在差分解调之前把主径的幅度和相位修正回来,多径带来的性能损失收回了大半。
4.4 AGC切换的瞬间,一帧数据直接报废
这是突发帧结构设计的问题,不是AD9361的锅。能量检测到信号到达之后,AGC从一个增益状态迁到另一个增益状态需要时间,这个过程中信号幅度一直在变,前端滤波器群延迟也在变。如果帧头恰好在AGC迁移过程中出现,相关检测的峰值会被拉平,之后整帧都完蛋。
我的解决办法是重新设计帧结构。帧头最前面放一段前导码,接收机用它做能量检测和粗略同步;紧接着是一段AGC锁定窗口,让AGC在这段时间内完成所有增益迁移;然后才是独特字,用来做精确帧同步;最后是有效数据和保护间隔。
FPGA这边配合做一件事:在检测到能量上跳沿之后,把AGC的增益状态冻结住,等整帧接收完毕再释放。这样AGC行为和接收状态机完全解耦,增益切换不再干扰判决。这个改动之后,AGC切换导致的整帧报废问题基本消失。
5. 把功能补全:从点对点DPSK到一套可交付的链路
5.1 突发检测与帧头设计
能量检测只能做粗粒度信号捕获,虚警率高,不能直接当帧同步用。精确对齐要靠独特字相关检测。我在前导里用了一段已知的伪随机序列做差分调制,接收端用滑动相关器在IQ采样流里扫描,相关峰超过门限就认为找到了帧头。
门限设置有点讲究。底噪和邻道干扰都会抬高相关值,如果把门限定得太低,虚警率会高到没法用。我的做法是先在系统空闲时统计一段噪声相关的基线电平,门限设为基线的若干倍,再留至少3dB余量。这样既不会漏检,也不会在静默状态下频繁误触发。帧结构里还应该包含一段保护间隔,防止前导太长吃掉过多有效载荷。
5.2 实测误码性能:别迷信理论值
我在2Msps符号率、DQPSK、无前向纠错、加性高斯白噪声信道下做过一组测试,达到1e-3误码率大约需要接收端等效信噪比在9dB出头。这个数值比理论差分解调的边界高了两三dB,来源包括滤波器群延迟非理想、参考时钟抖动、ADC量化噪声,以及校准残差。这些损耗属于正常范围,不需要过度焦虑。
如果加上前向纠错,同样误码率指标下需要的信噪比可以明显降下来,我之前在2Msps符号率下配了一段约束长度7的卷积码加维特比译码,达到1e-3误码率需要的信噪比从9dB左右降到了6dB附近。代价是带宽大概翻倍,时延增加几十个符号。工程上没有免费午餐,链路预算里永远是在带宽、时延和功耗之间做交换。
5.3 恒包络是DPSK被低估的工程优势
DPSK属于恒包络调制,峰均比非常低,几乎可以贴着功率放大器的饱和点附近发射。同样2Msps符号率,换成OFDM波形,峰均比动不动七八分贝,功率放大器必须回退一大截来保证线性度,实际发射功率反而低很多。DPSK省下来的功率余量,直接变成了覆盖距离和链路余量。
这带来一个附加好处:对功放线性度的要求降低,可以用更便宜的功放器件。但注意恒包络不代表频谱模板可以随便过,邻道泄漏还是要靠成形滤波和适当的功率回退来满足。我的做法是发射功率标定之后,用频谱仪测一遍占用带宽和邻道泄漏比,留足余量再固化配置。
5.4 往后扩展的方向:FEC、跳频和π/4-DQPSK
如果要继续演进这套系统,前向纠错和交织放在差分编码之前就行,两者不冲突。也可以把跳频功能加上去,AD9361的本振切换速度足够快,跳频图案可以作为帧同步的一部分。
如果希望进一步降低非线性信道下的包络跌落,可以考虑从DQPSK演进到π/4-DQPSK。它把相位跳变限制在最大135度,信号轨迹不会从原点附近穿过,对功放的非线性敏感性更低。映射表需要重新设计,但整体的调制解调框架完全不用推翻。
最后说一件让我印象很深的事。第一次把三层回环全部打通、射频自环误码率归零的时候,我心里还挺得意。后来把发射和接收之间的固定衰减器换成可调衰减器,一路扫功率,才发现低功率端性能很差、高功率端又压缩,中间那段平坦区间非常窄。也就是说,之前那个误码率归零,只是固定衰减量下的巧合。从那以后我的验收习惯就变了:链路测试不能只看一个功率点的误码率,至少要扫20dB的动态范围,把误码率随输入功率变化的曲线画出来。曲线形状对了,链路才是真的健康。这个习惯帮我躲过了好几次"假通过"的尴尬,建议你也试试。