M-PHY v6.0 PAM4自动化测试:示波器脚本控制与眼图测量实践
2026/9/7 1:34:08 网站建设 项目流程

做硬件测试的朋友应该都有这种感触:每次测 M-PHY 信号,都要反复调整示波器参数、手动寻找测量点、一次一次导出波形再判定合格性,遇到 PAM4 信号之后,这种重复劳动更是成倍增加。PAM4 每个电平都有独立的眼高、眼宽、电平误差,人工去拉标尺、读参数,效率低不说,还容易读错。最近在梳理 M-PHY v6.0 测试方案时,我把整套自动化测试流程重新走了一遍,从硬件连接到脚本控制、从参数测量到报告生成都做了闭环验证。这篇文章就围绕这套方案展开,适合正在做 M-PHY 一致性测试、PAM4 信号调试,或者想把手动示波器操作改造成自动化脚本的开发者参考。

在开始之前先说明一点:本文不会只给结论,而是把为什么要用自动化测试、PAM4 相比 NRZ 的测试难点在哪里、整个自动化脚本的框架怎么搭、每个关键命令起到什么作用都拆开讲。不管你是测试工程师、嵌入式硬件工程师,还是想往“硬件测试自动化”方向转的软件开发,都可以按本文步骤在自己环境中复现一遍。

1. M-PHY v6.0 与 PAM4 测试到底在测什么

1.1 M-PHY 是什么

M-PHY 是 MIPI 联盟定义的物理层串行接口标准,广泛用于移动终端的存储、显示、相机等高速数据传输场景。它和常见的 USB、PCIe 定位不同,M-PHY 更强调低功耗、低电磁干扰和灵活的速率配置,在手机、平板、车载娱乐系统里非常常见。

M-PHY 的速率不是固定的,而是通过不同 Gear(速率档位)和不同配置来组合。比如 Gear1、Gear2、Gear3、Gear4,每一档对应不同的线速率,实际工作中会根据应用场景自动切换。对于测试来说,这意味着同一套测试环境往往要覆盖多个速率点,手动测试的工作量会成倍增加。

1.2 v6.0 版本引入了什么新变化

M-PHY 规范从早期版本一路演进到 v6.0,最核心的变化之一就是引入了 PAM4 调制方式。传统 M-PHY 使用 NRZ(Non-Return-to-Zero)编码,每个符号只携带 1 bit 信息,信号只有高低两个电平。而 PAM4(Pulse Amplitude Modulation 4-Level)使用四个电平,每个符号可以携带 2 bit 信息。

在同样的波特率下,PAM4 能实现两倍于 NRZ 的数据吞吐量。这对 UFS(Universal Flash Storage)等需要大带宽的场景非常重要。

但代价也很直接:

  • 信号的信噪比预算变差。
  • 眼图从“一个大眼睛”变成“三个堆叠的眼”,眼高、眼宽的定义更复杂。
  • 电平之间容易出现非线性,需要单独测量每个电平的误差。
  • 时钟恢复、均衡器的配置对测量结果影响更大。

所以到了 v6.0 时代,M-PHY 测试不再只是把示波器接上、按下 AUTO SET 就能完成的。它需要一套可控、可重复、可追溯的测试流程,而自动化测试正好是解决这个问题的手段之一。

1.3 PAM4 信号测试的核心指标

在写自动化方案之前,先列出 PAM4 测试中常用的测量项,后文的脚本也会围绕这些参数展开:

测量项含义为什么重要
眼高(Eye Height)每个电平眼图的垂直张开度反映噪声裕量,直接影响误码率
眼宽(Eye Width)每个电平眼图的水平张开度反映抖动裕量,影响时序余量
电平误差(Level Error)实际电平与标准 PAM4 电平的偏差反映发送端线性度,影响接收端判决
抖动(Jitter)信号边沿的时间偏差影响高速链路误码率
上升/下降时间信号跳变速度反映驱动能力和信号完整性
均匀性(Uniformity)三个眼的参数是否一致PAM4 信号质量的核心指标

手动测试时,这些指标分散在示波器的不同菜单里,读一遍可能要几分钟。自动化方案要做的,就是一次采集,把这些参数全部算出来,再根据规范限值自动判定合格与否。

2. 手动测试的痛点:为什么 PAM4 让效率问题彻底暴露

2.1 传统 NRZ 测试还能“忍忍”

