☰
LDPC译码概率公式推导:从LLR到Tanh乘积的完整逻辑
2026/10/6 4:03:15 网站建设 项目流程

做通信物理层的,几乎没人能绕开LDPC码。我在刚接触LDPC码译码原理那会儿,最头疼的就是“概率公式推导”这一块,尤其是校验节点更新公式里那个tanh到底怎么冒出来的,整整卡了我好几天。后来我把整个译码过程的每个概率定义、每个对数似然比(LLR)的换算都从头推了一遍,才发现这几个公式并不是靠记忆硬背的,每一步都有严格的概率逻辑。这篇内容我打算用一套完整的推导流程,把LDPC码译码原理里的概率公式从信道初始化一路推到对数域迭代,最后再拿一个手算例子带你把消息传递走一遍。适合正在学编码理论的学生、刚接手LDPC译码器开发的工程师,以及做链路级仿真但一直对置信传播细节没吃透的朋友。

1. 概率译码的大框架:LDPC为什么绕不开软信息

1.1 硬判决丢掉了什么

先说一个最简单的直觉。如果接收机收到一个模拟采样值 y=0.35,硬判决只看符号,大于0判成+1,小于0判成-1,那这个采样值会被非常干脆地判成+1。但稍微有点噪声常识的人就知道,y=0.35距离0判决门限非常近,它的可信度其实很低。如果另一个采样值 y=2.1,同样是判成+1,后者的把握显然比前者大得多。

硬判决的问题在于把所有比特都拉到了同一置信水平上,丢失了“这个判决到底有多可靠”的信息。LDPC码译码跟传统硬判决译码最大的区别就在这:它希望用软信息。所谓软信息,就是不仅告诉译码器“这个比特是什么”,还告诉它“这个比特是+1或者-1的概率有多大”。LDPC译码之所以有逼近香农限的能力,核心就在于它能在整个迭代过程中不断搬运、融合这种概率信息,让可信度高的比特去帮助纠正可信度低的比特。

从数学上,译码要做的事情就是:在已知接收向量和校验约束的前提下,计算每个发送比特的后验概率 P(x_i = +1 | y, 校验关系)。然后根据后验概率最大准则做判决。LDPC码的H矩阵是稀疏的,这意味着每个变量节点只参与少数几个校验方程,每个校验方程也只约束少数几个变量节点。这种稀疏性使得联合后验概率可以被因子分解成局部概率的乘积,从而用消息传递算法在因子图上迭代逼近最优解。

1.2 对数似然比LLR:把乘除变成加减

直接使用概率 p 和 1-p 做乘法在数学上行得通,但在数值上非常不友好。一个校验方程连接几十个变量节点时,乘出来的概率会小到浮点数下溢。工程上常用的做法是把概率换成对数似然比(LLR),定义为:

$$ L = \ln \frac{P(x=+1|y)}{P(x=-1|y)} $$

这个定义有什么好处?后验概率比在迭代中会不断连乘,取对数之后,连乘变成了连加。加法在硬件和DSP实现里成本极低,而且不会因为连乘多个小于1的数导致精度瞬间崩溃。

举一个具体例子。假设BPSK调制,发送符号 x∈{+1,−1},信道是加性高斯白噪声,噪声方差为 σ²,接收值为 y。则:

$$ P(y|x=+1) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left( -\frac{(y-1)^2}{2\sigma^2} \right) $$

$$ P(y|x=-1) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left( -\frac{(y+1)^2}{2\sigma^2} \right) $$

假设先验等概率,即 P(x=+1)=P(x=−1),代入LLR定义,公共因子约掉后得到:

$$ L_{\mathrm{ch}} = \ln \frac{P(y|x=+1)}{P(y|x=-1)} = \frac{(y+1)^2 - (y-1)^2}{2\sigma^2} = \frac{2y}{\sigma^2} $$

