☰
GNU Radio+P201Pro实现QPSK收发系统:从bit流到星座图全解析
2026/10/31 10:38:04 网站建设 项目流程

1. 阶段背景与整体思路拆解

1.1 我为什么做这套收发系统

先说点题外话。软件无线电(SDR)这块,很多人一上来就奔着频谱图去了,打开GNU Radio Companion(GRC)拖几个块,看见瀑布图动起来就觉得自己入门了。但真要把“发一串bit”和“收回来还是一串bit”这个闭环跑通,中间隔着的东西比想象中多得多。我这次用P201Pro搭配GNU Radio搭一套简单的QPSK收发系统,目的就是把“bit流怎么变成空中信号,又怎么从空中信号变回bit流”这条链路彻底走一遍,不绕开任何一块。

P201Pro是款双通道软件无线电平台,板载AD9361,频率范围从70MHz到6GHz,支持带宽一路到56MHz,实际上覆盖了绝大多数业余无线电、物联网和教学频段。对实验室和教学场景来说,这套硬件性价比很合适,配套的GNU Radio环境也比某些商业软件灵活不少。市面上常见的USRP或者PlutoSDR也能做类似事情,但P201Pro胜在接口友好、开箱可用的教程相对完整,尤其适合在学校或者个人实验桌上跑QPSK这种中低速链路。

这次的实验目标很简单:先在GNU Radio里生成随机bit流,通过QPSK调制映射成复数符号,再经过脉冲成形滤波器,送入P201Pro的发射通道;接收端从P201Pro拿回采样数据,经过定时同步、载波同步、匹配滤波、解调判决,最后把误码率数出来。听上去是教科书级的流程,但真正在实测环境里把这些串起来,会遇到直流偏置、频偏、定时误差、增益失配等一堆问题。这篇总结就是把这套完整链路拆开揉碎,记录当时怎么设计、怎么接、怎么调、怎么踩坑。

1.2 这套方案解决的核心问题

先说清楚这套系统到底解决什么。假如你只是想看QPSK的星座图,完全可以直接在GRC里用数源模拟一个信号源,再接一个星座图显示块,几秒钟就能出图。但那个图是“理论图”,不是“实测图”,里面没有真实信道的噪声、没有收发时钟不同步、没有射频前端的幅度相位失真。

我这次要解决的核心问题是:让真实的bit流走完“调制→上变频→射频发射→空间/线缆传输→射频接收→下变频→解调→判决”整个过程,并且让收端恢复出的bit和发端一致。这要求收发两端时钟同步、载波同步、符号定时同步、幅度归一化、滤波器参数一致。任何一环出问题,星座图上就会出现旋转、散斑、错位,GNURadio星座图块能非常直观地暴露这些毛病,这也是我用它做调试的主要原因。

另一个要解决的问题是P201Pro和GNU Radio之间的数据接口适配。P201Pro的默认驱动框架通常是基于UHD或者独立API的,但GNU Radio环境里往往用gr-foo或SoapySDR这类第三方接口。调通“打开设备→配置频率→配置增益→配置采样率→收发数据”这一条通路,本身就需要大概半天时间。把它固化成一篇文章,后续再做OFDM或者MIMO实验就能少走弯路。

1.3 读完这篇你能拿走什么

无论你是刚开始碰SDR的学生,还是正在做通信系统仿真的工程师,这篇笔记的价值在于:我把我踩过的坑、测试过的参数、试错的结论都写出来了。你不是拿一套“装机即好用”的demo,而是拿一套“知道为什么这么配、出问题了怎么排查”的完整思路。

如果你已经完全熟悉GNU Radio的基本操作,可以直接跳到第3章的实操流程,对着我给的参数表和流程图去复现。如果你连GRC里一个块都还没拖过,也不慌,第2章我先讲讲QPSK和GNU Radio里核心块的原理,再从发射机开始逐步搭建。

这套系统的最终效果,是在P201Pro上用线缆自环(Tx直连Rx)的情况下,Eb/N0大约12dB时误码率能压到1e-4以下,星座图四个点簇清晰可辨。空间短距离(2-3米,加20dB衰减)也能跑通,但误码率会明显抬高到5e-3量级。这个水平谈不上工程级,但作为教学和基础研究平台,足够说明问题。

2. 关于QPSK和GNU Radio,你需要知道的基础

2.1 QPSK为什么适合入门

QPSK(Quadrature Phase Shift Keying,正交相移键控)是特别适合上手的第一种数字调制方式。它的原理可以这样理解:把二进制bit两两分组,比如“00”“01”“10”“11”,每两个bit对应四种相位之一。接收端靠判断信号的相位落在哪个象限,就能还原出这两位信息。

