1. 抖动概述与基本概念归纳
1.1 什么是抖动?
抖动这东西,说白了就是信号边沿偏离理想位置。你想想看,数字电路里的时钟本应该在0.5ns处跳变,结果它跑到0.52ns才跳——这0.02ns的偏差就是抖动。
我做高速接口项目那会儿,一开始觉得抖动只是“波形差一点”,直到眼图闭上,误码率直接飙到10⁻⁶,才明白这东西不搞清楚,芯片根本跑不起来。个人习惯,每接触新信号标准,第一件事就是查它允许的抖动预算。
1.2 抖动的来源
抖动能从哪冒出来?我归纳了下,常见就这几类:
- 电源噪声——电源纹波直接调制到时钟边沿。我曾经在DDR3调试时,发现抖动波形正好跟开关频率吻合,一查果然是电源去耦没做好。
- 串扰——相邻信号线之间的耦合。尤其是长走线并行时,串扰抖动简直防不胜防。
- 热噪声——半导体器件的散粒噪声、闪烁噪声,属于底噪,永远都在。
- 码间干扰(ISI)——前一个比特的状态影响当前比特的边沿。速率越高,ISI越明显。
- 时钟源自身——PLL的抖动、晶振的相位噪声。
检查思路:拿到抖动谱,先看是否存在固定频率尖峰。如果有,多半是电源或串扰;如果是宽频白噪,那就是热噪声主导。
1.3 抖动分类
业内最常用的分法:随机抖动(RJ)和确定性抖动(DJ)。前者无界但服从高斯,后者有界且有规律。
| 类型 | 特性 | 常见来源 | 分布形状 |
|---|---|---|---|
| 随机抖动(RJ) | 高斯分布,均方根描述 | 热噪声、散粒噪声 | 钟形曲线 |
| 确定性抖动(DJ) | 有界,峰峰值描述 | 电源噪声、串扰、ISI | 双峰、矩形等 |
| 其中:周期性抖动(PJ) | 单一或多个频率正弦抖动 | 电源纹波、时钟调制 | 正弦相位谱 |
| 其中:数据相关抖动(DDJ) | 码型决定,包括ISI和DCD | 信道不匹配、占空比失真 | 与码型相关 |
为什么要分这么细?因为不同的抖动,抑制手段完全不同。电力噪声靠滤波,ISI靠均衡,RJ只能靠扩频或冗余时钟。我记得有一次项目里眼图闭合,一开始怀疑是RJ,跑完分解才发现是0.1MHz的PJ主导——换一个LDO就解决了。嗯,分解的意义就在这里。
别搞混了:RJ用均方根(RMS),DJ用峰峰值(Peak-to-Peak),两者单位不一样,不能直接相加。很多新人直接把RMS×2当峰峰值用,结果眼图预算算错,流片回来才发现。
1.4 抖动的测量指标
光知道分类还不够,你得会量。常见指标就这几个:
- 峰峰值抖动(Jp-p)——采样窗口内边沿位置的最大偏差。简单但受采样数影响,采样越多测到越大。
- 均方根抖动(JRMS)——对高斯部分有效,稳定且可重复。
- 眼图开口——眼高、眼宽直接反映数据有效窗口。我习惯把眼宽跟抖动峰峰值放一起看,超过总预算的20%就危险了。
- 抖动谱(Phase Noise)——频域分析,能看出干扰频率点。
我的建议:量产测试用Jp-p,因为快;研发调试重点看抖动谱,因为定位快。
1.5 抖动分解的意义
你得到一组抖动数据,比如眼图闭合了,但你不知道是随机抖动太大还是确定性抖动干预。抖动分解算法的作用就是从总抖动(TJ)里分离出RJ和DJ,再进一步把DJ拆成PJ、DDJ等。这样你才能对症下药。
拿我经历的SerDes项目来说,总抖动6ps,直觉觉得是RJ太大。但分解后RJ只有1.2psRMS,DJ占了4.5pspp——再一细化,DDJ里面的ISI贡献了3ps。于是加了个CTLE,眼图立马打开。你说不分解行吗?
1.6 本章知识体系
1.7 代码示例:模拟简单抖动
分解之前,先看看抖动长什么样。用Python生成一个带随机抖动的时钟边沿:
import numpy as np
import matplotlib.pyplot as plt
fs = 100e9 # 采样率 100 GSa/s
f_clk = 1e9 # 时钟频率 1 GHz
t_period = 1e-9 # 1 ns
t = np.linspace(0, 10*t_period, 1000)
# 理想时钟沿(上升沿在 t = 0, 1ns, 2ns ...)
ideal_edges = np.arange(0, 10*t_period, t_period)
# 加入高斯抖动(RJ): sigma = 10 ps
jitter = np.random.normal(0, 10e-12, size=len(ideal_edges))
actual_edges = ideal_edges + jitter
# 构建时钟波形(方波)
clock = np.zeros_like(t)
for edge in actual_edges:
idx = np.searchsorted(t, edge)
clock[idx:] = 1 - clock[idx:] # 翻转
# 估算抖动峰峰值、RMS
pp_jitter = np.max(jitter) - np.min(jitter)
rms_jitter = np.std(jitter)
print(f"抖动峰峰值: {pp_jitter*1e12:.1f} ps")
print(f"抖动 RMS : {rms_jitter*1e12:.1f} ps")
跑这段代码,你会看到理想边沿被随机高斯噪声扰动。每次结果不同,但RMS稳定在10 ps左右。
改着玩:如果把噪声换成
np.random.normal(0, 5e-12),或者加一个正弦干扰模拟PJ,看看峰峰值怎么变。
记住,这只是一个模拟。真实芯片上的抖动需要考虑带宽、上升沿斜率、噪声谱形状等因素。但概念理解上,你已经知道抖动是什么、怎么量、为什么需要分解了。