揭秘维特比译码器:CommPy的viterbi_decode如何实现近最优解码(附硬判决与软判决对比)
【免费下载链接】CommPyDigital Communication with Python项目地址: https://gitcode.com/gh_mirrors/co/CommPy
CommPy 是一个用 Python 实现的数字通信开源工具箱(Digital Communication with Python),其中 convcode.py 提供了卷积码的三大件:网格(Trellis)、编码器conv_encode和维特比译码器viterbi_decode。本篇带你拆解viterbi_decode 维特比译码算法的内部工作原理:加法-比较-选择(ACS)如何逐时刻收敛到最优路径,以及硬判决与软判决在解码增益上的真实差距 🎯
一、为什么需要维特比译码器
先看一个直观的例子:信道上加噪会让"mouse"变成乱码,但只要在发送前加入冗余(FEC 前向纠错),接收端的维特比译码算法就能检测甚至纠正错误。
而卷积码恰好是维特比算法的"主场"——冗余比特被连续地编织进码字结构里,形成一张随时间展开的"网格地图"。
二、三步读懂 viterbi_decode 源码
打开 convcode.py,维特比译码其实只由三块组成:
1️⃣ Trellis:译码的"地图"
Trellis类根据记忆长度和生成矩阵 G(D) 自动生成两张表:
next_state_table:当前状态 + 当前输入 → 下一状态output_table:当前状态 + 当前输入 → 输出比特组
以经典的 G(D) = [1+D², 1+D+D²] 为例(memory=[2]、g_matrix=[[5,7]]),只有 4 个状态、每个状态 2 条分支,地图非常小巧。
2️⃣ 分支度量:衡量"这一步像不像"
核心函数_compute_branch_metrics按decoding_type分三种打分方式(这是硬/软判决差异的根源):
| 判决类型 | 输入形式 | 分支度量 | 适用场景 |
|---|---|---|---|
hard(硬判决) | 0/1 比特 | 汉明距离hamming_dist | 二进对称信道 BSC |
soft(软判决) | 对数似然比 LLR | 负对数似然之和 | 已量化为整数 LLR 的接收机 |
unquantized(未量化) | 实数符号 | 欧氏距离euclid_dist | AWGN 高斯信道 |
3️⃣ ACS + 回溯:_acs_traceback的"最优路径"搜索
每个时刻对每个状态执行:
- Add:各候选前驱的累积路径度量 + 分支度量;
- Compare & Select:只保留最小(最优)的那条,并记录前驱状态与输入到
paths/decoded_symbols中; - Traceback:当缓冲达到回溯深度
tb_depth(默认为5 倍记忆长度,经验上足以"冻结"幸存路径)后,从当前最优状态倒推,把幸存路径上的输入符号写进decoded_bits。
整个过程是流式的:边接收、边压缩、边输出,延迟恒定在tb_depth个时刻。
三、硬判决 vs 软判决:差在哪?
这是工程中最关键的取舍,源码里的细节一目了然:
- 硬判决把接收信号先"取整"成 0/1,再数错了几个比特。简单,但把幅度信息扔掉了;
- 软判决保留接收信号的"可信程度"(LLR),分支度量累加对数似然——弱证据也能参与投票;
- unquantized直接用实数做欧氏距离,最贴近 AWGN 信道最大似然解码;
- 稳定性细节:
soft模式的 LLR 输入会被clip 到 [-500, 500],防止指数运算溢出; - 尾部处理:终止后的时刻,硬判决补 0、软判决补 0、unquantized 补 -1,保证译码器能"驶回"零状态。
📈收益:同样的卷积码,软判决相比硬判决通常能拿到约 1~2 dB 的信噪比增益——在无线系统里这几乎等于免费的容量。
四、卷积码编码器结构长这样
下面这张图展示了一个典型卷积码编码器:移位寄存器组 + 模二加器,正是Trellis内部建模的对象。
五、最小可用示例:3 行代码完成编解码
想亲手跑一遍?参照 test_convcode.py 的测试用例:
from numpy import array from commpy.channelcoding.convcode import Trellis, conv_encode, viterbi_decode trellis = Trellis(array([2]), array([[5, 7]])) # G(D) = [1+D², 1+D+D²] coded = conv_encode(message_bits, trellis) decoded = viterbi_decode(coded, trellis) # 硬判决解码 llr = 10.0 * coded - 5 + noise # 模拟带噪接收(LLR) decoded_soft = viterbi_decode(llr, trellis, decoding_type='soft')无噪信道下decoded与原始message_bits完全一致;即使叠加随机噪声,软判决解码也能正确恢复——这正是测试用例反复验证的行为。
六、近最优解码,代价是什么?
维特比译码器本质上在做最大似然序列估计:逐时刻只保留每个状态的"幸存者",把指数级路径压缩到线性规模,复杂度约O(状态数 × 时间)。相比穷举所有 2ᴸ 条路径的暴力最大似然解码,它是经典的"用一点点性能损失换可计算性"的方案——而默认 5×M 的回溯深度,让这点损失在实际中几乎不可感知。
延伸探索路径🧭
- 卷积码编解码与维特比译码器实现:
commpy/channelcoding/convcode.py - 编解码往返测试(含软判决 LLR 用例):
commpy/channelcoding/tests/test_convcode.py - 802.11 WiFi 物理层完整链路示例:wifi80211_conv_encode_decode.py
- Turbo 码(内含 BCJR/MAP 译码器):
commpy/channelcoding/turbo.py
掌握viterbi_decode之后,你已经拥有了理解 Turbo 码、LTE/5G 卷积码信道的钥匙——维特比译码器,正是这一切的起点。
【免费下载链接】CommPyDigital Communication with Python项目地址: https://gitcode.com/gh_mirrors/co/CommPy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考