
简介极化码在高斯信道下的CA-SCL译码算法MATLAB实现面向通信、电子信息工程及数学等相关专业学生的课程设计、期末大作业与毕业设计。代码提供完整可运行的仿真框架支持MATLAB 2014/2019a/2024a通过参数化编程方式方便修改码长、信噪比等关键参数注释详细适合新手快速上手。压缩包内共17个文件以m脚本为主包含极化编码、AWGN信道、CRC附加与校验、路径度量计算、CA-SCL译码等核心模块另附fig与png便于查看波形及绘图结果cpp与mexw64用于加速似然比计算。代码附带可直接运行的案例数据替换数据即可验证算法性能帮助理解信道极化与列表译码原理。资源包仅57KB轻量易用已有132人学习下载是研究极化码译码技术的高性价比入门工具。1. 极化码CA-SCL译码算法在高斯信道下的验证路径极化码是第一个被证明容量可达的构造性信道编码5G 的 eMBB 控制信道里已经用上 CA-SCL 这种“CRC 辅助 列表搜索”的译码算法。实际做链路验证时AWGN 信道是第一个要过的关口LLR 有解析表达式误块率曲线可以和理论界对照排错也比衰落信道直观。这个标题讲的正是“在高斯信道下把 CA-SCL 译码算法用 MATLAB 跑通并测出误块率”的完整链路覆盖编码、BPSK 调制、加噪、LLR 计算、SCL 列表搜索和 CRC 选路六段。对刚接触信道编码的人来说极化码的难点往往不是原理而是把递归译码器改成列表译码器时“每条路径的度量怎么累加、分裂后怎么裁剪”这些工程细节对有经验的通信工程师来说噪声方差换算和 CRC 位数选择这类小参数反而最容易让两套实现得到差 0.3 dB 的结果。下面沿一条最小可复现的链路展开先立理论再给代码骨架最后落在参数权衡和加速技巧上遇到坑的地方会直接点出来。2. 高斯信道下CA-SCL译码算法的原理与路径度量2.1 从SC到SCL极化码译码算法的列表搜索SC 译码器按比特顺序逐个硬判前一个比特判错会沿递归结构向后扩散中短码长下误块率曲线很难压下去。SCL 的做法是每遇到一个信息位就把路径分裂成两条分别假设该位为 0 和 1然后只保留度量最好的 L 条继续往下走最后一次从 L 条完整候选里挑一条作为输出。CA-SCL 的“CA”就是在 SCL 之上叠一个 CRC编码前给 K 位信息追加 crcLen 位 CRCSCL 译到最后一层后先对 L 条完整候选做 CRC 校验再在通过的路径里选路径度量最优的一条。这里要特别注意一个容易混的点极化码编码输入的实际信息位数量是 KcrcLen不是 K。信息位集合 A 的尺寸、信道编码速率、以及最后算误块率时的“有效信息速率”是三套数字分别对应不同用途。SCL 的复杂度优势来自路径数量被限制在 L。每次信息位分裂后候选最多 2L 条排序后截断到 L 条整体复杂度大致是 O(L·N·logN)N 为码长。L1 时退化为 SCL 越大越接近最大似然译码但增益递减这个趋势到第 4 章会专门展开。2.2 高斯信道下的LLR初始化与路径度量PM的递推先固定调制。BPSK 映射把码字 c 变成 x1-2c接收端 yxnn 是零均值、方差 σ² 的高斯噪声σ² 与单边功率谱密度 N0 的关系是 σ²N0/2。接收 LLR 为alpha 2y / σ²设每符号能量 Es1则 Es/N0 1/N0于是 σ²1/(2·10^(EsN0dB/10))若曲线横轴用 EbN0则 Es/N0 R·Eb/N0换算为σ² 1 / (2·R·10^(EbN0dB/10))其中 R 按横轴定义取 K/N 或 (KcrcLen)/N。两种定义会让整条误块率曲线平移约 10·log10(K/(KcrcLen)) dB这部分在第 4 章再具体算。路径度量 PM 定义成“累计惩罚”越小越好。精确递推是PM_i PM_{i-1} log(1 exp(−(1−2u_i)·alpha_i))其中 u_i 是该路径在当前比特假设的取值。实际 MATLAB 实现里几乎不会用 log 和 exp而是用 min-sum 近似如果 u_i 与当前 LLR 的硬判一致惩罚为 0否则惩罚加 |alpha|。写成可复现的函数function pm updatePm(pmIn, alpha, uHat) pHard double(alpha 0); % alpha0 判为 0alpha0 判为 1 errBit (uHat ~ pHard); % 假设值是否与硬判相反 pm pmIn errBit .* abs(alpha); % 相反则累加 |alpha| end代码把 pmIn、alpha、uHat 都当作行向量一次算完一整组候选路径的 PM 更新。注意 pHard 来自 alpha 的符号和调制映射严格绑定上面定义里 LLR 为正对应发送比特 0负对应发送比特 1。若把 x 的映射写反PM 递推和最后候选排序会整体取反但误块率曲线形状仍然正常只有逐比特对照时才发现高位全错这是最容易被漏掉的错误。2.3 SCL列表剪枝每比特后只保留L条信息位分裂后候选变成 2L 条需要按 PM 从小到大排序再截断。冻结位不分裂直接按硬判扩展路径。常见做法是一次性把 2L 条分支的 PM 全部算出来再排序取前 L 条不要在递归调用里逐条比较后再决定MATLAB 的向量化在批量计算上的优势远大于手动循环。剪枝保留的是“PM 最小的 L 条路径”这一步不依赖信道状态信息因此也被称为无偏剪枝。也能用带阈值的提前剪枝某条路径 PM 明显大于当前最小 PM 就直接丢弃。工程上我一般不做绝对阈值因为阈值和信噪比强相关换一个 EbN0 点就要重新标定省下来的时间大概率不够填调参的坑。列表数量不大时直接排序截断就是最稳妥、最不容易写错的选择。3. 用MATLAB实现极化码CA-SCL译码算法的最小链路3.1 工程文件划分与关键参数表一条可复现的 CA-SCL 链路我习惯拆成 5 个文件主脚本控制蒙特卡洛循环polar_encode.m 做极化码编码awgn_llr.m 负责接收和 LLR 计算scl_decode.m 做列表译码并返回 L 条候选crc_utils.m 负责 CRC 追加和校验。模块拆开之后误块率统计、单帧调试、性能剖析可以各自独立进行排查问题时不用从头跑一遍。编码前的参数可以先对照这张表定清楚参数符号典型值说明码长N256必须是 2 的幂有效信息位数K128实际承载的用户比特CRC 位数crcLen8决定错误漏检概率列表大小L16路径数越大越接近 ML调制方式BPSK1 bit/符号AWGN 下 LLR 最简洁EbN0 范围EbN0dB1:0.5:3覆盖 SC 和 CA-SCL 的分水岭信息位集合 A 可以用高斯近似预先计算也可以直接查一张 256 长的可靠度排序表关键是 A 的编号必须和代码里生成矩阵 G 的构造顺序一致。下面生成矩阵用 kron(G,F) 自底向上堆叠那 A 也必须按同一套编号定义混用不同文献的索引表是复现代码时最常见的翻车点。3.2 主脚本与编码器核心代码先给可运行的主循环骨架% main_polar_ca_scl.m N 256; K 128; L 16; crcLen 8; EbN0dB 2.0; R K / N; % 横轴按 K 个有效信息比特定义 sigma2 1 / (2 * R * 10^(EbN0dB / 10)); % 噪声方差 A designInfoBits(N, K crcLen); % 高斯近似计算信息位集合 fz setdiff(1:N, A); % 冻结位集合 info randi([0 1], 1, K); u crcAppend(info, crcLen); % 追加 CRC 后长度 KcrcLen c polarEncode(u, A, N); % 码字长度 N x 1 - 2*c; % BPSK 调制 y x sqrt(sigma2) * randn(1, N); % AWGN 信道 alpha 2*y / sigma2; % LLR list sclDecode(alpha, A, fz, L); % 得到 L 条候选路径 out crcSelect(list, crcLen); % 通过 CRC 的路径里选 PM 最小者sigma2是每维噪声方差和单边功率谱密度 N0 的关系是 sigma2N0/2所以代码里完全不出现 N0 这个变量避免和 LLR 公式里的 2 混淆。RK/N表示横轴 Eb 按有效信息比特定义若你想把 CRC 也算作信息比特R 要换成 (KcrcLen)/N两条曲线的相对关系见 4.2 的换算公式。polarEncode的最小实现如下function c polarEncode(u, A, N) n log2(N); F [1 0; 1 1]; G 1; for j 1:n G kron(G, F); % 生成矩阵顺序必须与 A 一致 end x zeros(1, N); x(A) u; % 信息位放 u冻结位保持 0 c mod(x * G, 2); % 线性变换得到 N 位码字 end生成矩阵用 kron(G,F) 逐级扩展冻结位固定为 0。designInfoBits 和 sclDecode 是工程里最长的两个部分前者约 40 行后者递归部分约 120 行designInfoBits 可以用高斯近似对每个子信道计算可靠性度量取最大的 KcrcLen 个位置构成 A。crcAppend 和 crcSelect 用移位寄存器实现发送端对信息序列做模 2 多项式除法余数附在末尾接收端对每条候选路径重算相同的校验值丢弃不匹配路径。3.3 SCL递归译码器的列表数据结构SCL 递归每一层维护三样东西路径对应的部分信息位序列 uList、每条路径当前的 PM、以及递归中要传下去的 LLR。推荐直接用数值矩阵而不是结构体数组uList 是 L×m 的 0/1 矩阵pm 是 1×L。信息位分裂时用 repmat 复制路径再批量调 updatePm% sclDecode 中信息位分裂的一段 u2 repmat(uList, 2, 1); % 每条父路径复制两份 newBit [zeros(L, 1); ones(L, 1)]; % 前半补 0后半补 1 u2 [u2, newBit]; % 路径序列扩展一列 pm2 updatePm(repmat(pm, 1, 2), ... repmat(alphaCurrent, 1, 2), ... [zeros(1, L), ones(1, L)]); [~, idx] sort(pm2); % 按 PM 升序 keep idx(1:L); uList u2(keep, :); pm pm2(keep);uList是 L×mpm是 1×LalphaCurrent是该比特位置上每条路径各自的 LLR长度也是 1×L。repmat(pm,1,2) 把父路径的 PM 复制成 1×2LnewBit 的前 L 个 0 和后 L 个 1 正好对应复制出的前半段和后半段。注意 updatePm 里的 errBit 依赖 newBit 与 alpha 符号的一致性这条约定必须贯穿整个译码器。冻结位处理更简单直接按当前 LLR 硬判扩展 uList不增加候选数量pm 保持不变。4. 列表大小L和CRC长度对极化码误块率的影响4.1 L8、16、32增益递减与算力权衡列表大小是 CA-SCL 最直接的旋钮。以 N256、K128、crcLen8、BPSK 的典型配置为例相对趋势如下表不同实现会有差异但规律一致列表大小 L相对 L8 的 BLER 改善译码耗时相对值81×基准1.016约 0.3~0.5×约 1.8~2.232约 0.1~0.2×约 3.2~3.8L 翻倍在低信噪比区间增益明显高信噪比下主要影响错误地板但 L 从 16 到 32 的改善远小于从 8 到 16。原因是当 L 已经能覆盖“真正正确路径”时继续加路径只是在重复枚举同一条正确路径周围的错误序列。做蒙特卡洛仿真时我一般先在 L8 上跑通链路确认曲线趋势后再升到 16 或 32不要一上来就跑 L32参数设错时一次仿真要跑几个小时才能发现。若目标是看性能上界可以用 L128 跑一次小样本估算“天花板”再回来选一个性能和耗时都可接受的 L。4.2 CRC长度怎么选码率损失与漏检概率CRC 的作用是帮 SCL 在 L 条候选里挑“PM 不是最小但确实正确”的那条。CRC 太短错误路径恰好通过校验的概率高CRC 太长有效信息速率下降增益可能被码率损失抵消。经验配置是 N256 附近用 CRC-8N≥512 或要求更低误码地板时用 CRC-16。8 位 CRC 的漏检概率大约在 2^-8 量级16 位到 2^-16 量级注意这里说的是“错误帧被误判为正确的概率”不是误块率本身。码率损失这样算编码输入长度变成 KcrcLen信道编码速率变成 (KcrcLen)/N但有效信息速率仍是 K/N。例如 N256、K128、crcLen8两个速率的差异对应lossDb 10 * log10(K / (K crcLen));算出来约 -0.26 dB。也就是说如果把 CRC 位也算进横轴对应的信息比特里曲线会比按 K 定义的有效信息比特横轴虚高 0.26 dB。同一个译码器画出来的曲线不同不代表性能不同只是横轴标尺不一致。4.3 高斯信道仿真里最容易错的三个参数设置第一是噪声方差换算。sigma2 1/(2·R·10^(EbN0dB/10))其中 R 必须和横轴定义一致写错时整体曲线平移但形状不变非常隐蔽。建议把换算公式作为注释挂在主脚本开头每次改码率时同步改 R。第二是信息位集合 A 与生成矩阵顺序不一致。A 来自高斯近似G 来自 kron(G,F)两者编号不一致时编码端和译码端对同一位置的可靠性理解错位表现是误块率在高信噪比下掉不下去。第三是 LLR 符号约定。正负号定义必须贯穿 BPSK 映射、PM 累加、CRC 选路三处任何一处取反都会得到“看起来能跑、结果全错”的链路。5. 让MATLAB里的CA-SCL译码算法跑得更快一点5.1 用 mink 替换 sort 做路径修剪递归每一层都要从 2L 条候选里选 L 条sort 的复杂度是 O(2L·log(2L))mink 只需要 O(2L)。L 较小时差别不大L32 开始变得可观。替换只需要一行[pm, idx] mink(pm2, L); uList u2(idx, :);mink 从 R2018a 开始可用要求兼容旧版本时可以保留 sort。另一个等价写法是“先全部展开再剪枝”也就是第 3.3 节的做法而不是逐层只保留 L 条再进下一层两者最终候选集合等价但前者向量化更整齐运行效率反而更高。5.2 单帧调试固定随机数和断点回放把rng(2024)固定在主脚本开头蒙特卡洛循环里每次加噪前再rng(i)这样任一帧出错都能用相同索引的接收向量完整复现。调试时在 sclDecode 入口保存 alpha 和 A 到 .mat 文件出错帧直接读文件单步跟踪不需要重跑整个仿真循环。对递归函数在“信息位分裂”和“冻结位扩展”两个分支各打一个断点观察 uList 的尺寸是否按 L → 2L → L 变化能快速定位列表管理问题。绝大多数“结果不对”的情况在跟踪两次分裂后就能看出是排序方向反了还是 newBit 和 alpha 顺序对不上。5.3 路径排序里隐藏的结构化加速当 L 固定时2L 条候选来自 L 对“同父分支”可以先对每一对取局部最小值再对 L 个局部最小值排序最后补上对应的次小值。这样每层比较次数压缩到约 2L 量级作为练习很适合实际收益要看 MATLAB 的 JIT 是否把循环优化到位。更省事的优化是把所有父路径的分裂、PM 更新、mink 放在一层完成避免在每比特里写 for 循环这也是 3.3 代码强调向量化的原因。把列表数据结构从 struct 换成纯数值矩阵后L32 的单帧耗时常能再下降三分之一左右。本文还有配套的精品资源点击获取