概率整形技术这几年在光纤通信和高速光模块的实验室里被反复提起,尤其是把64QAM的星座图整形和GMI指标放在一起看的时候,不少刚接触这个方向的人第一反应是:这不就是把外圈点少发一点吗?对,直觉上是这样,但真做起来,从概率分布怎么定、分布匹配器怎么接,到最后GMI怎么算得准,每一环都有不少坑。这篇文章把我在64QAM概率整形链路上实际跑过的流程、参数和调试心得整理出来,给想自己搭仿真或者准备做实测复现的朋友做个参考。
1. 为什么要在64QAM上做概率整形
1.1 等概率调制离香农极限有多远
通信链路里,加性高斯白噪声信道的最优输入分布其实是连续高斯分布,不是等概率离散星座。但在现实中我们只能用有限个符号点,所以就有了“星座整形”这一说:让符号点出现的概率尽量接近高斯分布的形状,中心附近的点多发,边缘大能量点少发。
等概率64QAM在额定信噪比下,相对香农容量大约有1.53 dB的理论差距,这个差距就是高信噪比下均匀星座的整形损失。对普通场景可能无所谓,但在光纤通信这种每0.1 dB都要抠的系统里,能不能把这1 dB多拿回来,直接决定了无中继距离和功率预算。
我刚开始接触的时候也有个误区,以为概率整形就是“少发那些角上的点”。对,但更重要的一点是:少发外圈点会降低星座图的平均功率,而发射机功率是固定的,所以等价于在同样平均功率下把星座整体间距拉大了。接收端看到的是有效信噪比提高,不是单纯省电。
1.2 64QAM比16QAM、256QAM更适合做整形
16QAM每个维度只有2个幅度层,整形的操作空间太窄,理论整形增益大约只有0.4 dB上下,忙活半天收益有限。256QAM幅度层级够多,整形增益上限更高,但对相位噪声、非线性、均衡器精度要求非常苛刻,实际链路里很难稳住。64QAM正好在两个代价之间取平衡:单维度有4个幅度电平,二维星座有多个能量环,整形自由度足够,对硬件实现又没那么娇气。
在我个人的仿真里,64QAM用Maxwell-Boltzmann分布做中等强度整形,OSNR换取增益一般在0.5到1 dB这个区间,具体数值取决于目标熵和FEC码率。做系统级方案调研时,这个收益是实打实的,不是PPT里的概念。
1.3 整形增益的本质是省功率
用一个最直白的类比:等概率星座像每个小区都建一样密度的高楼,不管这块地人气高不高;概率整形则像是把高楼集中建在市中心,郊区少建一点。要满足同样的人口需求,后者的总占地面积更小。
在数学上,我们给星座点赋予不等的出现概率后,平均符号能量会下降。假设固定星座点的最小欧氏距离不变,平均能量的下降直接转化成发送功率的节省;反过来,如果维持当前功率,最小距离变大,误码性能就会变好。这个特性在64QAM上非常明显,因为外圈4个点能量高得很夸张,把它们概率压低,平均能量能降不少。
但代价也在这:整形会降低星座熵,原本64QAM携带6比特/符号信息,整形后可能只剩5.2到5.8比特/符号。如果系统目标净速率不变,就需要靠更强的FEC或者更大符号速率去补。所以整形的本质是在“速率损失”和“功率增益”之间做交换,这是整个设计里必须盯住的核心矛盾。
2. 星座映射与分布匹配器:概率不是想给就给
2.1 Maxwell-Boltzmann分布与整形参数
常用的概率整形分布就是Maxwell-Boltzmann分布,对64QAM来说,通常按I、Q两个维度独立整形。设单维度幅度集合是{1, 3, 5, 7},每个幅度的概率正比于exp(-ν·a²)。ν越大,外圈概率越低,整形强度越大,星座熵越小。
这里给一段最基础的Python代码,直接算概率:
import numpy as np A = np.array([1., 3., 5., 7.]) nu = 0.03 # 整形强度参数 p = np.exp(-nu * A**2) p = p / p.sum() print(p) # [0.398 0.313 0.194 0.094]当ν=0.03时,单维幅度熵约为1.9比特,加上I、Q两个维度的符号位各1比特,整个星座熵大约5.8比特/符号。如果ν加到0.05,幅度概率变成约[0.485, 0.325, 0.146, 0.044],星座熵降到5.3比特/符号左右,整形更强,但速率损失也更明显。
我实际使用中,一般先定目标净速率,再反推FEC码率和允许的熵下降,最后回去选ν。不要一上来就选个很大的ν,否则整形成功率很好看,但吞吐率可能撑不住系统需求。
2.2 分布匹配器的查表实现路线
概率定了之后,得有一个模块把均匀分布的原始比特映射成符合目标概率分布的幅度序列,这个模块就是分布匹配器。工程里最常见的是两类:常数组合分布匹配器,通常用算术编码或者枚举式编码实现;另一种是查表法,适合短块长和固定场景。
查表法理解起来最直接。假设我们选n=200个幅度符号为一个块,目标幅度概率是[0.485, 0.325, 0.146, 0.044],那这200个符号里1、3、5、7出现的次数大约是97、65、29、9。所有满足这个次数约束的排列数是一个巨大的组合数,我们从中挑选2^k种序列,每一种对应k比特输入。
如果k=160,意味着16比特的输入可以映射到200个幅度符号,输出熵就比均匀分布低。具体实现有两种:一种是把所有序列列出来,按字典序排序后取前2^k个;另一种用枚举式编码直接按组合数索引生成。后者不占内存,适合块长较大的场景,我建议工程实现直接上枚举式编码,别真去建一个几百万行的表格。
查表法虽然直观,但有一个很隐蔽的坑:如果只是简单按字典序截取前2^k个序列,序列集合会偏向某一类排列,实际输出概率会和目标概率有偏差,尤其当块长较短时偏差更明显。我踩过这个坑,后来改用按“平均能量”排序再截取,或者用完整的CCDM方案,偏差才压下来。
2.3 符号位和格雷映射的配合
64QAM符号一共有6个比特,其中I、Q两路各有一个符号位,另外4个比特是两路幅度电平。分布匹配器只处理幅度比特,符号位保持均匀随机,这样才能保证星座的对称性。
格雷映射在这个链路里依然重要,甚至比均匀星座时更敏感。因为概率整形让部分比特位置承载更多信息,如果映射不是格雷码,某些比特的LLR可靠性会明显降低,GMI损耗比均匀调制情况下更大。我在仿真里试过把标签随意改成自然二进制映射,同样熵条件下GMI掉了0.4 bit/symbol以上,这是一个很容易被忽略的细节。
3. GMI指标:为什么看它、怎么算准
3.1 只看BER不够用
在做概率整形链路时,很多人习惯用预FEC BER来评估链路余量,这在均匀调制下勉强够用,但在整形调制下非常不可靠。原因很简单:BER只反映了硬判决后的错误比例,而FEC解码真正依赖的是软信息质量。
GMI,也就是广义互信息,是基于软信息计算的一个更贴近FEC解码极限的指标。它衡量的是在当前映射、当前信噪比条件下,6个比特位置平均一共能从接收信号里获得多少可靠信息。工程上可以近似把GMI看成FEC能承受的“输入信息预算”,GMI大于码率加余量,译码才可能收敛。
我自己在固定FEC码率做系统调测时,通常直接在GMI曲线上找目标工作点,例如GMI高于某个阈值且留有0.1到0.2 bit/symbol的余量,再去看BER是否低于某个阈值。GMI能更早暴露链路劣化趋势,BER在低码率区间往往还很平缓,GMI已经开始掉了。
3.2 LLR计算方法与GMI公式
GMI的计算不复杂,关键是拿到每个比特的LLR。对64QAM每个符号有6个比特,每个比特独立算一次互信息,最后相加。假设把比特0映射为b=-1,比特1映射为b=+1,那么这个比特的互信息可以写成:
I = 1 - E[ log2(1 + exp(-b·L)) ]
其中L是该比特的LLR,b是±1的标签。如果LLR定义方向和我这里反了,公式里的符号也要跟着调整,实现时统一约定就行,不然结果会变成负数。
具体流程是:接收符号做完同步、相位恢复、幅度归一化之后,对每一个星座点计算6个比特的LLR,然后按比特位置累加统计。精确LLR要用全距离枚举:
L_i = ln( Σ_{s:b_i=0} exp(-|y-s|²/2σ²) / Σ_{s:b_i=1} exp(-|y-s|²/2σ²) )
其中σ²是等效噪声方差。使用max-log近似虽然省计算量,但在64QAM这种高阶调制下会低估短距离点的软信息质量,导致GMI系统偏低,不建议在GMI精确测量时用。
3.3 一段可直接跑的GMI计算伪代码
下面是我常用的MATLAB风格计算片段,核心思路就是按比特位置算均值再求和:
% rx: 归一化后的接收符号 % tx_syms: 发送符号索引, 范围0~63 % sigma2: 噪声方差 LLR = zeros(6, length(rx)); for b = 0:5 for m = 0:63 if bitand(m, 2^b) == 0 % 该星座点比特为0 metric = exp(-abs(rx - constellation(m+1)).^2 / (2*sigma2)); LLR(b+1, :) = LLR(b+1, :) + metric; end end end % 注意这里只算了分子,分母类似,需切换集合真正实现时建议用矩阵化加log-sum-exp,避免直接exp溢出。GMI则按比特位置统计:
b_label = bi2de(bit_labels) * 2 - 1; % 0/1 -> -1/+1 gmi_bit = 1 - mean(log2(1 + exp(-b_label .* LLR)), 2); gmi_total = sum(gmi_bit);样本量不够大的时候GMI波动很明显。我一般至少统计20万到50万个符号,想稳定到小数点后两位,至少要100万符号量级。
4. 典型链路搭建与一次实测结果
4.1 发射机链路的模块顺序
主机链路从源比特到星座符号,我的顺序通常是:
- 信息比特进入分布匹配器,生成整形后的幅度比特;
- 经过FEC编码,这里需要特别小心码率和分布匹配器的配合;
- 拼接均匀符号位;
- 按格雷映射表映射成64QAM符号;
- 脉冲成形,上采样。
这个顺序不是唯一的,但有一点我强烈建议:不要先做FEC再做分布匹配,因为FEC编码后的奇偶校验比特是近似均匀的,直接送进DM会破坏码字结构,导致性能损失。更常见的是“整形后再编码”,通过设计让校验比特不影响幅度分布。
4.2 接收机链路与噪声模型
接收端相对简单:匹配滤波、定时同步、均衡、相位恢复、幅度归一化、LLR计算、GMI统计。做纯AWGN仿真时,不需要那么复杂的均衡,核心就是往发送符号上加高斯噪声。
为了贴近实际,我习惯把噪声方差和等效信噪比直接关联起来。64QAM发端平均功率归一化后,用不同的噪声方差扫描,等价于扫不同OSNR。具体公式在不同定义下会有差别,我建议在代码里固定一个参考带宽,这样结果可重复性会好很多。
在光通信仿真里,我一般还会加一阶相位噪声,不然GMI在低SNR区会偏乐观。相位噪声会拉低外层符号的LLR可靠性,而概率整形降低外圈概率后,对相位噪声的敏感度也会变化,这是仿真时很有意义的现象。
4.3 一组典型结果与读法
下面这组数据来自我某次固定链路参数的仿真,不代表所有情况,但趋势是典型的。此时使用ν=0.03的1D-MB整形,符号数50万个。
| 等效SNR | 均匀64QAM GMI | 整形64QAM GMI |
|---|---|---|
| 18 dB | 4.72 bit/symbol | 4.88 bit/symbol |
| 20 dB | 5.03 bit/symbol | 5.22 bit/symbol |
| 22 dB | 5.36 bit/symbol | 5.54 bit/symbol |
可以看到,在18到22 dB区间,整形后GMI大约提升0.15到0.2 bit/symbol。如果反过来看,在GMI约为5 bit/symbol这个工作点,均匀64QAM大约需要20 dB,整形64QAM大约只需要19.3 dB,相当于换来0.7 dB左右的整形增益。
但注意,如果继续增加ν,星座熵会下降,GMI会提前饱和,增益反而变小。我在扫ν的时候发现,整形强度不是越大越好,需要和目标工作点匹配。
4.4 星座图变化
概率整形后的星座图直接用示波器看,最明显的特征是外圈点变暗,中心附近点更亮。这在光模块的DSP里是一个很好的“开关自检”方法:如果外圈亮度比内圈低,说明DM确实在工作;如果外圈亮度和内圈一样,大概率是符号位也被送进了DM,或者DM编码没生效。
我曾在联调时看到星座图四个角上依然很亮,排查了半天才发现是测试序列没做随机化,信号源短循环导致概率分布没有真正按设计运行。这种问题靠看GMI曲线看不出来,反而是星座图上的亮度分布最直观。
5. 常见问题与排查技巧
5.1 输出概率和目标概率对不上
这个问题多见于查表法分布匹配器。原因有几个:一是块长太短,统计概率涨落大;二是序列截取方法不当,造成了系统性偏差。
我的排查方法是直接在DM输出端做直方图统计,如果幅度频率和设计值差超过2%,就要拉长块长或者换用CCDM方案。不要只看符号熵,因为不同序列集合可以有相同熵,但形状差很多。
5.2 GMI结果系统性偏低
如果GMI比理论预期低0.2 bit/symbol以上,先别急着怀疑信道,大概率是计算侧的问题。我整理过一张自查表:
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| GMI工作点整体偏低 | LLR的噪声方差偏大或偏小 | 校准σ²,用EVM估算等效方差 |
| 高SNR时GMI饱和值低于设计熵 | 整形熵太低,ν过大 | 减小ν或提高DM码率 |
| 低SNR时GMI差距异常大 | max-log近似低估 | 换精确LLR |
| 星座图可见但GMI异常低 | 比特标签顺序不一致 | 检查Gray表和LLR bit排序 |
我试过一次最离谱的问题:发端和收端用的Gray表版本不同,GMI在22 dB只算出4.9,修好标签后直接回到5.4。这种低级错误反而最浪费时间。
5.3 发送功率归一化的理解
概率整形会降低平均符号能量,所以如果你在仿真里直接按“固定星座峰值”发射,整形的增益会被掩盖。正确做法是要么固定平均功率,要么固定发射功率,前者在MATLAB里比较直观,后者更贴近光模块实际。
我在代码里统一先让均匀64QAM的平均功率等于1,然后整形星座乘一个比例因子,使得平均功率也等于1。这样两者比较的就是同一功率预算下的性能,不会出现“整形后星座整体变小所以看起来变差”的假象。
5.4 LLR数值稳定性的小技巧
计算GMI时,LLR的数值范围很大,外层点可能有正的十几,内层点可能负十几。直接用log2(1+exp(-b·L))在L比较大的时候没问题,但如果L是负十几,exp会溢出。我习惯写成等价形式:
gmi_bit = 1 - mean(pos + log2(1 + exp(-abs(L))))
其中根据符号选择pos还是neg,这样数值稳很多。这个小细节看起来不起眼,但在跑百万符号仿真时能省掉大量NaNs导致的返工。
6. 一点个人体会与后续扩展
我自己在实际链路里踩过最深的坑,不是理论不会,而是仿真链路里“概率整形到底放在FEC前还是后”纠缠了很久。现在我的建议是,先抛开码率优化这些细节,把无编码的整形链路的GMI曲线跑通、跑准,再一步步引入FEC。GMI这个指标的好处就在于,它能直接把波形质量和信息论极限挂钩,帮你排除掉很多“看起来星座很漂亮但实际性能很怪”的中间状态。
后面我打算在这个链路上继续扩展两个方向:一是换成二维概率整形,看看比一维整形能不能再多争取0.1 dB;二是把整形参数做成自适应的,根据信道状态动态调整ν,让系统在低OSNR和高OSNR区间都能保持最优GMI。如果你也在玩概率整形,奉劝一句:先把分布匹配器这个“概率源头”搞扎实,否则后面所有指标都会跟着歪。