这就是信道初始化公式。注意这里有个符号约定:LLR大于0,表示+1更可信;LLR小于0,表示−1更可信。这一条看起来简单,但实际项目里因为符号约定不一致导致整个译码器输出反码的情况我见过太多次了。

1.3 因子图与外部信息:消息传递到底传什么

LDPC码的因子图又叫Tanner图,里面有两类节点:变量节点(对应码字比特)和校验节点(对应校验方程)。任何时候一条边上流动的消息,都表示上游节点对下游节点关于某个变量取值的“观点”。

消息传递最关键的一个原则是外部信息原则。什么叫外部信息?以校验节点 c 给变量节点 v 发消息为例,这个消息只能基于除了 v 之外其他连接到 c 的变量节点的信息来生成。v自己的信道信息不能直接反馈给v自己,否则就是自己给自己投票,迭代会很快收敛到错误方向。对应到工程实现上,就是计算 $L_{c \to v}$ 时,乘法乘积里必须排除 v 对应的那一项;计算 $L_{v \to c}$ 时,求和必须排除 c 对应的那一项。

这个原则来自贝叶斯推断中的“证据独立性”假设:在没有短环的情况下,来自不同校验节点的消息在给定变量节点取值时条件独立。如果漏掉这个排除步骤,会引入很强的信息相关性,导致性能断崖式下跌。后面在调试章节我还会专门讲这个问题。

2. 两种节点的消息更新公式:从概率定义一路推到LLR域

2.1 变量节点到校验节点:相加的直觉与推导

变量节点收集的信息来自两部分:一是信道观测给出的初始LLR $L_{\mathrm{ch}}$,二是所有相邻校验节点传回来的外部LLR。在给定 $x_v$ 的条件下,各校验消息近似独立,于是后验概率比可以分解为各源的信任度乘积:

$$ \frac{P(x_v=+1 | \text{所有信息})}{P(x_v=-1 | \text{所有信息})}

\frac{P(y_v|x_v=+1)}{P(y_v|x_v=-1)} \prod_{c' \in N(v)} \frac{P_{c' \to v}(x_v=+1)}{P_{c' \to v}(x_v=-1)} $$

取对数,所有乘积项变成加法:

$$ L_{v}^{\text{total}} = L_{\mathrm{ch},v} + \sum_{c' \in N(v)} L_{c' \to v} $$

但变量节点向外发送给某个校验节点 c 的消息,必须把来自 c 的那条消息去掉,否则 c 会收到自己刚发出去的消息的“回音”。所以:

$$ L_{v \to c} = L_{\mathrm{ch},v} + \sum_{c' \in N(v) \setminus {c}} L_{c' \to v} $$

第一次迭代时,变量节点还没有从任何校验节点收到过消息,因此初始化 $L_{v \to c} = L_{\mathrm{ch},v}$。

2.2 校验节点到变量节点:异或约束下的tanh乘积公式

校验节点是LDPC译码推导的难点。每条校验约束可以写成:

$$ x_{v_1} \oplus x_{v_2} \oplus \cdots \oplus x_{v_d} = 0 $$

用BPSK符号表示,即符号域的乘积为+1:

$$ \prod_{i} x_{v_i} = +1 $$

现在的问题是:已知除 v 之外的其他变量节点的LLR,校验节点能给 v 提供什么信息?关键观察是:如果其他变量节点的符号乘积为 S,那么为了让校验约束满足,必须有 $x_v = S$。所以校验节点给 v 的LLR,本质上是在问:其他变量节点的符号乘积 S 更可能是+1还是−1。

设 S = ∏_{v' ≠ v} x_{v'},求P(S=+1)与P(S=−1)的比值。这里有一个特别优雅的推导方法:考虑随机变量的期望。

对于每个二进制随机变量 $x_i$,取值为±1,有:

$$ P(x_i=+1) - P(x_i=-1) = E[x_i] $$

如果知道该变量对应的LLR为 $L_i$,那么:

$$ P(x_i=+1) = \frac{e^{L_i/2}}{e^{L_i/2} + e^{-L_i/2}}, \quad P(x_i=-1) = \frac{e^{-L_i/2}}{e^{L_i/2} + e^{-L_i/2}} $$

所以:

$$ E[x_i] = P(x_i=+1) - P(x_i=-1) = \frac{e^{L_i/2} - e^{-L_i/2}}{e^{L_i/2} + e^{-L_i/2}} = \tanh\left(\frac{L_i}{2}\right) $$

关键是独立随机变量乘积的期望等于各自期望的乘积:

$$ E[S] = E\left[ \prod x_{v'} \right] = \prod E[x_{v'}] = \prod_{v' \in N(c) \setminus {v}} \tanh\left(\frac{L_{v' \to c}}{2}\right) $$

