周期性抖动(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)
120.707
5103.536
10207.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与时钟谐波频谱关系示意图 幅度 频率 基频 f0 2次谐波 2f0 3次谐波 3f0 PJ尖峰 幅度 A 频率 fpj 频率相近 → 强耦合 PJ 特征 离散谱线 幅度不随频率变化

如何测量 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 创造“共振”的通道,让你测到的抖动突然变大。你拿着频谱仪去找那些离散尖峰,再对照时钟频率算算谐波次数,很多问题就能锁定了。