打个比方,你站在十字路口中间,四个方向代表四种两位组合。发信人往东北扔一个球,你看到球飞过来的方向就知道对方想说什么。QPSK就是让信号载波以0度、90度、180度、270度(实际编码时通常取45度、135度、225度、315度)的相位去表示两位bit。

调制过程中,I路(同相分量)和Q路(正交分量)分别承载奇数位和偶数位的符号序列。于是输入的串行bit流通过“串并转换”变成两路并行bit,再分别映射成幅度为±1/√2的实数序列,合起来就是一个复数符号。这个复数符号在复平面上的位置,就是星座图上的一个点。

之所以说它适合入门,是因为QPSK频谱效率适中(每符号2bit),实现复杂度低,对相位噪声的敏感程度比高阶QAM低。在GNU Radio里,从QPSK起步可以自然过渡到QAM和OFDM,后续扩展性也好。

2.2 GNU Radio里与bit流、符号流相关的核心块

从bit流到点簇,GNU Radio里需要明白几个核心块的作用,这些块在你之后做任何数字调制实验都会用到。

随机源与串并映射:Random Source块可以生成均匀分布的随机bit或字节。在QPSK实验里,我一般用这个块生成0到3的随机整数,直接作为符号索引。如果你习惯从bit开始,也可以用Vector Source配合Packed to Unpacked、Unpacked to Packed做bit和字节层的拆装。

Chunks to Symbols:这是“bit/字节到复符号”的关键块。它本质上是一张查找表,把输入整数映射成对应的复数符号。我给的符号表是[1+1j, -1+1j, -1-1j, 1-1j],这对应Gray编码的QPSK映射:0→45度、1→135度、2→225度、3→315度。Gray编码的重要性在于相邻符号只差1bit,判决出错时大概率只错1个bit,对误码率友好。

脉冲成形滤波器:QPSK符号序列如果不做成形直接发,频谱旁瓣会高到干扰相邻频段。常用的方案是根升余弦滤波器(RRC)。发射端和接收端各用一50%滚降系数的RRC,合成起来就是升余弦响应,既能限带,又能把符号间干扰降到最低。

星座图显示块(Constellation Sink):这是调试的“眼睛”。它把复数符号流画在I/Q平面上。理想QPSK就是四团点,每团点对应一个发射符号。所有同步问题的直接表现,都能在星座图上看到形态变化。

2.3 P201Pro在链路里的角色

P201Pro在整套系统里承担射频前端的工作。它内部集成AD9361,发射链路和接收链路都经过这个芯片完成基带到射频的转换。GNU Radio里的基带信号(复数采样序列)通过USB或以太网接口送到P201Pro,芯片把它上变频到设定中心频率,经过功率放大从天线口发出;接收方向,射频信号经过低噪放、混频、下变频、ADC,变成基带复数采样流送回GNU Radio处理。

理解这套系统,建议把P201Pro当作“黑盒射频前端”。你不需要操心混频器的本振怎么产生、AGC怎么工作,你只需要关心三个参数:中心频率、采样率、射频增益。这三个参数不对,后面所有数字信号处理都是白搭。

注意:P201Pro用线缆自环时,两个射频口的中心频率必须设成一致,采样率也必须一致。收发采样率不一致是最常见的“星座点乱飞”原因之一。

3. 发射端设计和参数取舍

3.1 发射机整体框图

发射端的设计逻辑是:bit/符号生成、插值成形、幅度归一化、送入射频。GRC里的流程大概是:

  1. Random Source生成0~3的随机整数(符号索引),也可以理解成“原始数据symbol”。
  2. Chunks to Symbols把符号索引映射为复数星座点。
  3. 根升余弦脉冲成形滤波器进行N倍插值,输出波形样值。
  4. 经过Rational Resampler把样值速率调整到与射频采样率匹配。
  5. 连接P201Pro sink块,设置中心频率、采样率、增益。

这个流程看着简单,但每一个块都有参数要抠。

3.2 为什么符号速率和采样率要这样配

这一步是很多人第一次接触时懵掉的地方。GNU Radio里,接收链路和发射链路里的信号速率,全部以“流”为单位。你设置一个采样率,实际上定义了“射频口每秒采多少个样值”。如果基带符号速率是Rs,成形滤波器的插值倍数是sps(每个符号的样值数),那么基带样值速率就是Rs × sps。这个速率必须等于你设置给P201Pro的采样率。

我用的是Rs = 100k symbol/s,sps = 4,所以基带样值速率是400k samples/s。这把采样率设成400k,正好和P201Pro的ADC/DAC匹配。

