使用 PyVISA 实现实验室自动化

将 Python 和 PvVISA 应用于自动化测试

Python 已成为电子测试自动化领域广泛使用的编程语言,尤其是在与 PyVISA 库配合使用时。虽然实验室自动化的基本原理(例如 SCPI 协议)由来已久,但 Python 和 PyVISA 使得快速启动测试自动化变得轻而易举。数据收集完成后,Python 还提供了大量的数据分析工具(pandas、scipy、scikit 等),可用于分析数据。

本文将介绍如何使用 Python/PyVISA 与仪器进行交互,并给出一个测量电源效率的实际示例。最后,我将介绍如何直接在 Python 中绘制收集到的效率数据。

SCPI 协议

可编程仪器标准命令 (SCPI) 是IEEE 488.2-1987 仪器通信标准之上的一个定义层。SCPI 最初是为IEEE 488.1(GPIB 连接)设计的,但后来扩展到RS-232以太网、USB 以及其他几种连接方式。SCPI 命令以 ASCII 格式发送,并以 ASCII 文本字符串的形式接收。以下是一个简单的 SCPI 事务示例:

主机查询:*IDN?

设备回复: Siglent Technologies,SDL1020X‑E,SDLxxxxxxxxxxx,1.1.1.21R2\n

SCPI 定义了许多通用命令,如MEASure和CONFigure ,可用于从测试设备读取数据或配置测试设备参数。

VISA规范

遗憾的是,对于 SCPI 标准来说,不同的操作系统、接口和设备意味着 SCPI 早期需要为每个设备和总线系统提供不同的库。为了缓解这一难题,虚拟仪器软件架构 (VISA) 规范应运而生,旨在与所有设备和总线系统无缝协作。

Python和PyVISA

即使有了 VISA 规范,在没有昂贵/繁琐的软件和硬件的情况下,将主机连接到测量设备一直以来都极具挑战性。鉴于这些缺陷,PyVISA 库应运而生,旨在简化仪器通信,提高实验室自动化效率。

ython 本身是一种免费的解释型编程语言,可以在任何现代操作系统上使用。由于它是一种解释型(而非编译型)语言,因此 Python 通常可以“安装”在任何系统上,即使用户没有管理员/root权限。虽然 Python 的语法可能需要一些时间来适应(使用空格而不是 ;或其他字符作为分隔符),但它是一种非常广泛的语言,拥有众多可用的库、示例和代码片段。

PyVISA 是 VISA 库的前端,简化了与仪器的通信过程。PyVISA 已通过 National Instruments VISA 和 Keysight IO Library Suite 的官方测试,并且可以与 National Instruments、Keysight 等众多公司的硬件适配器配合使用。

首先,这里有一个简单的程序,用于查询我的电脑上哪些仪器对 PyVISA 可见。在下面的代码片段中,我在一台运行 Python 3.11.5 和 PyVISA 1.13.0 的 64 位 Windows 计算机上使用 National Instruments VISA 

In [2]:

import pyvisa
instruments = pyvisa.ResourceManager().list_resources()
instruments

Out[2]:

(‘USB0::0xF4EC::0x1621::SDL13GCQ6R0772::INSTR’,
‘USB0::0x2A8D::0x3402::MY61003767::INSTR’,
‘GPIB0::12::INSTR’,
‘GPIB0::22::INSTR’)

此输出显示有四台仪器连接到我的计算机,其中两台通过 USB 连接,两台通过 GPIB 连接。现在我们可以为每台仪器创建一个对象并查询它是什么。请注意,所有仪器都会响应特殊的 *IDN? 命令:

In [5]:

for i in instruments:
    inst = pyvisa.ResourceManager().open_resource(i)
    print(i,inst.query(‘*IDN?’))

USB0::0xF4EC::0x1621::SDL13GCQ6R0772::INSTR Siglent Technologies,SDL1020X-E,SDL13GCQ6R0772,1.1.1.21R2

USB0::0x2A8D::0x3402::MY61003767::INSTR Keysight Technologies,E36234A,MY61003767,1.0.4-1.0.3-1.00

GPIB0::12::INSTR HEWLETT-PACKARD,34401A,0,7-5-2

GPIB0::22::INSTR HEWLETT-PACKARD,34401A,0,11-5-2

从查询结果中,您可以看到我有一个 Keysight 电源 (E35234A) 和一个 Siglent 电源 (SDL1020X-E)。以下示例中,我仅使用Siglent 电源读取被测设备 (DUT) 的输入和输出电压。

测量效率

对于电源来说,效率是衡量每单位输入功率输出功率的指标。由于P = VI,因此可以写成:

 

由于该等式得出的分数小于 1,因此通常将其乘以 100,并将效率表示为百分比。

电源设置

在接下来的测试中,我使用DROK 的 720 W 可调 DC-DC 电源( 如图1所示)。为了进行此示例效率测试,我使用25 V 的恒定输入电压和 12 V 的固定输出。请注意,电路板北侧附近有一个大风扇,当电源负载过重时,它会启动。我们将在全效率特性中观察这个风扇的效果。

 

