import numpy as np
import pyvisa
from time import sleep
from logging import getLogger, Logger
from lab_driver.scan_instruments import scan_instruments
[docs]
class DriverHMP40X0:
SerialDevice: pyvisa.Resource
_device_name_chck = "HMP"
_logger: Logger
def __init__(self, num_ch: int=4) -> None:
"""Class for Remote Controlling the Power Supply R&S HMP40X0 via USB
:param num_ch: Number of available device channels (HMP4030 = 3, HMP4040 = 4)
:return: None
"""
self._logger = getLogger(__name__)
self.__NoChannels = num_ch
self.SerialActive = False
self.ChannelUsed = [False, False, False, False]
self.SetCH = [ChannelInfoHMP40X0(idx) for idx in range(num_ch)]
def __write_to_dev(self, order: str) -> None:
"""Writing content to serial connection
Args:
order: String for content
Return:
None
"""
self.SerialDevice.write(order)
def __read_from_dev(self, order: str) -> str:
"""Reading content from serial connection
Args:
order: String for content
Return:
String with information from device
"""
text_out = self.SerialDevice.query(order)
return text_out
def __init_dev(self, do_reset=True) -> None:
"""Initialization of device
Args:
do_reset: Doing a reset of device
Return:
None
"""
if self.SerialActive:
if do_reset:
self.do_reset()
self.__write_to_dev("SYST:MIX")
print(f"Right device is selected with: {self.get_id(False)}")
else:
print("Not right selected device. Please check!")
def __do_check_idn(self) -> None:
"""Checking the IDN"""
id_back = self.get_id(False)
if self._device_name_chck in id_back:
self.SerialActive = True
else:
self.SerialActive = False
[docs]
def serial_open_known_target(self, resource_name: str, do_reset=False) -> None:
"""Open the serial connection to device
Args:
resource_name: Ressource name of serial communication from device
do_reset: Doing a device reset
Return:
None
"""
rm = pyvisa.ResourceManager()
self.SerialDevice = rm.open_resource(resource_name)
self.__do_check_idn()
self.__init_dev(do_reset)
[docs]
def serial_open(self, do_reset=False) -> None:
"""Open the serial connection to device"""
list_dev = scan_instruments()
rm = pyvisa.ResourceManager()
# --- Checking if device address is right
for inst_name in list_dev:
self.SerialDevice = rm.open_resource(inst_name)
self.__do_check_idn()
if self.SerialActive:
break
else:
self.serial_close()
# --- Init of device
self.__init_dev(do_reset)
[docs]
def serial_close(self) -> None:
"""Closing the serial connection"""
self.SerialDevice.close()
self.SerialActive = False
[docs]
def get_id(self, do_print=True) -> str:
"""Getting the device ID"""
id = self.__read_from_dev("*IDN?")
if do_print:
print(id)
return id
[docs]
def do_beep(self, num_iterations=1) -> None:
"""Doing a single beep on device"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
for ite in range(0, num_iterations):
self.__write_to_dev("SYST:BEEP")
sleep(1)
[docs]
def do_reset(self) -> None:
"""Reset the device"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
self.__write_to_dev("*RST")
sleep(2)
self.do_beep()
[docs]
def ch_read_parameter(self, sel_ch: int) -> [float, float]:
"""Read sense parameter from HMP40X0"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
text = list()
text.append(self.SetCH[sel_ch].sel_ch())
text.append(self.SetCH[sel_ch].read_ch_voltage())
text.append(self.SetCH[sel_ch].read_ch_current())
# Getting the information
self.__write_to_dev(text[0])
volt = float(self.__read_from_dev(text[1]))
curr = float(self.__read_from_dev(text[2]))
# Right-back information
self.SetCH[sel_ch].set_sense_parameter(volt, curr)
return volt, curr
[docs]
def output_activate(self) -> None:
"""Activate the already setted channels of HMP40X0"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
self.__write_to_dev("OUTP:GEN ON")
self.do_beep()
[docs]
def output_deactivate(self) -> None:
"""Deactivate all channels of HMP40X0"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
self.__write_to_dev("OUTP:GEN OFF")
for idx in range(0, self.__NoChannels):
text = "INST OUT " + str(idx + 1)
self.__write_to_dev(text)
self.__write_to_dev("OUTP OFF")
self.do_beep()
[docs]
def afg_start(self) -> None:
"""Starting the Arbitrary Generator on the configured channel"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
text = str()
for idx in range(self.__NoChannels):
if self.SetCH[idx].ChannelUsedAFG:
text = self.SetCH[idx].set_arbitrary_start()
self.__write_to_dev(text)
[docs]
def afg_stop(self) -> None:
"""Stopping the Arbitrary Generator on the configured channel"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
text = str()
for idx in range(self.__NoChannels):
if self.SetCH[idx].ChannelUsedAFG:
text = self.SetCH[idx].set_arbitrary_stop()
self.__write_to_dev(text)
[docs]
def ch_set_parameter(self, sel_ch: int, volt: float, cur: float) -> None:
"""Set parameters I/V of each channel"""
if not self.SerialActive:
print("... not done due to wrong device")
else:
text = list()
text.append(self.SetCH[sel_ch].sel_ch())
text.append(self.SetCH[sel_ch].set_ch_voltage(volt))
text.append(self.SetCH[sel_ch].set_ch_current_limit(cur))
text.append(self.SetCH[sel_ch].set_ch_output())
# Configuring the channels
for string in text:
self.__write_to_dev(string)
[docs]
class ChannelInfoHMP40X0:
def __init__(self, ch_no: int):
""""""
self.ChannelActive = False
self.ChannelUsedAFG = False
self.ChannelNumber = 1 + ch_no
self.VoltageSet = 0
self.VoltageSense = 0
self.CurrentLimit = 0
self.CurrentSense = 0
self.PowerSense = 0
self.__max_voltage = 32.05
self.__min_current = 0
self.__max_current = 10
self.__min_voltage = 0
self.__dec_voltage = 3
self.__dec_current = 3
self.__dec_time = 2
[docs]
def sel_ch(self) -> str:
""""""
return "INST OUT" + str(self.ChannelNumber)
[docs]
def set_ch_voltage(self, voltage_value: float) -> str:
""""""
self.VoltageSet = voltage_value
return "VOLT " + str(voltage_value)
[docs]
def set_ch_current_limit(self, current_value: float) -> str:
""""""
self.CurrentLimit = current_value
return "CURR " + str(current_value)
[docs]
def get_ch_parameter(self) -> str:
""""""
return "APPL?"
[docs]
def set_ch_output(self) -> str:
""""""
return "OUTP:SEL 1"
[docs]
def read_ch_voltage(self) -> str:
""""""
return "MEAS:VOLT?"
[docs]
def read_ch_current(self) -> str:
""""""
return "MEAS:CURR?"
[docs]
def set_sense_parameter(self, voltage: float, current: float) -> None:
""""""
self.VoltageSense = voltage
self.CurrentSense = current
self.PowerSense = voltage * current
print(f"Sense: {voltage: .3f} V - {current: .5f} A - {self.PowerSense: .6f} W")
[docs]
def set_arbitrary_repetition(self, num_cycles: int) -> str:
"""Setting the cycles numbers of arbitrary waveform (0= infinitely)"""
cycles_num = min(num_cycles, 255)
return "ARB:REP " + str(cycles_num)
[docs]
def set_arbitrary_transfer(self) -> str:
""""""
return "ARB:TRAN " + str(self.ChannelNumber)
[docs]
def set_arbitrary_start(self) -> str:
""""""
return "ARB:START " + str(self.ChannelNumber)
[docs]
def set_arbitrary_stop(self) -> str:
return "ARB:STOP " + str(self.ChannelNumber)