有人会问:为什么不多插值一点?插值倍数越高,每个符号的样值数越多,理论上成形滤波更平滑,但是数据率也会直线上升。400k的采样率在AD9361支持的范围内属于很低的一档,射频前端可能会在零中频结构下出现直流偏置问题,这些后面再讲。

3.3 关于增益的设置

AD9361的发射增益是可调的。P201Pro配套的GNU Radio驱动里,发射增益参数通常以dB显示。我最开始图省事,直接拉了默认增益,结果发现接收端星座图饱和成一坨。这背后的原因是发射增益太大,功率放大器进入非线性区。

正确的做法是从低增益开始慢慢往上加,观察接收星座图的“点簇半径”。最理想的情况是点簇清晰紧凑,但不要大到削顶。我最终确定的发射增益是-10dB,接收增益是10dB。这个值和你用的天线、线缆衰减、距离都直接相关,所以别照抄,要按实际星座图反馈去调。

4. 接收端的关键处理环节

4.1 接收机整体流程

接收端比发射端复杂得多,这也是QPSK实验真正“磨人”的地方。GPENU Radio里接收链路大概是:

  1. 从P201Pro sink拿到复数基带样值流。
  2. 经过低通滤波器(用RRC作匹配滤波)。
  3. 使用Symbol Sync块或手动搭建Gardner环路做定时同步。
  4. 使用Costas Loop块做载波同步,消除残余频偏和相偏。
  5. 用Constellation Sink观察星座图。
  6. 用Constellation Decoder块判决符号。
  7. 用Char To Float、Binary Slicer等映射回bit。
  8. 与原始bit对比,统计误码率。

接收端所有环节的核心逻辑,可以归纳成两句话:先把“时”对准,再把“相”稳住。时针不准,符号判决就串位;相位不稳,星座点就旋转。

4.2 定时同步为什么会这么容易出问题

发射端和接收端的ADC/DAC虽然是同一块板子上跑的,但如果只看基带层面,两个采样时钟并非来自同一个晶振源。时钟的微小偏差会导致接收端采样点逐渐滑到符号边缘,产生“时钟漂移”。

GNU Radio里的Symbol Sync块提供了几种定时误差检测器。我用的Gardner TED在QPSK这类恒包络或接近恒包络的调制方式下表现很稳健。它的好处是不需要载波先完全同步,对前端的频偏容忍度不错。

我把Symbol Sync块里的Samples per Symbol设为4,Loop Bandwidth设成2π/100,Damping Factor保持默认0.707。这几个参数直接决定同步环路的捕捉速度和稳态抖动。带宽太窄捕捉慢,太宽则稳态抖动大。100这个量级是对100k符号速率比较合适的折中。

4.3 载波同步:Costas环路参数怎么调

GNU Radio的Costas Loop块对QPSK来说,环路滤波器参数很重要。Order设为2(对QPSK)或4(对QPSK也可以用高阶),Loop Bandwidth我设的是2π/1000。这个值意味着环路对频率偏移的修正速度偏慢,但一旦锁定,星座点抖动很小。

如果你的收发频率完全一致、且使用线缆自环,很可能不需要Costas Loop也能看到清晰星座图。但实际中P201Pro两块板卡或空间链路的晶体偏差会让频偏达到百赫兹量级,如果不加这个环路,星座图会看到四个点在绕圈旋转——旋转速度就是频偏。

调环路带宽的时候,先给小带宽(比如2π/100),看能不能锁住;锁不住再加大。别一上来给很宽的带宽,那会让星座图看起来“一陀”而不是“四点”。

4.4 接收链路里的AGC问题

我最初没有在接收链路里加AGC(自动增益控制),直接用固定增益。结果发现,发射功率稍微波动,接收星座图就会变大变小。虽然数字域里星座点的绝对值大小不影响判决相位,但在用固定阈值判决的模块里,幅度归一化是必要的。

解决方案是加一个AGC块,放在匹配滤波之后,定时同步和载波同步之前。AGC的Reference一般设为1,Max Gain设成比如6000,Attack Rate和Decay Rate设成10m。这些参数不敏感,只要别设得太极端就行。

另外,你会看到有些人建议把AGC放在Costas Loop之后,也有人建议放之前。我实际试下来,放在匹配滤波之后、同步环路之前表现最稳。原因是载波同步环路对输入幅度有一定线性范围要求,先把幅度拉回标准值,环路参数的一致性更好。

5. 搭建环境的完整实操记录

5.1 软硬件清单