记这个乘积为 t。另一方面:

$$ E[S] = P(S=+1) - P(S=-1) $$

所以校验节点向 v 输出的LLR为:

$$ L_{c \to v} = \ln \frac{P(S=+1)}{P(S=-1)} = \ln \frac{1+t}{1-t} = 2 \operatorname{atanh}(t) $$

最终:

$$ L_{c \to v} = 2 \operatorname{atanh}\left( \prod_{v' \in N(c) \setminus {v}} \tanh\left(\frac{L_{v' \to c}}{2}\right) \right) $$

这个公式就是整个LDPC译码里看起来最“跳跃”的一个。理解了 S 的期望推导,它就不再是个需要硬背的魔术了。

2.3 从概率到对数域的“最后一公里”:符号约定是王道

很多初学者在这附近被绕晕,其实往往不是推导出了问题,而是符号约定摇摆不定。比如有的教材把比特0映射成+1,有的映射成−1;有的LLR定义是 ln(P(+1)/P(−1)),有的反过来。只要前后统一,所得判决结果应该一致。但我强烈建议固定一套约定:LLR大于0判为+1,LLR小于0判为−1,BPSK的+1对应比特0。

还有一点:在LLR域做判决只比大小,不需要对概率归一化。很多从概率域转过来的同学会习惯性地去算:

$$ P(x=+1|y) = \frac{p_+}{p_+ + p_-} $$

但在LLR域,归一化因子是公共项,对判决没有影响。直接看 $L$ 的正负即可。真正要小心的是从概率域转LLR域时,tanh的反变换要用对:$2\operatorname{atanh}(t) = \ln((1+t)/(1-t))$,如果写成 $1/(1+t)$ 那整个译码器就会输出一堆随机数。

3. 手算一遍完整迭代:用4变量2校验的例子看清公式

3.1 例子设定与初始LLR

纸上谈兵不如动手算一遍。我选一个非常小的H矩阵:

$$ H = \begin{bmatrix} 1 & 1 & 1 & 0 \ 1 & 1 & 0 & 1 \end{bmatrix} $$

对应的校验方程是:

$$ v_1 \oplus v_2 \oplus v_3 = 0 $$

$$ v_1 \oplus v_2 \oplus v_4 = 0 $$

这个码很简单,但校验节点度数为3,能完整体现tanh乘积公式,而不是退化成“直通”的特殊情况。

假设发送端BPSK映射,信道是AWGN,噪声方差 σ²=1。接收到的四个采样值为:

$$ y = [2.0,\ 0.5,\ -0.8,\ 1.2] $$

初始信道LLR按 $L_{\mathrm{ch},i} = 2y_i/\sigma^2$ 计算:

$$ L_1 = 4.0,\quad L_2 = 1.0,\quad L_3 = -1.6,\quad L_4 = 2.4 $$

如果直接按符号硬判决,初始判决是 [+, +, −, +]。检查校验约束:

$$ v_1 \oplus v_2 \oplus v_3 = + \oplus + \oplus - = 1 $$

不满足。需要译码迭代来修正v3。

3.2 第一轮迭代:校验消息计算与变量节点更新

第一次迭代时,变量节点还没有收到校验消息,所以直接 $L_{v \to c} = L_{\mathrm{ch}}$。

