周期性抖动(PJ):正弦波特征、幅度与频率,与时钟谐波的关系
周期性抖动(PJ),说白了就是抖动里那些有固定频率、重复出现的分量。我在项目里见过很多工程师一看到抖动超标就慌了,其实只要学会从频谱上揪出那几根孤独的谱线,问题就好解决一半。
PJ 的正弦波特征
为什么我们总用正弦波模型来描述 PJ?你想想看,任何周期信号都能分解成正弦波的叠加。PJ 的来源,比如开关电源的纹波、相邻信号的串扰、甚至隔壁风扇的振动,本质都是某个频率的周期性干扰。这个干扰叠加到时钟或数据边沿上,就产生了抖动。
数学上,一个典型的 PJ 可以写作:
J(t) = A * sin(2π * fpj * t + φ)
其中 A 是幅度(单位通常为 ps 或 UI),fpj 是抖动频率,φ 是初相。我个人的经验是,现场测到的 PJ 往往不是纯净的正弦,但用这个模型做拟合,90% 的工程问题都能搞定。
关键点:PJ 的时域波形是正弦形状,但如果你用示波器看眼图,它会导致眼图的上下边沿产生周期性的“呼吸”效果。锁相环对低频 PJ 有跟踪能力,高频部分则容易直通。
幅度与峰峰值的关系
很多人搞不清 PJ 的幅度和峰峰值有什么区别。我遇到过一位测试员,拿着示波器测出的峰值直接当幅度去算,差点把设计参数标错。实际上,PJ 的峰峰值 = 2 × 幅度 A(正弦波的峰峰差)。比如 A = 5 ps,那么峰峰值就是 10 ps。
| 幅度 A (ps) | 峰峰值 (ps) | 有效值 (RMS, ps) |
|---|---|---|
| 1 | 2 | 0.707 |
| 5 | 10 | 3.536 |
| 10 | 20 | 7.071 |
你注意,RMS 值 = A / √2,这在总抖动计算里特别有用。因为随机抖动(RJ)是高斯分布,你要把 PJ 和 RJ 叠加的时候,得用 RMS 做方和根。这个细节我后面再展开讲。
频率对系统的影响
PJ 的频率决定了它能不能穿过锁相环的带宽。
- 低频 PJ(比如几十 kHz):PLL 能跟踪,输出抖动很小。
- 高频 PJ(比如几 MHz 以上):PLL 来不及反应,会直接出现在输出上。
我在调试一块 10Gbps 的 SerDes 时,发现抖动超标,查了半天发现是板上一个 DCDC 开关频率 2.2 MHz 耦合到了时钟线上。它的谐波刚好落在 PLL 通带外面,结果眼图都关上了。最后加了个 RC 滤波,解决了。
注:并不是所有 PJ 频率都等于电源纹波频率。因为时钟是方波,方波的谐波会被干扰调制,产生“混频”效果。你测到的 PJ 频率可能是 |f_干扰 ± n × f_时钟| 的组合。
PJ 与时钟谐波的关系
这一点我见过太多人掉坑了。时钟信号不是理想正弦波,它包含丰富的奇次谐波(基频 f0、3f0、5f0…… 如果是非50%占空比,还有偶次谐波)。当干扰信号的频率接近某个谐波时,会产生强烈的串扰,在抖动频谱上表现为一个尖峰。
| 谐波阶次 | 频率 | 常见 PJ 来源举例 |
|---|---|---|
| 基频 | f0 | 时钟本身的相位噪声 |
| 二次谐波 | 2f0 | 整流纹波、倍频耦合 |
| 三次谐波 | 3f0 | 数字开关噪声、反射 |
举个真实例子:我测过一个 156.25 MHz 的时钟,在 312.5 MHz 处出现了一个很大的 PJ 尖峰。一开始以为是二次谐波,但仔细一查,是旁边一条 312.5 MHz 的数据线通过地平面回流,直接调制了时钟 buffer 的电源。这个频率恰好是时钟的二次谐波,所以强度特别大。
如何测量 PJ 的幅度与频率
我最常用的工具是相位噪声分析仪或者实时示波器 + 数学运算。用示波器测出时钟的时域抖动轨迹,然后做 FFT,就能在频谱上看到 PJ 的尖峰。不过要注意,示波器的垂直分辨率有限,如果 PJ 幅度太小(< 1 ps),容易被噪声淹没。这时候我习惯用相位噪声仪器,其本底噪声能低到 -150 dBc/Hz。
下面是一段简单的 Python 代码,用来从抖动的时域数据里拟合出 PJ 幅度和频率。我在实验室经常用它做快速验证:
import numpy as np
from scipy.optimize import curve_fit
def pj_model(t, A, fpj, phi, offset):
return A * np.sin(2*np.pi * fpj * t + phi) + offset
# 假设从示波器导出的时间戳序列 time 和抖动序列 jitter
# 用曲线拟合提取参数
popt, _ = curve_fit(pj_model, time, jitter,
p0=[5e-12, 2e6, 0, 0]) # 初始猜测:幅度5ps,频率2MHz
A_fit, fpj_fit, phi_fit, offset_fit = popt
print(f"拟合结果:幅度={A_fit*1e12:.2f} ps, 频率={fpj_fit/1e6:.3f} MHz")
小技巧:拟合前先做个带通滤波,可以把非相关的随机抖动滤掉一大半,拟合出的 PJ 参数更准。我在以前的项目里靠这招抓出过一个 4.3 MHz 的VCO注入噪声。
避坑指南
- 别把多个 PJ 当成一个:频谱上可能同时有多个尖峰,分别对应不同的干扰源。建议逐个分离,避免把不同的A和fpj混在一起拟合。
- 注意相位噪声的“裙边”:有时候看起来像 PJ 的尖峰,实际上是时钟本身的相位噪声由于某种调制展宽了。切换不同的RBW(分辨率带宽)可以区分——真正的 PJ 尖峰幅度不随 RBW 变化,而相位噪声会随 RBW 等比例变化。
- 时钟谐波引起的 PJ 往往与频率相关:我曾经遇到一个设计,PJ 在 156.25 MHz 时钟的 7 次谐波上特别明显,最后发现是 PCB 上一条长走线形成了驻波。换了端接电阻就没了。
好了,这一节的核心就是:PJ 是正弦波,幅度决定抖动的大小,频率决定它能不能逃过 PLL 的眼睛。而时钟谐波会给 PJ 创造“共振”的通道,让你测到的抖动突然变大。你拿着频谱仪去找那些离散尖峰,再对照时钟频率算算谐波次数,很多问题就能锁定了。