我用的软硬件环境如下,列出来省得大家猜版本:

  • 硬件:P201Pro(AD9361,双通道)
  • 主机:普通x86台式机,Ubuntu 20.04 LTS
  • GNU Radio:3.8.2.0,Python 3.8
  • 配套P201Pro驱动:使用基于SoapySDR的gr-soapy模块(不同批次板卡可能自带UHD兼容层,按厂家文档来)
  • 连线:SMA线缆一根,50Ω,连接Tx和Rx通道;必要时加20dB/40dB衰减器
  • 调试工具:GRC自带星座图、FFT图、时间瀑布图

5.2 环境安装要点

P201Pro的GNU Radio环境安装,核心就是两件事:装GNU Radio和装板卡驱动。如果厂商提供了脚本,直接用脚本装;如果没有,需要自己编译SoapySDR和对应的Soapy模块。

这里的一个经验是:不要用系统自带的GNU Radio版本太旧的源。Ubuntu 20.04的apt源里GNU Radio可能是3.8,这个版本够用。但如果你从源码编译,需要留意Boost、log4cpp、gmp等依赖。我建议直接apt安装gnuradio和相关的开发包,省去编译地狱。

安装gr-soapy时,尽量用pybombs或者从源码cmake安装。如果驱动匹配不对,打开GNU Radio的Soapy P201Pro Sink块时会报“No device found”,这基本就是驱动装错了或者权限没给。

5.3 首次跑通测试的完整流程

我的建议是先把收发都用线缆接好,中间加一个20dB衰减器,避免发射信号直接把接收前端的LNA打饱和。然后在GRC里按上面说的发射链路建一个只有“Random Source→Chunks to Symbols→RRC→Rational Resampler→P201Pro Sink”的图,运行它。接收链路暂时不用建,直接用GRC里的Soapy P201Pro Source块接一个“FFT Sink”,看看能不能收到一个清晰的带限信号。

如果你在FFT图上看到一个以中心频率为中央的、类似“香肠”形状的频谱突起,说明射频链路通了。到这一步,整套系统最难的一关已经过去。接下来再逐步加同步环路和判决模块。

如果FFT上没有信号,优先排查:中心频率是否一致、发射增益是否太低、衰减器是不是太大、SMA线是否接错口(Tx要接Rx口)。这些问题占了初跑失败原因的八成以上。

5.4 工具箱里最推荐的调试组合

我强烈推荐发射端加一个额外的“循环发送测试符号”设计:用Vector Source发射一段固定的已知序列,比如[0,1,2,3,0,1,2,3...],接收端就很容易对照星座图判断判决是否正确。随机源适合测误码率,但调试时用固定序列更直观。

另外,接收端图里建议同时放三个显示块:时间波形图看波形包络、FFT Sink看频谱、Constellation Sink看星座点。三个图一起看,能快速定位问题是出在频域、时域还是同步环路上。这也是我在实际调机时最常用的“三板斧”。

6. 常见问题与排查技巧实录

6.1 星座图出现旋转

现象:四个星座点不是静止的,而是绕原点旋转。

原因:接收信号和接收端本振之间存在残余频偏,Costas Loop带宽太窄,无法快速消除频偏。

处理步骤:

  1. 把Costas Loop带宽从2π/1000逐步加大到2π/100,观察旋转是否变慢甚至停下。
  2. 如果旋转停下来但星座点混沌,可能是定时同步还没锁好,加大Symbol Sync带宽试试。
  3. 如果加了带宽还不停,考虑硬件的实际中心频率漂移,用Frequency Xlating FIR Filter做一个粗略的频偏粗校正,再进Costas环路细调。

6.2 星座点“拖尾”成弧形

现象:星座图不是四团点,而像是四段弧线。

原因:这通常是脉冲成形和匹配滤波没配对,或者定时误差过大,导致判决时刻落在符号过渡区域。

处理:

  • 确认发射端RRC的滚降系数和接收端RRC一致,我用的都是0.5。
  • 检查Symbol Sync块的输入端口顺序:它需要一个复数基带信号,如果你把匹配滤波弄成了实数,波形就不对了。
  • 检查采样率是否为sps的整数倍关系。

6.3 接收端FFT上没信号

现象:发射端显示运行正常,但接收FFT一片平坦。

处理思路:

  1. 用另一台设备(比如手机和频谱App)确认发射通道是否真的在工作,排除SMA线虚接。
  2. 检查P201Pro的Tx和Rx口是否接对。如果接到同通道的loopback口上,有些板卡会默认禁用内部回环。
  3. 如果设置频率是2.45GHz,而接收链路里设错了成2.4GHz,那信号会被混频到10MHz中频的位置,FFT上看不到东西。

