1. 光模块自动化测试环境搭建与验证

光模块自动化测试环境搭建与验证 学习卡片

任务目标

用 Python + PyVISA 搭建一套最小可运行的光模块自动化测试台控制层:通过 LAN/GPIB 统一寻址可编程光衰减器、光功率计、误码仪、示波器和待测光模块(DUT),逐个执行 *IDN? 身份查询,并读取光功率计与衰减器的关键状态,确认远程通信链路全部正常。

环境与依赖

  • Python 3.9+,安装 pip install pyvisa pyvisa-py(无厂商 VISA 时用 pyvisa-py 后端)。
  • 各仪器已配置固定 IP 或 GPIB 地址,且与本机在同一网段/总线可达。
  • DUT 通过其控制接口(示例按 SCPI over TCP 处理)暴露可寻址资源串。

实现思路

用一张“资源名 → 角色”的配置表描述测试台拓扑,InstrumentRack 负责按配置打开 VISA 会话并缓存句柄;verify_all() 对每台仪器发送 *IDN? 并校验返回非空;随后对衰减器设置一个衰减值、对光功率计读取功率,作为“可读写”验证。任一环节异常都会被记录并计入失败,最终汇总通过/失败清单。

控制主机 PyVISA ResourceManager 可编程光衰减器 光功率计 误码仪 示波器 待测光模块 DUT 每台仪器执行 *IDN? 身份查询,衰减器/功率计额外做读写验证

关键完整代码

import pyvisa

# 资源名 → 角色。请按实际地址替换(LAN 用 TCPIP0::<ip>::inst0::INSTR,GPIB 用 GPIB0::<addr>::INSTR)
RACK = {
    "attenuator": "TCPIP0::192.168.1.31::inst0::INSTR",
    "power_meter": "TCPIP0::192.168.1.32::inst0::INSTR",
    "ber_tester": "TCPIP0::192.168.1.33::inst0::INSTR",
    "oscilloscope": "TCPIP0::192.168.1.34::inst0::INSTR",
    "dut": "TCPIP0::192.168.1.40::inst0::INSTR",
}

class InstrumentRack:
    def __init__(self, mapping, timeout_ms=5000):
        self.rm = pyvisa.ResourceManager("@py")  # 无厂商 VISA 时用 pyvisa-py 后端
        self.timeout_ms = timeout_ms
        self.mapping = mapping
        self.sessions = {}

    def open_all(self):
        for role, res in self.mapping.items():
            inst = self.rm.open_resource(res)
            inst.timeout = self.timeout_ms
            inst.write_termination = "\n"
            inst.read_termination = "\n"
            self.sessions[role] = inst

    def query(self, role, cmd):
        return self.sessions[role].query(cmd).strip()

    def write(self, role, cmd):
        self.sessions[role].write(cmd)

    def close_all(self):
        for inst in self.sessions.values():
            inst.close()
        self.rm.close()

def verify_all(rack):
    results = {}
    for role in rack.mapping:
        try:
            idn = rack.query(role, "*IDN?")
            results[role] = ("PASS", idn) if idn else ("FAIL", "empty *IDN?")
        except Exception as exc:  # 通信超时/地址错误等
            results[role] = ("FAIL", repr(exc))

    # 读写验证:衰减器设 10 dB,功率计读功率
    try:
        rack.write("attenuator", "ATT 10")
        results["attenuator_rw"] = ("PASS", rack.query("attenuator", "ATT?"))
    except Exception as exc:
        results["attenuator_rw"] = ("FAIL", repr(exc))

    try:
        results["power_meter_rw"] = ("PASS", rack.query("power_meter", "READ?"))
    except Exception as exc:
        results["power_meter_rw"] = ("FAIL", repr(exc))
    return results

if __name__ == "__main__":
    rack = InstrumentRack(RACK)
    try:
        rack.open_all()
        report = verify_all(rack)
    finally:
        rack.close_all()

    failed = [k for k, (s, _) in report.items() if s == "FAIL"]
    for k, (s, info) in report.items():
        print(f"{s:4} {k:16} {info}")
    print("\nRESULT:", "ALL PASS" if not failed else f"FAILED: {failed}")

运行与验证

  1. 把 RACK 中的资源串改成现场实际地址,保存为 rack_check.py。
  2. 执行 python rack_check.py。
  3. 观察输出:每台仪器应打印 PASS 及其 *IDN? 返回串;衰减器与功率计额外出现 attenuator_rw、power_meter_rw 两行。
  4. 判定通过条件:末行输出 RESULT: ALL PASS。若出现 FAILED: [...],对应角色即通信异常,需检查 IP/GPIB 地址、网段连通性或仪器远程模式是否开启。

注意:*IDN? 与 ATT/READ? 为通用示例命令,实际命令字以各仪器编程手册为准;若某仪器不支持某命令,会体现为该行 FAIL,属预期行为。