如果是 NRZ 信号,测眼图相对直接:示波器设置成眼图模式,选好时钟恢复方式,等波形累积到一定数量,直接读眼高、眼宽、抖动就行。整个流程虽然也要配置,但参数少,工程师凭经验就能快速完成。

2.2 PAM4 测试的参数组合爆炸

PAM4 信号测试就不一样了:

  • 需要针对 Upper Eye、Middle Eye、Lower Eye 分别测量。
  • 需要设置电平判决阈值,不同阈值下眼图参数不同。
  • 时钟恢复可能要用到 PLL 带宽设置,不同设置影响抖动测量结果。
  • 均衡器开不开、均衡系数是多少,也会显著改变眼图形态。

这意味着一次完整的 PAM4 测试,可能涉及几十个参数组合。手动在示波器面板上一组一组地配,效率非常低。

2.3 手动操作的一致性无法保证

手动测试还有一个隐蔽的问题:不同工程师操作示波器时,旋钮、菜单、测量区域的选择都可能略有差异。A 工程师测出来的眼高和 B 工程师测出来的眼高,可能相差几个毫伏。这种差异在报告审核时非常头疼,因为没有人能确认哪一组数据是“标准操作”的结果。

自动化测试可以规避这个问题。脚本固定了所有测量参数,不管谁来跑,只要脚本不变、环境不变,结果就具有可重复性。

2.4 回归测试需求放大了效率差距

芯片验证和产品量产阶段,经常要跑回归测试:

  • 修改了发送端驱动电路,要重新测全速率档位。
  • 换了 PCB 走线,要对比修改前后的眼图参数。
  • 固件更新了均衡器配置,要跑同一组用例确认没有劣化。

手动测试在这种回归场景下几乎不可行。一次全量回归涉及的用例数量很多,只有脚本化、自动化才能真正落地。

3. 自动化测试环境准备:硬件、软件与连接拓扑

3.1 测试系统组成

一套完整的 M-PHY v6.0 PAM4 自动化测试系统通常由以下部分组成:

被测设备(DUT) ↓ 差分信号线 / 探针 测试夹具或探针台 ↓ SMA / 电缆 高带宽实时示波器 ↑ 控制命令 自动化测试电脑(安装测试软件 + Python 环境) ↓ 报告输出 测试报告(HTML / CSV / Excel)

这里有一个关键点:示波器不仅是被测信号的采集设备,也是自动化测试的核心仪器。脚本通过标准 SCPI 命令控制示波器完成配置、采集、测量、导出等全部动作。

3.2 示波器的选型思路

M-PHY v6.0 的最高速率档位已经非常快,测试 PAM4 信号时,示波器带宽至少要覆盖被测信号基波的若干倍,否则测出来的眼图会严重失真。

选型时要关注几个参数:

  • 模拟带宽:建议不低于被测信号最高基波频率的 3 到 5 倍,具体倍数可参考 MIPI 一致性测试规范中的要求。
  • 采样率:至少要满足眼图测量的过采样要求,否则水平方向的测量精度不够。
  • 通道数:M-PHY 是差分信号,至少要两个通道同时采集正负端。
  • 本底噪声:PAM4 对噪声更敏感,示波器本底噪声过高会直接影响眼高测量结果。

由于不同厂商、不同型号示波器的实际性能和接口命令有差异,本文示例以常见的支持 SCPI 命令控制的高带宽实时示波器为例,具体型号请根据你的项目实际情况调整。

3.3 软件环境

自动化脚本我习惯用 Python 来写,主要原因是生态成熟、上手快,而且可以方便地结合 pandas、openpyxl 等库做测试报告生成。

推荐环境:

操作系统:Windows 10/11 或 Linux Python:3.8 及以上 依赖库:pyvisa、numpy、pandas、openpyxl VISA 后端:NI-VISA 或 Keysight IO Libraries Suite

如果你的电脑上还没有 pyvisa,可以通过 pip 安装:

pip install pyvisa numpy pandas openpyxl

需要注意,pyvisa 只是一个编程接口,它需要配合底层的 VISA 后端才能和示波器通信。Windows 下建议安装 NI-VISA 或 Keysight IO Libraries Suite,安装完成后,先用厂商提供的 Connection Expert 软件确认电脑能识别到示波器,再运行 Python 脚本。

3.4 仪器连接与地址确认