6.4 误码率居高不下但星座图清晰

现象:星座图看着是干净的四个点簇,但BER统计总在1e-2以上。

原因:多半是符号映射和比特映射的对应关系没对齐。比如发射端用Gray映射的[0,1,2,3]对应(1+j, -1+j, -1-j, 1-j),接收端判决后再映射回bit时顺序反了,或者polarity反了,就会出现“看起来很好但误码爆炸”的怪现象。

处理:

  • 先发固定序列[0,0,1,1,2,2,3,3],接收端显示判决后的符号索引。如果发现解出来的索引普遍错开一位,就检查的定时延时。
  • 检查Constellation Decoder块里的星座点顺序是否与发射端的Chunks to Symbols表精确一致。

6.5 接收端数据速率和发射端对不上

现象:接收端星座图正常,但BER统计需要对序列对齐很久才能统计出来,说明数据流的符号速率有细微偏差。

原因:收发采样时钟存在ppm级偏差。这种偏差用线缆自环时也依然存在,因为两个通道是同一晶振,偏差不会太大,但时间长了符号计数会漂移。

处理:用GNU Radio里的Delay块配合相关性估计做一个粗略对齐,或者在接收端用Correlate and Sync块实现帧同步。如果只是做误码率测试,也可以用“直接对比误码率窗口”的方式,把发射端数据截短到固定长度,接受端在固定窗口内对比。属于教学场景的简化处理。

7. 从bit流到点簇的实验结果与个人心得

7.1 实测结果记录

我在线缆自环情况下测到的结果如下:

参数数值
符号速率100k symbol/s
采样率400k samples/s
中心频率2.45GHz
发射增益-10dB
接收增益10dB
成形滤波RRC,滚降0.5
定时同步Gardner TED,环路带宽2π/100
载波同步Costas Loop,环路带宽2π/1000
误码率(线缆+20dB衰减)~2e-5
误码率(空间2m+20dB衰减)~3e-3

线缆自环时,误码率主要来自于数字域判决时的噪声和残余抖动。空间传输时,多径反射和天线的极化失配对误码率的影响非常明显,即使距离只有2-3米,误码率也比线缆高一到两个数量级。

7.2 我觉得最有价值的几个配置细节

第一,发射端应用一个固定幅度归一化。很多人忽视这个,导致AGC的工作范围没有落在线性区。我的做法是把符号直接映射为幅度1+1j、-1+1j等,不额外缩放,匹配滤波后幅度会自然归一化到合适范围。

第二,GNU Radio里每个块的“Output Type”和“Input Type”必须严格匹配。例如Chunks to Symbols输出是complex,而Symbol Sync输入也要是complex。经常看到初学者把中间某个块设成float,链路虽然能连上,但星座图一团糊。

第三,先固定频偏,再开环路。在没有Costas Loop的情况下,把接收中心频率手动调偏一点,再在链路上找出具体偏了多少,会大大降低环路捕捉的难度。这个技巧在真实射频实验中比想象中更够用。

7.3 接下来的几步扩展建议

这套系统再往前走,有几个方向特别值得做。

一是把QPSK升级成QAM16或QAM64。星座图从四个点簇变成十六或六十四个点簇,对相位噪声和幅度失配的敏感度会显著提升,锻炼效果也好。

二是加入帧同步和自适应均衡。在空间信道里,多径会让星座点重叠,需要加一个信道均衡器,或者改用OFDM在每个子载波上做单抽头均衡。

三是做实时的误码率曲线测试。通过修改发射端的Eb/N0模拟不同信噪比,或者用噪声源块加白噪声,在接收端画BER曲线。这类曲线放到课程设计或论文里特别有说服力。

四是尝试MIMO。P201Pro有双通道,天然可以做2×2的Alamouti空时编码实验。定时同步和载波同步同时处理两路信号,复杂度会上一个台阶,但理解也会深一层。

7.4 最后想补一句实际操作感受

这套实验做完,我最大的体会是:软件无线电里,最难调试的从来不是算法,而是那些“默认觉得没问题”的参数。频率差一拍,星座图就转;增益高一份,星座点就糊;背板晶振差几个ppm,符号数就对不上。所谓“从bit流到QPSK点簇”,本质上就是从一堆不确定参数里,逐步锁定一个确定性的映射关系。

如果你也卡在某个环节怎么都不出清晰星座图,我的建议是别急着堆模块,把链路拆开,一个一个环节去看。先用FFT确认频谱在不在,再用固定符号确认调制对不对,最后才开环同步。每一步都验证到位,QPSK这套系统其实半天就能跑通。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询