关于 matlab-analyze-ams-waveform
这是一项 MATLAB 技能,使用 Mixed-Signal Blockset 工具分析混合信号波形,面向电路与仿真工程师。它涵盖时序、相位噪声、抖动、PLL 锁定时间、重采样、ADC/DAC 表征和 HSpice 数据导入,并提供测量检查与报告流程。
主要功能
- 01相位噪声测量及抖动换算
- 02时钟抖动与 PLL 锁定时间分析
- 03波形时序与抗混叠重采样
- 04ADC/DAC INL/DNL 测量和校准
- 05导入 HSpice 仿真数据
适用场景
- 01测量 VCO 或 PLL 仿真的相位噪声
- 02计算周期抖动和周期到周期抖动
- 03表征 ADC 或 DAC 的线性度
- 04导入 HSpice 瞬态、交流或扫描数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-analyze-ams-waveform安装后在 Claude Code 中输入/matlab-analyze-ams-waveform确认已加载。
附带文件manifest.yaml
详细介绍
分析 AMS 波形 — Mixed-Signal Blockset 实用工具
使用 Mixed-Signal Blockset 中的 msblksutilities 函数分析波形数据。涵盖时序、相位噪声、抖动、锁定时间、重采样、INL/DNL、ADC/DAC 校准以及 HSpice 数据导入。
适用场景
- 测量时域 VCO/PLL 仿真输出的相位噪声
- 计算时钟信号的周期抖动或周期到周期抖动
- 将非均匀(变步长求解器)数据重采样到均匀网格
- 测量数字波形的上升/下降时间、占空比
- 计算 ADC/DAC 特性分析所需的 INL/DNL
- 导入 HSpice 仿真结果(.tr0、.ac0、.sw0)
- 将相位噪声曲线转换为积分 RMS 抖动
不适用场景
- 使用 Signal Processing Toolbox 进行频谱分析(FFT、PSD、谱图)——直接使用 SPT
- 信号质量指标(SNR、SINAD、THD、SFDR)——直接使用 SPT 函数(
snr、thd、sfdr、sinad) - 滤波或包络检测——直接使用 Signal Processing Toolbox
- 无需抗混叠重采样的均匀采样数据
工作流指引:收集相位噪声参数
当用户要求测量波形数据的相位噪声时,请先询问频率偏移点,再继续操作:
- 询问:“您想在哪些频率偏移处测量相位噪声?
默认值:
[10e3, 100e3, 1e6, 10e6]Hz——按 Enter 使用这些值,或指定您自己的值。” - 确认偏移后,根据最低偏移值建议 RBW:
RBW = min(offsets) / 2(例如,最低偏移为 10 kHz 时,使用 5 kHz)。说明: “我将使用 RBW = X Hz(最低偏移 / 2)。如需更改,请告知我。” - 除非用户另有要求,否则继续测量。
这样可以确保测量符合用户的应用需求,而无需用户事先了解 API 签名。
阶段 1:导入波形数据
1.1 确定数据源
% From workspace variables
x = t; y = v;
% From .mat file
data = load('waveform.mat');
x = data.time; y = data.voltage;
% From .csv
data = readmatrix('waveform.csv');
x = data(:,1); y = data(:,2);
% From HSpice transient (.tr0)
tr0Reader('sim.tr0', 'output.mat');
data = load('output.mat');
% From HSpice AC (.ac0)
ac0Reader('sim.ac0', 'output.mat');
% From HSpice DC sweep (.sw0)
sw0Reader('sim.sw0', 'output.mat');
% From Simulink simulation output (timeseries in logsout)
sig = simOut.logsout.get('signalName').Values;
x = sig.Time(:); % column vector
y = squeeze(sig.Data(:)); % column vector — squeeze removes trailing dims
1.2 波形基本摘要
分析前始终先打印摘要:
fprintf('=== Waveform Summary ===\n');
fprintf('Points : %d\n', numel(x));
fprintf('X range : [%.6g, %.6g]\n', min(x), max(x));
fprintf('Y range : [%.6g, %.6g]\n', min(y), max(y));
fprintf('Y mean : %.6g\n', mean(y));
fprintf('Y RMS : %.6g\n', rms(y));
if all(diff(x) > 0)
dx = diff(x);
if max(dx)/min(dx) < 1.01, uStr = 'yes'; else, uStr = 'no'; end
fprintf('X step : %.6g (uniform: %s)\n', median(dx), uStr);
if median(dx) > 0
fprintf('Sample rate: %.6g Hz\n', 1/median(dx));
end
end
1.3 MSB 分析菜单
Available MSB analyses for time-domain waveform:
--- Timing Measurements ---
[1] Rise time — timeDomainSignal2RiseTime
[2] Fall time — timeDomainSignal2FallTime
[3] Duty cycle — timeDomainSignal2DutyCycle
--- Clock / PLL Measurements ---
[4] Phase noise from frequency-domain data — phaseNoiseMeasure (default Type='Frequency')
[5] Phase noise from time-domain voltage — phaseNoiseMeasure (Type='Time')
[6] Period jitter & cycle-to-cycle jitter — clockJitterMeasure
[7] Phase noise to jitter conversion — phaseNoiseToJitter
[8] Lock time from control voltage — lockTimeMeasure
--- Resampling ---
[9] Anti-aliased resampling — lowpassResample
--- ADC/DAC Characterization ---
[10] INL / DNL measurement — inldnl
[11] ADC calibration — calibrateADC
[12] DAC calibration — calibrateDAC
--- Data Import ---
[13] HSpice transient (.tr0) — tr0Reader
[14] HSpice AC (.ac0) — ac0Reader
[15] HSpice DC sweep (.sw0) — sw0Reader
--- Frequency-Domain Utilities ---
[16] Interpolate/extrapolate to new grid — interpExtrap
[17] Laplace to biquad SOS — laplace2sos
阶段 2:执行分析
2.1 时序测量
% Rise time — 3rd arg is [low high] percent reference levels (required)
rt = timeDomainSignal2RiseTime(x, y, [10 90]);
fprintf('Rise time (10%%-90%%): mean = %.4g s (std = %.4g s, N=%d)\n', ...
mean(rt), std(rt), numel(rt));
% Fall time — same 3-arg signature
ft = timeDomainSignal2FallTime(x, y, [10 90]);
fprintf('Fall time (90%%-10%%): mean = %.4g s (std = %.4g s, N=%d)\n', ...
mean(ft), std(ft), numel(ft));
% Duty cycle — returns per-cycle values for multi-cycle waveforms
dc = timeDomainSignal2DutyCycle(x, y);
fprintf('Duty cycle: mean = %.4f%%, std = %.4f%%\n', mean(dc)*100, std(dc)*100);
2.2 相位噪声测量
**测量前检查(必需):**测量前确认仿真时长。
% Sim duration pre-check — STOP if insufficient
minDuration = 10 / min(FrOffset); % need >= 10 cycles of lowest offset
simDuration = x(end) - x(1);
if simDuration < minDuration
error('Simulation too short: %.4g s < %.4g s needed for %.0f Hz offset.\nIncrease sim stop time to >= %.4g s.', ...
simDuration, minDuration, min(FrOffset), minDuration);
end
% From time-domain voltage waveform (MSB variable-step simulation output)
% Type='Time' is REQUIRED — extracts phase via zero-crossings internally
Rbw = 1e3; % resolution bandwidth (Hz)
FrOffset = [10e3 100e3 1e6 10e6]; % offsets to measure
[PnAtOffsets, freqAxis, pnProfile] = phaseNoiseMeasure( ...
x(:), y(:), Rbw, FrOffset, 'on', 'PN Measurement', ...
-inf, ... % 7th arg: target PN level for plot overlay (-inf = no target line)
Type='Time');
% Note: To reduce ripple in pnProfile, use smaller RBW (increases freq resolution)
% or increase simulation duration. SpectralAverages is a PLL Testbench block
% parameter, NOT a phaseNoiseMeasure argument.
% From frequency-domain data (e.g., imported spectrum analyzer measurement)
% Default Type='Frequency': Xin=freq offset vector, Yin=power in dBc/Hz
[PnAtOffsets, freqAxis, pnProfile] = phaseNoiseMeasure( ...
freqOffsets, pnPower_dBcHz, Rbw, FrOffset, 'on', 'PN from Spectrum');
fprintf('Phase Noise Results:\n');
for k = 1:numel(FrOffset)
fprintf(' @ %.0f kHz : %.1f dBc/Hz\n', FrOffset(k)/1e3, PnAtOffsets(k));
end
% Save figure for Claude to read
figPath = fullfile(tempdir, 'phase_noise_plot.png');
saveas(gcf, figPath);
fprintf('Phase noise figure saved to: %s\n', figPath);
2.3 抖动测量
**必须进行后续操作:**每次测量相位噪声(第 2.2 节)后,始终使用 phaseNoiseToJitter 计算积分 RMS 抖动。以皮秒为单位报告抖动——这是工程师用来与规格比较的指标。
% Clock jitter from time-domain waveform
% Returns 2 outputs: [periodJitter, c2cJitter] (RMS values)
% threshold MUST cross the signal — use midpoint or known logic level
% Inputs must be column vectors
threshold = (max(y) + min(y)) / 2;
clockFreq = 1e9; % expected clock frequency (Hz)
[periodJitter, c2cJitter] = clockJitterMeasure(x(:), y(:), threshold, clockFreq);
fprintf('Period jitter (RMS): %.4f ps\n', periodJitter * 1e12);
fprintf('C2C jitter (RMS) : %.4f ps\n', c2cJitter * 1e12);
% Convert phase noise profile to jitter
% Exclude DC bin (freqAxis==0) — integration from 0 Hz returns Inf
validIdx = freqAxis > 0;
[jitterRad, jitterDeg, jitterSec] = phaseNoiseToJitter( ...
freqAxis(validIdx), pnProfile(validIdx), Frequency=carrierFreq);
fprintf('RMS jitter from PN : %.4f ps\n', jitterSec * 1e12);
2.4 锁定时间测量
% x = time, y = control voltage (loop filter output)
% lockTimeMeasure takes (voltage, time, tolerance) — note: voltage FIRST
% Both must be column vectors
x_col = x(:); y_col = y(:);
targetVoltage = y_col(end); % assume final value is lock voltage
errorTol = 0.01; % 1% tolerance
lockTime = lockTimeMeasure(y_col, x_col, errorTol);
fprintf('Lock time (%.0f%% tolerance): %.4g s\n', errorTol*100, lockTime);
**首选方法:**如果存在 PLL Testbench 模块,请使用其测得的锁定时间(get_param(tbBlk, 'UserData').lockTime)——与电压稳定检测相比,频率误差检测更准确。
2.5 重采样
% Anti-aliased resampling to new sample time
Ts_new = 1e-9;
tq = (x(1) : Ts_new : x(end))';
cfg.OutputRiseFall = Ts_new;
cfg.NDelay = 1;
cfg.SampleMode = 'variable';
cfg.CausalMode = 'off';
y_resampled = lowpassResample(x, y, tq, cfg);
x_resampled = tq;
2.6 INL/DNL 测量
% ADC: uses transition-based fit (works on ANY input stimulus, not just ramps)
result = inldnl(Analog, Digital, Range, 'ADC', ...
'INLMethod', 'All', 'DNLMethod', 'All', ...
'OffsetErrorUnit', 'All', 'GainErrorUnit', 'All');
fprintf('Max |Endpoint INL|: %.4f LSB\n', max(abs(result.EndpointINL)));
fprintf('Max |Endpoint DNL|: %.4f LSB\n', max(abs(result.EndpointDNL)));
fprintf('Offset Error: %.4f LSB\n', result.OffsetErrorLSB);
fprintf('Gain Error: %.4f LSB\n', result.GainErrorLSB);
% DAC: uses center-based fit (FitMode='centers' is default for DAC)
result_dac = inldnl(Analog, Digital, Range, 'DAC', ...
'INLMethod', 'All', 'DNLMethod', 'All');
**重要:**不要使用基于直方图的 DNL(代码箱计数)。该方法需要特定的输入激励(具有已知 PDF 的斜坡或正弦信号)。inldnl 函数使用基于转换的分析,可处理任意输入。
**ADC 与 DAC:**ADC 使用 FitMode='transitions'(默认值);DAC 使用 FitMode='centers'。使用错误的拟合模式会导致结果不正确。
2.7 ADC/DAC 校准
% Calibrate ADC: correct offset and gain errors
y_cal = calibrateADC(Digital, NBits, Polarity);
% Or infer errors from measured data:
y_cal = calibrateADC(Analog, Digital, Range, 'OffsetError', oe, 'GainError', ge);
% Calibrate DAC:
y_cal = calibrateDAC(Digital, NBits, Polarity);
% Or with reference/bias:
y_cal = calibrateDAC(Digital, Analog, Ref, Bias);
阶段 3:解读相位噪声图
3.1 斜率分析
| 区域 | 斜率 | 物理含义 |
|---|---|---|
| 近端(< 环路带宽) | -30 dB/dec | 1/f^3 —— 闪烁 FM 噪声占主导 |
| 中间范围 | -20 dB/dec | 1/f^2 —— 白 FM / VCO 热噪声 |
| 远端(> 环路带宽) | -20 dB/dec 后趋平 | VCO 开环噪声,随后为热噪声底 |
3.2 环路带宽峰值
出现隆起或峰值(3–10 dB)表示 PLL 闭环带宽。 若超过 10 dB,则环路可能欠阻尼(相位裕度较低)。
3.3 噪声底
远端噪声底(偏移超过 1–10 MHz)由 VCO 热噪声和仿真数值噪声决定。其数值应与 VCO 开环规格相符。
3.4 杂散与波纹
- 高频波纹:频谱平均不足
- 杂散音调:在小数分频 PLL 中,预期会出现在 fPFD 的整数倍频处
- 低偏移频率处平坦或上升:仿真时间过短(参见 W9)
3.5 示例解读
Phase noise from a 1 GHz VCO (MSB sim, 100 us, zero-crossing):
@ 10 kHz : -51.8 dBc/Hz <- marginal (sim too short)
@ 100 kHz : -82.4 dBc/Hz <- in 1/f^2 region, reasonable
@ 1 MHz : -98.4 dBc/Hz <- approaching noise floor
@ 10 MHz : -127.6 dBc/Hz <- VCO open-loop thermal floor
Observations:
- -20 dB/dec slope from 10-80 kHz confirms white FM noise
- Hump at 100-300 kHz suggests loop BW artifact
- Floor at -128 dBc/Hz consistent with VCO open-loop spec
- 10 kHz result unreliable -- need >= 1 ms sim for clean data
第 4 阶段:报告
4.1 保存图形以供检查
figPath = fullfile(tempdir, 'analysis_plot.png');
saveas(gcf, figPath);
fprintf('Figure saved to: %s\n', figPath);
MATLAB 打印出 figPath 后,使用 Read 工具打开 PNG
并提供观测结果(斜率、杂散、噪声底,参见第 3 阶段)。
4.2 生成 HTML 报告
始终生成 HTML 报告,包含:
- 标题(数据文件、日期、方法、MATLAB 版本)
- 深色主题
<pre>块中的 MATLAB 控制台输出 - 波形摘要表
- 测量配置表
- 数值结果表
- 通过
file:///URL 嵌入的图形 - 第 3 阶段的观测结果
- 建议
- 页脚:"Generated by Claude Code -- Waveform Analysis Skill -- {date}"
命名:在与数据文件相同的目录中保存为 report_{datafile_stem}.html。
快速参考:MSB 函数来源
| 函数 | 用途 |
|---|---|
phaseNoiseMeasure | 相位噪声测量 |
phaseNoiseToJitter | 相位噪声转抖动 |
clockJitterMeasure | 周期与周期到周期抖动 |
lockTimeMeasure | PLL 锁定时间 |
timeDomainSignal2RiseTime | 上升时间 |
timeDomainSignal2FallTime | 下降时间 |
timeDomainSignal2DutyCycle | 占空比 |
inldnl | INL/DNL 测量 |
calibrateADC | ADC 误差校准 |
calibrateDAC | DAC 误差校准 |
lowpassResample | 抗混叠重采样 |
interpExtrap | 多信号插值 |
laplace2sos | 拉普拉斯转双二阶节 SOS |
ac0Reader | 导入 HSpice AC 数据 |
tr0Reader | 导入 HSpice 瞬态数据 |
sw0Reader | 导入 HSpice DC 扫描数据 |
注意事项(MSB 专用)
- W1:始终根据数据计算
Fs(1/median(diff(x))),不要依赖假设值 - W2:对于相位噪声,RBW 应小于或等于最低偏移频率的一半
- W3:对于时域电压数据(MSB 仿真输出),始终传入
Type='Time'。有效类型只有'Frequency'(默认值)和'Time' - W4:对于非均匀采样数据,先使用
lowpassResample重采样到均匀网格 - W5:
clockJitterMeasure需要设计规格中的标称时钟频率,而不是根据数据估算的频率 - W6:HSpice 读取器会输出 .mat 文件——转换后再加载
- W7:MSB 使用变步长离散求解器,因此会产生非均匀时间数据。基于电压的 FFT 方法会失败——始终使用
phaseNoiseMeasure(..., Type='Time'),它会在内部通过零交叉提取相位 - W8:基于零交叉的
phaseNoiseMeasure会将中心频率报告为 f_carrier/2——这是一种显示惯例,载波仍然正确 - W9:仿真时长限制了可测量的最低偏移频率:时长需要 >=
10/f_offset_min秒。例如,10 kHz 偏移需要 >= 1 ms 的仿真时间 - W10:使用较小的 RBW 或较长的仿真时长可降低 PN 曲线的波纹。
SpectralAverages是 PLL Testbench 模块参数(通过set_param设置),不是phaseNoiseMeasure的参数 - W11:MSB 变步长数据会显示
max(dt)/min(dt) >> 1。这是预期行为——测量 PN 时使用Type='Time',或使用lowpassResample创建均匀网格以进行 FFT - W12:如果阈值未与信号相交,
clockJitterMeasure会返回 NaN。使用(max(y)+min(y))/2或已知的逻辑阈值 - W13:如果
freqAxis(1)==0,phaseNoiseToJitter会返回 Inf。调用前始终排除 DC 频点 - W14:绝不要对 MSB 仿真数据使用基于直方图的 DNL。MSB 输出不是均匀斜坡——直方图方法会产生 1000 倍以上的误差。始终使用
inldnl(Analog, Digital, Range, Type),它采用转换检测 - W15:ADC 使用
FitMode='transitions'(默认值)。DAC 使用FitMode='centers'。使用错误的拟合模式会导致 INL 结果失真 - W16:所有 MSB 测量函数(
lockTimeMeasure、clockJitterMeasure、phaseNoiseMeasureType='Time')都要求使用列向量。使用x(:)和y(:)确保形状正确。行向量会导致结果错误但不提示,或引发错误
版权所有 2026 The MathWorks, Inc.