ARTICLE DETAIL

资讯详情

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

BPSK+LDPC+扩频链路误码率仿真:MATLAB完整实现与避坑指南

BPSK+LDPC+扩频链路误码率仿真:MATLAB完整实现与避坑指南 通信系统仿真这活儿最怕的不是代码跑不动而是链路里每个模块都半懂不懂最后误码率曲线画出来却解释不清楚。这个题目我第一眼看到就很有共鸣——BPSK调制解调、LDPC编译码、扩频解扩三大块都是数字通信里避不开的核心技术把它串成一条完整链路做误码率仿真本质就是复刻一套缩略版的现代通信系统。更直接地说这就是课程设计、毕业设计里出现频率极高的那一类课题结构清晰、层次分明、每层都有独立指标合在一起又有整体性能验证。这篇文章我从自己的仿真过程出发把链路怎么搭、参数怎么定、噪声怎么加、曲线怎么读以及那些文档里不会写的坑全部摊开来讲。适合正在做通信方向课设、毕设或者刚入链路级仿真想系统练一次手的同学。我把话先说在前面这个仿真是理想链路——同步完全理想没有载波频偏和定时偏差只关心编码、调制、扩频这三级处理对误码率的影响。这是刻意做的简化它不是偷懒而是把复杂问题的层次拆开先验证每一级的作用再考虑更真实的信道和接收机模型。1. 链路整体设计与方案选型思路1.1 为什么选BPSK二进制调制是最稳的起点BPSK在所有二进制调制里抗噪声性能是最好的误码率理论公式也最简单Pb 0.5·erfc(√(Eb/N0))一条曲线就能画出理论下限。扩频通信里选择BPSK还有一个很实际的原因——直序扩频本质上是把每个符号的幅度乘上一串±1的PN码片BPSK映射恰好也是±1符号这样调制和扩频在数学上可以无缝衔接不需要额外处理复数结构。这个课题里BPSK不只是一个“简单选项”它更像是一个校准基准。先用纯BPSK链路跑出理论误码率曲线确认噪声模型正确再叠加LDPC编码看编码增益最后叠加扩频看系统在AWGN下性能是否保持这种“逐级叠加”的思路是最不容易出错的仿真路线。1.2 LDPC编码在链路里扮演什么角色LDPC是低密度奇偶校验码靠迭代译码逼近Shannon极限。和Turbo码并列为信道编码的两大支柱DVB-S.2、5G NR、Wi-Fi 6这些标准都在用。放在这条链路里它的任务是给BPSK调制之前的比特流加上冗余让接收端在低信噪比下仍然能通过校验关系把错误比特揪出来。更关键的是LDPC译码器是软判决译码输入不是硬判的0/1而是对数似然比LLR它利用每个比特的置信度信息做迭代。这让LDPC和BPSK的软解调天然匹配。仿真里要注意的就是把解扩后的软值正确换算成LLR再送入译码器这个换算关系很多人第一次做都会搞混后面我会单独拉一节详细讲。1.3 扩频与解扩从符号到码片的跳变扩频技术里最常见的是直序扩频DSSS原理一句话发送端把一个BPSK符号扩展成SF个码片每个码片被PN序列调制接收端用同一个PN序列做相关运算把宽带信号重新“压回”窄带符号。扩频本身的动机通常有三个抗窄带干扰、低截获概率、码分多址。在AWGN信道里做仿真单独加扩频并不会让误码率变好因为加性高斯白噪声对扩频信号和非扩频信号的影响是对称的。很多同学第一次仿真发现“加了扩频曲线没改善”就以为自己错了其实这是正确现象。扩频的优势只有在存在窄带干扰、频带重叠干扰或者多用户同频的背景下才会体现而有意思的是即使是AWGN链路扩频模块也必须存在因为这是完整链路的一部分并且在解扩之后你会拿到一组比之前更“结实”的软值信号配合LDPC译码才构成一个完整系统。1.4 三级级联后应该看到什么把三者连起来预期性能是未编码BPSK在误码率10的-5次方时需要Eb/N0约9.6dB加入码率1/2的LDPC编码后在1.5到2dB附近就能达到相同误码率而扩频的加入在AWGN下不会显著改变误码率曲线但链路整体具备了抗干扰潜力。这套链路完成之后你手里拥有的不只是几行代码和一个图而是一套“编码增益”和“扩频处理增益”可以分解量化的研究框架。搞清楚每一级各自贡献了多少比单纯跑出一个图要重要得多。2. 仿真前的参数准备与MATLAB关键配置2.1 系统参数总表与选取依据动手写代码前参数表必须先定清楚否则后面容易出现维度对不上、曲线横坐标错乱的问题。参数取值说明调制方式BPSK±1映射LDPC码率1/2DVB-S.2标准码率便于验证校验矩阵来源dvbs2ldpc(1/2)长帧64800或短帧16200扩频因子SF32每个符号扩展成32个码片PN序列m序列长度31扩展至32收发端保持同一个序列信息比特能量Eb归一化为1简化噪声功率换算Eb/N0范围0到8dB步进0.5dB能覆盖LDPC错误平底区域每信噪比点仿真帧数30到100帧视最低误码率需求调整扩频因子取32是合理的折中太小体现不出扩频特性太大仿真量按线性增长。LDPC码率1/2则是文献和标准里最常见的值编码增益容易和图谱里的理论值对照。2.2 LDPC校验矩阵与编解码器配置MATLAB里拿DVB-S.2校验矩阵最直接的方式是dvbs2ldpc函数。新版R2021b之后编码译码推荐用ldpcEncoderConfig和ldpcDecoderConfig配合ldpcEncode、ldpcDecode来用旧版本则是comm.LDPCEncoder和comm.LDPCDecoder对象。这两个接口我都列一下方便对照自己的MATLAB版本。H dvbs2ldpc(1/2); % 长帧校验矩阵 cfgEnc ldpcEncoderConfig(H); cfgDec ldpcDecoderConfig(H); K size(H, 2) - size(H, 1); % 信息比特长度旧版本写法hEnc comm.LDPCEncoder(ParityCheckMatrix, H); hDec comm.LDPCDecoder(ParityCheckMatrix, H);这里最容易被坑的点是K的取值。dvbs2ldpc返回的是校验矩阵H列数减行数才是信息比特数不是你想传多少位就传多少位LDPC码字长度是固定的。长帧模式下K是32400短帧模式下是7200。如果你只做教学验证长帧跑起来会很吃力可以采用短帧模式具体语法在MATLAB文档里有用之前务必doc dvbs2ldpc确认参数写法和当前版本的返回格式。2.3 信噪比与噪声功率换算整条链路最容易错的地方这是整个仿真的分水岭。很多人误码率曲线和理论对不上十有八九是噪声方差加错了。我做仿真习惯把信息比特能量Eb统一归一化为1这样Eb/N0换算成噪声功率谱密度就直接取倒数公式干净很多。链路里信息比特先经过码率R的LDPC编码再经过BPSK映射最后每个符号扩展成SF个码片所以每个码片的能量是Ec K比特对应的码片数 / K比特总数 × Eb R/SF也就是说发送端码片序列的幅度应该是sqrt(R/SF)如果直接采用±1幅度的码片就相当于把能量抬高了做出来的曲线也会偏移。AWGN信道下加性噪声方差取No/2其中No 1/(Eb/N0线性值)。对应的仿真噪声生成是EbNoLin 10^(EbNo_dB / 10); No 1 / EbNoLin; sigma sqrt(No / 2); tx sqrt(R / SF) * chip; rx tx sigma * randn(size(tx));这套换算有没有问题最快验证方法是先跑一条不加LDPC、不加扩频的纯BPSK链路把误码率曲线画出来和理论值0.5·erfc(sqrt(Eb/N0))对照。对得上说明噪声模型正确后面加模块才有意义对不上先别往下走一定是换算环节出错。3. 各模块的MATLAB实现与核心细节3.1 信源生成与BPSK映射信息比特用randi生成即可每一帧长度固定为K。映射方式我习惯用0映射为-1、1映射为1也就是symbol 1 - 2*bit。为什么用这个方向因为LDPC译码器输出的软信息约定通常是正值代表1负值代表-1保守起见两个方向都可以试真的遇到译码不收敛把LLR乘个负号往往就能解决。infoBits randi([0 1], 1, K); encodedBits ldpcEncode(infoBits., cfgEnc).; % 编码 symbols 1 - 2 * encodedBits; % BPSK映射注意ldpcEncode默认输入是列向量输出也是列向量记得转置。这个细节几乎每个人都有一次踩上去的机会。3.2 LDPC编码与译码实现细节译码端是整条链路的算力大户。软判决译码需要输入LLR选择DecisionType软判决方式。我建议最大迭代次数设到10到20之间太小性能损失明显太大每一轮仿真都要等很久。llr (2 * sqrt(R / SF) / sigma^2) .* y; % y是解扩后的软值 decodedBits ldpcDecode(llr, cfgDec, DecisionType, soft);这里再强调一次LLR的系数问题。解扩后的软值y里面信号分量是sqrt(R/SF)乘以SF噪声分量是SF个独立噪声样本之和。LLR的标准公式是2A·y/σn²A是信号幅度σn²是y的噪声方差代入推完会发现SF被约掉最后剩下的系数就是2·sqrt(R/SF)/σ²。很多教程里直接取y作为LLR也能跑因为译码器内部通常会做归一化但如果你发现误码率曲线出现奇怪的错误平底建议按完整系数重新算。3.3 m序列生成与扩频解扩的实现扩频码我建议用m序列因为它有明确的周期性和伪随机特性比用随机数生成的序列更像真实系统。一个n级线性反馈移位寄存器可以生成周期为2^n-1的m序列。实现代码很简短function seq mseq(states, taps) % states: 寄存器初始状态不能全0 % taps: 反馈抽头位置 n length(states); seqLen 2^n - 1; seq zeros(1, seqLen); for k 1:seqLen seq(k) states(1); fb mod(sum(states(taps)), 2); states [fb, states(1:end-1)]; end seq 2 * seq - 1; % 转成双极性±1 end调用时比如用五级寄存器pn mseq([1 0 0 0 0], [5 1])得到长度31的序列。如果扩频因子SF取32可以复制最后一个码片补到32位或者改用Gold序列组合出长度2^n的序列单用户场景差别不大。扩频发送时把每个符号和PN序列相乘再拼接成码片流这一步用矩阵操作比循环高很多chipStream reshape((symbols. * pn)., 1, []);接收端解扩是相关运算把连续码片流按SF长度重新组织成矩阵每一列乘上本地PN序列再求和rxMatrix reshape(rx, SF, []); y pn(:). * rxMatrix;这一步之后向量y变成了每个BPSK符号对应的软值它的信噪比和没扩频时单符号接收的信噪比保持一致这也是AWGN下扩频不改变误码率的直接体现。3.4 误码率统计与曲线绘制误码率统计要按信息比特算不是按编码比特算这样画出来的曲线才是和理论BPSK对比的正确横坐标。每一帧统计完毕把错误比特数和总比特数累加到外循环最后统一相除。ber(snrIdx) totalErrors / totalBits;绘图用semilogy。建议同时画两条线一条带LDPC的链路实测误码率一条未编码BPSK理论曲线。这样编码增益的大小一眼就能看出来。横坐标用Eb/N0dB不要用Es/N0或SNR否则和理论值无法对比。4. 仿真结果分析与调试实况4.1 典型误码率曲线的解读方法我按上面的参数跑下来典型结果是Eb/N00dB时有LDPC的链路误码率还在10的-1次方附近到1.5dB左右迅速降到10的-4次方以下到2dB左右曲线开始明显变陡。对照理论BPSK曲线10的-5次方需要约9.6dB这就是LDPC编码增益的直观体现大约7到8个dB。曲线形状有一个需要留意的特征LDPC误码率曲线在低SNR段下降比较平缓然后进入所谓的“瀑布区”下降斜率突然变陡最后在很高SNR下由于最小距离不够或者迭代不足出现错误平底。如果你发现曲线在10的-4次方附近降不下去了先别急着加仿真帧数检查迭代次数是不是太少或者LLR系数有没有问题。4.2 扩频增益为什么没有反映在AWGN误码率曲线上很多同学看到“加了扩频曲线和没加扩频几乎重合”会产生疑惑。这其实是正确结果。直序扩频在AWGN信道里解扩前后的符号信噪比是一样的解扩相关运算让信号能量和噪声能量都乘以SF比值不变。但它对整个通信系统的价值在于抗窄带干扰和抗多径以及多用户接入能力这些在纯AWGN单用户仿真里看不到。我在仿真时习惯额外留一个实验口在信道里叠加一个窄带干扰正弦再对比不扩频和扩频两种情况的误码率。你会发现没有扩频时干扰把曲线压得很高加了扩频后解扩相当于把窄带干扰的能量分散到整个频段上性能立刻恢复。这才是扩频增益的正确打开方式建议你自己动手加进去看看。4.3 用理论曲线反推链路搭建是否正确仿真结果出来之后第一件事不是分析自己的曲线多漂亮而是和理论值对表。纯BPSK理论误码率在任何一本通信原理教材里都能找到0.5·erfc(sqrt(Eb/N0))。如果你的纯BPSK实测曲线和理论线偏离0.3dB以上说明噪声方差换算肯定有问题。LDPC部分怎么自检同样地把码率、迭代次数固定与公开文档里DVB-S.2的性能曲线对比。1/2码率、8-PSK之外的BPSK传播场景下10的-5次方误码率对应的Eb/N0大约在1.5dB上下如果偏差超过0.5dB优先怀疑LLR极性、译码器输入格式、校验矩阵配置这三处。5. 常见问题排查与避坑记录5.1 LDPC编解码维度不匹配这是报错重灾区。症状是ldpcEncode传入长度不对或者ldpcDecode输出长度不对。根因通常是K计算错误或者把编码前的信息比特长度和编码后的码字长度搞混。DVB-S.2长帧模式下三种值要记清楚信息比特数K、码字比特数N、校验比特数M其中N等于K加MH矩阵的列对应N行对应M。每次写代码前先打印一次size(H)再算一次K不然错一次成本很高。5.2 误码率稳定在0.5附近先查LLR极性如果整条链路跑下来误码率一直在0.5上下浮动大概率不是噪声问题而是LLR正负方向和译码器的比特判决约定反了。遇到这种情况最直接的排查方式取一个高SNR点比如10dB先看硬判决是否全部正确。如果硬判决都对了译码输出还是错的那几乎可以确定是LLR极性反了把LLR乘上-1再跑一次。这个坑我至少踩过两次每次都是5分钟能定位但因为先入为主总觉得编码器配置错了反而绕了远路。5.3 误码率假收敛与统计充分性仿真到低误码率时比如10的-5次方如果只跑了10帧实际上只统计到几十个错误比特统计波动会非常大。我习惯设两个停止条件一是每个信噪比点至少累计到100个错误比特再停止二是达到最大帧数上限就停止。这样既能保证高SNR点不至于无限跑下去又能让低SNR点的曲线平滑。另一个细节是随机数种子在脚本开头rng(default)否则每次跑出来曲线形状略有不同排查问题时会怀疑人生。5.4 仿真太慢的优化思路长帧LDPC加高帧数整个仿真会很慢。三个优化方向第一校验矩阵改用短帧模式K从32400降到7200速度直接提升好几倍第二把内层帧循环改成向量化批处理一次处理多帧减少MATLAB循环开销第三if你有并行工具箱把不同的Eb/N0点丢给parfor并行跑这个场景下并行效率非常高因为每个点之间完全独立。还有一个容易被忽略的细节LDPC译码在低SNR段往往需要多次迭代高SNR段少量迭代就能收敛。如果盲设最大迭代次数为50大量时间都耗在低SNR点上。可以按信噪比动态调整最大迭代次数或者让译码器早期停止迭代MATLAB里可以通过配置codedBits的预处理来控制迭代终止条件具体看文档中ldpcDecode关于最大迭代次数的说明。6. 把这套链路继续往后扩展的几个方向最后分享一点我个人实际做仿真时的体会。这套链路跑通只是第一步真正有价值的是把它当平台继续加东西。最简单的扩展是把AWGN换成多径瑞利衰落信道观察BPSK加LDPC在平坦衰落下的性能会发现编码增益依然存在但衰落带来的误码平底会逼着你加交织器或者分集接收。再进一步把BPSK换成QPSK注意QPSK本质就是两路正交BPSK扩频和LDPC的接口几乎不用改只是软信息要从I/Q两路分别算。如果是往接收机方向走可以在解扩之前加一个简单的相关捕获模块用本地PN序列滑动相关找同步起点这比理想同步更接近真实系统。我自己在做这个扩展时发现捕获的峰值在低SNR下很容易被噪声淹没加粗捕获积分长度后又会导致同步时间变长这个矛盾本身就是很好的研究素材。还有一个小技巧仿真过程中把每个模块的输出都存下来而不是只存误码率比如解扩前的码片波形、解扩后的星座软值、译码前后的比特差异关键时刻可以省下大量定位时间。我第一次做这个链路时就是因为没有缓存中间变量出问题后只能从头重跑浪费了一个下午。这套链路做完你会对整个数字通信的“信源到比特、比特到波形、波形再回到比特”的闭环有很实的感觉。它不复杂但每一层都有独立的技术逻辑合起来又有一个明确的性能指标。保持这种逐级拆解、逐级验证的习惯后面做OFDM、MIMO、信道估计这些更复杂的系统你也会比直接照着代码抄的人踏实得多。
返回列表