4. 测试仪器程控基础与SCPI指令

光模块自动化测试平台的核心能力,是把光功率计、可调衰减器、误码仪等仪器从“手动旋钮”变成“程序可寻址、可读回、可判定”的受控对象。实现这一点的技术底座是 SCPI 指令、VISA 通信层与 PyVISA 编程接口。本节围绕这三层展开,并补充连接超时、错误查询与状态寄存器等工程细节。

SCPI 指令结构:一棵可预测的命令树

SCPI(Standard Commands for Programmable Instruments)建立在 IEEE 488.2 通用命令之上,采用树状层级结构。命令由冒号分隔的路径组成,例如 :SOURce:POWer:LEVel:IMMediate:AMPLitude。SCPI 的关键规则是:大写字母为缩写必需部分,小写可省略,因此上述命令可写作 :SOUR:POW:LEV:IMM:AMPL。命令分为两类:设置类(无问号,如 :POW 3.0)和查询类(以问号结尾,如 :POW?),查询会返回响应,必须由程序读取,否则会残留在输出缓冲区中污染后续查询。

参数与单位也需注意。SCPI 允许在数值后附加单位后缀,如 DBM、MW、NM、HZ,仪器会按后缀换算。例如设置光功率计波长 :SENS:WAV 1310NM,设置衰减器衰减量 :INP:ATT 10DB。若省略单位,仪器使用当前默认单位,容易产生歧义,工程代码中建议始终显式带单位。

SCPI 命令树与三类仪器控制路径 SCPI 命令树(以光功率计为例) :SENSe :WAVelength :POWer:UNIT :READ? 设置类:无问号,写入参数 查询类:以 ? 结尾,必须读取 缩写规则 大写为必需,小写可省略 :SENS:WAV 1310NM :READ? → 返回功率值 VISA / PyVISA 层 ResourceManager() 枚举与打开资源 open_resource() 建立会话 write() / query() 发送与读回 timeout 属性 超时抛异常 资源地址示例 TCPIP0::192.168.1.10:: inst0::INSTR ASRL3::INSTR (串口) 三类仪器常用命令 光功率计 :SENS:WAV 1310NM :SENS:POW:UNIT DBM :READ? → -3.25 读回功率,单位 dBm 可调衰减器 :INP:ATT 10DB :INP:ATT? :OUTP:STAT ON 设置衰减量并回读确认 误码仪 :SOUR:DATA PRBS31 :SENS:PATT? :SENS:ERR? :SENS:RATE? 误码率、误码数、速率

常用仪器控制命令

光功率计的核心是波长设置与功率读取。不同波长下光电探测器响应度不同,因此测试前必须设置与光源一致的波长。典型流程::SENS:WAV 1310NM 设置波长,:SENS:POW:UNIT DBM 指定单位,随后 :READ? 返回当前功率。若返回 -3.25,表示 -3.25 dBm。部分仪器支持 :INIT 触发一次测量后再 :FETC? 取结果,适合需要精确同步的场景。

可调衰减器用于模拟链路损耗,验证接收灵敏度。设置衰减量用 :INP:ATT 10DB,回读用 :INP:ATT?。工程上建议“设置后回读”,因为机械式或步进式衰减器存在最小步进(如 0.1 dB),写入 10.05 dB 可能被量化为 10.1 dB,回读可确认实际生效值。输出开关 :OUTP:STAT ON/OFF 用于保护被测件,切换衰减量前可先关闭输出。

误码仪负责发送码型并统计误码。发送侧设置码型 :SOUR:DATA PRBS31,接收侧查询误码率 :SENS:ERR?、误码数 :SENS:ERR:COUN?、速率 :SENS:RATE?。误码测试需要先复位计数器 :SENS:ERR:RES,再等待统计时间,最后读取。若误码率为 0 但误码数不为 0,说明统计窗口内误码数极少,需结合总比特数判断是否可信。

VISA 库与 PyVISA 使用

VISA(Virtual Instrument Software Architecture)是仪器通信的统一抽象层,屏蔽 GPIB、USB、LAN、串口等物理差异。PyVISA 是 VISA 的 Python 绑定,安装后需配合后端(如 NI-VISA 或 pyvisa-py)。基本用法如下:

import pyvisa

rm = pyvisa.ResourceManager()
print(rm.list_resources())
# ('TCPIP0::192.168.1.10::inst0::INSTR', 'ASRL3::INSTR')

opm = rm.open_resource('TCPIP0::192.168.1.10::inst0::INSTR')
opm.timeout = 3000          # 单位 ms
opm.write(':SENS:WAV 1310NM')
opm.write(':SENS:POW:UNIT DBM')
power = float(opm.query(':READ?'))
print(power)                # 例如 -3.25
opm.close()

资源地址格式为 接口类型::地址::INSTR。LAN 仪器常用 TCPIP0::IP::inst0::INSTR,串口为 ASRL3::INSTR,USB 为 USB0::0x1234::0x5678::SN::INSTR。若 list_resources() 为空,通常是后端未安装或仪器未上电。

仪器连接与超时处理

超时是自动化测试最常见的故障。PyVISA 的 timeout 属性默认可能为 2000 ms,对于需要长时间统计的误码测试明显不足。建议按仪器类型分别设置:光功率计 2000 ms,衰减器 3000 ms,误码仪 10000 ms 以上。超时后 PyVISA 抛出 VisaIOError,应捕获并记录,而不是让程序崩溃。

try:
    ber = float(ber_meter.query(':SENS:ERR?'))
except pyvisa.errors.VisaIOError as e:
    print('查询超时:', e)
    ber_meter.clear()   # 清空缓冲区,恢复会话

超时后必须调用 clear() 或 read_raw() 清空残留数据,否则下一次查询可能读到上一次的旧值。这是“超时后数据错位”的典型根因。

错误查询与状态寄存器

SCPI 提供两层错误机制。第一层是错误队列:SYST:ERR? 返回最早的一条错误,格式为 <错误码>,"<描述>",如 0,"No error" 表示无错误,-113,"Undefined header" 表示命令头拼写错误。建议每次关键操作后查询一次,直到返回 0 为止。

第二层是状态寄存器。IEEE 488.2 定义了状态字节寄存器(STB),其中 bit5 为 ESB(事件状态位),bit6 为 MSS(主状态汇总)。通过 *ESE 32 使能 ESB,再用 *STB? 读取状态字节,可判断是否发生过错误事件。更细的故障可用 STAT:QUES:EVEN? 查询 questionable 状态寄存器。工程实践中,建议在测试脚本开头执行 *CLS 清状态、*RST 复位仪器,再开始正式测试,避免历史错误干扰判断。

推荐初始化顺序:*RST → *CLS → 设置超时 → 设置波长/单位/衰减量 → 回读确认 → 开始测试。每一步都应有回读或错误查询作为确认,而不是“发完即认为成功”。
常见误区:只写不读。设置类命令虽无返回,但若仪器因参数越界拒绝执行,错误会进入队列。若从不查询 SYST:ERR?,程序会“看起来正常”但实际未生效,导致测试结果不可信。