简介:本资源面向卫星通信、数字电视广播及纠错编码方向的研究生、工程师与算法开发者,提供DVB-S2与DVB-S2X标准下LDPC+BCH级联编码配合BPSK、QPSK、8PSK、16APSK、32APSK多种调制的Matlab仿真实现,可用于误码率、信噪比与吞吐量等关键指标的评估与方案对比。压缩包共40个文件,以mat数据文件与m脚本为主,另有少量txt说明与asv备份,整体约42KB,涵盖调制解调、参数配置、仿真对象创建与BER统计等模块,便于按流程调用与二次修改。目前已有559人学习下载。读者可借助完整示例理解编码、调制、信道加噪、解调译码到性能评估的全链路逻辑,快速搭建可复现的仿真环境,并在此基础上调整码率、调制阶数与信道参数,验证不同配置下的纠错能力与频谱效率,为系统设计与算法优化提供参考。
1. 从一条误码率曲线说起:DVB-S2 的 LDPC+BCH 到底难在哪
第一次在 MATLAB 里把 DVB-S2 的 LDPC+BCH 链路跑出接近理论值的 BER 曲线时,我盯着屏幕看了很久——不是因为曲线漂亮,而是因为在此之前我已经连续三天卡在同一个地方:BCH 译码后的误码率不降反升。后来才发现,问题出在 LDPC 软判决输出的量化位宽和 BCH 硬判决输入之间的对接上,一个看似不起眼的位宽截断,把整个级联码的纠错能力吃掉了大半。
DVB-S2 和它的扩展版 DVB-S2X 是卫星通信领域里被广泛引用的物理层标准,核心卖点就是那套 LDPC+BCH 级联纠错编码配合多种调制方式(BPSK、QPSK、8PSK、16APSK、32APSK)。LDPC 负责主体纠错,BCH 作为外码清理 LDPC 译码后残留的零星错误,两者级联之后在低信噪比下依然能逼近香农限。这套方案适合做卫星链路仿真、通信算法验证、FPGA 原型前期建模的工程师和学生。本文不讲标准文本的逐条翻译,而是把我在 MATLAB 里复现这套链路时踩过的坑、调过的参数、验证过的结构,按可复现的顺序讲清楚。
2. 编码链路怎么搭:从 BCH 外码到 LDPC 内码的 MATLAB 实现
2.1 为什么是 BCH 在外、LDPC 在内
DVB-S2 的 FEC 编码采用串行级联结构:信息比特先经过 BCH 编码,再送入 LDPC 编码器。这个顺序不能反。原因是 LDPC 码在译码时会出现所谓的“错误地板”现象——当信噪比高到一定程度后,LDPC 译码后的误码率下降变得极慢,残留的错误比特虽然少但持续存在。BCH 码作为外码,它的任务就是把这些残留错误清理干净,让最终输出达到准无误码水平。
从参数上看,DVB-S2 定义了两种帧长:64800 比特的正常帧和 16200 比特的短帧。每种帧长对应多种码率,从 1/4 到 9/10。BCH 码的参数是跟着 LDPC 走的——BCH 的信息位长度等于 LDPC 的信息位长度,BCH 的码字长度等于 LDPC 的信息位长度加上 BCH 校验位。以正常帧、码率 1/2 为例,LDPC 信息位是 32400 比特,BCH 校验位是 192 比特,所以 BCH 码字长度是 32592 比特,这 32592 比特再送入 LDPC 编码器产生 64800 比特的 LDPC 码字。
在 MATLAB 里,BCH 编码可以直接用bchgenpoly和bchenc函数,但要注意 DVB-S2 用的 BCH 码是缩短码,不是标准长度的 BCH 码。你需要根据标准里给出的生成多项式系数手动构造,或者用comm.BCHEncoder系统对象并指定缩短后的参数。
% DVB-S2 正常帧、码率1/2的BCH编码参数 % BCH(32592, 32400),纠错能力12比特 n_bch = 32592; % BCH码字长度 k_bch = 32400; % BCH信息位长度 t_bch = 12; % 纠错能力 % 构造BCH生成多项式(DVB-S2标准给定的系数) % 这里用MATLAB内置函数生成一个接近的BCH码作为演示 % 实际工程中需要按标准Table 6a/6b的系数构造 [genpoly, t] = bchgenpoly(n_bch, k_bch); % genpoly是伽罗瓦域上的生成多项式 % 编码 msg = randi([0 1], k_bch, 1); % 随机信息比特 enc_bch = bchenc(gf(msg'), n_bch, k_bch, genpoly); enc_bch_bits = double(enc_bch.x)'; % 转回二进制向量这段代码里bchgenpoly返回的生成多项式是 MATLAB 根据码长和信息位自动搜索的,和 DVB-S2 标准里明确规定的生成多项式可能不一致。实际做标准兼容仿真时,必须用标准文档里给出的生成多项式系数,否则 BCH 译码器无法正确工作。bchenc的输入要求是伽罗瓦域元素,输出也是伽罗瓦域元素,需要转回 double 类型才能送入后续的 LDPC 编码器。
2.2 LDPC 编码:准循环结构与校验矩阵构造
DVB-S2 的 LDPC 码是准循环码,校验矩阵由若干个循环置换矩阵构成。标准里直接给出了每个码率对应的校验矩阵地址表,你需要根据这些地址表构造出完整的 H 矩阵。这是整个仿真里最繁琐的一步,也是最容易出错的一步。
常见做法是先把标准里的地址表读进来,然后按规则展开成稀疏矩阵。以正常帧、码率 1/2 为例,H 矩阵的大小是 32400×64800,其中信息位部分 32400 列,校验位部分 32400 列。校验位部分是一个双对角线结构,信息位部分由地址表决定。
% 构造DVB-S2 LDPC校验矩阵(以正常帧、码率1/2为例) n_ldpc = 64800; k_ldpc = 32400; m_ldpc = n_ldpc - k_ldpc; % 校验位长度 % 初始化稀疏矩阵 H = sparse(m_ldpc, n_ldpc); % 校验位部分的双对角线结构 for i = 1:m_ldpc H(i, k_ldpc + i) = 1; if i < m_ldpc H(i, k_ldpc + i + 1) = 1; end end % 信息位部分:按标准地址表填充 % 这里用简化的随机地址演示,实际需查标准Table B.1 % 每个信息位分组对应若干校验位地址 q = 60; % 对于码率1/2,q = 60 for j = 1:k_ldpc % 实际地址从标准表中读取 % H(addr, j) = 1; end这里要特别注意q值。DVB-S2 标准里每个码率对应一个q值,码率 1/2 时q=60,码率 3/4 时q=45,等等。q决定了地址表中每个信息位分组对应的校验位地址的间隔规律。如果q值搞错,构造出来的 H 矩阵不满足标准,译码性能会严重偏离。
LDPC 编码本身可以用H矩阵做高斯消元得到生成矩阵,但 64800 维的矩阵求逆在 MATLAB 里非常慢。更实用的做法是利用 DVB-S2 校验矩阵的特殊结构,直接用累加方式生成校验位。标准里给出了具体的编码算法,核心思想是利用双对角线结构做递推。
% 利用双对角线结构快速编码 % 假设H = [A | B],B是双对角线矩阵 % 编码过程:先算A*msg,再递推求校验位 A = H(:, 1:k_ldpc); B = H(:, k_ldpc+1:end); % 计算中间向量 temp = mod(A * msg, 2); % 递推求校验位 p = zeros(m_ldpc, 1); p(1) = temp(1); for i = 2:m_ldpc p(i) = mod(temp(i) + p(i-1), 2); end % 完整码字 codeword = [msg; p];这个递推编码的复杂度是 O(m_ldpc),比矩阵求逆快几个数量级。但前提是 B 矩阵确实是标准的双对角线结构,如果地址表读错了导致 B 矩阵结构不对,递推结果就是错的。
2.3 调制映射:BPSK 到 32APSK 的星座点与比特映射
DVB-S2 支持五种调制方式:BPSK、QPSK、8PSK、16APSK、32APSK。BPSK 和 QPSK 的映射比较直观,APSK 的星座图是同心圆结构,每个圆环上的点数不同。16APSK 是 4+12 结构,内环 4 个点,外环 12 个点;32APSK 是 4+12+16 结构,三个圆环。
星座点的具体坐标在标准里有明确定义,但比特到星座点的映射规则(也就是格雷映射还是其他映射)会直接影响误码率性能。DVB-S2 用的是特定的比特映射方式,不是简单的格雷映射。
% 16APSK星座图生成 % 内环半径r1,外环半径r2,r2/r1由标准给定 gamma = 2.85; % 16APSK的半径比,码率不同值不同 r1 = 1; r2 = gamma * r1; % 内环4个点 inner_angles = (0:3) * pi/2 + pi/4; inner_points = r1 * exp(1j * inner_angles); % 外环12个点 outer_angles = (0:11) * pi/6 + pi/12; outer_points = r2 * exp(1j * outer_angles); % 合并星座图 constellation = [inner_points, outer_points]; % 比特映射:4比特对应一个符号 % 具体映射表需按标准Table 9构造 % 这里给出映射框架 bits_per_symbol = 4; num_symbols = 2^bits_per_symbol; % 实际映射需要按标准定义的比特顺序排列gamma值是 16APSK 的关键参数,标准里对不同码率给出了不同的gamma值。比如码率 2/3 时gamma=2.85,码率 3/4 时gamma=2.85,码率 5/6 时gamma=2.85——等等,这里需要查标准确认。实际上 DVB-S2 标准里 16APSK 的gamma值随码率变化,从 2.85 到 3.15 不等。如果gamma设错,解调端的星座点判决边界就会偏移,误码率曲线会整体右移。
32APSK 更复杂,三个圆环的半径比gamma1和gamma2都需要按标准设定。而且 32APSK 对相位噪声非常敏感,仿真时如果没加相位噪声模型,结果会过于乐观。
3. 译码端怎么调:LDPC 置信传播与 BCH 硬判决的对接
3.1 LDPC 译码:归一化最小和算法的参数选择
LDPC 译码用置信传播算法,工程上常用的是最小和算法的变体——归一化最小和或偏移最小和。DVB-S2 的 LDPC 码校验矩阵里存在大量短环,直接用标准置信传播算法会震荡,必须做归一化。
% 归一化最小和译码(简化框架) max_iter = 50; % 最大迭代次数 alpha = 0.75; % 归一化因子 LLR = 2 * rx_symbol / sigma^2; % 初始对数似然比 % 初始化 Lq = zeros(size(H)); % 变量节点到校验节点的消息 Lr = zeros(size(H)); % 校验节点到变量节点的消息 for iter = 1:max_iter % 校验节点更新 for each check node % 找最小和次最小的LLR绝对值 % 符号相乘 % 归一化 end % 变量节点更新 for each variable node % 求和 end % 硬判决 hard_decision = (total_LLR < 0); % 校验 if mod(H * hard_decision, 2) == 0 break; % 译码成功 end endalpha的取值直接影响译码收敛速度和性能。经验值在 0.7 到 0.8 之间,码率越高alpha可以取得越大。max_iter一般设 50 次,但实际仿真中大部分帧在 20 次以内就收敛了。如果发现译码不收敛,先检查 H 矩阵构造是否正确,再调alpha。
初始 LLR 的计算里sigma^2是噪声方差,这个值必须和信道仿真里加的噪声功率一致。如果sigma^2估计不准,LLR 的尺度就错了,译码性能会明显下降。实际系统里sigma^2是估计出来的,仿真里可以直接用真实值,但要注意单位换算。
3.2 BCH 译码:从 LDPC 软输出到硬判决输入的位宽处理
LDPC 译码输出的是硬判决比特,直接送给 BCH 译码器。但这里有一个容易被忽略的细节:LDPC 译码器内部的 LLR 量化位宽会影响最终硬判决的可靠性。如果 LLR 量化太粗,硬判决的误码率会偏高,BCH 译码器需要纠正的错误就更多。
% LDPC译码后的硬判决 rx_bch = hard_decision(1:k_bch); % 取前k_bch个比特作为BCH码字 % BCH译码 dec_bch = bchdec(gf(rx_bch'), n_bch, k_bch, genpoly); dec_bits = double(dec_bch.x)'; % 计算误码率 bit_errors = sum(dec_bits ~= msg); ber = bit_errors / k_bch;bchdec的输入必须是伽罗瓦域元素,而且码字长度和信息位长度必须和编码时一致。如果 LDPC 译码输出的硬判决里有超过 12 个比特的错误(对于纠错能力 12 的 BCH 码),BCH 译码器会译码失败,输出可能比输入还差。这就是为什么级联码的性能不是简单叠加——LDPC 必须把误码率降到 BCH 纠错能力以内,BCH 才能发挥作用。
实际调试时,我会在 LDPC 译码后统计误码率,确认它低于 BCH 的纠错能力门限,再看 BCH 译码后的最终误码率。如果 LDPC 译码后误码率就很高,BCH 译码后的结果会非常差,这时候调 BCH 参数没有意义,要回去检查 LDPC 译码。
3.3 不同调制方式下的信噪比设置与性能对比
做 BER 曲线仿真时,信噪比的设置方式直接影响结果的可比性。DVB-S2 标准里用的是 Es/N0(符号信噪比),而 MATLAB 里常用的是 Eb/N0(比特信噪比)。两者之间的换算关系取决于调制方式和码率。
| 调制方式 | 每符号比特数 | Es/N0 到 Eb/N0 换算 |
|---|---|---|
| BPSK | 1 | Eb/N0 = Es/N0 |
| QPSK | 2 | Eb/N0 = Es/N0 - 3dB |
| 8PSK | 3 | Eb/N0 = Es/N0 - 4.77dB |
| 16APSK | 4 | Eb/N0 = Es/N0 - 6dB |
| 32APSK | 5 | Eb/N0 = Es/N0 - 7dB |
这个换算是在码率为 1 的情况下,如果码率不是 1,还要加上码率的修正:Eb/N0 = Es/N0 - 10*log10(bits_per_symbol * code_rate)。很多初学者在这里翻车,把 Es/N0 直接当 Eb/N0 用,结果 BER 曲线和标准里对不上,还以为是编码实现错了。
% 信噪比设置示例 EbN0_dB = 2:0.5:6; % Eb/N0范围 code_rate = 1/2; bits_per_symbol = 2; % QPSK for i = 1:length(EbN0_dB) EbN0 = 10^(EbN0_dB(i)/10); EsN0 = EbN0 * code_rate * bits_per_symbol; sigma = sqrt(1/(2*EsN0)); % 复高斯噪声标准差 % 加噪声、解调、译码... endsigma的计算里有个 1/2 因子,因为复高斯噪声的实部和虚部各占一半功率。如果忘了这个因子,噪声功率会差一倍,BER 曲线整体偏移 3dB。
4. 避坑与排查:仿真跑不通时先看这几个地方
4.1 BER 曲线不下降反而上升
现象:随着信噪比增加,BER 曲线先降后升,或者在高信噪比区域平坦不降。
原因:最常见的是 LDPC 译码器不收敛,硬判决输出错误率高于 BCH 纠错能力,BCH 译码器把正确码字“纠”成了错误码字。另一个可能是 LLR 的符号定义反了,导致译码器朝着错误方向迭代。
解决:先单独测 LDPC 译码器,不加 BCH,看 LDPC 译码后的 BER 是否随信噪比单调下降。如果 LDPC 单独跑都不对,检查 H 矩阵构造和 LLR 计算。确认 LDPC 没问题后,再检查 BCH 的生成多项式是否和标准一致。
4.2 译码迭代次数设很大但性能不变
现象:把max_iter从 50 加到 200,BER 曲线几乎不动。
原因:归一化因子alpha设得不对,或者初始 LLR 的尺度不对。如果alpha太小,消息衰减太快,迭代再多也传不到远处;如果alpha太大,消息震荡,迭代多了反而发散。
解决:固定信噪比,扫描alpha从 0.5 到 1.0,看译码成功率的峰值在哪里。同时检查sigma^2是否和实际噪声功率匹配,LLR 的绝对尺度不对,归一化因子再准也没用。
4.3 高信噪比下 BER 降到某个值就下不去了
现象:BER 曲线在 1e-5 附近出现地板,继续增加信噪比也不降。
原因:这是 LDPC 码的错误地板现象,正常。但如果地板出现在 1e-3 以上,说明 BCH 外码没有正常工作。可能是 BCH 译码器输入的不是 LDPC 译码后的硬判决,而是解调后的软信息直接硬判,中间漏了 LDPC 译码步骤。
解决:确认信号流是“解调 → LDPC 译码 → BCH 译码”,不是“解调 → BCH 译码”。BCH 的输入必须是 LDPC 译码后的比特,不能跳过 LDPC。
4.4 16APSK 和 32APSK 的 BER 曲线异常差
现象:BPSK 和 QPSK 的 BER 曲线正常,但 16APSK 和 32APSK 的曲线差很多,甚至不收敛。
原因:APSK 的星座点半径比gamma设错了,或者比特映射表不对。APSK 对半径比非常敏感,gamma偏 0.1 就能让 BER 差一个数量级。另一个可能是解调时星座点判决用了错误的边界。
解决:先画星座图,确认内外环半径比和标准一致。再单独测解调器,不加编码,看无编码 BER 是否和理论值吻合。如果无编码都不对,问题在调制映射;如果无编码对但加编码后不对,问题在 LLR 计算——APSK 的 LLR 计算比 QPSK 复杂,每个比特的 LLR 需要根据星座点的距离单独算。
4.5 短帧和正常帧的性能差异被忽略
现象:用短帧(16200)仿真得到的 BER 曲线比正常帧(64800)差,但标准里短帧的性能损失没有这么大。
原因:短帧的 LDPC 码校验矩阵构造方式和正常帧不同,q值不一样,地址表也不一样。如果直接套用正常帧的构造方法,短帧的 H 矩阵是错的。
解决:短帧和正常帧的地址表要分别读取,不能混用。短帧的q值对于码率 1/2 是 30,正常帧是 60。构造 H 矩阵时确认帧长和码率对应的q值。
5. 进阶技巧:用外部信息传递图验证级联码的收敛门限
5.1 为什么要看 EXIT 图而不是只看 BER
BER 曲线告诉你“在某个信噪比下误码率是多少”,但不告诉你“为什么是这个值”。当你想优化级联码的参数——比如调整 LDPC 和 BCH 之间的码率分配——BER 曲线只能给你试错的结果,不能给你方向。外部信息传递图(EXIT Chart)能可视化 LDPC 译码器和 BCH 译码器之间的信息交换过程,让你看到级联码的收敛门限在哪里。
EXIT 图的核心思想是:把每个译码器看作一个信息处理器,输入是先验信息,输出是外信息,两者都用互信息来度量。当 LDPC 的外信息曲线和 BCH 的先验信息曲线在图中不相交时,迭代译码可以收敛;如果相交,说明存在一个固定点,迭代无法继续改善。
5.2 在 MATLAB 里画 LDPC 的 EXIT 曲线
LDPC 译码器的 EXIT 函数可以通过蒙特卡洛仿真得到。固定信噪比,给译码器输入不同质量的先验信息,测量输出的外信息互信息。
% LDPC EXIT曲线仿真框架 EbN0_dB = 3; % 固定信噪比 sigma = sqrt(1/(2*10^(EbN0_dB/10))); IA = 0:0.1:1; % 输入互信息范围 IE = zeros(size(IA)); for i = 1:length(IA) % 根据IA生成先验LLR % 互信息IA和LLR方差的关系:sigma_llr^2 = J^{-1}(IA) sigma_llr = sqrt(2) * erfinv(IA(i)); % 近似 % 生成先验LLR prior_LLR = sigma_llr * randn(n_ldpc, 1) / 2; % 加信道LLR channel_LLR = 2 * rx_symbol / sigma^2; % LDPC译码(一次迭代) % 计算外信息LLR extrinsic_LLR = ldpc_decode_one_iteration(prior_LLR, channel_LLR, H); % 估计输出互信息 IE(i) = estimate_mutual_information(extrinsic_LLR); end % 画EXIT曲线 plot(IA, IE, 'b-', 'LineWidth', 2); hold on; plot(IA, IA, 'k--'); % 对角线 xlabel('输入互信息 I_A'); ylabel('输出互信息 I_E');estimate_mutual_information函数用直方图法估计互信息,核心是把 LLR 的值分桶,统计每个桶里的比特是 0 还是 1 的比例,然后按互信息公式计算。这个估计需要足够多的样本,一般每个信噪比点跑 1000 帧以上。
5.3 用 EXIT 图判断级联码的匹配程度
把 LDPC 的 EXIT 曲线和 BCH 的 EXIT 曲线画在同一张图上。BCH 是硬判决译码器,它的 EXIT 曲线是一条从 (0,0) 到 (1,1) 的曲线,形状取决于 BCH 的纠错能力。如果 LDPC 的曲线在 BCH 曲线的上方,两者之间的“隧道”是开放的,迭代译码可以收敛到零误码;如果两条曲线相交,隧道关闭,存在误码地板。
这个方法的实用价值在于:当你调整 LDPC 和 BCH 的码率分配时,不用每次都跑完整的 BER 仿真,只需要画 EXIT 图看隧道是否开放。隧道开放的最小信噪比就是级联码的收敛门限,和 BER 仿真得到的门限应该一致。如果两者不一致,说明 BER 仿真里的迭代次数不够,或者 EXIT 图的假设条件不满足。
我自己的习惯是:先用 EXIT 图快速筛选参数组合,把隧道开放的组合挑出来,再跑 BER 仿真确认。这样能把参数扫描的时间从几天压缩到几个小时。EXIT 图不是万能的,它假设译码器的外信息服从高斯分布,对于短码或者高码率的情况这个假设不太成立,这时候 EXIT 图只能做定性参考,最终还是要靠 BER 仿真。
希望帮到你。
本文还有配套的精品资源,点击获取