示波器和电脑常见的连接方式是:

  • 网线连接:通过 LAN 口连接,适合脚本自动化。
  • USB 连接:通过 USB-TMC 接口连接,适合单台仪器的临时调试。
  • GPIB 连接:较老式仪器常用,现在新设备已经很少保留 GPIB 接口。

连接完成后,用下面的小脚本扫描仪器地址:

import pyvisa rm = pyvisa.ResourceManager() print(rm.list_resources())

如果输出类似TCPIP0::192.168.1.100::inst0::INSTR这样的地址,说明仪器已经被电脑识别到了。把这个地址保存下来,后面所有控制脚本都基于它来通信。

4. PAM4 自动化测试方案的整体设计

4.1 自动化测试流程

整套自动化测试流程可以拆成下面几个步骤:

1. 连接仪器:建立 VISA 会话,复位仪器到默认状态。 2. 设置采集参数:根据测试规范配置示波器的采样率、存储深度、垂直刻度、水平时基。 3. 配置通道与触发:选择差分通道,设置触发电平。 4. 配置时钟恢复:选择与规范一致的时钟恢复方式。 5. 配置 PAM4 分析参数:设置电平数、判决阈值、均衡器参数。 6. 触发采集并等待波形稳定。 7. 执行测量:逐项读取眼高、眼宽、电平误差、抖动等参数。 8. 记录结果:将数据保存到 CSV 或 Excel。 9. 判定合格:对照规范限值生成 PASS/FAIL 结论。 10. 生成测试报告:输出 HTML 报告,便于归档和评审。

这个流程看起来简单,但每一步都有细节。比如时钟恢复配置如果和规范不一致,测出来的抖动数据直接不可信;通道垂直刻度如果设置不当,PAM4 信号可能削顶或太小,影响眼高测量。

4.2 为什么要用 SCPI 命令控制示波器

SCPI(Standard Commands for Programmable Instruments)是仪器控制领域的通用标准命令集。它的特点是命令可读性好、跨厂商兼容性好。

例如:

*RST

表示复位仪器。

:ACQuire:TYPE EYE

表示将采集模式设置为眼图模式。

:MEASure:EYE:HEIGht?

表示查询眼高测量结果。

不同厂商可能在一些高级测量命令上有私有扩展,但基础命令基本遵循 SCPI 标准。所以用 Python + pyvisa 发送 SCPI 命令,是目前最通用的示波器自动化控制方式。

4.3 项目目录设计

为了方便后续扩展,把整个自动化项目按模块拆分:

mphy_pam4_auto_test/ ├── config/ │ └── test_config.yaml # 测试参数配置 ├── core/ │ ├── instrument.py # 示波器控制封装 │ ├── measurement.py # 测量项执行 │ └── report.py # 报告生成 ├── scripts/ │ ├── run_all_tests.py # 主入口脚本 │ └── quick_check.py # 快速连通性检查 ├── results/ │ ├── raw_data/ # 原始测量数据 │ └── reports/ # HTML 报告 └── requirements.txt

这种结构的好处是:配置和代码分离,换一台被测设备时只需要改配置文件,不需要改代码;测量逻辑封装成独立模块,后续新增测量项时影响面小。

5. 核心代码实现:从仪器控制到报告生成

5.1 示波器控制封装

先封装一个基础的示波器控制类,统一管理连接、断开和命令收发。

# 文件路径:core/instrument.py import pyvisa import time class Oscilloscope: def __init__(self, resource_address, timeout=30000): self.rm = pyvisa.ResourceManager() self.instr = self.rm.open_resource(resource_address) self.instr.timeout = timeout self.instr.encoding = "latin1" def write(self, command: str): """发送写命令,不读取返回值。""" self.instr.write(command) def query(self, command: str): """发送查询命令并读取返回值。""" return self.instr.query(command).strip() def reset(self): """复位仪器,清除之前的配置和测量结果。""" self.write("*RST") time.sleep(2) def clear_status(self): self.write("*CLS") def wait_for_operation_complete(self): """等待仪器当前操作完成。""" self.query("*OPC?") def close(self): self.instr.close()

这里有几个细节说明:

  • timeout设置为 30000 毫秒,是因为 PAM4 眼图采集有时需要较长时间,如果超时时间太短,脚本会提前抛异常。
  • encoding="latin1"是为了兼容部分示波器返回二进制数据时的字符编码问题。
  • *RST之后加了time sleep,给仪器留出复位后的初始化时间。

5.2 加载测试配置

使用 YAML 格式管理测试参数,好处是结构清晰、容易修改。

