mcpField
M
matlab-analyze-ams-waveform

matlab-analyze-ams-waveform

github.com/matlab数据与数据库1.2k52 次安装1 天前更新
代码仓库

关于 matlab-analyze-ams-waveform

这是一项 MATLAB 技能,使用 Mixed-Signal Blockset 工具分析混合信号波形,面向电路与仿真工程师。它涵盖时序、相位噪声、抖动、PLL 锁定时间、重采样、ADC/DAC 表征和 HSpice 数据导入,并提供测量检查与报告流程。

主要功能

  1. 01相位噪声测量及抖动换算
  2. 02时钟抖动与 PLL 锁定时间分析
  3. 03波形时序与抗混叠重采样
  4. 04ADC/DAC INL/DNL 测量和校准
  5. 05导入 HSpice 仿真数据

适用场景

  1. 01测量 VCO 或 PLL 仿真的相位噪声
  2. 02计算周期抖动和周期到周期抖动
  3. 03表征 ADC 或 DAC 的线性度
  4. 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
  • 无需抗混叠重采样的均匀采样数据

工作流指引:收集相位噪声参数

当用户要求测量波形数据的相位噪声时,请先询问频率偏移点,再继续操作:

  1. 询问:“您想在哪些频率偏移处测量相位噪声? 默认值:[10e3, 100e3, 1e6, 10e6] Hz——按 Enter 使用这些值,或指定您自己的值。”
  2. 确认偏移后,根据最低偏移值建议 RBW: RBW = min(offsets) / 2(例如,最低偏移为 10 kHz 时,使用 5 kHz)。说明: “我将使用 RBW = X Hz(最低偏移 / 2)。如需更改,请告知我。”
  3. 除非用户另有要求,否则继续测量。

这样可以确保测量符合用户的应用需求,而无需用户事先了解 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/dec1/f^3 —— 闪烁 FM 噪声占主导
中间范围-20 dB/dec1/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 报告,包含:

  1. 标题(数据文件、日期、方法、MATLAB 版本)
  2. 深色主题 <pre> 块中的 MATLAB 控制台输出
  3. 波形摘要表
  4. 测量配置表
  5. 数值结果表
  6. 通过 file:/// URL 嵌入的图形
  7. 第 3 阶段的观测结果
  8. 建议
  9. 页脚:"Generated by Claude Code -- Waveform Analysis Skill -- {date}"

命名:在与数据文件相同的目录中保存为 report_{datafile_stem}.html。


快速参考:MSB 函数来源

函数用途
phaseNoiseMeasure相位噪声测量
phaseNoiseToJitter相位噪声转抖动
clockJitterMeasure周期与周期到周期抖动
lockTimeMeasurePLL 锁定时间
timeDomainSignal2RiseTime上升时间
timeDomainSignal2FallTime下降时间
timeDomainSignal2DutyCycle占空比
inldnlINL/DNL 测量
calibrateADCADC 误差校准
calibrateDACDAC 误差校准
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、phaseNoiseMeasure Type='Time')都要求使用列向量。使用 x(:) 和 y(:) 确保形状正确。行向量会导致结果错误但不提示,或引发错误

版权所有 2026 The MathWorks, Inc.


评论

支持 Markdown