先计算校验节点 c1 的消息。c1连接 v1, v2, v3。

c1给v1的消息,根据公式应排除v1自身,只用v2和v3的消息:

$$ L_{c1 \to v1} = 2 \operatorname{atanh}\left( \tanh(1.0/2) \cdot \tanh(-1.6/2) \right) $$

查一下数值:tanh(0.5)≈0.4621,tanh(−0.8)≈−0.6640,乘积约−0.3069。atanh(−0.3069)约−0.3172,再乘以2得到约−0.634。

同理:

$$ L_{c1 \to v2} = 2 \operatorname{atanh}\left( \tanh(4.0/2) \cdot \tanh(-1.6/2) \right) \approx -1.517 $$

$$ L_{c1 \to v3} = 2 \operatorname{atanh}\left( \tanh(4.0/2) \cdot \tanh(1.0/2) \right) \approx 0.958 $$

再算校验节点 c2 的消息。c2连接 v1, v2, v4:

$$ L_{c2 \to v1} = 2 \operatorname{atanh}\left( \tanh(1.0/2) \cdot \tanh(2.4/2) \right) \approx 0.812 $$

$$ L_{c2 \to v2} = 2 \operatorname{atanh}\left( \tanh(4.0/2) \cdot \tanh(2.4/2) \right) \approx 2.217 $$

$$ L_{c2 \to v4} = 2 \operatorname{atanh}\left( \tanh(4.0/2) \cdot \tanh(1.0/2) \right) \approx 0.958 $$

现在所有校验节点消息都发出来了,变量节点汇总后验LLR:

$$ L_{v1}^{\text{total}} = 4.0 + (-0.634) + 0.812 = 4.178 $$

$$ L_{v2}^{\text{total}} = 1.0 + (-1.517) + 2.217 = 1.700 $$

$$ L_{v3}^{\text{total}} = -1.6 + 0.958 = -0.642 $$

$$ L_{v4}^{\text{total}} = 2.4 + 0.958 = 3.358 $$

第一轮判决仍然为 [+, +, −, +],v3没有翻转,校验方程依然不满足。这是正常的,置信传播很少在第一次迭代就解决问题,需要多轮迭代,让外部信息在图上“转一圈”。

3.3 第二轮迭代:观察错误比特如何被外部信息扳回

第二轮迭代前,必须先计算变量节点发给各个校验节点的外部消息。注意前面我反复强调过,这个时侯必须排除目标校验节点。

变量节点 v1 给 c1 的消息:

$$ L_{v1 \to c1} = 4.0 + L_{c2 \to v1} = 4.0 + 0.812 = 4.812 $$

变量节点 v1 给 c2 的消息:

$$ L_{v1 \to c2} = 4.0 + L_{c1 \to v1} = 4.0 - 0.634 = 3.366 $$

变量节点 v2 给 c1 的消息:

$$ L_{v2 \to c1} = 1.0 + L_{c2 \to v2} = 1.0 + 2.217 = 3.217 $$

变量节点 v2 给 c2 的消息:

$$ L_{v2 \to c2} = 1.0 + L_{c1 \to v2} = 1.0 - 1.517 = -0.517 $$

v3只连接c1,v4只连接c2,所以它们没有其他外部消息可选:

$$ L_{v3 \to c1} = -1.6,\quad L_{v4 \to c2} = 2.4 $$

有了这些边消息,再次做校验节点更新。重点看c1给v3的消息,因为v3是第一轮唯一被判错的比特:

$$ L_{c1 \to v3} = 2 \operatorname{atanh}\left( \tanh(4.812/2) \cdot \tanh(3.217/2) \right) $$

tanh(2.406)≈0.9836,tanh(1.6085)≈0.9228,乘积约0.9076。atanh(0.9076)≈1.5135,两倍约3.027。这个来自校验节点的外部消息非常强地指向+1,足以把v3从−1.6的信道LLR拉回来。

