EXIT_TURBO:Turbo码迭代收敛分析与EXIT图仿真指南
发布时间:2026/10/1 10:59:56来源:尧图网络
简介这是一份围绕Turbo码EXIT图迭代分析的开源学习与仿真资源包面向无线通信、纠错编码方向的研究人员、工程师以及通信专业高年级学生聚焦Turbo码原理、SISO迭代译码与EXIT互信息分析适合需要从理论走向仿真验证的读者。压缩包共43个文件大小3.89MB以MATLAB脚本15个.m、仿真数据14个.mat、参考论文10个.pdf和可视化图形4个.fig为主代码覆盖RSC编码、交织、LLR生成、BCJR/Log-MAP迭代译码、EXIT曲线计算与绘制、迭代轨迹追踪等关键环节。已有253人学习下载。包内不仅提供了可用于计算互信息直方图的工具函数还附带了不同信噪比与码率条件下的EXIT性能图和对应轨迹数据并结合多篇经典论文帮助读者对照理解。通过运行这些程序可以深入观察迭代译码的收敛行为优化交织器与码率设计是一份兼具教学与科研参考价值的完整实践资料。1. EXIT_TURBOTurbo 码迭代解码收敛性分析的完整工具箱压缩包名字里连着一串“turbo_turbo_turbo”但里面装的东西并不玄乎。EXIT_TURBO 是一套围绕 Turbo 码 EXIT 图外信息转移图的迭代分析工具核心产出是两条外信息转移曲线外加一条迭代解码轨迹。调试 Turbo 码最折磨人的地方在于单看 BER 曲线你只能看见“不降了”看不见为什么不降。EXIT_TURBO 把每次迭代交换的外信息量化成互信息曲线相当于把迭代解码这个黑匣子打开直接回答三个问题——这个信噪比下能不能收敛、要迭代多少次才能走出错误平台、改哪个参数能最快打开收敛隧道。适合正在做信道编码课程设计、Turbo 码论文仿真或者给迭代解码系统定收敛门限的工程师照着复现。2. Turbo 码迭代解码为什么必须用 EXIT 图从收敛问题到外信息转移曲线2.1 迭代解码的收敛问题为什么 BER 曲线看不出来Turbo 码的译码器由两个 RSC递归系统卷积分量译码器组成中间夹着一个交织器。迭代解码时分量译码器 1 输出的外信息经过交织变成分量译码器 2 的先验输入分量译码器 2 的外信息再反交织回来作为分量译码器 1 下一次迭代的先验。这个循环里真正被交换的“商品”是外信息不是硬判决比特。实际问题在于同一套 Turbo 码在某个 SNR 区间内增加迭代次数不一定能换来 BER 下降甚至会出现 BER 平台——多迭代几十次误码率纹丝不动。从 BER 曲线上看这只是一个“曲线平了”的现象从迭代解码内部看是两个分量译码器之间的外信息交换停止增长进入了“互锁”状态。要诊断这种状态必须把每一次迭代交换的外信息量化出来而不是只看最终判决结果。EXITExtrinsic Information Transfer图就是干这个的。它把分量译码器看成一个软信息处理单元输入是带先验信息的 LLR 序列输出是外信息 LLR 序列用互信息来度量输入和输出各自携带了多少信息比特。横轴是输入先验互信息纵轴是输出外信息互信息一条曲线就是分量译码器在某个信道 SNR 下的“外信息转移特性”。2.2 EXIT 曲线的数学定义互信息、一致性与 J 函数先把符号定下来。对一个分量译码器输入有三路系统位信道 LLR、校验位信道 LLR、来自另一个分量译码器的先验 LLR。输出的外信息 LLR 记为 L_e。衡量这些 LLR 质量的标准是它与对应比特 X 之间的互信息I_A I(X; L_a)I_E I(X; L_e)其中 I_A 是横轴先验互信息I_E 是纵轴外信息互信息。对一个确定的 LLR 序列直接用直方图估计互信息当然可以但 EXIT 分析里常用一个更强的假设在迭代稳定后LLR 分布近似满足对称性和一致性。对称性指的是 p(l | X1) p(-l | X-1)一致性指的是均值和方差满足 μ σ²/2。在这个假设下互信息只需要一个期望式就能算出来I 1 - E[ log₂(1 e^{-l·x}) ]这就是蒙特卡洛互信息估计的理论基础。它不需要分 bin 统计联合分布直接对样本平均数值上稳定得多。后面第 3 章的代码就按这个式子写。对于先验 LLR 的生成也需要一致性高斯分布。给定目标互信息 I_A需要反解出高斯分布的 σ。这个映射关系就是 J 函数J(σ) I(L; X)其中 L ~ N(σ²/2, σ²)。J 函数本身单调递增σ 从 0 到无穷大J 从 0 到 1。实际仿真中一般不直接求解析反函数而是预先把 J 函数做成查找表再用二分或线性插值反查 σ我在 3.3 里给出这套查表代码。2.3 收敛判据解码轨迹、隧道与交点有了分量译码器 1 的 EXIT 曲线 C1 和分量译码器 2 的 EXIT 曲线 C2就能预测整个迭代解码的行为。注意一个关键点交织器不改变外信息的统计分布所以两个分量译码器配置相同时C1 和 C2 是同一族曲线C2 画在 C1 的坐标系里就是 C1 关于 45 度对角线镜像后的曲线。迭代解码的轨迹可以这样追踪第一次迭代时分量译码器 1 没有先验所以 I_A1 0从曲线 C1 的左端点出发得到 I_E1这个 I_E1 交织后成为分量译码器 2 的先验互信息 I_A2于是在 C2 曲线上找到对应的 I_E2再作为下一轮 C1 的先验。画在图上就是一条在 C1 和 C2 两条曲线之间往返的阶梯状折线。收敛判据很直观如果两条 EXIT 曲线之间存在一个竖直方向的“隧道”解码轨迹就能沿着隧道一路爬向 (1, 1) 附近代表外信息越换越多最终收敛到低误码率如果两条曲线相交且交点不在 (1, 1) 附近轨迹就会被困在交点处外信息不再增长对应 BER 平台。这就是为什么 EXIT 图能提前预判收敛行为而 BER 仿真不能——它不需要跑完整个迭代过程只需要两条静态曲线。3. 用 EXIT_TURBO 跑通最小仿真从 RSC 编码器到 EXIT 曲线3.1 准备分量码和交织器RSC 编码器的表驱动实现EXIT 仿真的最小系统只需要一个 RSC 分量码、一个随机交织器、一个 BCJR 解码器。分量码选最经典的 (7, 5) 八进制 RSC约束长度 K3反馈多项式 71DD²前向多项式 51D²。EXIT 曲线对交织器的具体样式不敏感随机交织即可但帧长要足够长否则有限码长效应会把曲线噪声放大。编码器和 BCJR 解码器都建议用表驱动方式实现预先构建状态转移表和校验位输出表避免每个比特都重新做多项式移位。import numpy as np def build_rsc_tables(K, fb_poly, ff_poly): 构建 RSC 编码网格表 K: 约束长度; 状态数 2^(K-1) fb_poly: 反馈多项式(八进制), 不含常数项参与反馈的写法直接按二进制位来 ff_poly: 前向多项式(八进制) 返回 nxt[s, u] 和 par[s, u], s 为当前状态, u 为输入比特 S 1 (K - 1) fb_taps [1 if (fb_poly (i 1)) 1 else 0 for i in range(K - 1)] ff_taps [1 if (ff_poly (i 1)) 1 else 0 for i in range(K - 1)] ff_in ff_poly 1 nxt np.zeros((S, 2), dtypeint) par np.zeros((S, 2), dtypeint) for s in range(S): reg [(s i) 1 for i in range(K - 1)] # bit i 对应第 i 个寄存器 for u in (0, 1): w_in u for i in range(K - 1): w_in ^ (reg[i] fb_taps[i]) p_bit w_in ff_in for i in range(K - 1): p_bit ^ (reg[i] ff_taps[i]) nxt[s, u] ((w_in 0) | (s 1)) (S - 1) # 新状态 par[s, u] p_bit return nxt, par这里状态用寄存器内容直接编码bit 0 是最靠近输入的寄存器。nxt[s, u] (w_in | (s 1)) (S-1)的意思是新寄存器的 bit 0 写入反馈值 w_in其余位从旧状态左移一位得到。par[s, u]是校验位由当前输入与寄存器组合的线性异或决定。注意前向多项式的常数项ff_in决定当前输入是否直接参与校验位这是 RSC 与普通卷积码容易写错的地方。有了网格表编码就简单了。对一帧信息比特逐位过一遍状态转移输出系统位和校验位末尾补零。注意 EXIT 分析里帧尾不做归零也没关系甚至可以截断网格因为统计的是外信息互信息而不是误码率。3.2 BCJR 解码器外信息从哪里来BCJR 是整个流水线的核心。为了教学清晰我用 max-log 近似版本把前向度量、后向度量里的 log-sum 直接用 max 代替。代价是外信息幅度略偏大趋势与精确 log-MAP 一致对 EXIT 图判断收敛门限没有实质影响。def bcjr_maxlog(L_sys, L_par, L_apr, nxt, par_tab, K): max-log-MAP 分量译码, 返回外信息 L_e L_sys / L_par: 系统位与校验位的信道 LLR L_apr: 先验 LLR (来自另一分量译码器) N len(L_sys) S 1 (K - 1) NEG -1e30 # 反向状态表: prev[s_new][u] [所有能转移到 s_new 的旧状态] prev [[[] for _ in range(2)] for _ in range(S)] for s in range(S): for u in (0, 1): prev[int(nxt[s, u])][u].append(s) # 前向度量, alpha[k][s] alpha np.full((N 1, S), NEG) alpha[0, 0] 0.0 for k in range(N): for s in range(S): if alpha[k, s] NEG / 2: continue for u in (0, 1): ns int(nxt[s, u]) gam (L_apr[k] if u else -L_apr[k]) \ (L_sys[k] if u else -L_sys[k]) \ (L_par[k] if par_tab[s, u] else -L_par[k]) alpha[k 1, ns] max(alpha[k 1, ns], alpha[k, s] gam) # 后向度量, beta[k][s], 不假设帧尾归零, beta[N] 全状态均匀 beta np.full((N 1, S), 0.0) for k in range(N - 1, -1, -1): for s in range(S): for u in (0, 1): ns int(nxt[s, u]) gam (L_apr[k] if u else -L_apr[k]) \ (L_sys[k] if u else -L_sys[k]) \ (L_par[k] if par_tab[s, u] else -L_par[k]) beta[k, s] max(beta[k, s], gam beta[k 1, ns]) # 计算后验对数似然比, 再扣掉先验与信道系统位信息得外信息 L_app np.zeros(N) for k in range(N): num, den NEG, NEG for s in range(S): for u in (0, 1): ns int(nxt[s, u]) gam (L_apr[k] if u else -L_apr[k]) \ (L_sys[k] if u else -L_sys[k]) \ (L_par[k] if par_tab[s, u] else -L_par[k]) val alpha[k, s] gam beta[k 1, ns] if u 1: num max(num, val) else: den max(den, val) L_app[k] num - den return L_app - L_apr - L_sys这段代码的逻辑是标准的前向从 0 状态出发递推后向从等概率状态出发反向递推最后把后验 LLR 分解为“先验 信道系统信息 外信息”三部分返回第三部分。分支度量gam的三个分量分别对应先验 LLR、系统位信道 LLR、校验位信道 LLR符号由比特值决定。一个值得注意的简化beta[N, :] 0.0表示帧尾没有归零约束各状态等概率回推。如果实际编码器做了尾归零这里应该把 beta[N, 0] 置 0、其余置 NEG不然尾部几比特的外信息会被污染。EXIT 曲线对帧中间比特的外信息统计敏感度低但为了干净我建议仿真用同一约定编码器不归零解码器也不假设归零。3.3 先验 LLR 生成与互信息估计EXIT 曲线的两个核心函数EXIT 扫描的每一个点都对应一个目标 I_A。需要生成一批先验 LLR它们的互信息恰好等于该 I_A然后喂给 BCJR 得到外信息序列再估计外信息互信息 I_E。两个关键函数J 函数查表和互信息估计。def build_j_lut(sigma_max12.0, points20001): 预计算 J(sigma) 查找表: J I(L; X), L ~ N(sigma^2/2, sigma^2) 用数值积分直接算 J(sigma) 1 - E[log2(1exp(-l*x))] sigmas np.linspace(0, sigma_max, points) js np.zeros(points) for i, sg in enumerate(sigmas): if sg 1e-9: js[i] 0.0 continue x np.linspace(-12*sg, 12*sg, 3000) px np.exp(-(x - sg*sg/2.0)**2 / (2*sg*sg)) / np.sqrt(2*np.pi*sg*sg) js[i] 1.0 - np.sum(px * np.log2(1.0 np.exp(-x))) * (x[1] - x[0]) return sigmas, js def gauss_llr_from_IA(IA, size, sigmas, js): 反查 J 表得到 sigma, 生成满足一致性条件的先验 LLR if IA 0: return np.zeros(size) if IA 1: return np.full(size, 30.0) sigma np.interp(IA, js, sigmas) # 注意: interp 要求 js 单调增, 而 sigmas 作为纵坐标 mu sigma * sigma / 2.0 return mu np.random.randn(size) * sigma这里有个细节容易翻车np.interp(IA, js, sigmas)是把 js 当自变量、sigmas 当因变量做反查要求 js 严格单调。数值积分出来的 J 表在 σ 接近 0 和接近上限时会有轻微非单调抖动所以建表时 σ 从 0.001 起步IA 也限制在 0.02~0.98 区间超出范围直接钳位。互信息估计用对称期望式比直方图法稳定得多def estimate_MI(L, bits_pm): bits_pm: 1/-1 序列; L: 对应 LLR 在对称一致性假设下, MI 1 - E[log2(1exp(-L*bits))] x np.clip(-L * bits_pm, -50, 50) # 防 exp 溢出 return 1.0 - np.mean(np.log2(1.0 np.exp(x)))x裁剪到 ±50 是为了避免exp(50)溢出成 inf。注意这个公式只在分布满足对称一致性时准确BCJR 输出的外信息在高 SNR 下基本满足这个条件。3.4 整条 EXIT 曲线的扫描与绘图万事俱备主扫描循环就是把 3.1~3.3 串起来。一个典型的扫描参数组合帧长 N_frame2048每个 IA 点跑 300 帧IA 网格从 0.05 到 0.95 步长 0.05。def scan_exit_curve(EbN0_db, N_frame2048, frames300, ia_gridNone): if ia_grid is None: ia_grid np.arange(0.05, 0.96, 0.05) K, fb, ff 3, 0b111, 0b101 nxt, par build_rsc_tables(K, fb, ff) sigmas, js build_j_lut() # BPSK AWGN: Es1, R1/2, 所以 sigma^2 2 / (Eb/N0 线性值) ebno_lin 10 ** (EbN0_db / 10) sigma_n np.sqrt(2.0 / ebno_lin) ie_vals [] for ia in ia_grid: ie_sum 0.0 for _ in range(frames): info_bits np.random.randint(0, 2, N_frame) # 编码 交织 (这里用同一个随机交织, EXIT 对交织器不敏感) interleaver np.random.permutation(N_frame) sys1, par1 rsc_encode_bits(info_bits, nxt, par) sys2, par2 rsc_encode_bits(info_bits[interleaver], nxt, par) # 加噪声, 生成信道 LLR x1 1.0 - 2.0 * np.array(sys1); x2 1.0 - 2.0 * np.array(sys2) y1 x1 sigma_n * np.random.randn(N_frame) y2 x2 sigma_n * np.random.randn(N_frame) L_c 2.0 / sigma_n**2 L_sys1 L_c * y1; L_par1 L_c * y2 # 目标 IA 的先验 LLR L_apr gauss_llr_from_IA(ia, N_frame, sigmas, js) L_e bcjr_maxlog(L_sys1, L_par1, L_apr, nxt, par, K) bits_pm 1.0 - 2.0 * np.array(info_bits) ie_sum estimate_MI(L_e, bits_pm) ie_vals.append(ie_sum / frames) return np.array(ia_grid), np.array(ie_vals)注意系统位和校验位都用同一个分量译码器这里只扫描分量译码器 1 的 EXIT 曲线。分量译码器 2 的曲线在绘图时用镜像得到。rsc_encode_bits是 3.1 表驱动编码的外层封装把信息比特逐位移入网格表取校验位即可帧尾不补零。扫描完成后画图import matplotlib.pyplot as plt ia, ie scan_exit_curve(0.5) # 0.5 dB plt.plot(ia, ie, o-, labelC1) plt.plot(ie, ia, o-, labelC2 mirrored) plt.plot([0, 1], [0, 1], k--, linewidth0.8) plt.xlabel(I_A); plt.ylabel(I_E) plt.legend(); plt.grid(alpha0.3)镜像曲线(ie, ia)就是在同一坐标系下把横纵坐标对调它对应另一个分量译码器在第一次迭代后的外信息转移特性。隧道是否存在就看这两条曲线之间在竖直方向上有没有空隙。4. 从 EXIT 图到参数决策读图方法、门限判定与调参方向4.1 读图三件事隧道、交点与平台区拿到一张 EXIT 图先看三样东西。第一是隧道也就是两条曲线之间的竖直间隙。间隙明显张开说明每次迭代外信息都能稳定增长收敛是大概率事件。第二是交点位置两条曲线在 (1,1) 之外的某个点相交意味着解码轨迹会停在那里交点越高错误平台越难降。第三是轨迹到达 (1,1) 之前要跨多少级台阶——台阶密集说明每次迭代只带来微小增益对应慢收敛。具体操作上迭代次数与台阶数直接对应。如果轨迹走了 10 步还停在 I_A0.7 附近那调大最大迭代次数到 18 次也没什么用因为瓶颈是 EXIT 曲线本身不是迭代预算不够。4.2 用 EXIT 曲线二分找收敛门限EXIT 图最实用的功能是估门限。Turbo 码的收敛门限定义为低于这个 Eb/N0两条 EXIT 曲线闭合成链轨迹到不了 (1,1)高于这个 Eb/N0隧道打开。用二分法扫几组 SNR 就能把门限压到 0.1 dB 精度。lo, hi 0.0, 3.0 for _ in range(6): mid (lo hi) / 2 ia, ie scan_exit_curve(mid, N_frame2048, frames200) tunnel_width (ie[1:] - ia[:len(ie)-1]).min() # 粗略看隧道最小宽度 if tunnel_width 0: hi mid else: lo mid print(fconvergence threshold ~ {hi:.2f} dB)这个脚本只是示意隧道最小宽度的判据要谨慎用。更稳的做法是直接看两条曲线是否相交对曲线1 和镜像曲线2找(ie - ia)的最小值小于某个容差比如 0.02就认为闭合。帧数和 IA 网格密度直接影响这个容差粗扫描时宁可用 0.05 的阈值只做趋势判断。4.3 调参实例约束长度与多项式如何改变交点EXIT 曲线形状和分量码直接相关这也是参数调优的主要抓手。常见的观察约束长度 K 越大EXIT 曲线越陡意味着少量先验就能换来大量外信息增益隧道更容易打开。代价是 BCJR 状态数按 2^(K-1) 膨胀仿真时间急剧上升。反馈多项式不同曲线在低 IA 区的起点位置会变。起点越高第一次迭代就能获得越多的外信息这对低 SNR 场景最有利。两个分量码多项式做得不对称时两条 EXIT 曲线不再互为镜像隧道形状会偏离理想情况。有时刻意不对称能压低交点位置换取出更均匀的收敛行为但大多数课程设计不需要这层优化。调参后的验证方式不是直接跑 BER而是先重扫 EXIT 曲线看隧道是否改善再挑 2~3 个 SNR 点跑 BER 对照。这样一次调参的成本只有几分钟仿真而不是几小时。5. EXIT_TURBO 仿真避坑指南6 个高频翻车现场与排查记录5.1 高 IA 区曲线回折先验生成与信道尺度没对齐现象IA 超过 0.8 后IE 曲线不但不上升反而往下掉出现一个明显的“钩子”。原因这个坑十有八九是gauss_llr_from_IA里反查 σ 出了问题。J 函数表建得不密或者 σ 太大时数值积分的网格步长不够导致反查出来的 σ 偏小先验 LLR 尺度低于目标 IA。另一个常见诱因是信道 LLR 的尺度公式用错BCJR 内部先验和信道信息的权重失调。解决把 σ 上限收紧到 10 左右IA 网格上限设 0.95并且用np.interp(IA, js, sigmas)前先对 js 做去重和单调检查。先验 LLR 生成后可以单独验证一下实际互信息是否与目标 IA 一致偏差超过 0.01 就要查生成函数。5.2 曲线对 SNR 完全不敏感信道 LLR 被重复注入现象0 dB 和 2 dB 扫出来的两条 EXIT 曲线几乎重合只有噪声抖动差异。原因最常见的是系统位和校验位信道 LLR 都用了同一个噪声方差但在某个代码里把系统位的信道 LLR 乘以 2 再叠加进了先验或者 BCJR 的外信息提取时忘了扣掉L_sys导致信道信息被当成外信息返回到对方译码器。表现为外信息里始终包含固定信道增益曲线形状被“焊死”。解决用单帧单步调试法——给 BCJR 输入已知的先验 LLR 和高 SNR 信道 LLR检查输出 L_e 是否与输入 L_apr 在统计上独立递增。再用一个零先验的特例L_apr 0时外信息应该等于信道观测带来的增量此时 IE 应该随 SNR 明显变化。5.3 互信息估计偏高样本数、裁剪与条件期望现象估计的 I_E 时大时小曲线毛毛刺刺甚至出现超过 1 的值。原因np.clip(-L*bits, -50, 50)的裁剪下限太宽时个别异常大的正 LLR 样本会让 log₂(1exp(x)) 变成 0 项少量大样本就能拉高均值造成上偏。另外帧数太少时小概率大 LLR 样本没有被充分采样估计方差很大。解决把裁剪上限从 50 收到 20对教学仿真足够且更抗异常值帧数每点至少 200 帧。如果想要更稳的估计可以退回去按条件分布分别统计E[log2(1exp(-L)) | X1]和E[... | X-1]再平均这样不依赖对称性假设代价是编码时要把 ±1 标签留到估计函数里。5.4 log-MAP 数值溢出与 NaN前向度量没做缩放现象跑到一半 alpha 或 beta 出现 inf 或 NaN曲线直接画不出。原因精确 log-MAP 用 exp/log 运算度量的绝对值随帧长线性增长指数部分会溢出。max-log 版本虽然用 max 代替了 logsum但如果你在gam里用了np.exp或没有对alpha做每步减去最大值的缩放同样会炸。解决教学用 max-log 就不要碰 exp如果确实需要精确 log-MAP在每步递推后把alpha[k1, :]减去该行的最大值再做 logsumbeta 同理。帧长 2048 时溢出概率不大但把编码器改成带尾归零的版本后尾部 beta 的初始值设置不当也会出 NaN检查点放在beta[N]的初始化上。5.5 仿真耗时爆炸复杂度预算没算过现象帧长设了 50000每个 IA 点跑 2000 帧IA 步长 0.01跑了整夜没出结果。原因BCJR 的复杂度是 O(N × 2^(K-1) × 2) 的记忆化递推纯 Python 三重循环的常数很大。帧长 5 万、状态数 16、2000 帧、19 个 IA 点叠加起来是上亿次内层操作瓶颈全卡在 Python 解释器上。解决先算复杂度再开跑。EXIT 分析的标准经验值是 N_frame2048、每点 300~500 帧、IA 步长 0.05这样一条曲线约 10~20 分钟纯 Python。如果嫌慢降帧数到 150曲线略有抖动但门限判断不受影响。再不够就把内层循环换成 Cython、numba 或者直接用 MATLAB 写递推——但别在 Windows 下为了编译扩展去硬碰编译环境后面一条专门讲这个。5.6 Windows 下编译扩展失败cl.exe 或 ld 报错不是你的错现象为了提速安装某个带 C 扩展的 Python 包弹出error: command c:\\users\\...\\cl.exe failed with exit status 2或者collect2.exe: ld returned 1 exit status。原因这类报错几乎都是当前环境缺 MSVC 编译工具链或对应版本的 wheel 包不是你代码的问题。网上大量 Turbo 码仿真都是纯 Python/numpy 或 MATLAB 实现不需要任何编译步骤。解决不要在这个环境硬编。优先用预编译 wheelpip install --only-binary :all: 包名或者直接回到纯 numpy 的实现。非要编译去装 VS Build Tools 并确保与 Python 版本匹配但仍建议把重活放到 WSL 或 Linux 服务器上跑别在桌面环境里浪费一下午。EXIT 仿真本身计算量不大纯 Python 足够完成全部课程设计内容。6. 进阶用 EXIT 图指导系统级设计的三个经验技巧6.1 用 EXIT 曲线预判交织器增益EXIT 图是在无限交织长度假设下推导的所以不同交织器画出的曲线形状几乎一致。但实际系统的交织器长度是有限的迭代解码时外信息的方差会受交织距离影响。我的经验是先用 EXIT 图找候选 SNR 门限再用两种交织器长度比如 1024 和 4096分别跑一次迭代轨迹和 BER差距在 0.3 dB 以内说明交织器不是瓶颈差距明显则说明有限码长效应主导了收敛需要加大交织器。6.2 用迭代器把 SNR 扫描批跑省得手动改参数跑门限搜索时多组 SNR 的 EXIT 扫描完全可以写成生成器惰性求值算完一组存一组避免一次性开太多内存也方便半路查看已有结果def exit_scan_batch(snr_list, frames200): for snr in snr_list: ia, ie scan_exit_curve(snr, framesframes) np.savez(fexit_{snr:.2f}dB.npz, iaia, ieie) yield snr, ia, ie for snr, ia, ie in exit_scan_batch([0.0, 0.5, 1.0, 1.5]): print(snr, tunnel width , float((ie - ia).min()))这段代码本质是一个带边界的迭代器每次迭代完成一个 SNR 点的扫描、落盘、返回下次再从断点继续。相比一次性循环所有 SNR好处是中途 CtrlC 后已算的点不丢调参时能立刻对比已有多条曲线。6.3 与 BER 曲线互相验证EXIT 门限到底可不可信EXIT 图门限不是精确的东西它基于高斯一致性假设实际编码结构会有偏差。我现在的做法是EXIT 说能收敛的 SNR 点跑 BER 仿真时大概率已经脱离错误平台但门限位置往往比实测 BER 瀑布区低 0.2~0.5 dB。所以要验证某个参数改动是否有效应该两套仿真一起看——先跑两分钟 EXIT 判断方向再跑 BER 精确量化。如果 EXIT 说隧道开了但 BER 还平着问题通常出在交织器长度或迭代次数上限上而不是分量码本身。这套流程我现在每个项目都会走一遍EXIT 图已然成了我调 Turbo 码的第一道烟囱测试先确认收敛方向再动手跑大仿真。做信道编码的人都知道迭代解码是最容易“看着收敛、实则困住”的系统一份能复现的 EXIT 工具包比盲目调迭代次数值钱得多。希望这份梳理能帮你在自己的仿真里少走几步弯路。本文还有配套的精品资源点击获取
网站建设高端定制企业官网