# 文件路径:config/test_config.yaml instrument: address: "TCPIP0::192.168.1.100::inst0::INSTR" acquisition: sample_rate: 128e9 memory_depth: 200e6 horizontal_scale: 1e-9 vertical_scale: 150e-3 channels: positive: "1" negative: "2" voltage_range: 0.3 clock_recovery: enabled: true pll_bandwidth: 4e6 reference_rate: 9.6e9 pam4: levels: 4 eye_measurement: ["upper", "middle", "lower"] equalizer_enabled: false limits: eye_height_min_mv: 50.0 eye_width_min_ps: 12.0 level_error_max_percent: 5.0

注意:具体的采样率、存储深度、时钟恢复参考频率,要以你的被测信号速率和 MIPI 一致性测试规范为准。上面配置只是示例框架。

读取配置的代码:

# 文件路径:core/config_loader.py import yaml def load_config(path="config/test_config.yaml"): with open(path, "r", encoding="utf-8") as f: config = yaml.safe_load(f) return config

5.3 配置示波器采集参数

下面这段代码把 YAML 中的采集参数下发到示波器。

# 文件路径:core/measurement.py import time def configure_acquisition(scope, config): """配置采集模式、采样率、存储深度、时基和垂直刻度。""" acq = config["acquisition"] # 设置为眼图采集模式 scope.write(":ACQuire:TYPE EYE") scope.write(f":ACQuire:SRATe {acq['sample_rate']}") scope.write(f":ACQuire:MDEPth {acq['memory_depth']}") scope.write(f":TIMebase:RANGe {acq['horizontal_scale']}") # 设置垂直刻度 ch = config["channels"] scope.write(f":CHANnel{ch['positive']}:RANGe {ch['voltage_range']}") scope.write(f":CHANnel{ch['negative']}:RANGe {ch['voltage_range']}") time.sleep(1) def configure_clock_recovery(scope, config): """配置时钟恢复参数。""" cr = config["clock_recovery"] if not cr["enabled"]: return # 不同的示波器时钟恢复命令差异较大,这里给出常见形式 scope.write(":EYE:CRECovery:SOURce CHANnel1") scope.write(f":EYE:CRECovery:PLL:BANDwidth {cr['pll_bandwidth']}") scope.write(f":EYE:CRECovery:REFerence {cr['reference_rate']}") time.sleep(1)

这里特别提醒一下:时钟恢复的 SCPI 命令在不同品牌、不同代际的示波器上差异比较明显。上面这组命令表达的是“配置 PLL 带宽和参考速率”的思路,实际使用时请查询你所使用示波器的编程手册,把命令替换成对应仪器支持的写法。

5.4 执行 PAM4 测量

PAM4 测量的核心是让示波器分别计算 Upper、Middle、Lower 三个眼的参数。不同示波器的实现方式可能不同,有的是通过设置测量区域,有的是通过内置的 PAM4 分析功能。

一个比较通用的思路是:

  1. 先开启 PAM4 分析模式。
  2. 让示波器自动识别四个电平。
  3. 分别读取三个眼的眼高、眼宽。
  4. 读取电平误差。
  5. 读取抖动。

示例代码如下:

# 文件路径:core/measurement.py def enable_pam4_mode(scope): """开启 PAM4 测量模式。""" # 该命令在不同示波器上差异较大,这里以常见写法演示思路 scope.write(":MEASure:PAM4:ENABle ON") scope.write(":MEASure:PAM4:STATes 4") def measure_eye_height(scope, eye_level): """ 测量指定 level 的眼高。 eye_level: "upper", "middle", "lower" """ result = scope.query(f":MEASure:PAM4:EYE:HEIGht? {eye_level}") return float(result) def measure_eye_width(scope, eye_level): """测量指定 level 的眼宽。""" result = scope.query(f":MEASure:PAM4:EYE:WIDTh? {eye_level}") return float(result) def measure_level_error(scope): """测量 PAM4 电平误差。""" result = scope.query(":MEASure:PAM4:LEVel:ERRor?") return float(result) def measure_jitter(scope): """测量总抖动。""" result = scope.query(":MEASure:PAM4:JITTer?") return float(result)

如果你使用的示波器不支持:MEASure:PAM4:*这类高级命令,还有一个备选方案:先在设备上手动配置 PAM4 分析,然后开启自动测量,最后通过示波器的自动化接口读取屏幕上已经显示的测量值。这种做法相当于“用脚本读面板数据”,虽然集成度低一些,但在许多老型号仪器上是可行的。