再看其他几个关键消息:

$$ L_{c1 \to v1} \approx -1.426,\quad L_{c1 \to v2} \approx -1.561 $$

$$ L_{c2 \to v1} \approx -0.428,\quad L_{c2 \to v2} \approx 2.079,\quad L_{c2 \to v4} \approx -0.481 $$

第二轮变量节点总后验:

$$ L_{v1}^{\text{total}} = 4.0 - 1.426 - 0.428 = 2.146 $$

$$ L_{v2}^{\text{total}} = 1.0 - 1.561 + 2.079 = 1.518 $$

$$ L_{v3}^{\text{total}} = -1.6 + 3.027 = 1.427 $$

$$ L_{v4}^{\text{total}} = 2.4 - 0.481 = 1.919 $$

判决结果变成 [+, +, +, +]。校验约束全部满足,迭代终止。v3被成功从−1翻到+1,这就是可信度传播的一次完整展示。手算数值保留三位小数,不同计算精度下最后一位可能有差异,但判决方向已经足够清楚。

4. 从公式到工程:对数域实现的近似与避坑

4.1 浮点下溢、溢出与数值稳定

概率域做LDPC译码在理论上没问题,但在有限精度实现里简直是灾难。假设一条长度为1000的码字,每个变量节点后验概率乘上几十个接近1或接近0的数,很快就会突破浮点数能表达的范围。LLR域把乘法换成加法,数值范围立刻温和了很多。

但LLR域并非完全无忧。消息的LLR绝对值可能变得很大。当 $|L|$ 超过大概20时,$\tanh(L/2)$ 已经非常接近±1,再往后就是饱和区。如果此时多个乘积项都饱和成1,$\operatorname{atanh}(1)$ 会得到无穷大。实际工程中必须做钳位,比如把LLR钳在[-16, 16],或者把乘积钳在±(1−2^{-k})。

我用过一个很土但有效的办法:在校验节点更新后,检查输出LLR绝对值是否超过门限,超过就钳制成门限值。这个门限通常取最大迭代LLR的一半左右,能在性能和数值稳定性之间取得平衡。

4.2 Min-Sum近似:为什么取最小绝对值

直接实现:

$$ 2 \operatorname{atanh}\left( \prod \tanh\left(\frac{L_i}{2}\right) \right) $$

在FPGA里需要大量查找表或者CORDIC求tanh和atanh,面积和延迟都不小。于是有了Min-Sum近似:

$$ L_{c \to v} \approx \left( \prod \operatorname{sgn}(L_i) \right) \cdot \min_{i} |L_i| $$

这个近似的直观理由是,$\tanh(x/2)$ 在0附近接近线性,在远离0时快速饱和到±1。连乘的结果主要由绝对值最小的那一项决定,其他项只是让结果更靠近饱和边界而已。反过来做一次 $2\operatorname{atanh}$,相当于把最小项的LLR“原样退还”。

用前面的数据验证一下。第二轮的 $L_{c1 \to v1}$,参与计算的外部消息是3.217和−1.6,Min-Sum给出:

$$ -\min(3.217,\ 1.6) = -1.6 $$

精确值是约−1.426,误差0.174。对于硬判决来说,这个误差通常可以容忍。但Min-Sum在高信噪比下整体会偏保守,出现性能平台。工程上常用归一化Min-Sum:

$$ L_{c \to v} \approx \alpha \cdot \left( \prod \operatorname{sgn}(L_i) \right) \cdot \min_{i} |L_i| $$

其中 α 取0.75左右。这个系数不是拍脑袋定的,我一般会在目标信噪比附近扫一版α,观察误块率平台,选一个曲线上最稳的值。

4.3 定点量化与查表:FPGA和DSP里怎么落地

如果要做定点实现,第一步是确定LLR的量化格式。常见做法是用Q格式,比如Q4.2表示4位整数、2位小数,总位宽6位。信道LLR动态范围很宽,但经过迭代后,外部消息的绝对值通常被限制在一个较小的区间内,过度增加位宽对性能提升不大,只会浪费资源。

