3. SCPI命令与仪器控制实战

SCPI(Standard Commands for Programmable Instruments)是射频自动化测试的“通用语言”。它把仪器功能抽象成一套基于文本的命令树,例如设置频率、查询功率、启动扫描,都可以通过短字符串完成。本节以Keysight信号发生器(如N5172B/EXG)和频谱仪(如N9020B/MXA)为例,使用Python与PyVISA建立连接,完成频率、功率、扫描等基本设置与读取。核心目标不是背命令,而是理解“命令—响应—数据”的闭环,并能独立写出可运行的脚本。

一、SCPI命令结构与常用命令

SCPI命令分为设置命令和查询命令。设置命令不带问号,例如 FREQ 1GHz;查询命令以问号结尾,例如 FREQ?。命令树用冒号分隔层级,如 :SOURce:FREQuency。实际编程中可使用缩写形式,但要注意大小写规则:大写字母为必需部分,小写可省略。例如 :SOUR:FREQ 等价于 :SOURce:FREQuency。

信号发生器常用命令::SOUR:FREQ 1e9 设置载波频率;:SOUR:POW -10 设置输出功率(dBm);:OUTP ON 打开射频输出;:SOUR:SWE:FREQ:STAR、:SOUR:SWE:FREQ:STOP 设置扫描起止频率;:SOUR:SWE:FREQ:MODE SWE 进入扫描模式。频谱仪常用命令::SENS:FREQ:CENT 1e9 设置中心频率;:SENS:FREQ:SPAN 10e6 设置扫宽;:SENS:BAND:RES 100e3 设置RBW;:DISP:WIND:TRAC:Y:RLEV -20 设置参考电平;:INIT:IMM 触发一次扫描;:CALC:MARK:MAX 将标记放到峰值;:CALC:MARK:X? 和 :CALC:MARK:Y? 读取标记频率与幅度。

二、PyVISA连接与资源发现

PyVISA是Python访问VISA库的接口,支持USB、LAN、GPIB等。安装后先确认后端可用:python -m visa info。连接前用 ResourceManager().list_resources() 列出资源字符串,例如 USB0::0x2A8D::0x1D0B::MY12345678::INSTR 或 TCPIP0::192.168.1.10::inst0::INSTR。连接时建议设置超时,避免查询卡死:

import pyvisa
rm = pyvisa.ResourceManager()
sg = rm.open_resource('TCPIP0::192.168.1.10::inst0::INSTR')
sg.timeout = 5000
sa = rm.open_resource('USB0::0x2A8D::0x1D0B::MY12345678::INSTR')
sa.timeout = 5000
print(sg.query('*IDN?'))
print(sa.query('*IDN?'))

*IDN? 返回厂商、型号、序列号、固件版本,是确认通信成功的第一步。若返回空或超时,优先检查IP、端口、VISA地址和防火墙。

三、频率与功率设置:从写入到回读

设置频率和功率时,写入后应回读确认。示例:将信号发生器设为1 GHz、-10 dBm,并打开输出:

sg.write(':SOUR:FREQ 1e9')
sg.write(':SOUR:POW -10')
sg.write(':OUTP ON')
print(sg.query(':SOUR:FREQ?'))
print(sg.query(':SOUR:POW?'))

回读值可能因仪器分辨率略有差异,例如 1.000000E+09 和 -1.000000E+01。若回读与设定不符,检查是否处于扫描模式、是否被外部参考锁定,或功率是否受上限保护。频谱仪侧设置中心频率1 GHz、扫宽10 MHz、参考电平-20 dBm:

sa.write(':SENS:FREQ:CENT 1e9')
sa.write(':SENS:FREQ:SPAN 10e6')
sa.write(':DISP:WIND:TRAC:Y:RLEV -20')
sa.write(':INIT:IMM')
sa.query('*OPC?')

*OPC? 用于等待操作完成,返回1表示扫描结束。随后用标记读取峰值:

sa.write(':CALC:MARK:MAX')
print(sa.query(':CALC:MARK:X?'))
print(sa.query(':CALC:MARK:Y?'))

若峰值频率接近1 GHz、幅度接近-10 dBm(考虑线损和不确定度),说明信号链路基本正常。

四、扫描设置与数据读取

信号发生器扫描模式可设置起止频率、步进或点数、驻留时间。示例:从900 MHz扫到1.1 GHz,线性步进,驻留10 ms:

sg.write(':SOUR:SWE:FREQ:STAR 900e6')
sg.write(':SOUR:SWE:FREQ:STOP 1.1e9')
sg.write(':SOUR:SWE:FREQ:STEP:LIN 1e6')
sg.write(':SOUR:SWE:FREQ:DWEL 10e-3')
sg.write(':SOUR:SWE:FREQ:MODE SWE')
sg.write(':TRIG:SOUR IMM')
sg.write(':INIT:IMM')

频谱仪读取迹线数据时,先设置数据格式为ASCII,再查询:

sa.write(':FORM:DATA ASC')
trace = sa.query(':TRAC:DATA? TRACE1')
print(trace[:80])

返回的是逗号分隔的幅度值列表,可配合 numpy 解析并绘图。若数据量较大,建议使用二进制传输 :FORM:DATA REAL,32 提高速度。

五、命令执行与数据流关系

下图展示从Python脚本到两台仪器的命令与数据流:设置命令经VISA写入,查询命令返回字符串或数组,形成“写入—触发—等待—读取—判断”的闭环。

Python脚本 PyVISA write / query 信号发生器 N5172B / EXG 频谱仪 N9020B / MXA 设置命令 FREQ / POW / SWE 查询响应 FREQ? / MARK:X? 结果判断 频率/功率/峰值 是否在容差内 VISA写 VISA读 SCPI SCPI

六、常见问题与排查要点

第一,查询无响应:检查是否漏写问号、是否使用了正确的资源字符串、超时是否过短。第二,设置不生效:确认仪器是否处于远程模式,前面板是否被锁定;部分命令需先 :SOUR:SWE:FREQ:MODE SWE 才生效。第三,数据异常:频谱仪迹线数据可能包含参考电平偏移,需结合 :DISP:WIND:TRAC:Y:RLEV? 换算。第四,扫描速度慢:减少点数、增大RBW、使用二进制传输。第五,多台仪器同步:可用 *TRG 或外部触发,避免软件轮询造成时序偏差。

建议每写完一组设置命令,立即用查询命令回读关键参数,并把回读值打印到日志。这样既能确认命令生效,也便于后续复现和排障。

掌握以上内容后,你已经可以用Python完成信号发生器与频谱仪的基本控制:设置频率、功率、扫描,读取标记和迹线数据,并判断结果是否合理。下一步可在此基础上封装函数、加入异常处理和自动报告,形成可复用的测试脚本。