5.5 采集波形数据并保存

除了读取测量参数,通常还希望把原始波形保存下来,方便后续复现和分析。

# 文件路径:core/measurement.py import numpy as np def fetch_waveform(scope, channel="1", max_points=10000): """ 从指定通道读取波形数据。 返回 (时间数组, 电压数组) """ scope.write(":WAVeform:SOURce CHANnel" + channel) scope.write(f":WAVeform:POINts {max_points}") scope.write(":WAVeform:FORMat BYTE") data = scope.query_binary_values(":WAVeform:DATA?", datatype="b") t_start = float(scope.query(":WAVeform:XORigin?")) t_incr = float(scope.query(":WAVeform:XINCrement?")) y_origin = float(scope.query(":WAVeform:YORigin?")) y_incr = float(scope.query(":WAVeform:YINCrement?")) t = t_start + np.arange(len(data)) * t_incr v = y_origin + np.array(data) * y_incr return t, v

这里要注意,示波器返回波形数据时,不同仪器的字节格式可能有差异。有的返回BYTE类型,有的返回WORD类型,还有的返回 ASCII 字符串。上面示例用的是BYTE类型,如果你的示波器报错或数据明显不对,可以改成WORD并配合datatype="h"读取。

5.6 合格性判定

拿到测量值之后,需要和规范限值做比较,输出 PASS 或 FAIL。

# 文件路径:core/measurement.py def check_limits(measurements, limits): """ 根据限值配置判定测试结果。 measurements: dict,例如 {"upper_eye_height_mv": 80.2} limits: dict,来自 YAML 配置 """ results = {} upper_height_mv = measurements.get("upper_eye_height_mv") if upper_height_mv is not None: results["upper_eye_height"] = upper_height_mv >= limits["eye_height_min_mv"] upper_width_ps = measurements.get("upper_eye_width_ps") if upper_width_ps is not None: results["upper_eye_width"] = upper_width_ps >= limits["eye_width_min_ps"] level_error_percent = measurements.get("level_error_percent") if level_error_percent is not None: results["level_error"] = level_error_percent <= limits["level_error_max_percent"] results["overall"] = all(results.values()) return results

这里体现了一个重要的测试思路:不要只输出一个总 PASS/FAIL,要保留每一项的判定结果。否则遇到失败时,你无法快速定位是哪一项指标超限。

5.7 主控脚本

最后串起来的运行脚本如下:

# 文件路径:scripts/run_all_tests.py import sys import os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) import pandas as pd from core.instrument import Oscilloscope from core.config_loader import load_config from core.measurement import ( configure_acquisition, configure_clock_recovery, enable_pam4_mode, measure_eye_height, measure_eye_width, measure_level_error, measure_jitter, check_limits, ) from core.report import generate_html_report def main(): config = load_config("config/test_config.yaml") scope = Oscilloscope(config["instrument"]["address"]) scope.reset() scope.clear_status() # 1. 基础配置 configure_acquisition(scope, config) configure_clock_recovery(scope, config) # 2. 开启 PAM4 模式 enable_pam4_mode(scope) # 3. 等待波形稳定 scope.wait_for_operation_complete() # 4. 执行测量 measurements = { "upper_eye_height_mv": measure_eye_height(scope, "upper"), "middle_eye_height_mv": measure_eye_height(scope, "middle"), "lower_eye_height_mv": measure_eye_height(scope, "lower"), "upper_eye_width_ps": measure_eye_width(scope, "upper"), "middle_eye_width_ps": measure_eye_width(scope, "middle"), "lower_eye_width_ps": measure_eye_width(scope, "lower"), "level_error_percent": measure_level_error(scope), "jitter_ps": measure_jitter(scope), } # 5. 合格性判定 results = check_limits(measurements, config["limits"]) # 6. 保存原始数据 df = pd.DataFrame([measurements]) os.makedirs("results/raw_data", exist_ok=True) df.to_csv("results/raw_data/measurements.csv", index=False) # 7. 生成报告 generate_html_report(measurements, results, "results/reports/report.html") scope.close() print("测试完成,报告已生成。") print(results) if __name__ == "__main__": main()

整个流程很直观:连接仪器 → 复位 → 配置 → 采集 → 测量 → 判定 → 存数据 → 出报告。脚本写完后,后续跑回归测试只需要在命令行执行一次:

python scripts/run_all_tests.py

运行成功后,终端会输出:

测试完成,报告已生成。 {'upper_eye_height': True, 'upper_eye_width': True, 'level_error': True, 'overall': True}

如果你的 DUT 信号质量比较好,大概率所有判定项都是True。如果有False出现,说明对应指标不合格,需要回到硬件设计或测试配置上去排查。

6. 测试报告生成:从数据到可交付文档

6.1 为什么需要自动生成报告

测试报告不只是给工程师自己看的,还要给项目经理、客户、认证机构看。一份规范的报告应该包含:

  • 被测器件信息。
  • 测试环境信息。
  • 测试日期和操作人员。
  • 每一项测量值和限值的对比。
  • PASS/FAIL 结论。
  • 原始波形截图或数据文件位置。

手动填这些内容非常耗时,而且容易漏项。自动化生成报告可以保证每次测试的格式一致,数据直接从测量结果中写入,避免转抄错误。

6.2 简单的 HTML 报告生成

这里用纯 Python 生成一个简单的 HTML 报告,不依赖额外框架。

# 文件路径:core/report.py import datetime def generate_html_report(measurements, results, output_path): now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") rows = "" for key, value in measurements.items(): status = "PASS" if results.get(key, False) else "FAIL" color = "green" if status == "PASS" else "red" rows += f""" <tr> <td>{key}</td> <td>{value}</td> <td style="color:{color}; font-weight:bold;">{status}</td> </tr> """ html_content = f""" <html> <head> <meta charset="utf-8"> <title>M-PHY v6.0 PAM4 自动化测试报告</title> <style> body {{ font-family: Arial, sans-serif; margin: 40px; }} h1 {{ color: #333; }} table {{ border-collapse: collapse; width: 100%; }} th, td {{ border: 1px solid #ccc; padding: 8px; text-align: left; }} </style> </head> <body> <h1>M-PHY v6.0 PAM4 自动化测试报告</h1> <p>生成时间:{now}</p> <p>整体结论:<strong style="color:{'green' if results.get('overall') else 'red'};"> {'PASS' if results.get('overall') else 'FAIL'}</strong></p> <table> <tr> <th>测量项</th> <th>测量值</th> <th>判定</th> </tr> {rows} </table> </body> </html> """ with open(output_path, "w", encoding="utf-8") as f: f.write(html_content)

跑完测试后,直接打开results/reports/report.html就能看到完整报告。如果需要更正式的格式,可以把数据继续导出到 Excel,再用固定模板生成 Word 或 PDF,但核心思路是一样的。

7. 自动化测试中的常见问题与排查思路

在实际搭建这套自动化测试环境时,最容易遇到下面这些问题。

问题现象常见原因解决思路
脚本无法连接示波器网络不通、VISA 地址错误、防火墙拦截先用厂商的 Connection Expert 软件确认能识别仪器,再检查 Python 里用的地址是否一致
示波器能连上,但命令执行报错SCPI 命令与仪器型号不匹配查询对应型号的编程手册,确认命令语法
测量眼高结果偏小垂直刻度设置不当,信号削顶或本底噪声过大调整通道垂直范围,确保信号完整显示在屏幕内
时钟恢复配置无效时钟恢复源选择错误,或参考速率不匹配检查被测信号速率,确认时钟恢复参考值
波形数据读取异常返回格式设置错误,或点数过多导致超时尝试切换BYTE/WORD格式,减少读取点数
不同批次测试结果波动大未等待波形稳定就读取测量值在触发采集后增加延时,或使用*OPC?等待操作完成
PAM4 分析模式无法开启示波器带宽或软件选件不支持 PAM4 分析确认示波器是否安装了对应测量选件

7.1 连接失败时怎么排查

连接失败是最常见的问题。按这个顺序检查:

  1. 电脑和示波器能否互相 ping 通?如果网络不通,先解决网络问题。
  2. 厂商软件里能不能看到仪器?如果厂商软件都看不到,说明 VISA 驱动或网络配置有问题。
  3. Python 脚本中列出的资源和厂商软件是否一致?有时候同仪器会暴露多个地址,要用正确的那个。
  4. 是否有其他程序占用了仪器连接?比如厂商软件正在连接仪器,Python 脚本再连可能会失败。

7.2 测量结果不稳定怎么排查