tanh和atanh查表时要注意量化步长的选择。直接用输入LLR作为查表地址有个问题:LLR的分布很不均匀,大部分集中在中小幅度区间。如果等间隔量化,小消息的分辨率可能不够。我见过一种做法是分段线性查表,在|L|<2的区间用更密的表项,在|L|较大时用稀疏表项,效果比均匀表好很多。

迭代调度上,常见的洪泛调度是每一轮先更新所有校验节点,再更新所有变量节点。分层调度则利用校验更新的先后顺序,后更新的校验节点能立刻吃到前面校验节点刚产出的新消息,收敛速度大约快一倍。代价是逻辑上更像串行处理,吞吐率设计时需要额外权衡。

5. 调试译码器时的常见问题速查

5.1 消息符号全反了:约定不一致

症状很典型:译码器输出的误码率接近0.5,甚至固定输出全0或全1。首要怀疑对象就是符号约定。信道LLR公式是 $2y/\sigma^2$,如果写成 $y/\sigma^2$ 或者漏掉系数2,不会造成方向错误,但性能损失明显。真正致命的是把+1映射成比特1、−1映射成比特0后,所有LLR方向都反了,译码器等于在译一个取反后的码字,永远收敛不到正确结果。

排查办法很简单:输入一个全零码字,加一个比较干净的AWGN信道,打印第一次迭代前的所有信道LLR。如果噪声不大,LLR应当全部为正。出现负的,立刻检查调制映射和LLR定义是否配套。

5.2 迭代振荡不收敛:短环与调度

如果你发现迭代到最大次数仍然无法通过所有校验约束,而且后验LLR忽正忽负,像钟摆一样来回震荡,先看H矩阵中是否存在4环。什么是4环?就是因子图里从某个变量节点出发,经过校验节点、另一个变量节点、再经过另一个校验节点,绕一圈回到起点。4环会让两条消息路径在迭代几次后相互引用,产生相关性,等价于把外部信息“抄”回自己家里。

LDPC码设计阶段通常会避免4环,但如果你用的是随意构造的矩阵做验证,就很容易踩坑。临时调试时可以增大最大迭代次数,但性能上不来。最终方案是换用标准的QC-LDPC矩阵,或者用PEG等算法构造无4环矩阵。如果矩阵没问题但仍然振荡,检查分层调度和洪泛调度的消息更新顺序是否一致,串行更新比并行更新更容易出现不同步导致的震荡。

5.3 性能曲线下不了:外部信息泄漏

性能曲线在某个误块率位置突然变平,通常不是信道问题,而是消息更新时出现了信息泄漏。最常见的一种错误是,变量节点更新后,直接把后验总LLR当作向外发送的消息,但后验总LLR里包含了目标校验节点刚才传回来的内容。这等于让校验节点听到自己的回声,置信度被反复叠加,最终所有比特都会被吹向同一个方向。

调试时可以在每一轮迭代里单独打印某一条边上的 $L_{v \to c}$,检查它是否总是比 $L_{\mathrm{ch}} + \sum_{c' \neq c} L_{c' \to v}$ 多出或少了某一条分量。用小的测试矩阵一条边一条边对,很快就能定位。

5.4 一个实用的调试手段

我个人的习惯是,在正式实现FPGA或DSP代码之前,先用Python写一个“概率域金标准”译码器:直接用后验概率做乘除,不碰LLR近似,也不碰Min-Sum。然后把LLR域译码器跑同一组接收数据,对比每一轮每个比特的软输出符号和迭代终止状态。

如果两者在数值误差范围内完全一致,说明公式和流程没有大问题。接下来再换成Min-Sum,性能损失应该在0.1到0.3dB以内,如果超过这个范围,回去检查归一化因子和钳位门限。这个流程能帮你把“公式推导正确”和“工程实现正确”两件事分离开来,排查问题时会轻松很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询