恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
极化码与QAM软解调:LLR计算、量化与链路级仿真实践
首页
资讯中心
/
极化码与QAM软解调:LLR计算、量化与链路级仿真实践
极化码与QAM软解调:LLR计算、量化与链路级仿真实践
发布时间:2026/10/12 20:15:16
简介这份资源面向数字通信与无线通信方向的学习者与工程实践者聚焦调制解调链路中的关键环节帮助理解从信号映射到比特恢复的完整流程。包内共2个文件均为m脚本文件分别对应16-QAM调制与解调的实现压缩包整体约1KB体量轻便便于直接阅读与二次修改。内容围绕16-QAM星座映射、相干检测与软解调展开并可与极化码等信道编码方案衔接用于分析软信息在错误纠正中的价值适合作为课程实验、算法验证或通信系统仿真的参考素材。目前已有163人学习下载说明该主题在相关学习群体中具有一定关注度。读者可借助脚本梳理调制与解调的核心步骤理解幅度相位联合映射、匹配滤波与概率估计之间的关系并在此基础上扩展至更高阶QAM或结合极化码进行链路级性能评估为后续系统设计与优化提供可复用的代码基础。1. 从 QAM 软解调值不值得做极化码链路里最容易被低估的一环做无线通信基带的人迟早会撞上这样一个组合极化码Polar Code做信道编码QAM 做高阶调制中间夹一层软解调。标题里这一串关键词——调制与解调、极化码、QAM 解调、软解调——说的就是这条链路。它解决的核心问题是在 16QAM、64QAM 这类高阶调制下怎么把接收符号里那点“可信度”完整地喂给极化码译码器而不是粗暴地硬判决成 0/1 再丢进去。适合谁看正在做链路级仿真、基带算法验证或者被“硬解调性能上不去”卡住的工程师。软解调不是玄学它决定了你的极化码能拿到多少编码增益做对了能省下好几个 dB 的发射功率做错了就是白忙一场。2. 极化码 QAM 软解调先搞清楚 LLR 到底在算什么2.1 硬判决丢掉了什么软解调补回了什么先把这个链路的数据流捋一遍。发送端信息比特 → 极化码编码 → 比特交织 → QAM 星座映射 → 上变频发射。接收端反过来下变频 → QAM 符号 → 软解调输出 LLR → 极化码译码 → 信息比特。关键就在“QAM 符号 → LLR”这一步。硬解调只输出 0 或 1等于把接收符号里“我有多确定它是 0”这个信息全扔了。软解调输出的是对数似然比LLR(b) ln[ P(b0 | y) / P(b1 | y) ]LLR 的绝对值越大说明这个比特越确定符号表示偏向哪一边。极化码的 SCSuccessive Cancellation或 SCL 译码器吃的就是这个软信息。你给它硬判决它就只能当每个比特同等可信编码增益直接打折。常见做法是对每个接收符号 y遍历星座图上所有点算欧氏距离再按比特分组做 log-sum-exp 近似。这就是所谓的 max-log 近似工程上最常用因为复杂度可控。2.2 16QAM 软解调的完整推导与实现16QAM 星座图是 4×4 的方格每个符号携带 4 个比特。假设采用格雷映射Gray MappingI 路和 Q 路各 2 个比特可以独立处理。这是工程上最省事的做法也是我一般会推荐的第一步。设接收符号为 y (y_I, y_Q)星座点间距为 2d即相邻点坐标差 2d则 I 路两个比特 b0、b1 的 LLR 可以写成import numpy as np def qam16_soft_demod(y_i, y_q, d1.0, noise_var1.0): 16QAM 软解调max-log 近似格雷映射 y_i, y_q: 接收符号的 I/Q 分量已做信道均衡 d: 星座点半间距标准 16QAM 归一化后 d 1/sqrt(10) noise_var: 噪声方差 sigma^2 返回: 长度为 4 的 LLR 数组顺序 [b0, b1, b2, b3] # I 路b0 决定符号b1 决定幅度 # 格雷映射下b0 的判决边界在 y_i 0 llr_b0 4 * d * y_i / noise_var # b1 的判决边界在 |y_i| 2d llr_b1 4 * d * (2 * d - np.abs(y_i)) / noise_var # Q 路同理 llr_b2 4 * d * y_q / noise_var llr_b3 4 * d * (2 * d - np.abs(y_q)) / noise_var return np.array([llr_b0, llr_b1, llr_b2, llr_b3])这段代码的逻辑说明max-log 近似下LLR 可以化简成“到最近 0 点距离平方减去到最近 1 点距离平方”再除以噪声方差。对于格雷映射的 16QAMI 路和 Q 路完全解耦b0 只看 y_i 的符号b1 只看 y_i 的绝对值离 2d 有多远。参数 d 是星座点半间距noise_var 是噪声方差这两个值必须和实际链路匹配否则 LLR 的尺度会错译码器性能会明显下降。注意noise_var 的估计精度直接影响软解调效果。工程上一般用导频或前导码做信噪比估计再换算成噪声方差。如果噪声方差估大了LLR 整体偏小译码器会“不信任”软信息估小了LLR 偏大容易过自信导致译码错误。2.3 64QAM 与高阶调制的扩展思路64QAM 是 8×8 星座每符号 6 比特。I 路 3 比特Q 路 3 比特。格雷映射下仍然可以按路独立处理但每个比特的判决边界不再是简单的 0 和 2d而是 0、2d、4d 三个边界。我一般会用一个通用公式来写def qam64_soft_demod_axis(y, d1.0, noise_var1.0): 64QAM 单路I 或 Q软解调3 比特格雷映射 y: 单路接收分量 返回: 3 个 LLR llr np.zeros(3) # b0: 判决边界 0 llr[0] 4 * d * y / noise_var # b1: 判决边界 4d 和 -4d取最近边界 llr[1] 4 * d * (4 * d - np.abs(y)) / noise_var # b2: 判决边界 2d 和 6d需要分段 if np.abs(y) 2 * d: llr[2] 4 * d * (2 * d - np.abs(y)) / noise_var elif np.abs(y) 6 * d: llr[2] 4 * d * (np.abs(y) - 4 * d) / noise_var else: llr[2] 4 * d * (6 * d - np.abs(y)) / noise_var return llr参数说明d 的取值取决于归一化方式。如果星座点坐标是 ±1d、±3d、±5d、±7d那么平均功率是 (192549)/4 × 2d² 42d²归一化到 1 需要 d 1/sqrt(42)。这个 d 必须和发射端一致否则 LLR 尺度全错。对于更高阶的 256QAM思路一样只是分段更多。工程上更推荐用查表法预先算好每个星座点的距离接收时直接查表加比较比实时算公式更稳。3. 把软解调接进极化码译码器LLR 怎么喂、参数怎么调3.1 极化码译码器对 LLR 的尺度要求极化码的 SC 译码核心是 f 函数和 g 函数f(a, b) sign(a) * sign(b) * min(|a|, |b|) g(a, b, u) b (1 - 2u) * a这两个函数对 LLR 的绝对尺度不敏感但对相对尺度敏感。也就是说如果你把所有 LLR 同比例放大或缩小译码结果不变。但如果你对某些比特的 LLR 估得偏大、另一些偏小译码器就会做出错误判断。所以软解调输出的 LLR 必须保持一致的尺度。这就是为什么 noise_var 估计这么重要——它决定了所有 LLR 的全局缩放因子。工程上我一般会在软解调之后加一步 LLR 归一化把 LLR 的方差归一化到 1 附近这样译码器不用关心前端增益变化。def normalize_llr(llr, target_var1.0): 将 LLR 序列归一化到目标方差 用于消除前端增益波动对译码器的影响 current_var np.var(llr) if current_var 1e-10: return llr scale np.sqrt(target_var / current_var) return llr * scale这个归一化步骤在链路级仿真里经常被忽略但在实际硬件实现中非常关键。因为 AGC自动增益控制会引入增益波动如果不归一化译码器看到的 LLR 尺度会随信号强度变化导致性能不稳定。3.2 从仿真到定点LLR 量化位宽怎么选浮点仿真跑通之后下一步就是定点化。LLR 的量化位宽直接影响硬件资源和译码性能。我一般会按这个流程走第一步统计浮点 LLR 的分布。在典型信噪比下跑一段数据看 LLR 的绝对值范围。16QAM 在 SNR10dB 时LLR 绝对值一般在 0 到 20 之间。第二步选量化格式。常用的是 6 比特或 8 比特有符号数其中 1 位符号位其余整数位。6 比特能表示 -32 到 31对大多数场景够用。第三步做饱和处理。超过量化范围的 LLR 直接截断到最大值不要溢出。def quantize_llr(llr, bit_width6): LLR 定点量化有符号饱和截断 bit_width: 总位宽含符号位 max_val (1 (bit_width - 1)) - 1 min_val -(1 (bit_width - 1)) quantized np.clip(np.round(llr), min_val, max_val) return quantized.astype(np.int32)参数说明bit_width 越大量化误差越小但硬件资源消耗越大。工程上 6 比特是性能和面积的平衡点8 比特用于对性能要求极高的场景。注意饱和截断的方向正数截到 max_val负数截到 min_val不要搞反。3.3 链路级仿真的最小验证框架要验证软解调 极化码这条链路最小仿真框架需要包含极化码编码、QAM 映射、AWGN 信道、软解调、极化码译码、误码率统计。def simulate_polar_qam16(snr_db, num_blocks1000, n256, k128): 极化码 16QAM 软解调链路级仿真 snr_db: 信噪比 num_blocks: 仿真块数 n: 极化码码长 k: 信息比特数 snr_linear 10 ** (snr_db / 10.0) noise_var 1.0 / (2 * snr_linear) # 复数噪声方差 d 1.0 / np.sqrt(10) # 16QAM 归一化半间距 bit_errors 0 total_bits 0 for _ in range(num_blocks): info_bits np.random.randint(0, 2, k) # 极化码编码此处用简化占位实际需完整编码器 coded_bits polar_encode(info_bits, n) # 16QAM 映射 symbols qam16_map(coded_bits, d) # AWGN noise np.sqrt(noise_var / 2) * ( np.random.randn(len(symbols)) 1j * np.random.randn(len(symbols)) ) received symbols noise # 软解调 llr [] for s in received: llr.extend(qam16_soft_demod(s.real, s.imag, d, noise_var)) llr np.array(llr) # 极化码译码SC 或 SCL decoded polar_decode(llr, n, k) bit_errors np.sum(decoded ! info_bits) total_bits k ber bit_errors / total_bits return ber这个框架的关键点noise_var 的计算要和 QAM 归一化方式匹配。如果星座点平均功率是 1那么复数噪声方差就是 1/(2×SNR_linear)。d 的取值也要和映射函数一致。仿真时先跑高 SNR 确认无误码再逐步降低 SNR 看瀑布曲线。4. 软解调落地时最容易翻车的几个地方4.1 现象译码器性能比硬判决还差原因LLR 符号搞反了。软解调输出的 LLR 定义是 ln[P(b0)/P(b1)]如果译码器期望的是 ln[P(b1)/P(b0)]那所有软信息都是反的译码器会系统性地往错误方向走。解决在链路里加一个已知序列测试。发全 0看软解调输出的 LLR 是不是全正发全 1看是不是全负。如果不是把 LLR 取反。4.2 现象低 SNR 下性能急剧恶化高 SNR 下正常原因LLR 饱和截断太狠。低 SNR 时 LLR 绝对值本来就小如果量化位宽不够很多小 LLR 被截断成 0译码器丢失了软信息。解决检查量化位宽低 SNR 下 LLR 动态范围更大需要更多比特。或者改用浮点仿真确认是量化问题还是算法问题。4.3 现象不同 SNR 下性能波动大曲线不平滑原因噪声方差估计不准。如果 noise_var 用固定值而实际噪声功率随 SNR 变化LLR 尺度就会错。解决每个 SNR 点单独估计噪声方差或者用信噪比估计模块实时输出。仿真时直接用真实噪声方差硬件实现时用导频估计。4.4 现象64QAM 比 16QAM 性能差很多超出理论预期原因格雷映射没做对。64QAM 的格雷映射比 16QAM 复杂如果映射表错了相邻星座点之间会有多个比特翻转软解调出来的 LLR 质量会严重下降。解决用标准格雷映射表或者用计算机搜索验证相邻星座点的比特差异应该只有 1 位。4.5 现象极化码译码器偶尔崩溃输出全 0 或全 1原因LLR 里出现了 NaN 或 Inf。通常是 noise_var 设成了 0或者 log-sum-exp 计算时出现了数值溢出。解决在软解调输出加保护noise_var 下限设为 1e-6LLR 做 clip 到 [-100, 100]。5. 进阶技巧用 LLR 分布反推软解调是否健康跑完仿真别只看 BER 曲线我习惯再画一张 LLR 分布图。具体做法在固定 SNR 下把软解调输出的 LLR 按“发送比特为 0”和“发送比特为 1”分成两组分别画直方图。健康的软解调两组 LLR 应该分得很开发送 0 的那组集中在正半轴发送 1 的那组集中在负半轴中间重叠区域越小越好。如果两组几乎重叠说明软解调没提供有效信息译码器再强也救不回来。更进一步可以算一下 LLR 的互信息def llr_mutual_information(llr, tx_bits): 计算 LLR 与发送比特之间的互信息 用于评估软解调质量 # 将 LLR 分桶近似计算条件概率 bins np.linspace(-20, 20, 50) mi 0.0 for b in [0, 1]: mask tx_bits b hist, _ np.histogram(llr[mask], binsbins, densityTrue) p hist * (bins[1] - bins[0]) p p / np.sum(p) for i, pi in enumerate(p): if pi 0: mi 0.5 * pi * np.log2(2 * pi / (p[i] 1e-10)) return mi这个互信息值在 0 到 1 之间越接近 1 说明软解调质量越好。我一般会在不同 SNR 下扫一遍看互信息随 SNR 的增长曲线。如果曲线在某个 SNR 点突然变平说明软解调在这个区间出了问题通常是量化或噪声估计的锅。还有一个习惯每次改完软解调参数先跑一遍“无噪声”测试。把 noise_var 设成极小值看译码器能不能 100% 正确译码。如果无噪声都译不对那肯定是 LLR 符号或映射表的问题不用往下查了。这个习惯帮我省过很多次 debug 时间算是血泪经验。希望帮到你。本文还有配套的精品资源点击获取