简介针对SCMA系统中软判决消息传递算法SD-MPA的MATLAB仿真资源面向无线通信方向的研究生、工程师以及学习非正交多址技术的开发者解决瑞利信道下多用户信号检测与性能评估问题。压缩包共4个文件全部为.m脚本整体仅4KB包含系统仿真主脚本、SD-MPA检测算法、SCMA编码模块以及log-sum-exp数值稳定函数代码结构紧凑适合逐步阅读。已有323人学习可作为理解稀疏编码多址接入原理的入门样例。通过修改迭代次数默认6次等参数可直观对比不同检测轮数下的误码率表现与计算复杂度完整覆盖从编码、发送、瑞利信道到检测译码的仿真链路有助于深入学习MPA消息传递机制和SCMA系统设计要点。1. 四个单词背后SCMA 的检测难题和 SD-MPA 的机会SCMA稀疏码多址的接收机里MPA消息传递算法几乎是默认的检测器但标准 MPA 的收敛速度一直是工程里的老大难。SD-MPA 这类改进思路不改码本、不换信道模型只动消息更新的调度顺序就有机会把达到目标误码率所需的迭代次数压下去这对高过载、低信噪比场景尤其值钱。本文围绕 SCMA 下行/上行链路的检测问题讲清楚 SD-MPA 比标准 MPA 强在哪、代码怎么落、参数怎么调再把仿真里最容易翻车的几个坑挨个点名。适合正在做 SCMA 物理层仿真的同学也适合想把接收机往 FPGA 或并行处理器上搬的工程师——前者关心收敛与误码率后者关心复杂度与定点实现。2. SCMA 检测为什么绕不开 MPA从叠加信号到因子图推理2.1 稀疏叠加模型资源块上究竟叠了几个用户SCMA 和传统 CDMA 最本质的区别在“码本”上。传统 CDMA 是每个用户用一个扩频序列做线性扩频接收端解扩后还能靠正交性或准正交性把用户分开SCMA 则把“扩频 调制”合成一步每个用户不是拿一维星座点乘序列而是从一个多维复数码本里直接选取一个码字。这个码字在一组资源块RE上取值并且设计成“稀疏”的——每个码字只在一小部分资源块上有非零值其余位置是零。常见配置是 4 个资源块、6 个用户或 8 个用户也就是过载率 150% 甚至 200%。资源块数量记为 N用户或层数记为 JN 个资源块上每个资源块被多个用户重叠占用。这一步叠加不是简单的功率相加因为码字本身携带多维调制信息多个用户的码字在同一资源块上线性叠加后再加高斯噪声接收端看到的观测模型是y_r Σ h_{j,r} · c_j(m_j) n_r其中 r 是资源块索引j 是用户索引h_{j,r} 是信道系数c_j(m_j) 是用户 j 的第 m_j 个码字在该资源块上的取值n_r 是复高斯噪声。很多人第一次看 SCMA 都会试着拿 LMMSE 或者 ZF 去做线性检测结果在高过载率下性能惨不忍睹。原因是码本向量之间并不是正交的线性均衡会把噪声放大好几倍更关键的是SCMA 的码字本身就是多维星座接收机真正要估计的是“每个用户选了哪个码字”这是一个离散符号检测问题线性接收机天然吃亏。所以工程界普遍回到最大似然ML的思路但直接穷举 6 个用户、每个用户 4 种码字组合数是 4 的 6 次方即 4096 种放在 N4 的资源块模型里还能忍稍微扩到 J15 就完全不可行。这里需要强调的是稀疏性带来的并不只是“可叠加更多用户”更重要的是它让检测问题的图结构变稀疏了。每个资源块上只有部分用户有非零贡献每个用户也只出现在部分资源块上所以联合检测可以在因子图上用消息传递来做而不是对全体用户做联合枚举。这就是 MPA 能成为 SCMA 主流检测方案的根本原因——它不是近似而是把联合后验分解成可计算的局部乘积。2.2 因子图建模变量节点、资源节点与积和算法把 SCMA 检测问题画成因子图节点分两类。变量节点对应每个用户或层的符号取值资源节点对应每个资源块的观测。变量节点和资源节点之间只在“该用户在该资源块上有非零码字取值”时连边。因为码本稀疏平均每个资源块只连 2 到 3 个用户每个用户也只连 1 到 3 个资源块图整体非常稀疏这是 MPA 能落地的结构前提。因子图上的消息传递基于积和算法。消息的本质是“一方对另一方状态的概率估计”。两类消息交替更新一类是从变量节点发给资源节点表示该用户符号取各码字的当前可信度另一类是从资源节点发给变量节点表示该资源节点基于自身观测和来自其他用户的先验信息对这个用户的符号做出的判断。每一轮迭代信息在图上来回传一遍误差逐渐被压缩最后每个变量节点汇总所有相邻资源节点给出的消息乘上先验就得到该用户每个码字的后验概率。实际工程里几乎都用对数域实现也就是 log-MPA。原因是概率乘法在对数域变成加法并且在低信噪比下概率值会小到浮点数下溢对数域可以稳定放大动态范围。资源节点更新时对除了目标用户以外的所有相连用户符号做边缘化求和这是 MPA 里最重的计算。但如果每个资源块只连 df 个用户消息更新的复杂度就是 M 的 df 次方而不是 M 的 J 次方。这就是稀疏性的价值。因子图建模这一步特别容易出现“图连错”的问题。代码里如果用手写数组去定义连接关系很容易把码本中的零位置也当成有效连接或者在用户索引上差一位导致消息在错误路径上更新。常见做法是直接从码本的非零项生成连接关系不要手写边表这样能少踩一个隐蔽的坑。2.3 MPA 迭代在算的到底是什么外信息与后验概率MPA 每一轮迭代做的其实就三件事资源节点接收变量节点的消息并更新自己的输出消息变量节点接收资源节点的消息并更新自己的输出消息判断是否收敛如果相邻两轮的消息差小于阈值就提前退出。关键是“外信息”这个概念资源节点发给用户 j 的消息计算时要把用户 j 自己发给这个资源节点的消息排除掉否则就等于用自己的观点强化自己迭代会假性收敛。用 log-MPA 来看变量节点发给资源节点的消息是该用户所有其他资源节点消息之和加上先验。资源节点发给变量节点的消息是用高斯条件概率对除该用户以外所有可能符号组合做求和再经过 max 或 log-sum-exp 近似。最终汇总时把该用户所有资源节点的 r2v 消息加起来得到的软信息就近似于后验对数概率。要转成比特 LLR再把每个码字对应的比特组合做边缘化。逻辑上值得注意的是MPA 给出的是软输出不是硬判决。这意味着它可以很方便地级联信道译码器把每个比特的 LLR 送给 LDPC 或 Turbo 译码器译码器返回的外信息再作为下一次 MPA 迭代的先验。这个特性正是第 6 章联合迭代的基础。标准 MPA 的问题不在于算不对而在于要迭代多少次才算得够。消息在因子图上传播需要时间低信噪比时消息更新幅度小收敛慢高过载时节点之间耦合强可能出现消息振荡也就是相邻两轮迭代结果反复横跳。这时候就轮到 SD-MPA 出场了。3. 从标准 MPA 到 SD-MPA标准差调度改在哪个环节3.1 标准 MPA 的两个痛点收敛慢与消息振铃先看标准 MPA 最常见的两种调度方式。并行调度flooding schedule每一轮同时更新所有资源节点和所有变量节点实现最简单但在消息还没稳定时所有节点一起变收敛速度受限于图直径。串行调度serial schedule每一轮按固定顺序逐个更新节点刚更新完的节点消息立刻被后面的节点使用信息传播快一轮收敛通常比并行快但顺序固定对信道和码本的状态无感知。实际仿真里会碰到两个让人挠头的问题。第一个是低信噪比下消息更新幅度很小迭代初期每一轮的变化都是“毛毛雨式”的要跑到第 5、6 轮才明显收紧第二个是到迭代后期某些资源节点的消息在相邻两轮之间出现明显振荡——这一轮更新让它往一个方向偏下一轮更新又被拉回来像打摆子。两个问题叠加标准 MPA 的迭代次数被迫设到 8 轮甚至 10 轮每轮资源节点更新都是指数级复杂度的计算总开销很可观。如果仔细追踪每个资源节点的消息变化曲线会发现“振幅”差异很大。有的节点在第二轮就基本稳定了有的节点到第六轮还在剧烈抖动。固定调度对这两种节点一视同仁既浪费了稳定节点的计算也没有给振荡节点足够的“照顾”。这就像优化问题里对所有维度用同一个学习率收敛自然慢。SD-MPA 的核心就是把这一步改成动态的根据消息的抖动程度决定下一次优先更新谁。3.2 SD-MPA 的 3 个关键改动标准差度量、调度阈值、串行并行切换第一个改动是定义一个衡量消息“是否稳定”的统计量。常见做法是取某个资源节点在最近一轮更新中发出的全部消息计算它们的标准差。标准差大说明该节点刚刚发出的消息之间差异很大还在快速变化中理应被优先处理标准差小说明消息已经趋于一致或收敛再更新它意义不大。这里的“消息”可以取对数域的 LLR 值也可以取概率域的归一化概率工程上更推荐用对数域因为概率域在接近 0 或 1 时数值变化不敏感。第二个改动是引入调度阈值 tau。每一轮更新结束后对所有资源节点计算标准差排序后取标准差最大的前 ceil(tau * N) 个节点下一轮只对这些节点做串行更新其余节点保持上一轮的结果。tau 太小会让聚焦范围过窄很多仍在振荡的节点没被选上tau 太大则退化成接近全量更新失去自适应调度的意义。经验范围一般在 0.3 到 0.5 之间具体取值和码本结构、用户数有关。第三个改动是迭代阶段的切换。迭代早期各节点刚开始交换信息标准差普遍偏大这个阶段适合用近似并行更新让消息在整个图上快速传播迭代进入中后期一部分节点已经收敛标准差分化明显此时切到基于标准差的串行聚焦更新优先消掉剩余的振荡。实现上不需要复杂判断可以在前 max_iter 的 30% 轮次用并行更新之后每轮按照标准差选焦点节点做串行更新。这一步的复杂度开销非常小。计算每个资源节点消息的标准差只需要对 M 个消息值做一次均值与平方偏差求和复杂度是 O(N·M·df)而资源节点本身的消息更新是 O(N·M^df)当 M 是 4 或 8、df 是 2 或 3 时标准差计算可以忽略不计。真正要小心的是排序如果每次都调 Python 的 sorted 做全排序开销会放大直接用 numpy 的 argsort 处理长度为 N 的数组几乎不占时间。3.3 一个可复现框架Python 里把调度逻辑加进 MPA 主循环下面给一个演示 SD-MPA 核心调度逻辑的 Python 骨架省略了完整码本生成和信道系数生成聚焦在“标准 MPA 消息更新 标准差调度”这一段。import numpy as np def sd_mpa_detect(y, codebook, mapping, sigma2, max_iter8, tau0.4): y: 接收向量形状 (N,)复数 codebook: 码本形状 (J, N, M)零位置表示未占用该资源块 mapping: 列表mapping[r] 为占用资源块 r 的用户索引列表 sigma2: 噪声方差 tau: 调度阈值决定每轮聚焦多少个资源节点 J, N, M codebook.shape # v2r 和 r2v 都存对数域消息初始化为 0均匀先验在log域是0 v2r np.zeros((J, N, M)) r2v np.zeros((J, N, M)) # 把每个用户在每个资源块上的码字列出来方便查表 # user_symbols[j][r][m] 表示用户 j 在资源块 r 上发送第 m 个码字时的复数值 user_symbols codebook # 形状已经对齐 for it in range(max_iter): std_scores [] # 标准 MPA 更新遍历所有资源节点更新 r2v for r in range(N): users mapping[r] # 基于当前 v2r计算资源节点发给每个相连用户的对数域消息 # 公式对除目标用户外所有用户符号做 log-sum-exp 边缘化 for j in users: others [u for u in users if u ! j] log_vals np.zeros(M) for comb in np.ndindex(*([M] * len(others))): # 计算该组合下资源块 r 的期望接收值 expect user_symbols[j][r][:] for k, u in enumerate(others): expect expect user_symbols[u][r][comb[k]] # 高斯对数似然-|y_r - expect|^2 / sigma2 log_lik -np.abs(y[r] - expect) ** 2 / sigma2 # 加上其他用户当前先验消息做 log-sum-exp prior_sum sum(v2r[u][r][comb[k]] for k, u in enumerate(others)) log_vals np.exp(log_lik prior_sum) # 去除自身消息的影响外信息 r2v[j][r] log_vals - v2r[j][r] # 简化未做 max normalize # 统计该资源节点刚更新出来的消息标准差 node_msgs np.concatenate([r2v[j][r] for j in users]) std_scores.append(np.std(node_msgs)) # 变量节点更新把资源消息汇总并减去发送方消息 for j in range(J): connected_r [r for r in range(N) if codebook[j][r].any()] for r in connected_r: total sum(r2v[j][rr] for rr in connected_r if rr ! r) v2r[j][r] total # SD-MPA 调度选出标准差最大的 ceil(tau * N) 个资源节点 focus_count int(np.ceil(tau * N)) focus_nodes np.argsort(std_scores)[-focus_count:] # 对焦点资源节点再做一次串行更新 for r in focus_nodes: users mapping[r] for j in users: others [u for u in users if u ! j] log_vals np.zeros(M) for comb in np.ndindex(*([M] * len(others))): expect user_symbols[j][r][:] for k, u in enumerate(others): expect expect user_symbols[u][r][comb[k]] log_lik -np.abs(y[r] - expect) ** 2 / sigma2 prior_sum sum(v2r[u][r][comb[k]] for k, u in enumerate(others)) log_vals np.exp(log_lik prior_sum) r2v[j][r] log_vals - v2r[j][r] v2r[j][r] sum(r2v[j][rr] for rr in connected_r if rr ! r) # 收敛判断比较两轮之间 v2r 的变化幅度 if it 1 and np.max(np.abs(v2r - v2r_prev)) 1e-4: break v2r_prev v2r.copy() # 汇总后验 LLR每个用户的所有资源消息之和 posterior_llr np.zeros((J, M)) for j in range(J): connected_r [r for r in range(N) if codebook[j][r].any()] posterior_llr[j] sum(r2v[j][r] for r in connected_r) return posterior_llr这段代码的逻辑分三块。第一块是标准资源节点更新核心是对“其他用户所有可能符号组合”做边缘化计算高斯对数似然并累加先验消息第二块是变量节点更新把用户相连资源节点的消息加起来并减掉发给当前资源节点的自身消息保证传递的是外信息第三块是 SD-MPA 的调度逻辑先算出每个资源节点的消息标准差再选标准差最大的节点做一轮额外的串行更新。代码里要注意两个关键点。第一np.ndindex 生成所有其他用户的符号组合当 M4、df2 时只有 4 种组合非常快如果 df 到了 4组合数变成 256 种仍然可以接受。第二log_vals 里用了 np.exp(log_lik prior_sum) 做 log-sum-exp这个写法在数值上不够鲁棒工程上应该直接用 scipy 的 logsumexp 或者自己实现 max 提取防止数值上溢。代码里 sigma2 直接用理想值实际系统里需要从导频估计这也是第 5 章避坑要重点说的。4. 把 SD-MPA 跑起来仿真信号、参数表与效果对比4.1 生成 SCMA 上行信号码本、资源映射与 AWGN 信道跑 SD-MPA 之前要先把发射信号和信道模型搭起来。常见做法是随机生成多个用户的比特每个用户按码本映射成码字然后把同一资源块上的码字按信道系数加权叠加最后加复高斯白噪声。下面这个 Python 片段展示了发射端最小闭环。import numpy as np def generate_scma_tx(J, N, M, codebook): # J 个用户每个用户随机生成 log2(M) 比特并映射成码字索引 symbols np.random.randint(0, M, sizeJ) # 每个用户一个符号索引 tx np.zeros(N, dtypecomplex) for j in range(J): tx codebook[j][:, symbols[j]] # 用户 j 的码字叠加到资源块 return tx, symbols def add_awgn(tx, snr_db, sigma2_ref1.0): # 根据目标 SNR 计算噪声功率sigma2_ref 是信号归一化功率 noise_power sigma2_ref * 10 ** (-snr_db / 10) noise np.sqrt(noise_power / 2) * (np.random.randn(len(tx)) 1j * np.random.randn(len(tx))) return tx noise, noise_power这段代码里codebook 的形状是 (J, N, M)第三个维度是码字索引。tx 是长度 N 的复向量每个资源块上的值等于所有占用该资源块的用户码字取值之和。加噪声时要注意信号功率必须是归一化的否则后面 MPA 里的 sigma2 和信噪比关系就对不上。一般建议把每个用户的码字平均能量归一为 1这样总共叠了 df 个用户时每个资源块上的平均信号功率近似为 df再在这个基础上算噪声功率。生成码本是整个仿真里最影响结果的一步。SCMA 码本不能随便填它需要满足稀疏性、相同用户不同码字之间的最小距离足够大、不同用户码字之间干扰尽量均匀。手写一个 4 用户 2 资源块的码本很简单但 6 用户 4 资源块的高性能码本一般靠计算机搜索或从标准规范里抄表。自己做算法对比时如果码本性能不达标SD-MPA 和标准 MPA 的相对差距还能看但绝对误码率会整体偏高容易被误判成算法问题。仿真流程还有一个容易忽略的细节信道系数。上行仿真里每个用户到基站的信道增益不同常见做法是生成复高斯信道并做功率归一。如果直接把所有信道系数设成 1相当于退化成 AWGN 多址信道MPA 方法的优势会被压缩。建议至少区分两种场景信道系数全 1 的对称场景和随机信道系数的非对称场景前者用于验证算法收敛性后者用于评估实际性能。4.2 SD-MPA 的 5 个必调参数码本规模、过载率、迭代次数、阈值、SNR 区间SD-MPA 可以直接抄作业的参数配置我整理成了一张表下面逐个解释。参数建议初始值作用与调节方向码本大小 M4 或 8M 越大每用户携带比特越多但资源节点更新的组合数按 M^df 增长资源块数 N / 用户数 JN4, J6过载 150%过载率越高多用户干扰越强SD-MPA 的调度收益越明显最大迭代次数 max_iterSD-MPA 设 4~6标准 MPA 设 8对比时两者分别设到各自合理值公平对比要看“达到目标 BER 所需迭代次数”调度阈值 tau0.4tau 越大聚焦节点越多接近并行tau 越小越激进适合高过载场景SNR 扫描区间0 到 14 dB步进 2 dB低 SNR 看收敛性高 SNR 看错误平层M4 是默认配置每个资源块连接的节点数 df 一般取 2 或 3这样资源节点更新的组合数分别是 4^216 或 4^364和 6 用户全枚举的 4096 种相比完全可接受。如果换成 M8df3 时组合数是 512仍然能算但仿真时间会明显上一个台阶。做算法对比时建议先用 M4 把结论跑出来再补 M8 的验证。迭代次数不要盲目加大。SD-MPA 的优势就是少迭代如果你把 max_iter 设成 10大概率看不出来收益因为标准 MPA 在更多轮次里也收敛了。公平做法是固定一个 BER 目标比如 1e-3统计两种算法平均需要多少轮迭代达到这个目标再换算成复杂度。另一种做法是固定迭代轮数相同对比同轮数下的 BER 曲线这样能直接反映“每轮更新效率”的差距。SNR 区间要覆盖两个关键点一是 0 到 4 dB 的低信噪比区这里消息收敛最慢SD-MPA 调度收益最大二是 10 dB 以上的高信噪比区这里容易暴露消息振荡和错误平层。如果只跑中间 6~8 dB很容易得出“两种算法几乎没区别”的结论那是因为高 SNR 下标准 MPA 本来也不需要几次迭代就能收敛。4.3 怎么验证收敛更快BER 曲线、外信息交换次数、运行时长验证 SD-MPA 是否真的有效不能只看最终 BER 曲线。要回答“收敛更快”这个问题需要三个维度的证据。第一个是 BER 随迭代次数的变化曲线固定 SNR横轴是迭代轮数纵轴是 BER看 SD-MPA 比标准 MPA 提前几轮进入平台。第二个是达到目标误码率所需平均迭代次数这是工程上最直接的复杂度指标。第三个才是 BER vs SNR 曲线用来确认在同等迭代轮数下误码率平台是否有改善以及高 SNR 下有没有错误平层。我在某个模拟项目X里用 N4、J6、M4、信道系数随机复高斯场景跑过对比标准 MPA 通常要 7 到 8 轮才能把 BER 压到稳定平台SD-MPA 用 tau0.4 时一般 5 到 6 轮就进入平台差距在 1 到 2 轮之间。这不是一个巨大的数字但对于每轮都要做指数组合求和的 MPA 来说少两条迭代意味着省掉约 20% 到 30% 的检测计算量。更值得注意的是在低信噪比段SD-MPA 的收敛曲线比标准 MPA 少了一段“振荡区”这是调度带来的稳定性收益。运行时长上要注意如果 tau 设得太小比如 0.1每轮只更新不到一个节点的均值那么每轮的实际计算量虽然小但总迭代次数可能要更多才能收敛反而得不偿失。验证时建议把“每轮总消息更新次数”也作为指标统计出来用这个指标对比而不是只看 wall-clock 时间。因为 Python 里的排序开销会掩盖真正消息更新的成本换到 C 或硬件上跑排序几乎可以忽略。5. SD-MPA 落地避坑四条血泪经验与排查清单5.1 半天不收敛码本归一化与噪声方差估计全查一遍现象SD-MPA 跑出来的 BER 曲线在低信噪比时比理论曲线差很多甚至在 0 dB 附近完全收敛不到任何有价值的判决概率误码率接近随机猜测。最气人的是标准 MPA 也有同样的问题你会以为算法本身出了问题。原因八成是噪声方差 sigma2 和实际加进信道的噪声对不上。仿真时如果信号功率没有归一化或者 SNR 计算公式写错MPA 里的高斯条件概率 exp(-|y - expect|^2 / sigma2) 就会偏大或偏小。sigma2 偏大时所有消息被压平迭代怎么跑都分不清谁是谁sigma2 偏小时某个错误组合会被放大消息快速收敛到错误解。解决第一步把每个用户的码字能量归一化让每个用户在所有资源块上的平均能量等于 1。第二步在接收端用导频或者接收信号能量估计噪声方差不要直接使用发射端理想值。第三步在代码里打印每轮消息的最大值和标准差如果标准差从第二轮开始就小于 1e-3说明 sigma2 大概率偏大了。这三步按顺序检查绝大多数“不收敛”问题都能定位。5.2 一排序就变慢调度开销大过节省的迭代次数现象把 SD-MPA 加到代码里之后总仿真时间反而比标准 MPA 更长尤其是 SNR 比较高时差距更明显。原因每个资源节点更新时算出消息标准差不贵但如果每轮都对全部 N 个资源节点做一次排序然后还要对焦点节点做第二轮串行更新实际增加的计算量就会超过省下来的迭代次数。迭代轮数越少、M 越小调度开销在总时间里的占比越高反而拖慢整体。解决调度更新不需要每一轮都做。我一般会每隔一轮做一次标准差排序或者在前两轮并行更新之后才开始启用调度逻辑此外把排序对象从“全部资源节点”改成“上一轮标准差没低于阈值的节点”可以进一步减少排序次数。tau 设到 0.5 以上时聚焦节点数量多串行更新的收益变小也可以考虑直接跳过额外串行更新。本质上是让调度这个“管理动作”的频率适配消息更新的节奏。5.3 消息回流导致 BER 假象因子图连接关系要对齐现象SD-MPA 的收敛曲线很好看两三轮就稳定了但最终 BER 在高信噪比段出现一个推不下去的平台比如停在 1e-2。你会怀疑是码本不够好换了更好的码本仍然不见起色。原因这是因子图连接关系错了。如果 mapping 数组里把某个用户和某个资源块的连接写了进去但码本在该位置的实际取值为零消息更新时就会把“不该存在的连接”当成有效路径反过来码本里非零但 mapping 里漏掉的情况会让该用户在这个资源块上的信息永远传不出去。消息在黑匣子里绕圈把自身消息反复当作外信息使用看起来收敛极快实际是假收敛。解决连接关系不要手写直接从码本的非零项生成。具体做法是遍历 codebook[j][r] 是否全零非零则记为连接。跑仿真之前画一个 N 行 J 列的二进制矩阵逐行核对每个资源块连了哪些用户再对照理论因子图。这一步 30 秒能做完但能省掉大半天的排查时间。5.4 仿真通过、上板翻车硬件里对数运算和查表精度不一致现象浮点仿真里 SD-MPA 的 BER 曲线和标准 MPA 相比有可见增益但把算法移植到定点或查找表实现之后增益消失甚至整体性能掉 3 dB 以上。原因浮点环境里 log、exp、log-sum-exp 都有足够精度SD-MPA 的排序逻辑对数值误差不敏感但硬件实现通常用查找表替代 exp 和对数归一化查找表的分辨率不够时低信噪比下消息更新的微小差异会被量化噪声淹没。更隐蔽的是标准差计算在定点环境下的动态范围问题log 域消息可能从 -20 到 20定点位宽不够时标准差排序结果直接失真。解决在做浮点仿真的同时并行做一个定点模型把消息位宽设为 12 比特或 16 比特先看性能损失是否在可接受范围。SD-MPA 的排序逻辑在硬件上可以只比较标准差大小而不一定算真实值比如比较消息绝对值的最大值或者均方误差减少乘法器资源。经验法则是消息位宽低于 10 比特时几乎必然损失性能12 比特起步比较稳妥。6. 再进一步把 SD-MPA 和外码迭代联合起来6.1 从软输出到 Turbo 式联合迭代把 SD-MPA 当成内码检测器SD-MPA 的输出不是硬判决符号而是每个比特的 LLR这给联合迭代留了很大的空间。把 SD-MPA 当内码检测器后面接 LDPC 或 Turbo 译码器译码器输出的外信息反馈回来作为 MPA 新一轮的先验这就是经典的 Turbo 式联合迭代结构。实现时的关键改动只有一处SD-MPA 的消息初始化从均匀分布改成使用译码器返回的外信息其余逻辑完全不用动。联合迭代的收益在低信噪比段最明显。外码先验相当于给 MPA 的消息更新提供了额外的约束让那些单独看资源节点还分不清的符号组合能利用码字之间的校验关系提前收敛。代价是延迟和复杂度每做一轮外码译码就要重新跑一轮 SD-MPA 检测整体时延成倍增加。做系统设计时要先问清楚目标误码率在什么量级如果 1e-2 就够了联合迭代没必要上。6.2 验证联合迭代效果的最小实验验证联合迭代是否值得做不需要把整套协议栈都搭起来。可以先用一个简单的卷积码或者重复码做外码验证把 SD-MPA 输出的 LLR 送进译码器得到外信息再送回 SD-MPA 重新检测。对比两种工作模式的 BER 曲线一种是一次检测后直接硬判决另一种是迭代 2 到 3 轮联合检测。如果增益小于 0.5 dB说明当前码本和信道条件下联合迭代的收益有限果断放弃如果超过 1 dB再考虑完整的链路实现。我个人早期的习惯是只看最终 BER 曲线后来发现不看收敛轨迹很吃亏。SD-MPA 的优点恰恰体现在“每轮更新的效率”上把每轮迭代后的消息变化幅度打出来能看到标准 MPA 在低信噪比时那一段典型的振荡平台而 SD-MPA 能平滑地穿过这一段。建议所有跑这个方向的人先留一组跑仿真时打印收敛轨迹的代码再决定要不要花精力做联合迭代和定点移植。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?