如果连续跑两次测试,结果差异很大,优先检查:

  • 波形是否真的稳定了?有些示波器在触发点附近没有足够的波形累积时,眼图会看起来“缺肉”,这时候测出来的眼高和眼宽都偏小。
  • 信号路径是否一致?换过线缆、探针之后,测试结果可能会有明显变化。
  • 被测设备是否处于相同的配置状态?比如 UFS 设备处于不同功耗模式时,信号质量可能不同。

7.3 不要忽略示波器选件的影响

PAM4 分析在很多示波器上属于选件功能。如果你的仪器没有安装对应选件,面板上可能没有 PAM4 分析菜单,程序中的:MEASure:PAM4:*命令也会执行失败。

这种情况下有两种处理方式:

  • 联系仪器厂商开通选件试用。
  • 退而求其次,用传统的 NRZ 眼图测量方式分别测三个电平区间,但要注意这并不能完全替代真正的 PAM4 分析。

8. 最佳实践:把自动化测试真正落地到项目中

8.1 先做出“最小可行版本”

不要一上来就追求全自动、全量用例、花哨报告。先实现一个最小可行版本:连上仪器、配置一次采集、读取三项参数、输出一行结果。这个版本能在半天到一天内跑通,它最大的价值是验证整体链路是否可行。

链路通顺之后,再逐步增加新的测量项、新速率档位、更完整的报告模板。

8.2 配置文件与代码分离

M-PHY 测试要覆盖多个 Gear 速率,每个速率下的采样率、参考速率、时基可能都不一样。把这些差异放到 YAML 配置文件中,用--config参数指定不同配置文件,要比修改代码逻辑优雅得多。

例如:

python scripts/run_all_tests.py --config config/mphy_gear4.yaml python scripts/run_all_tests.py --config config/mphy_gear5.yaml

8.3 原始数据必须存档

测量结果可以一键生成,但原始波形数据同样重要。遇到争议时,原始波形是唯一能还原现场的证据。建议每次测试都保存一份原始波形文件,文件名包含测试日期、速率档位、用例编号。

8.4 异常处理要提前设计

示波器测试过程中可能出现各种异常:

  • 信号未连接,波形是平的,测量结果毫无意义。
  • 信号幅度异常,导致削顶或触发失败。
  • 仪器长时间不响应,脚本卡死。

脚本里应该加入基础保护逻辑:

  • 测量前检查波形是否有效。
  • 每个命令执行后设置超时。
  • 异常时保存日志,方便定位。

下面是一段简单的检查思路:

def check_signal_valid(scope, channel="1"): """检查通道是否有有效波形。""" amplitude = float(scope.query(f":MEASure:VAMPlitude? CHANnel{channel}")) if amplitude < 1e-6: raise RuntimeError(f"通道 {channel} 无有效信号,请检查连接。") return amplitude

8.5 对自动化测试保持合理的预期

硬件自动化测试的价值是“把人从重复劳动中解放出来”,但并不能完全取代测试工程师的判断。

举个例子:眼高指标 FAIL,可能是 DUT 本身信号质量不好,也可能是示波器垂直刻度太小引入了量化噪声。这时候需要工程师去分析是测试配置问题还是硬件设计问题。自动化测试给出的是“高可信的测量数据”,而最终决策仍然需要人来完成。

所以我在项目里经常跟团队说一句话:自动化测试把我们从“花时间测数据”中解放出来,让我们把时间花在“分析数据为什么不好”上。这才是自动化的真正意义。

9. 下一步:从脚本到测试平台

目前这套方案已经可以完成单台仪器的 PAM4 自动化测试。如果你希望把它做成一个可推广的测试平台,可以考虑下面几个方向:

  • 增加多台仪器适配,用统一的测量接口屏蔽厂商差异。
  • 接入 CI/CD 系统,在硬件版本更新后自动触发回归测试。
  • 增加历史数据管理与趋势分析,观察信号质量随版本演进的波动。
  • 结合机器学习方法,对历史测量数据做异常检测,提前发现信号劣化趋势。

M-PHY v6.0 和 PAM4 带来的测试复杂度提升是客观存在的,但通过自动化手段把测量流程固化下来之后,你会发现测试时间可以从原来的“按天计算”缩短到“按分钟计算”。希望这篇文章能帮你把这条路走通。建议你先从最小版本开始,跑通一次完整的 PAM4 测量,再逐步扩展测量项和报告模板,最终沉淀成属于自己团队的自动化测试资产。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询