图1:Drok 720 W可调直流电源

 

图2:用于效率测量的电源实用仪器

实际效率测量

为了测量DC-DC电源的效率,我们必须施加源电压v s和负载电流i LOAD。电压源是直流电压,负载电流是在恒流模式下运行的电子负载。我们提高负载电流,并测量不同负载点的效率,以绘制完整的电源效率特性图。

由于每次测量需要四个值(输入电压、输入电流、输出电压和输出电流),我们需要足够的设备来读取所有这些参数。实际操作中,最好使用尽可能靠近被测设备的独立仪表来测量输入和输出电压。

对于电流测量,使用现代校准的设备时,直接从电压源(用于输入电流)和电子负载(用于输出电流)读取电流通常足够接近。

用于高效数据收集的仪器对象

我们可以使用 Python 中提供的工具为每台设备创建一个对象,并创建一个标准方法列表,供我们的仪器使用。例如,我们可以为所有仪器对象创建一个 read_v() 方法,用于读取电压值。在顶层,我们只看到方法 instrument.read_v(),但它实际上映射到我们仪器的特定 SCPI 命令,并返回 Python 可以读取的数据。

对于这个测试,我们将需要四个仪器对象,尽管电压测量将是具有不同地址(相同的仪表,不同的 GPIB 地址)的同一对象的实例。

In [6]:

#Basic object for Keysight E36200 series power supply
#Note that channel must be specified
class keysight_E36200(object):

    def __init__(self, visa_address, **kwargs):
        self.pyvisa = pyvisa.ResourceManager().open_resource(visa_address)
        #
        #Setup some things
        #
        self.__channel = int(kwargs[‘channel’])

        #check if this is the correct device

    def set_v(self, voltage):
        self.pyvisa.write(‘VOLT {0:G}, (@{1})’.format(voltage,self.__channel))

    def set_i(self, current):
        self.pyvisa.write(‘CURR {0:G}, (@{1})’.format(current,self.__channel))

    def read_v(self):
        return float( self.pyvisa.query(‘MEAS:VOLT? (@{0})’.format(self.__channel)) )

    def read_i(self):
        return float( self.pyvisa.query(‘MEAS:CURR? (@{0})’.format(self.__channel)) )

    def output_enable(self):
        self.pyvisa.write(‘OUTP 1, (@{0})’.format(self.__channel))

    def output_disable(self):
        self.pyvisa.write(‘OUTP 0, (@{0})’.format(self.__channel))

In [7]:

class SDL1000X(object):

    def __init__(self, visa_address):
        self.pyvisa = pyvisa.ResourceManager().open_resource(visa_address)
        #
        #Setup some things
        #    

    def read_v(self):
        return float(self.pyvisa.query(‘MEASure:VOLTage:DC?’))

    def read_i(self):
        return float(self.pyvisa.query(‘MEASure:CURRent:DC?’))

    def set_i(self, current):
        self.pyvisa.write(‘:SOURce:CURRent:LEVel:IMMediate {0:f}’.format(current))

    def output_enable(self):
        self.pyvisa.write(‘:SOURce:INPut:STATe ON’)

    def output_disable(self):
        self.pyvisa.write(‘:SOURce:INPut:STATe OFF’)

In [8]:

class hp34401(object):

    def __init__(self, visa_address):
        self.pyvisa = pyvisa.ResourceManager().open_resource(visa_address)

    def read_v(self, average=1):
        #start from v=0, add values and average as needed
        v = 0.0
        self.pyvisa.write(“CONFigure:VOLTage:DC”)

        for x in range(average):
            v += float(self.pyvisa.query(“READ?”))

        voltage = v / average

        return voltage

我们还需要导入一些有助于此测试的库:

In [9]:

import time
import numpy as np
import pandas as pd

然后,为每个仪器创建一个具有描述性名称的对象:

In [10]:

inst_load = SDL1000X(‘USB0::0xF4EC::0x1621::SDL13GCQ6R0772::INSTR’)
inst_supply = keysight_E36200(‘USB0::0x2A8D::0x3402::MY61003767::INSTR’,channel=1)
inst_vin_sense = hp34401(‘GPIB0::12::INSTR’)
inst_vo_sense = hp34401(‘GPIB0::22::INSTR’)

我们现在有了用于测量效率的四种仪器的对象,每种仪器都有具有描述性名称的高级方法。再次注意,发送给每个对象的实际 SCPI 命令非常不同,但预期数据(例如测量电流)会返回适合 Python 的数据。

校准输入电压

连接电源和被测器件 (DUT) 的导线具有有限的阻抗,当输入电流增加(由于负载电流增加)时,DUT 输入端的输入电压会降低。为了补偿这种影响,我们可以直接测量 DUT 上的电压,并增加/减少电源电压,使其保持在一定范围内(在本例中为 10mV)。

In [11]:

