ARTICLE DETAIL

资讯详情

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

基于P201Pro与GNU Radio的QPSK收发链路:从比特流到星座图

基于P201Pro与GNU Radio的QPSK收发链路:从比特流到星座图 1. 从比特流到星座图这套收发链路到底在做什么软件无线电这个东西刚上手的时候很容易陷入一种工具会用但不知道自己在干嘛的状态。GNU Radio 的界面拖拖拽拽几个模块连起来一运行瀑布图上花花绿绿的东西出来了但你要问这中间每一步到底发生了什么很多人是答不上来的。我写这个阶段性总结就是想把这套基于 P201Pro 和 GNU Radio 搭起来的简单收发系统从最源头的比特流一路捋到 QPSK 星座点簇把中间每个环节的逻辑讲透。先说说这套系统的基本定位。它做的事情本质上很简单在发射端把一串二进制数据映射成 QPSK 符号经过脉冲成型、上变频送到射频前端发出去在接收端从射频前端拿到信号下变频、匹配滤波、符号同步、载波恢复最后在星座图上看到四个点簇。听起来是教科书上的标准流程但真正动手搭起来你会发现每一个环节都有坑而且这些坑在书本上往往一笔带过。P201Pro 这块板子在这个系统里扮演的角色是射频前端。它负责把基带的数字信号变成空中的电磁波也负责把接收到的电磁波变回基带数字信号。GNU Radio 跑在主机上负责所有的基带信号处理。两者之间通过高速接口传输 IQ 采样数据。这个架构的好处是灵活——你想换调制方式、换滤波器的参数、换同步算法改软件就行硬件不用动。这也是软件无线电最核心的价值所在。适合谁来参考这份总结如果你已经跑通过 GNU Radio 的入门教程比如那个经典的 FM 接收例子但想进一步理解数字通信收发链路的完整流程那这份内容就是写给你的。如果你正在用 P201Pro 或者类似的 AD9361 方案做实验遇到了一些同步或者星座图上的问题也可以看看我踩过的坑对你有没有帮助。我不打算从什么是软件无线电这种层面开始讲默认你已经有了基本的数字信号处理概念知道什么是 IQ 采样知道傅里叶变换大概是怎么回事。整条链路的信号流向我用文字描述一下方便后面展开。发射侧比特流生成 → 差分编码 → QPSK 符号映射 → 上采样 → 根升余弦脉冲成型 → 送入射频前端。接收侧射频前端输出基带 IQ → 匹配滤波 → 定时同步 → 载波频偏估计与校正 → 相位模糊消除 → 符号判决 → 星座图显示。每一个箭头背后都有一堆细节我接下来会逐个拆开讲。2. 发射链路的核心细节与参数选择2.1 比特流生成与差分编码的考量比特流的生成看起来是最没技术含量的一步但这里有一个选择会影响后面接收端的设计你到底发的是随机比特还是某种有规律的序列。我一开始图省事直接用 GNU Radio 里的 Random Source 生成随机比特。这样做的好处是频谱上看起来比较均匀不会因为数据本身的周期性导致某些频点能量异常。但坏处是调试的时候很难判断接收是否正确——你看到星座图上有四个点簇但你不知道解出来的比特对不对。后来我改成了发送固定的伪随机序列PN 序列。PN 序列的好处是接收端可以本地生成同样的序列做对比直接算误码率。这个改动对调试效率的提升是巨大的。你可以很直观地看到误码率随信噪比的变化而不是靠肉眼看星座图猜。差分编码这一步很多人会跳过觉得 QPSK 直接映射就行了。但如果你用的是非相干接收或者你的载波恢复环节存在相位模糊差分编码就是救命的。QPSK 的载波恢复通常会有 90 度的相位模糊也就是说恢复出来的载波可能相对于原始载波旋转了 0 度、90 度、180 度或 270 度。如果不做差分编码你解出来的比特会整体错位而且这种错位是恒定的不是随机的。差分编码把信息编码在相邻符号的相位差上这样即使有恒定的相位旋转相位差不变解出来的比特就是对的。具体实现上我用的是 GNU Radio 的Differential Encoder模块约束长度设为 1因为 QPSK 每个符号携带 2 比特差分编码的模是 4。这里要注意差分编码的模必须和调制阶数匹配QPSK 是 48PSK 就是 8搞错了整个映射就乱了。2.2 QPSK 符号映射与格雷码QPSK 符号映射说白了就是把每两个比特映射到一个复平面上的点。四个点通常在单位圆上均匀分布相位分别是 45 度、135 度、225 度、315 度。但具体哪个比特对映射到哪个点这里面有讲究。我用的是格雷码映射。格雷码的特点是相邻星座点之间只有一个比特不同。为什么要这样因为在实际信道中噪声导致的最常见错误是符号被判到了相邻的星座点上。如果用格雷码这种相邻错误只导致一个比特出错如果用自然二进制映射相邻错误可能导致两个比特同时出错。在误码率曲线上格雷码映射的 QPSK 比自然映射的 QPSK 在相同信噪比下误比特率要低虽然误符号率是一样的。GNU Radio 的Constellation QPSK模块默认就是格雷码映射星座点坐标是 (11j)/sqrt(2)、(-11j)/sqrt(2)、(-1-1j)/sqrt(2)、(1-1j)/sqrt(2)。除以 sqrt(2) 是为了归一化功率让平均符号能量为 1。这个归一化很重要因为后面的脉冲成型和增益控制都依赖于信号功率的标定。如果你自己写映射忘了归一化信号功率会偏大 3dB可能导致射频前端饱和。2.3 上采样与根升余弦脉冲成型上采样和脉冲成型是发射链路里最容易被忽视但影响最大的环节。上采样的目的是让符号速率匹配到射频前端的采样率。比如你的符号速率是 100k symbols/s每个符号 2 比特那就是 200kbps 的比特率。但射频前端可能要求 1M samples/s 的基带采样率那你就需要 10 倍上采样每个符号用 10 个采样点来表示。上采样本身只是插零在符号之间插入零值采样点。但插零之后的信号频谱是周期延拓的直接送出去会产生严重的邻道干扰。所以必须做脉冲成型把信号的频谱限制在符号速率附近。我用的脉冲成型滤波器是根升余弦RRC滚降系数 0.35。为什么用根升余弦而不是升余弦因为在收发链路中发射端和接收端各用一个根升余弦两者级联之后正好构成一个完整的升余弦响应满足奈奎斯特第一准则在符号采样点上没有码间干扰。如果你只在发射端用升余弦接收端不用匹配滤波器那在噪声存在的情况下接收信噪比会恶化。滚降系数 0.35 是一个折中。滚降系数越小频谱效率越高但时域拖尾越长对定时同步的精度要求越高。0.35 是一个比较通用的值频谱扩展大约是符号速率的 1.35 倍。如果你做的是带宽受限的系统可以降到 0.2 甚至 0.1但同步难度会显著增加。我试过 0.2在低信噪比下定时同步经常失锁后来还是回到 0.35。滤波器的阶数我设的是 10 个符号跨度也就是 10 * 每符号采样数。比如每符号 10 个采样点滤波器就是 101 阶10*101。阶数越高滤波器的频率响应越接近理想但计算量也越大。在 GNU Radio 里跑101 阶的 FIR 滤波器对现代 CPU 来说毫无压力所以没必要省这个计算量。2.4 射频前端的接口与增益分配P201Pro 通过 USB 或者以太网接口和主机通信GNU Radio 里对应的模块是UHD: USRP Sink。这个模块的参数配置直接决定了发射信号的质量。我重点说几个关键参数。采样率这个必须和你的基带采样率匹配。比如你基带是 1M samples/s那 USRP Sink 的采样率就设 1M。但要注意AD9361 的采样率有它自己的约束不是任意值都能设。通常它会内部插值或抽取到你的目标采样率。如果设了一个它不支持的值UHD 会报错或者自动调整到最近的支持值这时候你的实际采样率就和预期不一致了整个链路的时间关系都会乱。中心频率这个不用多说设成你允许的频段就行。但要注意AD9361 的本振泄漏在中心频率处会有一个直流分量。如果中心频率正好落在你信号的频带中间这个直流分量会叠加在你的信号上。解决办法是在基带把信号搬偏一点比如偏 100kHz让直流分量落在信号频带之外。增益这是最容易出问题的地方。AD9361 的发射增益范围大概是 0 到 90dB但并不是越大越好。增益太大信号被削顶星座图会变成方形而不是圆形误码率急剧恶化。增益太小信号淹没在噪声里接收端根本解不出来。我的经验是先把增益设到一个中间值比如 30dB然后用频谱仪或者接收端观察信号质量再微调。如果你没有频谱仪可以看接收端的星座图慢慢增加增益直到星座点开始扩散然后回退 3 到 5dB。注意AD9361 的增益调整不是线性的不同增益档位对应的实际放大倍数可能跳变。调增益的时候要小步慢走每次调 1 到 2dB观察效果。3. 接收链路的同步与判决3.1 匹配滤波与定时同步接收端的第一个环节是匹配滤波。匹配滤波器的系数就是发射端脉冲成型滤波器的时域反转共轭。因为根升余弦滤波器是实对称的所以时域反转就是它自己。在 GNU Radio 里我直接用和发射端相同的Root Raised Cosine Filter模块参数也保持一致。这样级联之后的整体响应就是升余弦满足无码间干扰条件。匹配滤波之后是定时同步。定时同步要解决的问题是你到底在哪个时刻采样才能采到符号的最佳点如果采样时刻偏了采到的值会落在两个符号之间受到相邻符号的干扰。GNU Radio 里我用的定时同步模块是Polyphase Clock Sync它基于多相滤波器组实现可以在符号速率未知的情况下自适应地找到最佳采样时刻。Polyphase Clock Sync的几个关键参数Samples per Symbol 设成和发射端上采样倍数一致比如 10。Loop Bandwidth 设成归一化带宽我一般设 0.01 到 0.05 之间。带宽越大同步越快但对噪声越敏感带宽越小同步越稳但收敛越慢。对于连续传输的系统0.01 就够了如果是突发传输可能需要 0.05 甚至更大。Filter Size 设成 32 或者 64这个参数影响的是多相滤波器的精度越大越精确但计算量越大。我踩过的一个坑是Polyphase Clock Sync的输出采样率是每个符号一个采样点但它的输出类型是复数而且符号的幅度和相位都保留着。如果你后面直接接星座图显示看到的是四个点簇但点簇的位置可能不在标准的 QPSK 星座点上因为还有载波频偏和相位偏移没有校正。3.2 载波频偏估计与校正载波频偏是接收端最头疼的问题之一。发射端和接收端的本振不可能完全同频总有一个小的频率偏差。这个偏差会导致星座图上的点簇旋转频偏越大旋转越快。如果频偏大到一定程度星座图会变成一个圆环完全无法判决。GNU Radio 里我用的载波恢复模块是Costas Loop。Costas Loop 本质上是一个锁相环它通过比较同相和正交分量的乘积来估计相位误差然后调整本地振荡器的频率和相位使得星座图稳定下来。Costas Loop 的关键参数Loop Bandwidth 同样设 0.01 到 0.05。Order 设成 4因为 QPSK 的载波恢复需要四阶非线性来消除调制信息。这里要注意Order 必须和调制阶数匹配QPSK 是 4BPSK 是 28PSK 是 8。设错了环路根本锁不住。我实测下来Costas Loop 能纠正的频偏范围大概是符号速率的 1% 到 2%。如果你的频偏超过这个范围Costas Loop 会失锁。这时候需要在 Costas Loop 之前加一个粗频偏估计和校正模块比如Frequency Xlating FIR Filter配合 FFT -based 的频偏估计。我一般会在接收链路最前面加一个FFT Sink观察频谱手动估计频偏然后用Frequency Xlating FIR Filter搬回去。虽然手动不优雅但对于实验系统来说够用了。3.3 相位模糊与差分译码Costas Loop 锁定之后星座图会稳定下来但可能存在 90 度的相位模糊。也就是说星座图可能相对于标准位置旋转了 90 度、180 度或 270 度。这是因为 Costas Loop 的鉴相特性有多个稳定点它可能锁定在任何一个稳定点上。解决相位模糊的方法有两种一种是使用差分编码在发射端把信息编码在相位差上接收端做差分译码这样恒定的相位旋转不影响结果另一种是使用独特的同步字接收端通过相关检测确定相位旋转量然后校正。我两种都试过差分编码更简单不需要额外的同步字开销但代价是误码率比相干检测略高大概差 1 到 2dB。对于实验系统来说这点性能损失可以接受。差分译码在 GNU Radio 里用Differential Decoder模块约束长度和发射端的编码器一致。译码之后输出的就是比特流了。这时候你可以接一个BER模块和本地生成的 PN 序列对比直接算出误码率。3.4 星座图观察与判决星座图是调试 QPSK 系统最直观的工具。GNU Radio 里的Constellation Sink模块可以把接收到的符号画在复平面上。理想情况下你应该看到四个清晰的点簇分别位于四个象限。点簇越集中说明信号质量越好点簇越扩散说明噪声或干扰越大。但星座图能告诉你的信息远不止这些。如果四个点簇整体偏离了标准位置说明有固定的相位偏移可能是 Costas Loop 没有完全锁定或者存在残余的频偏。如果点簇被拉长成椭圆形说明有 IQ 不平衡可能是射频前端的 I 路和 Q 路增益不一致或者相位不正交。如果星座图中心有一个亮点说明有直流偏移可能是 AD9361 的本振泄漏。如果点簇旋转成一个圆环说明频偏太大Costas Loop 失锁了。我调试的时候会同时观察星座图和频谱图。频谱图看信号的频域形状对不对有没有异常的杂散星座图看信号的解调质量。两者结合基本能定位大部分问题。判决就是根据星座图上的位置判断这个符号是四个点中的哪一个。GNU Radio 的Constellation Decoder模块会自动做这件事输出对应的比特对。判决的准则是最大似然也就是找离接收符号最近的星座点。在加性高斯白噪声信道下最大似然判决就是最优判决。4. 实操过程中踩过的坑与排查技巧4.1 采样率不匹配导致的鬼影星座图这个问题我卡了整整一个下午。现象是星座图上确实有四个点簇但每个点簇旁边还有一个淡淡的鬼影像是重影一样。一开始我以为是多径效应但实验室环境哪来的多径。后来用频谱仪看发射信号发现频谱上有两个峰间隔正好是符号速率。排查下来发现是采样率不匹配。我在 GNU Radio 里设的基带采样率是 1M但 USRP Sink 实际工作的采样率是 1.024M因为 AD9361 的采样率是 40M 除以某个整数不能精确得到 1M。这个 2.4% 的偏差导致符号速率也有同样的偏差接收端的定时同步模块按照 1M 的假设去同步结果每个符号都偏一点点累积起来就产生了周期性的采样点偏移在星座图上表现为鬼影。解决办法有两个一是把基带采样率改成 AD9361 能精确支持的值比如 1.024M二是在 GNU Radio 里加一个Resampler模块把 1M 重采样到 1.024M。我选了第一种因为少一个模块少一份计算量而且 1.024M 和 1M 差别不大对实验没有影响。提示AD9361 的采样率约束是 40M 除以 2 的幂次再除以某个整数。常见的精确值有 1.024M、2.048M、4.096M 等。设采样率之前最好查一下数据手册或者用 UHD 的get_sample_rates接口查一下支持的值。4.2 Costas Loop 失锁的典型表现与处理Costas Loop 失锁的时候星座图会变成一个圆环或者四个点簇模糊成一团。这时候你调 Loop Bandwidth 是没用的因为根本问题是频偏超出了环路的捕获范围。我的处理流程是这样的先在接收链路最前面接一个FFT Sink观察接收信号的频谱。如果频谱整体偏离了零频偏离量就是频偏的粗略估计。然后用Frequency Xlating FIR Filter把信号搬回零频附近搬移量就是估计出来的频偏。搬移之后再接 Costas Loop这时候频偏已经很小了环路很容易锁定。频偏估计的精度不需要很高因为 Costas Loop 还能纠正残余的频偏。一般来说粗估计的误差在符号速率的 0.5% 以内Costas Loop 就能锁住。如果粗估计误差太大Costas Loop 还是锁不住那就需要更精确的频偏估计算法比如基于 FFT 的精细估计或者基于循环前缀的估计。4.3 增益设置不当导致的非线性失真发射增益设得太高信号被削顶星座图会从圆形变成方形。这是因为削顶相当于对信号做了非线性变换产生了谐波和互调分量。在星座图上削顶表现为点簇向外扩散而且扩散的形状不是圆形的而是沿着某些方向被压扁了。我一开始把发射增益设到了 60dB因为觉得信号越强越好。结果接收端星座图惨不忍睹误码率居高不下。后来把增益降到 30dB星座图立刻变得清晰。所以增益不是越大越好要找到一个线性工作点。怎么找这个点我的方法是从低增益开始慢慢增加同时观察星座图。当星座图开始出现非线性失真的时候回退 3 到 5dB。如果你有频谱仪可以看信号的 ACLR邻道泄漏比ACLR 开始恶化的时候就是增益过高的信号。接收增益也是类似的道理。接收增益太高AD9361 的 ADC 会饱和星座图同样会失真。接收增益太低信号淹没在量化噪声里星座图会变得模糊。我一般先把接收增益设到中间值然后根据星座图的清晰度微调。4.4 常见问题速查表现象可能原因排查方法解决办法星座图四个点簇模糊信噪比太低看频谱底噪增加发射增益或降低接收增益星座图变成圆环频偏太大FFT 看频谱偏移加粗频偏校正星座图整体旋转相位偏移看 Costas Loop 锁定状态调 Loop Bandwidth 或检查差分编码星座图有鬼影采样率不匹配对比基带和射频采样率统一采样率或加重采样模块星座图点簇被压扁非线性失真降低增益看是否改善回退增益到线性区星座图中心有亮点直流偏移看零频处是否有尖峰搬移中心频率或加隔直模块误码率居高不下定时同步不准看定时误差信号调 Polyphase Clock Sync 参数星座图四个点簇不对称IQ 不平衡看 I 路和 Q 路增益校准 AD9361 的 IQ 平衡4.5 几个容易被忽视的细节第一个细节是 GNU Radio 的缓冲区大小。默认的缓冲区可能太小导致高速采样时数据溢出表现为随机的丢包和星座图上的突发错误。我一般会把缓冲区设成 2 的 16 次方或者更大具体看采样率和主机性能。第二个细节是线程优先级。GNU Radio 的流图默认在普通优先级线程里跑如果主机同时跑着其他任务可能会出现调度延迟导致采样数据断流。在 Linux 下可以用chrt命令把 GNU Radio 的线程提到实时优先级Windows 下可以在任务管理器里把进程优先级设为高。第三个细节是 USB 或以太网的带宽。P201Pro 通过 USB 3.0 或者千兆以太网传输 IQ 数据如果你设的采样率太高比如 10M samples/s每个采样点 4 字节16 位 I 加 16 位 Q那就是 40MB/s 的数据率。USB 3.0 理论带宽 5Gbps实际能到 3Gbps 左右40MB/s 也就是 320Mbps完全没问题。但如果你用的是 USB 2.0理论带宽 480Mbps实际能到 300Mbps 左右40MB/s 就接近极限了可能会出现丢包。所以接口类型和采样率的匹配也要注意。5. 从实验系统到更接近实际的扩展方向这套系统跑通之后你可能会想接下来往哪个方向扩展我分享几个我试过或者正在试的方向。第一个方向是加入信道编码。现在的系统没有纠错编码误码率完全由信噪比决定。如果加上卷积码或者 LDPC 码在相同信噪比下误码率可以降低几个数量级。GNU Radio 里有Convolutional Encoder和Viterbi Decoder模块可以直接用。但要注意编码之后符号速率会变因为要插入冗余比特整个链路的速率匹配要重新算。第二个方向是加入帧同步。现在的系统是连续传输的没有帧的概念。如果要传数据包就需要在数据前面加前导码和同步字接收端通过相关检测找到帧的起始位置。GNU Radio 里有Correlate Access Code模块可以做这件事。帧同步做好之后就可以实现真正的数据包收发而不是现在的连续比特流。第三个方向是尝试更高阶的调制。QPSK 是最基础的相位调制你可以试试 8PSK 或者 16QAM。调制阶数越高频谱效率越高但对信噪比的要求也越高。16QAM 在相同误码率下需要比 QPSK 高大约 7dB 的信噪比。而且高阶调制对定时同步和载波同步的精度要求更苛刻你会遇到更多同步方面的问题是个很好的练手项目。第四个方向是加入自适应均衡。如果信道不是理想的加性高斯白噪声信道而是有频率选择性衰落或者多径那就需要均衡器来补偿信道失真。GNU Radio 里有Linear Equalizer和Decision Feedback Equalizer模块。均衡器的参数调整是个技术活需要根据信道的特性来定。第五个方向是把整个链路做成一个完整的通信系统加上 MAC 层和网络层实现真正的数据传输。这个方向的工作量比较大但做完之后你对通信系统的理解会上升一个层次。我个人觉得对于实验系统来说先把 QPSK 这一套吃透把每个环节的原理和参数都搞清楚比急着上高阶调制更有价值。因为 QPSK 遇到的问题在高阶调制里同样会遇到而且会更严重。基础打牢了后面扩展就是水到渠成的事。最后分享一个我在调试过程中养成的习惯每次改动参数之前先把当前的流图保存一份改完之后如果效果变差了可以快速回退。GNU Radio 的流图文件是文本格式的用 git 管理起来很方便。我现在的实验目录里有一个 git 仓库每次成功的配置都提交一次commit message 写清楚改了什么参数、效果如何。这样积累下来你就有了一个自己的参数配置库下次遇到类似的问题翻翻历史记录就能找到答案。
返回列表