SCPI命令是由助记符构成的字符串,发送到仪器以修改/检索其设置并读取测量值。我希望能够构建和发送这样的字符串:"SENSe:VOLTage:DC:RANGe 10 V"
使用这样的代码:
inst.sense.voltage.dc.range('10 V')
但它似乎是一个非常深的兔子洞,我不确定我是否要开始它。每个子系统和选项的类加载....
更好的方法是:
def sense_volt(self, currenttype='DC', RANG='10 V'):
cmdStr = 'SENS:VOLT:' + currenttype + ':RANG: ' + RANG
return self.inst.write(cmdStr)
仅仅实现我需要的命令并保留inst.query(arg)
和inst.write(arg)
方法来手动构建其他命令是微不足道的,但我希望最终拥有一个完整的仪器界面,其中所有命令都由自动完成方法。
答案 0 :(得分:0)
我成功了,虽然我对结果很不满意。我已经三年没有接触过这些了,所以我不知道为什么我会按照自己的方式做一些事情。我知道我在组织一切以实现便携性方面遇到了很多麻烦。我敢肯定,经过漫长的等待,现在我会收到很多关于我应该如何做的建议。
我编写了解析函数来解释 SCPI 命令。它们可以将命令与参数分开,确定必需和可选参数,识别查询等。例如:
def command_name(scpi_command):
cmd = scpi_command.split(' ')[0]
new = ''
for i, c in enumerate(cmd):
if c in '[]':
continue
if c.isupper() or c.isdigit():
new += c.lower()
continue
if c == ':':
new += '_'
continue
if c == '?':
new += '_qry'
break
return new
来自 CONFigure[:VOLTage]:DC [{<range>|AUTO|MIN|MAX|DEF} [, {<resolution>|MIN|MAX|DEF}]]
的命令可以解析为 conf_volt_dc
或 conf_dc
。我在实验中没有使用删节选项。我认为我的一些不满源于超长的方法名称。
我编写了一个构建器脚本来从文件中读取命令,解析它们,然后编写一个带有扩展“命令处理程序”的“命令集”类的新脚本。每个命令都被解析并转换为几个样板方法之一,例如:
query_str_no_args = r'''
def {name}(self):
"""SCPI instrument query.
{s}
"""
cmd = '{s}'
return self._command_handler(command=cmd)
'''
解析器还包括一个命令处理程序类来处理命令和参数。每个命令都是从其示例文本中解析出来的,ala >>> _command_handler(0.1, 'MAX', command='CONFigure[:VOLTage]:DC [{<range>|AUTO|MIN|MAX|DEF} [, {<resolution>|MIN|MAX|DEF}]]'
。参数(如果有)被验证,命令字符串被重建并发送到仪器,
class Cmd_Handler():
def _command_handler(self, *args, command):
# command string 'SENS:VOLT:RANG'
cmd_str = command_string(command)
# argument dictionary {0: [True, '<range>, 'AUTO', 'MIN', 'MAX', 'DEF'],
# 1: [False, '<resolution>', 'MIN', 'MAX', 'DEF']}
arg_dict = command_args(command)
if debug_mode: print(arg_dict)
for k, v in arg_dict.items():
for i, j in enumerate(v[1:]):
...
# Validate arguments
# count mandatory arguments
if len(args) < len([arg_dict[k] for k in arg_dict.keys() if arg_dict[k][0]]):
...
if '?' in cmd_str:
return self._query(cmd_str + arg_str)
else:
return self._write(cmd_str + arg_str)
构建器完成后,您最终会得到一个大脚本(Ag34401 和 Ag34461 文件分别为 2600 和 3600 行),如下所示:
#!/usr/bin/env python3
from scpi.scpi_parse import Cmd_Handler
class Ag34461A_CS(Cmd_Handler):
...
def calc_scal_stat(self, *args):
"""SCPI instrument command.
CALCulate:SCALe[:STATe] {OFF|ON}
"""
cmd = 'CALCulate:SCALe[:STATe] {OFF|ON}'
return self._command_handler(*args, command=cmd)
def calc_scal_stat_qry(self):
"""SCPI instrument query.
CALCulate:SCALe[:STATe]?
"""
cmd = 'CALCulate:SCALe[:STATe]?'
return self._command_handler(command=cmd)
然后你用你简短的、甜美的乐器类来扩展这个类:
#!/usr/bin/env python3
import pyvisa as visa
from scpi.cmd_sets.ag34401a_cs import Ag34401A_CS # Extend the command set
class Ag34401A(Ag34401A_CS):
def __init__(self, resource_name=None):
rm = visa.ResourceManager()
self._inst = None
if resource_name:
inst = rm.open_resource(resource_name)
else:
for resource in rm.list_resources():
inst = rm.open_resource(resource)
if '34401' in inst.query("*IDN?"):
self._inst = inst
break
if not self._inst:
raise visa.errors.VisaIOError
assert isinstance(self._inst, visa.resources.GPIBInstrument)
self._query = self._inst.query
self._write = self._inst.write
我还有一个 SCPI 仪器父类,我试图用所有星号命令(*IDN?、*CLS 等)填充它。我对之前的结果不满意并且被一些星命令的安装复杂性吓倒了(其中一些看起来真的是特定于仪器的),并放弃了它。这是第一点
class SCPI_Instrument(object, metaclass=ABCMeta):
@abstractmethod
def query(self, message, delay):
pass
@abstractmethod
def write(self, message, delay):
pass
# *CLS - Clear Status
def cls(self, termination = None, encoding = None):
"""Clears the instrument status byte by emptying the error queue and clearing all event registers.
Also cancels any preceding *OPC command or query."""
return self.write("*CLS", termination, encoding)
最后,我能够挤进去的文档并没有我想要的那么有用。自动完成功能无法按名称提示输入参数,并且建议 每个命令 的帮助比我预期的要小。试图保持导入路径直对我来说已经够困难了,更不用说最终可能会使用我的代码的人了。
最终,编码从来都不是我工作描述的一部分,我被调到了一个更不可能尝试仪器控制的位置。