
看着QT GUI里的星座图从一片雪花里慢慢聚拢最后变成四个边界清晰的小点团时我才敢确认这周的软件无线电实验算是真正跑通了。这次实验用的是手头这台P201Pro一块基于AD9361方案的软件无线电开发板软件侧全部跑GNU Radio目标很朴素让一串随机bit流经过发射链路映射成QPSK符号发射、接收、解调最后在对端屏幕上看到四团干净的点簇。看起来就是教科书里的东西真正在SDR平台上走一圈坑比想象的多得多。这篇算是软件无线电实验第四期的阶段性总结核心就是“从bit流到QPSK点簇”这条链路的完整搭建过程。适合正在搭简单收发系统、或者在GNU Radio里见过一团混沌星座图的朋友参考。无论你用的是P201Pro还是其他AD9361开发板只要也是通过SoapySDR接入GNU Radio整个调试思路基本是通用的。1. 项目整体架构与设计思路1.1 为什么用 P201Pro GNU Radio 这套组合选这套组合很大程度上是图省事。P201Pro这类板子把射频前端、正交调制解调器、ADC/DAC都集成在AD9361这颗芯片里覆盖70MHz到6GHz带宽从200kHz到56MHz可调。以前做类似实验要自己搭正交混频器、滤波器和基带板现在一块板子全搞定。类似ADI官方AD-FMCOMMS5-EBZ也是同一颗AD9361方案操作逻辑和P201Pro基本一致驱动栈可以复用。GNU Radio的价值在于所有基带信号处理都变成流图里的一个个方块。你不需要先精通DSP才能做实验搭模块的过程本身就是画框图的思路。对于这种验证型实验GNU Radio的调试效率比Matlab高一大截流图里的QT GUI仪器可以直接看波形、频谱、星座图。软件定义无线电的“软件”二字在GNU Radio里体现得淋漓尽致。还有一个选型理由就是成本。为了测试QPSK收发链路去弄一套专用测试台架不现实手头这块几千块的板子加一台普通电脑就够了。这套组合非常适合学生做课程实验、工程师验证算法、或者爱好者复现通信原理。1.2 从 bit 流到 QPSK 点簇链路到底经历了什么很多人看星座图觉得玄乎其实就是把接收端解调后的IQ采样点以I为横轴、Q为纵轴画在二维平面上。整个链路可以用一条线串起来随机bit源 → QPSK符号映射 → RRC脉冲成形 → AD9361的DAC和IQ混频 → 射频发射 → 电磁波传播 → 接收端射频前端和下变频 → ADC得到数字IQ → RRC匹配滤波 → 载波同步 → 定时同步 → 星座图显示。bit流是二进制的0和1进入映射器后每两个bit被编成一个符号对应IQ平面上的一个复数点。QPSK一共四个点所以叫四相相移键控。发射时这四个点被脉冲成形滤波器处理变成适合信道传输的波形到接收端经过匹配滤波和同步恢复理想情况下采样点应当精确地落在四个理想位置上。真实系统里噪声、干扰、频偏、相位噪声都会让采样点偏离理想位置于是就成了“点簇”——每一个簇的中心基本对应一个理想星座点散开的半径反映了信道质量。这个过程中最容易忽略的点是星座图上看到的不是调制器里的理想点而是经过完整收发链路之后、尚未判决的采样值。所以它既反映了发射端的符号映射和滤波质量也反映了接收端的同步是否精确、增益是否合适、滤波是否匹配。看到四个干净的点簇说明这条链路每一环都工作正常。1.3 调试顺序先回环、再空口这次实验我坚持了一个顺序先在GNU Radio内部做数字回环再用射频电缆短接测试最后才上双天线空口。数字回环就是把发射流图里的调制后的信号直接通过虚连模块送给接收流图此时整个链路里没有射频器件、没有空中损耗、没有频偏如果星座图还是乱的那一定是基带算法或参数问题。射频电缆回环加入AD9361的发射和接收可以检查板卡本身的IQ通道、增益设置、本振配置是否正常。最后做空口加上天线和信道因素。很多人第一次做实验就迫不及待拿两根天线对打结果星座图转成一圈或者糊成毛球根本不知道问题出在哪个环节。按这个三级顺序出问题时至少能把故障范围缩小到数字域、射频前端还是空间信道。2. QPSK 映射bit 是怎么变成星座点的2.1 一个符号如何携带两个 bitQPSK的本质是用载波的四种不同相位来携带信息。在一个符号周期内载波相位可以取45度、135度、225度、315度四个值每一个相位对应一个2bit组合所以一个符号就是2bit。在复基带信号里这四个相位对应的是四个复数点相位复数表达归一化后对应bit按常见Gray映射45°1j00135°-1j01225°-1-j11315°1-j10这里I路对应复数的实部Q路对应虚部。发射端把连续的bit流每两位切一组映射成上面四个复数点之一接收端拿到采样值后比较它离哪个理想点最近再反推回bit。整个过程看起来像查一张表这张表就是星座图的定义。GNU Radio里做映射并不需要你自己写复数计算。用一个Random Source输出0到3之间的字节流然后接Chunks to Symbols模块在Symbol Table参数里填上四个复数常量比如(1j)/√2、(-1j)/√2、(-1-j)/√2、(1-j)/√2。输入字节0、1、2、3就会依次映射成对应复数符号。这个模块输出的数据流是每个符号一个采样点也就是符号率采样率。2.2 Gray映射与功率归一化上面表格之所以按00、01、11、10来排序而不是顺时针00、01、10、11是因为这是Gray码排列。相邻相位对应的bit组合只差1位。一旦某一点因为噪声被推到了相邻象限判决错误之后只会错1个bit而不是2个bit都错。在相同误码率指标下Gray映射能给链路留出更多噪声余量。星座图里四个点正好落在单位圆上功率被归一化了。为什么要除以√2因为(1j)的模是√2除以√2之后模长变成1。让四个理想点的能量都等于1方便后面接收端做幅度判决和EVM计算。如果不做归一化不同调制下的星座点能量不同比较性能和设置门限时会出现很多混乱。实际调试时容易踩一个坑GNU Radio里Constellation Object的符号表顺序和输入字节的映射关系不同版本可能不一致。以我的GNU Radio 3.10为例Chunks to Symbols按输入值0、1、2、3对应Symbol Table第0、1、2、3个元素。这个顺序一旦搞错QPSK也能工作但星座图上的四个点位会旋转映射逻辑和接收端解调对不上。所以我建议先用固定序列[0,1,2,3]循环测试看星座图是否按预期落到四个象限再换随机bit流。2.3 差分编码什么时候要什么时候可省做空口实验时接收端通常要用Costas环做载波同步而Costas环存在一个经典问题相位模糊。QPSK的Costas环锁相后恢复的相位可能是正确相位的0度、90度、180度或270度这会导致解调出来的符号整体旋转Quadrant整团歪掉。有经验的工程师会加差分编码发射端把当前bit和前一bit做异或后再映射接收端再做逆差分用相对相位来解调这样即使相位旋转了整圈也能恢复出正确数据。但差分编码会带来误码扩散一个符号解错可能导致后面连续几个符号跟着错。这次实验我没有加差分编码原因是调试目标只是观察QPSK点簇不是做严格误码率测试。只要Costas环收敛正确、星座图点簇位置正常就达到了目的。如果后续要做真实数据传输建议加上差分编码或者用帧同步头来纠正相位模糊。3. 发射链路设计GNU Radio流图的搭建与参数计算3.1 发射流图长什么样发射端的流图很直接。我为了让每一步都可观测没有用“一步到位”的Constellation Modulator模块而是把符号映射、脉冲成形、速率调整分开。核心模块链是Random Source输出0~3字节 → Chunks to SymbolsQPSK映射 → Interpolating FIR FilterRRC成形插值倍数4 → SoapySDR SinkP201Pro射频输出。Random Source要设置成Byte类型Minimum为0、Maximum为3这样可以保证它只产生4种符号索引。Chunks to Symbols的Symbol Table填上面那四个归一化复数点。RRC滤波器的抽头系数用firdes.root_raised_cosine函数生成关键参数为增益1采样率4MHz符号率1MHz滚降系数0.35过采样倍数4。插值滤波器设置Interpolation为4意思是对每个符号插值复制出4个样点并完成频谱整形。这里有一个看起来矛盾、但很重要的事项**当流图最终接的是SoapySDR Sink这种硬件设备时不要在这个流图里加Throttle模块。**Throttle只用于无硬件时的纯仿真它的作用是限制流图处理速率。接了硬件之后板卡的采样时钟才是主时钟Throttle的节奏会和硬件时钟打架轻则速率不匹配重则终端不停刷U/O提示。3.2 符号率、滚降系数和硬件采样率怎么配对这三个参数是发射链路里最需要动脑子的地方。QPSK的射频占用带宽大约是(1α)×Rs其中Rs是符号率α是滚降系数。符号率定得越高带宽越宽滚降系数定得越大频谱滚降越平缓带外衰减越快但占用带宽也越大。我这次选择符号率1Msps、α0.35算出来的占用带宽是1.35MHz。硬件采样率取4Msps过采样倍数就是sps4。为什么不用更高的sps因为sps越大数据吞吐量越大软件对实时性的要求也越高。sps4到8之间是工程上比较常见的折中。4Msps对于P201Pro来说是很宽松的配置AD9361的ADC/DAC最高采样率远高于此。符号率、过采样倍速和硬件采样率之间必须满足硬件采样率符号率×sps。最好不要在中间加一个非整数倍的重采样器否则既增加计算量又可能引入额外失真。先定符号率再考虑运放带宽再算硬件采样率这个顺序比较合理。如果后面要测试不同符号率直接改这三个参数并同步更新滤波器抽头就行。3.3 为什么脉冲成形不能省直接拿Chunks to Symbols输出的矩形符号脉冲去调制虽然星座图在理想情况下也能看但射频信号频谱的旁瓣衰减非常慢能量会泄漏到相邻频段。对带限信道来说这就是符号间干扰的直接来源。传输链路的频率选择性会把这些矩形脉冲“弄脏”接收端采样判决时前一个符号的能量会残留到后一个符号上四个点在星座图上会拉出明显拖尾。脉冲成形的思路是给每个符号一个基带成形脉冲限制其带宽同时让相邻符号在采样点上不互相干扰。收发两端都使用RRC滤波器时级联响应正好是升余弦滤波器满足Nyquist第一准则。通俗理解发射端RRC把符号“削”成合适形状接收端再配一个RRC做匹配滤波两个“削波”叠加之后在正确的采样时刻正好只留下当前符号的值前后的符号贡献是零。滚降系数α的取值很关键。α越小频谱越窄越省但对定时误差越敏感α越大频谱越宽但抗定时误差能力越强。0.35是一个常见工程值兼顾频谱效率和实现难度。如果你在频谱仪上看到的信号带宽明显窄于按公式算出来的带宽先检查发射端sps或α是不是设错了。RRC滤波器抽头怎么生成很多教程都写得含糊。GNU Radio里用firdes.root_raised_cosine。gain参数设为1sampling_freq填4MHzsymbol_rate填1MHzalpha填0.35sps也就是滤波器中的每个符号抽头数填4。生成出来会是一组浮点抽头直接给Interpolating FIR Filter用就可以了。注意发射端和接收端的RRC抽头系数必须完全一致否则级联不再是升余弦会出现额外ISI。3.4 射频端增益与中心频率设置中心频率我选了2.45GHz这个频段对于P201Pro这类AD9361方案非常成熟天线也好找。不过2.4GHz附近有WiFi信号频谱环境不算干净所以发射增益不要一开始就拉满。我的经验是先用功率增益20dB发射接收端手动增益调到30dB左右先观察有没有信号等链路调通后再逐渐调节增益看看星座图变化。AD9361的发射输出功率并不是越高越好。发射增益过高会导致信号经过放大器后产生非线性失真星座图外围点会被“压扁”或“顶到极限”点簇形状不圆润。正确做法是先用QT GUI Frequency Sink接收端看频谱确认信号出现了、带宽形状正确再关注星座图。如果频谱上信号已经很明显但星座图还是很差通常不是缺发射功率而是同步或匹配问题。4. 接收链路与点簇恢复从 IQ 采样到星座图4.1 接收端标准流图接收端和发射端相比要复杂一些多出的部分全部用于“对抗信道和硬件损伤”。我用的接收链路是SoapySDR Source → AGC → RRC匹配滤波 → Costas Loop → Symbol Synchronizer → QT GUI Constellation Sink。SoapySDR Source设置中心频率2.45GHz、采样率4MHz与发射端保持一致。AGC模块把接收到的信号幅度归一化到1附近否则发射增益或接收增益变化时星座图的缩放比例会变看起来像是点簇时大时小。RRC匹配滤波器的抽头参数和发射端完全一样。Costas Loop负责载波同步Symbol Synchronizer负责定时同步最后星座图窗口把这些恢复好的符号采样点画出来。这个流图里最难理解的是Costas Loop和Symbol Synchronizer的顺序。我把Costas放在前面Symbol Sync放在后面因为Gardner定时同步在残余频偏较大时表现会变差。先用Costas把大部分频偏纠正掉定时环路处理起来就稳得多。4.2 匹配滤波为什么必须和发射端成对很多人以为接收端滤波就是随便加个低通这是误区。发射端用了RRC成形接收端就必须也用RRC做匹配滤波两个RRC级联后才等效于升余弦。如果只用一个RRC频响是另一个RRC的前半段不会形成无ISI的Nyquist形状星座图上的点会明显散开。匹配滤波还有一层含义是“最大信噪比接收”。在加性白高斯噪声信道下接收滤波器的频率响应匹配发射信号的频谱形状时输出信噪比最大。RRC根升余弦滤波器的平方等于升余弦恰好同时满足匹配滤波和零ISI两个要求。我最初调试时就吃了一次亏发射端α设了0.35接收端随手设了0.25星座图点簇虽然没有转圈但每个点像被上了一层短毛怎么调增益都不解决。后来把接收端α改回0.35点簇立刻清晰。遇到点簇模糊先检查两边RRC参数是否一致成本几乎为零。4.3 载波同步与定时同步把旋转的星座图按停空口实验中收发两端的本振不可能完全同频接收信号会存在载波频偏。频偏的直观表现就是星座图绕着原点旋转。频偏越大旋转越快。我这次实验里两个板卡的本振频偏大概在几十到一两百赫兹符号率1Msps时看起来是缓慢旋转肉眼可见如果频偏达到几千赫兹星座图就会变成几圈同心圆环完全看不出四个点。Costas Loop在这里的核心作用是用锁相环跟踪残余频偏和相位。模块参数Order设4对应QPSK。Loop Bandwidth控制环路的噪声带宽设太大环路跟踪快但噪声大点簇会有明显的抖动设太小锁相慢甚至锁定失败。我的经验是先用2π×0.01如果发现锁定太慢再逐步放大到2π×0.02左右。定时同步解决的是采样时刻偏移问题。发射端和接收端的采样时钟来自不同晶振即使标称都是4MHz实际频率也会有微小偏差长时间运行后采样点会渐渐偏离符号最佳判决时刻。Symbol Synchronizer模块里的Gardner定时错误检测算法不需要事先知道载波相位很适合这种场景。Samples per Symbol填4Loop Bandwidth同样从2π×0.01开始调。点簇如果从清晰的四团变成“四个朦胧椭圆”大概率是定时环路没有锁定或者参数太钝。4.4 点簇质量的量化EVM星座图肉眼看着“还行”是不够的最好用EVM误差矢量幅度来量化。EVM衡量实际接收到的符号点与理想星座点之间的误差矢量归一化到理想点幅度后取百分比EVM(%) sqrt(mean(|r - s|²) / P_ref) × 100其中r是实际接收点s是最近理想星座点P_ref是理想星座点平均功率。EVM在5%到10%之间通常说明链路质量不错超过15%星座图四个点之间开始有粘连风险误码率会明显上升。GNU Radio中没有现成的EVM显示模块但你可以用Python块写一个简单的计算器把Constellation Sink的输出去算一下。我的做法是在Symbol Synchronizer后面接一个Python Block接收复数符号流对每个符号做判决计算误差矢量平方再用滑动窗口取平均值。写这个块比调整整个链路快因为你可以把EVM数值直接打印到终端。5. 调试实录那些让点簇变团的坑5.1 星座图在旋转频偏第一次上射频空口时四个点的位置明明能看到但每个时刻都在绕原点转圈转得不快像是有人用鼠标拖着星座图在转。这是典型的残余频偏。解决方案是检查Costas Loop的Order、Loop Bandwidth以及是否放对了位置。我在GNU Radio流图里加了一个Frequency Lock LoopFLL做粗频率估计再接Costas细调效果更稳定。但是如果你只是观测点簇不要求极低EVMCostas Loop也能单独完成。旋转速度很慢时说明频偏不大可以先把Costas的Loop Bandwidth稍微调大一点点让环路跟上旋转。5.2 点簇“发棉”噪声、增益和失配星座图不旋转、位置也基本正确但每个点周围糊了一大片像棉花糖。优先级比较高的排查项是接收增益。接收增益不足时信号幅度低、信噪比差EVM变大增益太高时AD9361的ADC会削波点簇的外部轮廓被“削平”甚至会看到方形的簇边界。看频谱确认信号带宽正常后从低增益往上微调找到一个让EVM最小的点。还要检查收发端RRC滚降系数是否一致、Symbol Synchronizer是否锁定。这个排查顺序百试百灵不要一开始就去改滤波器而是先排除最底层的信噪比和增益问题。5.3 只有2个点簇而不是4个这个现象让不少人怀疑人生。实际上问题通常出在映射环节Random Source输出的范围没设置好或者Chunks to Symbols的Symbol Table和输入值没对上。如果数据源只输出0和1两类值星座图自然只有两个点。先用固定序列循环0、1、2、3去测试确认四个点都在之后再检查随机源的范围。另一个可能原因是你用了Constellation Modulator模块但其内部调制的符号表不是你设的那一组。模块封装越深调试时越不透明这也是我坚持把Chunks to Symbols和Interpolating FIR Filter分开的原因。5.4 硬件欠载/过载流图节奏乱了终端刷“U”表示数据溢出也就是接收端数据处理不过来“O”表示欠载发射端送数据不够快。这两个问题通常与流图调度有关。首先检查是不是在硬件流图里加了Throttle加了就果断删掉。其次看QT GUI的刷新频率尤其QT GUI Constellation Sink和Frequency Sink同时开启时绘图消耗很大可以把FFT大小或刷新率调低。电脑性能不够时降低符号率到500ksps再试链路逻辑完全一样QPSK四个点照样能看到。5.5 我自己绕过的几个小坑第一IQ不平衡会让星座图在某个方向上被拉伸比如本应是圆的四个点变成四个椭圆。AD9361有数字校准功能最好是先用板卡自带的校准脚本跑一遍再开始实验。第二接收端如果使用了AGC不要太贪心把参考电平设得太高否则信号稍微增强就削波。第三最后一次调试时我把发射天线和接收天线靠得很近信号直接灌进接收前端星座图反而变得一团糟——接收前端饱和了。拉开几米距离后点簇恢复正常。空口实验不是功率越大越好天线近场效应和接收饱和都是真实存在的。做完这个实验之后再回头看软件无线电最大的特点就是把原来要动烙铁和示波器的射频工作变成了GNU Radio里拖拽方块和调参数。调试时我心里一直默念的一个顺序是先用频域确认信号在不在、带宽对不对再用时域看波形有没有包络分明最后才看星座图和EVM。把问题分层剥开每一条链路都按这个顺序查大多数坑都能定位到具体的环节。这次实验的心得就是不要迷信任何“一步到位”的模块不透明的东西越少出问题时越容易找到根源。如果你也卡在点簇转圈或者糊成一片的问题里按上面这个顺序走一遍大概率比自己瞎猜参数更快见效。