def calibrate_vin(supply, sense, v_target):

    v_meas = sense.read_v()
    v_diff = v_meas – v_target

    #Keep input to within 10mV
    while abs(v_diff) > 0.01:
        supply.set_v(supply.read_v() – v_diff/1.5)
        time.sleep(1)        

        v_meas = sense.read_v()

        v_diff = v_meas – v_target

冷却

在负载电流非常高的情况下使用校准功能时,输入电压可能会过高,从而导致被测器件发生电气过载 (EOS)。为了避免这种情况,我们可以创建一个简单的“冷却”循环,降低负载并将电源电压缓慢降至安全电压:

In [12]:

def cooldown(v_final,steps):
    #Read current and voltage right now
    v_now = inst_supply.read_v()
    i_now = inst_load.read_i()

    #Determine step size
    v_step = (v_now – v_final)/steps
    i_step = i_now/steps

    #Reduce by step sizes
    i_now -= i_step
    v_now -= v_step

    for s in range(steps):
        inst_supply.set_v(v_now)
        inst_load.set_i(i_now)
        i_now -= i_step
        v_now -= v_step
        time.sleep(1)
    #Disable when current is 0 and voltage is at target
    inst_load.output_disable()
    inst_supply.output_disable()

初始设置

接下来,我们需要设置用于测试的负载点并设置其余参数。所有测试数据都将存储在 Pandas DataFrame 对象中,这将有助于稍后绘制和导出为 .csv。

In [13]:

load_currents = np.linspace(0,5,51) #100mA steps
#load_currents = np.logspace(-2,0.6989700043360189,100)

supply_voltage = 25

inst_supply.set_v(supply_voltage)
inst_supply.output_enable()
time.sleep(1)

inst_load.set_i(0)
inst_load.output_enable()

input(“Press ENTER when ready\n”)

row_counter = 0

column_labels = [‘Vin_set’,’Iload_set’,’Vin’,’Iin’,’Vout’,’Iout’,’Efficiency’]
all_data = pd.DataFrame(columns=column_labels)

环路电流

主循环的工作原理如下:

  1. 在电子负载上设置下一个负载电流值;
  2. 等待电流稳定;
  3. 校准输入电压(就在 DUT 处),使其接近电源电压值;
  4. 读取所有仪表并计算效率;
  5. 将所有读取的数据作为新行存储在 all_ data DataFrame 中;并且
  6. 增加行计数器并继续下一个加载值。

In [14]:

for lc in load_currents:
    inst_load.set_i(lc)
    time.sleep(1)
    calibrate_vin(inst_supply, inst_vin_sense, supply_voltage)

    data = [supply_voltage,
    lc,
    inst_vin_sense.read_v(),
    inst_supply.read_i(),
    inst_vo_sense.read_v(),
    inst_load.read_i()]

    efficiency = (100* data[4] * data[5]) / (data[2] * data[3])
    data.append(efficiency)

    #print(*data, sep=”,”)
    all_data.loc[row_counter] = data

    row_counter += 1

冷却和保存数据

循环完成后,以 10 步冷却并将  all_data DataFrame 保存到 .csv 文件(带有时间戳,以保证所有数据文件都是唯一的):

In [15]:

cooldown(supply_voltage,10)

timestamp = time.strftime(“%Y.%m.%d.%H.%M.%S”)

all_data.to_csv(‘.\\data\\Efficiency_’+timestamp+’.csv’)

内联绘制数据

由于整个 all_data DataFrame 仍然存在于内存中,我们可以使用 matplotlib 轻松地绘制它:

In [22]:

%matplotlib inline

import matplotlib.pyplot as plt

In [31]:

all_data.plot(x=’Iout’,y=’Efficiency’)
plt.title(‘Efficiency vs. Load Current’)
plt.xlabel(‘Load Current (A)’)
plt.ylabel(‘Efficiency (%)’)
plt.show()

 

图 3:效率与负载电流的 Python 图

请注意,当负载电流接近 2 A 时,效率会出现大幅下降。此时 DC-DC 转换器上的风扇会打开,并导致效率特性出现明显的扭曲。

使用对数 X 轴进行绘图

类似地,我们可以将 X 轴改为对数刻度,这样在绘制效率时往往会呈现平滑的曲线:

In [37]:

fig, axs = plt.subplots(1)
all_data.plot(ax=axs,x=’Iout’,y=’Efficiency’)
plt.title(‘Efficiency vs. Load Current’)
plt.xlabel(‘Load Current (A)’)
axs.set_xscale(‘log’)
plt.ylabel(‘Efficiency (%)’)
plt.show()

 

图 4:效率与负载电流的关系图,X 轴为对数

概括

我们利用 Python 和 PyVISA 库创建了仪器对象和一个简单的程序,用于计算直流电源的效率。我们还使用了 Python 中的绘图工具来绘制本次测试的效率图表。

有了基本程序,就可以修改该程序以添加功能,包括:

  • 循环不同的输入电压;
  • 改变测试电流;
  • 将绘图数据保存为图像或 pdf 文件;
  • 将数据保存为 Word 文档或 PowerPoint 幻灯片。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

David WangYang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值