diff --git a/equipment_control/__pycache__/dmm.cpython-311.pyc b/equipment_control/__pycache__/dmm.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84320a1ca1f6ef1565659367e52e192a271cd3f3 Binary files /dev/null and b/equipment_control/__pycache__/dmm.cpython-311.pyc differ diff --git a/equipment_control/__pycache__/equipment.cpython-311.pyc b/equipment_control/__pycache__/equipment.cpython-311.pyc index 656e109941a4e89daec1764462b956ead1dce9bd..83a47f5dd9896150bb92f4f2dfbbd2fe940651ea 100644 Binary files a/equipment_control/__pycache__/equipment.cpython-311.pyc and b/equipment_control/__pycache__/equipment.cpython-311.pyc differ diff --git a/equipment_control/__pycache__/hp4145.cpython-311.pyc b/equipment_control/__pycache__/hp4145.cpython-311.pyc index 7427a598aa61f7d6a06b6b5568801b2db1caeeb2..dfc03a98e1bb6f4e1aab97330c3c072f6662cf7c 100644 Binary files a/equipment_control/__pycache__/hp4145.cpython-311.pyc and b/equipment_control/__pycache__/hp4145.cpython-311.pyc differ diff --git a/equipment_control/__pycache__/k2450.cpython-311.pyc b/equipment_control/__pycache__/k2450.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ada50c438bcb1a1c83e32da6e9062b025e7e93d Binary files /dev/null and b/equipment_control/__pycache__/k2450.cpython-311.pyc differ diff --git a/equipment_control/__pycache__/k24xx.cpython-311.pyc b/equipment_control/__pycache__/k24xx.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0615ce1d658c1ad7ba226efdc9ea220aa3ca7b2 Binary files /dev/null and b/equipment_control/__pycache__/k24xx.cpython-311.pyc differ diff --git a/equipment_control/__pycache__/k4200.cpython-311.pyc b/equipment_control/__pycache__/k4200.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a7bcbb2bba58af1122ba628d6589d291c2e97780 Binary files /dev/null and b/equipment_control/__pycache__/k4200.cpython-311.pyc differ diff --git a/equipment_control/cm110.py b/equipment_control/cm110.py index 8658953f32c981bde4bcb138bfd2d668bbe6e93f..3c10e61a006374dc7207fc24288ec5c2bbe43fe3 100644 --- a/equipment_control/cm110.py +++ b/equipment_control/cm110.py @@ -7,11 +7,11 @@ class cm110(equipment.equipment): """Class to control CM110 monochromator""" model="CM110" company="Spectral Product" - link="https://www.spectralproducts.com/CM110" + url="https://www.spectralproducts.com/CM110" def __init__(self,port): self.serial_resource = serial.Serial( - port='COM5', + port=port, baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, diff --git a/equipment_control/dmm.py b/equipment_control/dmm.py index 7444a6e546c2627dbc82c3447a744bd2e304f393..62256bd1b223e4abc8549f795552b21ade9ca0b3 100644 --- a/equipment_control/dmm.py +++ b/equipment_control/dmm.py @@ -1,4 +1,5 @@ import equipment_control.equipment as equipment +import time class dmm(equipment.equipment): @@ -7,45 +8,78 @@ class dmm(equipment.equipment): company="Keithley" url="https://www.tek.com/en/products/keithley/benchtop-digital-multimeter" - def initialize(self, mode, autozero=True, offset_compensation=True, nplc=1,timeout=10e3): + def initialize(self, mode, autozero=True, offset_compensation=True, nplc=1,timeout=10e3,digits=6,k2000=False,continuous_trigger=False,disp_enable=True): """ mode: - "voltage": voltage measurement - "current": current measurement - "resistance": resistance measurement - - "4 wires": 4 wires measurement + - "4 wires": 4wires measurement """ + self.continuous_trigger=continuous_trigger + self.k2000=k2000 self.pyvisa_resource.write("*RST") # self.set_connection_parameter_dic({"write_termination":'\r\n',"read_termination":'\r\n',"send_end":True}) - if mode=="voltage": - self.pyvisa_resource.write(":SENS:FUNC 'VOLT'") - elif mode=="current": - self.pyvisa_resource.write(":SENS:FUNC 'CURR'") - elif mode=="resistance": - self.pyvisa_resource.write(":SENS:FUNC 'RES'") - elif mode=="4 wires": - self.pyvisa_resource.write(":SENS:FUNC 'FRES'") - - - self.pyvisa_resource.write(":SENS:FRES:RANG:AUTO ON") # set automatic range - self.pyvisa_resource.write(":DISP:DIG MAX") # Query largest allowable display resolutio - self.pyvisa_resource.write(":DISP:ENAB ON") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. - self.pyvisa_resource.write("INIT:CONT ON") # able continuous triggering - - if offset_compensation: - self.pyvisa_resource.write(":SENS:FRES:OCOM ON") # enable offset compensation - else: - self.pyvisa_resource.write(":SENS:FRES:OCOM OFF") - - if autozero: - self.pyvisa_resource.write(":SENS:FRES:AZER ON") # enable auto-zero + mode_name={"voltage":"VOLT", "current":"CURR", "resistance":"RES", "4wires":"FRES", "4 wires":"FRES"} + + self.pyvisa_resource.write(":SENS:FUNC '%s'"%mode_name[mode]) + + self.pyvisa_resource.write(":SENS:%s:RANG:AUTO ON"%mode_name[mode]) # set automatic range + + + if k2000: + self.pyvisa_resource.write(":SENS:%s:DIG %d"%(mode_name[mode],digits)) + if disp_enable: + self.pyvisa_resource.write(":DISP:ENAB ON") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + else: + self.pyvisa_resource.write(":DISP:ENAB OFF") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + + if continuous_trigger: + self.pyvisa_resource.write("INIT:CONT ON") # able continuous triggering + else: + self.pyvisa_resource.write("INIT:CONT OFF") # able continuous triggering + else: - self.pyvisa_resource.write(":SENS:FRES:AZER OFF") - - self.pyvisa_resource.write(":SENS:FRES:NPLC %d"%nplc) # set NPLC. For a PLC of 1, the integration period would be 1/50 (for 50Hz line power) which is 20 msec - + if disp_enable: + self.pyvisa_resource.write(":DISP:LIGHT:STAT ON100") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + else: + self.pyvisa_resource.write(":DISP:LIGHT:STAT OFF") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + + self.pyvisa_resource.write(":DISP:%s:DIG %d"%(mode_name[mode],digits)) + self.pyvisa_resource.write(":SENS:%s:NPLC %d"%(mode_name[mode],nplc)) # set NPLC. For a PLC of 1, the integration period would be 1/50 (for 50Hz line power) which is 20 msec + + # if mode_name[mode]=="RES" or mode_name[mode]=="FRES": + + # if offset_compensation: + # self.pyvisa_resource.write(":%s:OCOM ON"%mode_name[mode]) # enable offset compensation + # else: + # self.pyvisa_resource.write(":%s:OCOM OFF"%mode_name[mode]) + + if autozero: + self.pyvisa_resource.write(":%s:AZER ON"%mode_name[mode]) # enable auto-zero + else: + self.pyvisa_resource.write(":%s:AZER OFF"%mode_name[mode]) + + if continuous_trigger: + self.pyvisa_resource.write("TRIG:CONT REST") # able continuous triggering + else: + self.pyvisa_resource.write("TRIG:CONT OFF") def read_single(self): - data=self.pyvisa_resource.query("READ?") + if self.k2000: + if self.continuous_trigger: + data=self.pyvisa_resource.query("FETCH?") + else: + data=self.pyvisa_resource.query("READ?") + else: + if self.continuous_trigger: + self.pyvisa_resource.write("TRIG:CONT OFF") + time.sleep(0.1) + data=self.pyvisa_resource.query("MEAS?") + self.pyvisa_resource.write("TRIG:CONT REST") + else: + data=self.pyvisa_resource.query("MEAS?") + return float(data) + diff --git a/equipment_control/equipment.py b/equipment_control/equipment.py index 739c56604aa389024521c6ee3617cb77277cff6f..d275b920846371dece200396baac7b90b4fea9c8 100644 --- a/equipment_control/equipment.py +++ b/equipment_control/equipment.py @@ -51,25 +51,42 @@ class equipment(): def close_connection(self): self.pyvisa_resource.close() - def write_in_file(self,file_path,data,delimiter=",",extension="txt"): + def write_in_file(self,file_path,data,delimiter=",",extension="txt",overwrite=False,header=None,date=True): if file_path.split(".")[-1]=="csv": delimiter="," # Create file and header - f = open(file_path, "a") - f.write("%s\n"%(datetime.datetime.now().strftime("%c"))) + if overwrite: + f = open(file_path, "w") + else: + f = open(file_path, "a") + + if date: + f.write("# %s\n"%(datetime.datetime.now().strftime("%c"))) - shape=np.shape(data) + if isinstance(header, str): + for line in header.split("\n"): + f.write("# "+line+"\n") + - if len(shape)==1: + shape=np.shape(data) + if len(shape)==0: + f.write("%.6E\n"%(data)) + elif len(shape)==1: for i in range(shape[0]): - f.write("%.6f\n"%(data[i])) + if i==0: + f.write("%.6E"%(data[i])) + else: + f.write("%s%.6E"%(delimiter,data[i])) + + f.write("\n") + elif len(shape)==2: for i in range(shape[0]): for j in range(shape[1]): if j==0: - f.write("%.6f"%(data[i,j])) + f.write("%.6E"%(data[i,j])) else: - f.write("%s%.6f"%(delimiter,data[i,j])) + f.write("%s%.6E"%(delimiter,data[i,j])) f.write("\n") f.close() diff --git a/equipment_control/example/single_equipment/dmm_script.py b/equipment_control/example/single_equipment/dmm_script.py new file mode 100644 index 0000000000000000000000000000000000000000..cf0643d7e2c07cde7469046a86dcd49b8555f233 --- /dev/null +++ b/equipment_control/example/single_equipment/dmm_script.py @@ -0,0 +1,68 @@ + + +# ============================================================================= +# 1. Import classes and modules +# ============================================================================= + +import sys +#sys.path.insert(1, '/path/to/application/app/folder') +sys.path.insert(1, 'D:/Roisin/Documents/chopes') + +import equipment_control.equipment as eq +import equipment_control.dmm as dmm +import time + +# ============================================================================= +# 2. List available connections (chopes use pyvisa package for communicate with most equipments) +# ============================================================================= +rm=eq.resource_manager() +list_connections= eq.available_connections() +print("Available connections: %s"%str(list_connections)) + +# ============================================================================= +# 3. Connection to the equipments +# ============================================================================= +mydmm=dmm.dmm('USB0::0x05E6::0x6500::04529651::INSTR',timeout=1e3) + +# ============================================================================= +# 4. Measurement parameters +# ============================================================================= +units={"voltage":"V", "current":"A", "resistance":"Ohms", "4wires":"Ohms"} + +mode="current" +autozero=True +offset_compensation=True +nplc=1 +digits=4 +continuous_trigger = False +disp_enable=True +k2000=False +file_path='temp.txt' +t_init=time.time() + +# ============================================================================= +# 5. Initialization of the equipments +# ============================================================================= +mydmm.initialize( mode=mode, autozero=autozero, offset_compensation=offset_compensation, + continuous_trigger=continuous_trigger, digits=digits,nplc=nplc,disp_enable=disp_enable + ,k2000=k2000) + +# ============================================================================= +# 6. Measurement script +# ============================================================================= +data=mydmm.read_single() +t_data=time.time()-t_init +print("%s measured: %E %s"%(mode,data,units[mode])) +# ============================================================================= +# 7. Close connection +# ============================================================================= +mydmm.close_connection() + + +# ============================================================================= +# 8. Save data +# ============================================================================= +data_to_write=[t_data,data] +header="Time (s), %s (%s)"%(mode,units[mode]) +mydmm.write_in_file(file_path,data_to_write,header=header,date=True,overwrite=True) +mydmm.write_in_file(file_path,data_to_write,header=None,date=False,overwrite=False) diff --git a/equipment_control/example/single_equipment/hp4145_script.py b/equipment_control/example/single_equipment/hp4145_script.py index 93848b6825f6e783b3e9befcc0d4e24629fe129e..5c50d64c5a01ec1d06b1d5200b64c0eb787e49a5 100644 --- a/equipment_control/example/single_equipment/hp4145_script.py +++ b/equipment_control/example/single_equipment/hp4145_script.py @@ -6,47 +6,60 @@ import sys #sys.path.insert(1, '/path/to/application/app/folder') sys.path.insert(1, 'D:/Roisin/Documents/chopes') -import equipment_control.equipment as eq -import equipment_control.hp4145 as hp4145 - +import equipment_control.equipment as eq # Parent class that handle the connections with the equipments +import equipment_control.hp4145 as hp4145 # Child class that inherits from equipment parent class +import traceback # to write error message in try/except command +import datetime # ============================================================================= # 2. List available connections (chopes use pyvisa package for communicate with most equipments) # ============================================================================= -rm=eq.resource_manager() -list_connections= eq.available_connections() -print("Available connections: %s"%str(list_connections)) +rm=eq.resource_manager() # you can use the function from equipment class or directly the pyvisa command rm = pyvisa.ResourceManager() +list_connections= eq.available_connections(rm=rm) # you can use the function from equipment class or directly the pyvisa command rm.list_resources() +print("-------------------------------------------------\n Available connections: %s"%str(list_connections)) # ============================================================================= # 3. Connection to the equipments # ============================================================================= -myHP4145=hp4145.hp4145("GPIB0::1::INSTR") +myHP4145=hp4145.hp4145("GPIB0::1::INSTR",timeout=100e3) # ============================================================================= # 4. Measurement parameters # ============================================================================= file_path='temp.txt' -mode="voltage sweep" -number_channel=4 -smu_bias={"SMU2":0,"SMU3":0,"SMU4":0} +smu_type={"SMU1":"voltage","SMU2":"current","SMU3":"current","SMU4":"current"} +smu_used={"SMU1":"on","SMU2":"off","SMU3":"on","SMU4":"on"} +smu_master=1 +smu_bias={"SMU1":10,"SMU2":0,"SMU3":0,"SMU4":0} smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6} -sweep_param={"start":0,"stop":1,"step":0.1} +sweep_param={"start":0,"stop":1,"step":0.05} +sweep_type="linear" integration_mode="IT1" delay_time=0 hold_time=0 + # ============================================================================= # 5. Initialization of the equipments # ============================================================================= -myHP4145.initialize(mode=mode,number_channel=number_channel,smu_bias=smu_bias, - smu_compliance=smu_compliance,sweep_param=sweep_param, - integration_mode=integration_mode,delay_time=delay_time,hold_time=hold_time) +print("-------------------------------------------------\n Starting initialisation ...", end='') + +myHP4145.initialize(smu_type=smu_type,smu_used=smu_used,smu_master=smu_master,smu_bias=smu_bias, + smu_compliance=smu_compliance,sweep_param=sweep_param,sweep_type=sweep_type, + integration_mode=integration_mode,delay_time=delay_time,hold_time=hold_time) +print(" Done!") # ============================================================================= # 6. Measurement script # ============================================================================= -data=myHP4145.launch_measurements() +print("-------------------------------------------------\n Starting measurement ...", end='') +try: + data,data_header=myHP4145.launch_measurements() +except Exception: + traceback.print_exc() + myHP4145.close_connection() +print(" Done!") # ============================================================================= # 7. Close connection @@ -56,4 +69,11 @@ myHP4145.close_connection() # ============================================================================= # 8. Save data # ============================================================================= -myHP4145.write_in_file(file_path,data) +custom_header="IV results with HP4145\n" + +print("-------------------------------------------------\n Print in file %s"%file_path) +print(" - Header:") +print(" # %s"%(datetime.datetime.now().strftime("%c"))) +for line in (custom_header+data_header).split('\n'): + print(" # "+line) +myHP4145.write_in_file(file_path,data,overwrite=True,header=custom_header+data_header) diff --git a/equipment_control/example/single_equipment/k2400_script.py b/equipment_control/example/single_equipment/k2400_script.py new file mode 100644 index 0000000000000000000000000000000000000000..b94598f41a1f09dcd229464284455f37e1d946b2 --- /dev/null +++ b/equipment_control/example/single_equipment/k2400_script.py @@ -0,0 +1,71 @@ + + +# ============================================================================= +# 1. Import classes and modules +# ============================================================================= + +import sys +#sys.path.insert(1, '/path/to/application/app/folder') +sys.path.insert(1, 'D:/Roisin/Documents/chopes') + +import equipment_control.equipment as eq +import equipment_control.k2400 as k2400 +import time + +# ============================================================================= +# 2. List available connections (chopes use pyvisa package for communicate with most equipments) +# ============================================================================= +rm=eq.resource_manager() +list_connections= eq.available_connections() +print("Available connections: %s"%str(list_connections)) + +# ============================================================================= +# 3. Connection to the equipments +# ============================================================================= +myk2400=k2400.k2400("GPIB0::29::INSTR",timeout=1e3) + +# ============================================================================= +# 4. Measurement parameters +# ============================================================================= +units={"voltage":"V", "current":"A", "resistance":"Ohms"} + +source_mode = "current" +measurement_mode = "voltage" +compliance = 1 +autozero = True +offset_compensation = True +nplc = 1 +digits = 6 +continuous_trigger = False +disp_enable = True +bias_source = 1e-6 +file_path = 'temp.txt' +t_init=time.time() +# ============================================================================= +# 5. Initialization of the equipments +# ============================================================================= +myk2400.initialize(source_mode=source_mode, measurement_mode=measurement_mode, + compliance=compliance, autozero=autozero, offset_compensation=offset_compensation, + digits=digits,continuous_trigger=continuous_trigger,disp_enable=disp_enable, nplc=nplc) + +# ============================================================================= +# 6. Measurement script +# ============================================================================= +myk2400.set_source(bias_source) +myk2400.set_output("ON") +data=myk2400.read_single() +t_data=time.time()-t_init +print("%s measured: %E %s"%(measurement_mode,data,units[measurement_mode])) +# ============================================================================= +# 7. Close connection +# ============================================================================= +myk2400.close_connection() + + +# ============================================================================= +# 8. Save data +# ============================================================================= +data_to_write=[t_data,data] +header="Time (s), %s (%s)"%(measurement_mode,units[measurement_mode]) +myk2400.write_in_file(file_path,data_to_write,header=header,date=True,overwrite=True) +myk2400.write_in_file(file_path,data_to_write,header=None,date=False,overwrite=False) diff --git a/equipment_control/example/single_equipment/k2450_script.py b/equipment_control/example/single_equipment/k2450_script.py new file mode 100644 index 0000000000000000000000000000000000000000..e3aad27544a33b944b7909d1fb4de2324ad742c6 --- /dev/null +++ b/equipment_control/example/single_equipment/k2450_script.py @@ -0,0 +1,71 @@ + + +# ============================================================================= +# 1. Import classes and modules +# ============================================================================= + +import sys +#sys.path.insert(1, '/path/to/application/app/folder') +sys.path.insert(1, 'D:/Roisin/Documents/chopes') + +import equipment_control.equipment as eq +import equipment_control.k2450 as k2450 +import time + +# ============================================================================= +# 2. List available connections (chopes use pyvisa package for communicate with most equipments) +# ============================================================================= +rm=eq.resource_manager() +list_connections= eq.available_connections() +print("Available connections: %s"%str(list_connections)) + +# ============================================================================= +# 3. Connection to the equipments +# ============================================================================= +myk2450=k2450.k2450("GPIB0::29::INSTR",timeout=5e3) + +# ============================================================================= +# 4. Measurement parameters +# ============================================================================= +units={"voltage":"V", "current":"A", "resistance":"Ohms"} + +source_mode = "voltage" +measurement_mode = "current" +compliance = 1e-6 +autozero = True +offset_compensation = True +nplc = 1 +digits = 6 +continuous_trigger = True +disp_enable = True +bias_source = 1 +file_path = 'temp.txt' +t_init=time.time() +# ============================================================================= +# 5. Initialization of the equipments +# ============================================================================= +myk2450.initialize(source_mode=source_mode, measurement_mode=measurement_mode, + compliance=compliance, autozero=autozero, offset_compensation=offset_compensation, + digits=digits,continuous_trigger=continuous_trigger,disp_enable=disp_enable, nplc=nplc) + +# ============================================================================= +# 6. Measurement script +# ============================================================================= +myk2450.set_source(bias_source) +myk2450.set_output("ON") +data=myk2450.read_single() +t_data=time.time()-t_init +print("%s measured: %E %s"%(measurement_mode,data,units[measurement_mode])) +# ============================================================================= +# 7. Close connection +# ============================================================================= +myk2450.close_connection() + + +# ============================================================================= +# 8. Save data +# ============================================================================= +data_to_write=[t_data,data] +header="Time (s), %s (%s)"%(measurement_mode,units[measurement_mode]) +myk2450.write_in_file(file_path,data_to_write,header=header,date=True,overwrite=True) +myk2450.write_in_file(file_path,data_to_write,header=None,date=False,overwrite=False) diff --git a/equipment_control/example/single_equipment/k4200_script.py b/equipment_control/example/single_equipment/k4200_script.py new file mode 100644 index 0000000000000000000000000000000000000000..557ae5c487c72120cc2157eb1086d109f752e1c3 --- /dev/null +++ b/equipment_control/example/single_equipment/k4200_script.py @@ -0,0 +1,79 @@ +# ============================================================================= +# 1. Import classes and modules +# ============================================================================= + +import sys +#sys.path.insert(1, '/path/to/application/app/folder') +sys.path.insert(1, 'D:/Roisin/Documents/chopes') + +import equipment_control.equipment as eq # Parent class that handle the connections with the equipments +import equipment_control.k4200 as k4200 # Child class that inherits from equipment parent class +import traceback # to write error message in try/except command +import datetime + +# ============================================================================= +# 2. List available connections (chopes use pyvisa package for communicate with most equipments) +# ============================================================================= +rm=eq.resource_manager() # you can use the function from equipment class or directly the pyvisa command rm = pyvisa.ResourceManager() +list_connections= eq.available_connections(rm=rm) # you can use the function from equipment class or directly the pyvisa command rm.list_resources() +print("-------------------------------------------------\n Available connections: %s"%str(list_connections)) + +# ============================================================================= +# 3. Connection to the equipments +# ============================================================================= +myK4200=k4200.k4200("GPIB0::17::INSTR",timeout=10e3) + +# ============================================================================= +# 4. Measurement parameters +# ============================================================================= +file_path='temp.txt' + +smu_type={"SMU1":"voltage","SMU2":"voltage","SMU3":"voltage","SMU4":"voltage"} +smu_used={"SMU1":"on","SMU2":"on","SMU3":"on","SMU4":"on"} +smu_master=1 +smu_bias={"SMU1":10,"SMU2":0,"SMU3":0,"SMU4":0} +smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6} +sweep_param={"start":0,"stop":1,"step":0.05} +sweep_type="linear" +integration_mode="IT1" +delay_time=0 +hold_time=0 + + +# ============================================================================= +# 5. Initialization of the equipments +# ============================================================================= + +print("-------------------------------------------------\n Starting initialisation ...", end='') + +myK4200.initialize(smu_type=smu_type,smu_used=smu_used,smu_master=smu_master,smu_bias=smu_bias, + smu_compliance=smu_compliance,sweep_param=sweep_param,sweep_type=sweep_type, + integration_mode=integration_mode,delay_time=delay_time,hold_time=hold_time) +print(" Done!") +# ============================================================================= +# 6. Measurement script +# ============================================================================= +print("-------------------------------------------------\n Starting measurement ...", end='') +try: + data,data_header=myK4200.launch_measurements() +except Exception: + traceback.print_exc() + myK4200.close_connection() +print(" Done!") + +# ============================================================================= +# 7. Close connection +# ============================================================================= +myK4200.close_connection() + +# ============================================================================= +# 8. Save data +# ============================================================================= +custom_header="IV results with K4200\n" + +print("-------------------------------------------------\n Print in file %s"%file_path) +print(" - Header:") +print(" # %s"%(datetime.datetime.now().strftime("%c"))) +for line in (custom_header+data_header).split('\n'): + print(" # "+line) +myK4200.write_in_file(file_path,data,overwrite=True,header=custom_header+data_header) diff --git a/equipment_control/example/single_equipment/temp.txt b/equipment_control/example/single_equipment/temp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff704737c1b7ca6b6da9b585048f0dac2dee61dd --- /dev/null +++ b/equipment_control/example/single_equipment/temp.txt @@ -0,0 +1,4 @@ +# Mon Mar 10 17:02:23 2025 +# Time (s), current (A) +-1.114205E+00,1.364986E-12 +-1.114205E+00,1.364986E-12 diff --git a/equipment_control/hp4145.py b/equipment_control/hp4145.py index baab7d695d8888b2d861827b9dda1faf083f5582..de71eefed301378424f27f5f4fdbcfa91b812b22 100644 --- a/equipment_control/hp4145.py +++ b/equipment_control/hp4145.py @@ -10,8 +10,9 @@ class hp4145(equipment.equipment): company="Keysight" url="https://www.keysight.com/dk/en/assets/9018-07935/service-manuals/9018-07935.pdf" - def initialize(self, mode="voltage sweep",number_channel=4,smu_bias={"SMU2":0,"SMU3":0,"SMU4":0}, - smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6},sweep_param={"start":0,"stop":0,"step":0}, + def initialize(self, smu_type={"SMU1":"voltage","SMU2":"voltage","SMU3":"common","SMU4":"common"}, smu_used={"SMU1":"on","SMU2":"on","SMU3":"on","SMU4":"on"}, + smu_master=1,smu_bias={"SMU1":0,"SMU2":0,"SMU3":0,"SMU4":0}, + smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6},sweep_param={"start":0,"stop":0,"step":0},sweep_type="linear", integration_mode="IT1",delay_time=0,hold_time=0): @@ -19,8 +20,10 @@ class hp4145(equipment.equipment): mode: - "voltage sweep": voltage sweep with SMU1 and current measurements on all the SMUs """ - self.mode=mode - self.number_channel=number_channel + self.smu_type=smu_type + self.sweep_type=sweep_type + self.smu_used=smu_used + self.smu_master=smu_master self.sweep_param=sweep_param self.smu_compliance=smu_compliance self.smu_bias=smu_bias @@ -28,36 +31,60 @@ class hp4145(equipment.equipment): self.delay_time=delay_time self.hold_time=hold_time - # self.set_connection_parameter_dic({write_termination":'\r\n',"read_termination":'\r\n',"send_end":True}) + index_measurement_type={"sweep":1, "constant":3} + index_smu_type={"voltage":1, "current":2, "common":3} try: self.pyvisa_resource.write("BC") # clear all buffer. self.pyvisa_resource.write("DR1") # This command enables or disables service request for data ready when communications is set to GPIB. self.pyvisa_resource.write("EC 1") # This command sets the condition to exit the test if compliance is reached. - if mode =="voltage sweep": - self.length_data=int(abs((sweep_param["stop"]-sweep_param["start"])/sweep_param["step"])) - self.pyvisa_resource.write("DE") # DE: Accesses SMU channel definition page. + self.pyvisa_resource.write("DE") # DE: Accesses SMU channel definition page. + + self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', %d, %d"%(smu_master,smu_master,smu_master,index_smu_type[smu_type["SMU%d"%smu_master]],index_measurement_type["sweep"])) # 1/2/3: voltage/current/Common 1/2/3: VAR1/VAR2/constant + + for smu_index in range(4): + if (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="off": + self.pyvisa_resource.write("CH%d"%(smu_index+1)) + elif (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="on": + self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', %d, %d"%(smu_index+1,smu_index+1,smu_index+1,index_smu_type[smu_type["SMU%d"%(smu_index+1)]],index_measurement_type["constant"])) - self.pyvisa_resource.write("CH1, 'V1', 'I1', 1, 1") # 1/2/3: voltage/current/Common 1/2/3: VAR1/VAR2/constant - - for i in range(number_channel-1): - self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', 1, 3"%(i+2,i+2,i+2)) + self.pyvisa_resource.write("SS")# Accesses source setup page + if smu_type["SMU%d"%smu_master]=="voltage": + if sweep_type=="linear": + self.pyvisa_resource.write("VR1, %.6E, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],smu_compliance["SMU%d"%smu_master])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif sweep_type=="log": + self.pyvisa_resource.write("VR2, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],smu_compliance["SMU%d"%smu_master])) # VR2 for log sweep of VAR1 source function, vmin, vmax, compliance + elif smu_type["SMU%d"%smu_master]=="current": + if sweep_type=="linear": + self.pyvisa_resource.write("IR1, %.6E, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],smu_compliance["SMU%d"%smu_master])) # IR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif sweep_type=="log": + self.pyvisa_resource.write("IR2, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],smu_compliance["SMU%d"%smu_master])) # IR2 for log sweep of VAR1 source function, vmin, vmax, compliance + + for smu_index in range(4): + if (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="on": + if smu_type["SMU%d"%(smu_index+1)]=="voltage": + self.pyvisa_resource.write("VC%d, %.2f, %.6E"%(smu_index+1,smu_bias["SMU%d"%(smu_index+1)],smu_compliance["SMU%d"%(smu_index+1)])) + elif smu_type["SMU%d"%(smu_index+1)]=="current": + self.pyvisa_resource.write("IC%d, %.2f, %.6E"%(smu_index+1,smu_bias["SMU%d"%(smu_index+1)],smu_compliance["SMU%d"%(smu_index+1)])) + time.sleep(20) + self.pyvisa_resource.write("HT %f"%hold_time) # Sets a hold time that delays the start of a sweep + self.pyvisa_resource.write("DT %f"%delay_time) # delay time: Sets the time to wait between when the output voltage is set and when the measurement is made in a sweep. + self.pyvisa_resource.write(integration_mode) # integration time, IT1/IT2/IT3 : short/medium/long - self.pyvisa_resource.write("SS")# Accesses source setup page - self.pyvisa_resource.write("VR1, %s, %s, %s, %s"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],sweep_param["compliance"])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance - self.pyvisa_resource.write("VC2, %.2f, %s"%(smu_bias[0],smu_compliance[0])) - self.pyvisa_resource.write("VC3, %.2f, %s"%(smu_bias[1],smu_compliance[1])) - self.pyvisa_resource.write("VC4, %.2f, %s"%(smu_bias[2],smu_compliance[2])) + self.pyvisa_resource.write("SM") + self.pyvisa_resource.write("DM2") - self.pyvisa_resource.write("HT %f"%hold_time) # Sets a hold time that delays the start of a sweep - self.pyvisa_resource.write("DT %f"%delay_time) # delay time: Sets the time to wait between when the output voltage is set and when the measurement is made in a sweep. - self.pyvisa_resource.write(integration_mode) # integration time, IT1/IT2/IT3 : short/medium/long - - self.pyvisa_resource.write("SM") - self.pyvisa_resource.write("DM2") - self.pyvisa_resource.write("LI 'I1','I2','I3','I4'") + list_display="" + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + list_display+=",'%s%d'"%("I",smu_index+1) + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + list_display+=",'%s%d'"%("V",smu_index+1) + + self.pyvisa_resource.write("LI %s"%list_display[1:]) # self.pyvisa_resource.write("DM1") # self.pyvisa_resource.write("XN 'V1', 1, %.1f, %.1f"%(v_sweep_param["start"],v_sweep_param["stop"])) # self.pyvisa_resource.write("YA 'I1',2, 1E-15, 1E-12") @@ -65,12 +92,15 @@ class hp4145(equipment.equipment): print("/!\ VisaIOError : timeout expired") self.pyvisa_resource.close() - return {"mode":mode, "number_channels":number_channel, "sweep_param":sweep_param} + return 42 - def launch_measurements(self): + def launch_measurements(self,activate_segmentation=True): - N_v=self.length_data - data={} + number_channel=0 + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + number_channel+=1 + if self.integration_mode=="IT1": Nmax=50 @@ -80,39 +110,80 @@ class hp4145(equipment.equipment): Nmax=10 - if self.mode=="voltage sweep": - v_list=np.round(np.arange(self.sweep_param["start"],self.sweep_param["stop"]+self.sweep_param["step"],self.sweep_param["step"]),6) + sweep_list=np.round(np.arange(self.sweep_param["start"],self.sweep_param["stop"]+self.sweep_param["step"],self.sweep_param["step"]),6) + N_v=len(sweep_list) + data=np.zeros((N_v,number_channel+1)) + data[:,0]=sweep_list + j=0 - data=np.zeros((N_v,self.number_channel)) - data[:,0]=v_list - + if activate_segmentation: iteration=int(N_v/Nmax)+1 index=0 - j=0 while iteration>0: - v_start=v_list[index] + sweep_start=sweep_list[index] if index+Nmax>N_v: - v_end=v_list[-1] + sweep_end=sweep_list[-1] else: - v_end=v_list[index+Nmax-1] - + sweep_end=sweep_list[index+Nmax-1] + + if self.smu_type["SMU%d"%self.smu_master]=="voltage": + if self.sweep_type=="linear": + self.pyvisa_resource.write("VR1, %.6E, %.6E, %.6E, %.6E"%(sweep_start,sweep_end,self.sweep_param["step"],self.smu_compliance["SMU%d"%self.smu_master])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif self.smu_type["SMU%d"%self.smu_master]=="current": + if self.sweep_type=="linear": + self.pyvisa_resource.write("IR1, %.6E, %.6E, %.6E, %.6E"%(sweep_start,sweep_end,self.sweep_param["step"],self.smu_compliance["SMU%d"%self.smu_master])) # IR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + + self.pyvisa_resource.write("SS") + if self.smu_type["SMU%d"%(self.smu_master)]=="voltage": + self.pyvisa_resource.write("VR1, %.6E, %.6E, %.6E, %.6E"%(sweep_start,sweep_end,self.sweep_param["step"],self.smu_compliance["SMU%d"%self.smu_master])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif self.smu_type["SMU%d"%(self.smu_master)]=="current": + self.pyvisa_resource.write("IR1, %.6E, %.6E, %.6E, %.6E"%(sweep_start,sweep_end,self.sweep_param["step"],self.smu_compliance["SMU%d"%self.smu_master])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + self.pyvisa_resource.write("MD") # This command controls measurements. self.pyvisa_resource.write("ME1") # Run a single trigger test and store readings in a cleared buffer: 1 - time.sleep(10) - - N=int(abs((v_end-v_start)/self.sweep_param["step"]))+1 - for i in range(self.number_channel): - data_list=self.pyvisa_resource.query("DO 'I%d'"%(i+1))# Read measurements - for data_i in data_list.split(","): - data[j,i+1]=float(data_i[1:]) - if i==0: + i=0 + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + i+=1 + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + data_list=self.pyvisa_resource.query("DO 'I%d'"%(smu_index+1))# Read measurements + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + data_list=self.pyvisa_resource.query("DO 'V%d'"%(smu_index+1))# Read measurements + j=0 + for data_i in data_list.split(","): + data[index+j,i]=float(data_i[1:]) j+=1 index+=Nmax iteration-=1 - j+=1 + else: - return data + self.pyvisa_resource.write("MD") # This command controls measurements. + self.pyvisa_resource.write("ME1") # Run a single trigger test and store readings in a cleared buffer: 1 + time.sleep(10) + i=0 + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + i+=1 + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + data_list=self.pyvisa_resource.query("DO 'I%d'"%(smu_index+1))# Read measurements + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + data_list=self.pyvisa_resource.query("DO 'V%d'"%(smu_index+1))# Read measurements + + j=0 + for data_j in data_list.split(","): + data[j,i]=float(data_j[1:]) + j+=1 + + + header="%s%d"%(self.smu_type["SMU%d"%self.smu_master][0].upper(),self.smu_master) + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + header+=", %s%d"%("I",smu_index+1) + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + header+=", %s%d"%("V",smu_index+1) + return data, header diff --git a/equipment_control/k2400.py b/equipment_control/k2400.py new file mode 100644 index 0000000000000000000000000000000000000000..72d8b9937feb04af0aaffff3252379be7fc2fe27 --- /dev/null +++ b/equipment_control/k2400.py @@ -0,0 +1,112 @@ +import equipment_control.equipment as equipment +import time +class k2400(equipment.equipment): + + """Class to control K2400 or k2450 SMU""" + model="K2400 or K2450" + company="Keithley" + url="https://www.tek.com/en/products/keithley/digital-multimeter/dmm7510" + + + def initialize(self, source_mode,measurement_mode, compliance, autozero=True, offset_compensation=True, nplc=1,digits=6,continuous_trigger=False,disp_enable=True): + + """ + source_mode: + - "voltage": voltage source + - "current": current source + measurement_mode: + - "voltage": voltage measurement + - "current": current measurement + - "resistance": resistance measurement + """ + mode_name={"voltage":"VOLT", "current":"CURR", "resistance":"RES"} + self.output_state="OFF" + self.pyvisa_resource.write("*RST") + self.source_mode=source_mode + self.continuous_trigger=continuous_trigger + + if source_mode=="voltage": + self.pyvisa_resource.write(":SOUR:FUNC VOLT") + self.pyvisa_resource.write(":SENS:CURR:PROT %E"%compliance) # set automatic range + + if source_mode=="current": + self.pyvisa_resource.write(":SOUR:FUNC CURR") + self.pyvisa_resource.write(":SENS:VOLT:PROT %E"%compliance) # set automatic range + + + + if measurement_mode=="voltage": + self.pyvisa_resource.write(":SENS:FUNC 'VOLT'") + self.pyvisa_resource.write(":SENS:VOLT:RANG:AUTO ON") # set automatic range + + elif measurement_mode=="current": + self.pyvisa_resource.write(":SENS:FUNC 'CURR'") + self.pyvisa_resource.write(":SENS:CURR:RANG:AUTO ON") # set automatic range + + elif measurement_mode=="resistance": + self.pyvisa_resource.write(":SENS:FUNC 'RES'") + self.pyvisa_resource.write(":SENS:RES:RANG:AUTO ON") # set automatic range + + + self.pyvisa_resource.write(":DISP:DIG %d"%digits) # Query largest allowable display resolutio + if disp_enable: + self.pyvisa_resource.write(":DISP:ENAB ON") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + else: + self.pyvisa_resource.write(":DISP:ENAB OFF") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + + # self.pyvisa_resource.write("INIT:CONT ON") # able continuous triggering + + # if offset_compensation: + # self.pyvisa_resource.write(":SENS:FRES:OCOM ON") # enable offset compensation + # else: + # self.pyvisa_resource.write(":SENS:FRES:OCOM OFF") + + if autozero: + self.pyvisa_resource.write(":SYST:AZER:STAT ON") # enable auto-zero + else: + self.pyvisa_resource.write(":SYST:AZER:STAT OFF") + + + self.pyvisa_resource.write(":SENS:%s:NPLC %d"%(mode_name[measurement_mode],nplc)) # set NPLC. For a PLC of 1, the integration period would be 1/50 (for 50Hz line power) which is 20 msec + self.pyvisa_resource.write(":FORM:ELEM %s"%mode_name[measurement_mode]) + + if continuous_trigger: + self.pyvisa_resource.write(":ARM:SOUR TIMer") + self.pyvisa_resource.write(":ARM:TIMer 0.001") + self.pyvisa_resource.write(":ARM:COUNT INF") + else: + self.pyvisa_resource.write(":ARM:SOUR IMMediate") + + def read_single(self): + self.pyvisa_resource.write(":OUTP ON") + + if self.continuous_trigger: + self.pyvisa_resource.write(":ABORt") + self.pyvisa_resource.write(":ARM:COUNT 1") + data=self.pyvisa_resource.query(":READ?") + self.pyvisa_resource.write(":ARM:COUNT INF") + self.pyvisa_resource.write(":INIT") + + else: + data=self.pyvisa_resource.query("READ?") + self.pyvisa_resource.write(":OUTP %s"%self.output_state) + + + return float(data) + + def set_source(self,value): + if self.source_mode=="current": + self.pyvisa_resource.write(":SOUR:CURR %.2E"%value) #set output voltage + elif self.source_mode=="voltage": + self.pyvisa_resource.write(":SOUR:VOLT %.2E"%value) #set output voltage + + + def set_output(self,output_state="ON"): + self.output_state=output_state + + self.pyvisa_resource.write(":OUTP %s"%output_state) + if self.continuous_trigger: + self.pyvisa_resource.write(":INIT") + + + diff --git a/equipment_control/k2450.py b/equipment_control/k2450.py new file mode 100644 index 0000000000000000000000000000000000000000..ab1dedf081d0ee1a5a624842f41671aa9b8e4dfd --- /dev/null +++ b/equipment_control/k2450.py @@ -0,0 +1,101 @@ +import equipment_control.equipment as equipment +import time +class k2450(equipment.equipment): + + """Class to control k2450 SMU""" + model="K2400 or K2450" + company="Keithley" + url="https://www.tek.com/en/products/keithley/digital-multimeter/dmm7510" + + + def initialize(self, source_mode,measurement_mode, compliance, autozero=True, offset_compensation=True, nplc=1,digits=6,continuous_trigger=False,disp_enable=True): + + """ + source_mode: + - "voltage": voltage source + - "current": current source + measurement_mode: + - "voltage": voltage measurement + - "current": current measurement + - "resistance": resistance measurement + """ + mode_name={"voltage":"VOLT", "current":"CURR", "resistance":"RES"} + self.output_state="OFF" + self.pyvisa_resource.write("*RST") + self.source_mode=source_mode + self.continuous_trigger=continuous_trigger + + if source_mode=="voltage": + self.pyvisa_resource.write(":SOUR:FUNC VOLT") + self.pyvisa_resource.write(":SOUR:VOLT:ILIM %E"%compliance) # set automatic range + + if source_mode=="current": + self.pyvisa_resource.write(":SOUR:FUNC CURR") + self.pyvisa_resource.write(":SOUR:CURR:VLIM %E"%compliance) # set automatic range + + + if measurement_mode=="voltage": + self.pyvisa_resource.write(":SENS:FUNC 'VOLT'") + self.pyvisa_resource.write(":SENS:VOLT:RANG:AUTO ON") # set automatic range + + elif measurement_mode=="current": + self.pyvisa_resource.write(":SENS:FUNC 'CURR'") + self.pyvisa_resource.write(":SENS:CURR:RANG:AUTO ON") # set automatic range + + elif measurement_mode=="resistance": + self.pyvisa_resource.write(":SENS:FUNC 'RES'") + self.pyvisa_resource.write(":SENS:RES:RANG:AUTO ON") # set automatic range + + + self.pyvisa_resource.write(":DISP:%s:DIG %d"%(mode_name[measurement_mode],digits)) + self.pyvisa_resource.write(":SENS:%s:NPLC %d"%(mode_name[measurement_mode],nplc)) # set NPLC. For a PLC of 1, the integration period would be 1/50 (for 50Hz line power) which is 20 msec + + if disp_enable: + self.pyvisa_resource.write(":DISP:LIGHT:STAT ON100") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + else: + self.pyvisa_resource.write(":DISP:LIGHT:STAT OFF") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. + + if autozero: + self.pyvisa_resource.write(":SENS:%s:AZER ON"%mode_name[measurement_mode]) # enable auto-zero + else: + self.pyvisa_resource.write(":SENS:%s:AZER OFF"%mode_name[measurement_mode]) + + + + if continuous_trigger: + self.pyvisa_resource.write(":TRIG:LOAD 'LoopUntilEvent', DISP, 0") # able continuous triggering + + else: + self.pyvisa_resource.write("TRIG:CONT OFF") + + + + def read_single(self): + self.pyvisa_resource.write(":OUTP ON") + + if self.continuous_trigger: + self.pyvisa_resource.write(":ABORt") # able continuous triggering + data=self.pyvisa_resource.query("MEAS?") + self.pyvisa_resource.write(":TRIG:LOAD 'LoopUntilEvent', DISP, 0") # able continuous triggering + self.pyvisa_resource.write(":INIT") # able continuous triggering + else: + data=self.pyvisa_resource.query("MEAS?") + self.pyvisa_resource.write(":OUTP %s"%self.output_state) + + return float(data) + + def set_source(self,value): + if self.source_mode=="current": + self.pyvisa_resource.write(":SOUR:CURR %E"%value) #set output voltage + elif self.source_mode=="voltage": + self.pyvisa_resource.write(":SOUR:VOLT %E"%value) #set output voltage + + + def set_output(self,output_state="ON"): + self.output_state=output_state + self.pyvisa_resource.write(":OUTP %s"%output_state) + if self.continuous_trigger: + self.pyvisa_resource.write(":INIT") + + + diff --git a/equipment_control/k24xx.py b/equipment_control/k24xx.py deleted file mode 100644 index ce91ad446f06e2d945093b67089f5a46a254b85d..0000000000000000000000000000000000000000 --- a/equipment_control/k24xx.py +++ /dev/null @@ -1,86 +0,0 @@ -import equipment_control.equipment as equipment - -class k24XX(equipment.equipment): - - """Class to control K2400 or k2450 SMU""" - model="K2400 or K2450" - company="Keithley" - url="https://www.tek.com/en/products/keithley/digital-multimeter/dmm7510" - - - def initialize(self, source_mode,measurement_mode, compliance, autozero=True, offset_compensation=True, nplc=1): - - """ - source_mode: - - "voltage": voltage source - - "current": current source - measurement_mode: - - "voltage": voltage measurement - - "current": current measurement - - "resistance": resistance measurement - - "4 wires": 4 wires measurement - """ - - self.pyvisa_resource.write("*RST") - self.source_mode=source_mode - - if source_mode=="voltage": - self.pyvisa_resource.write(":SOUR:FUNC 'VOLT'") - self.pyvisa_resource.write(":SOUR:CURR:VLIM %f"%compliance) # set automatic range - - if source_mode=="current": - self.pyvisa_resource.write(":SOUR:FUNC 'CURR'") - self.pyvisa_resource.write(":SOUR:VOLT:CLIM %f"%compliance) # set automatic range - - - - if measurement_mode=="voltage": - self.pyvisa_resource.write(":SENS:FUNC 'VOLT'") - self.pyvisa_resource.write(":SENS:VOLT:RANG:AUTO ON") # set automatic range - - elif measurement_mode=="current": - self.pyvisa_resource.write(":SENS:FUNC 'CURR'") - self.pyvisa_resource.write(":SENS:CURR:RANG:AUTO ON") # set automatic range - - elif measurement_mode=="resistance": - self.pyvisa_resource.write(":SENS:FUNC 'RES'") - self.pyvisa_resource.write(":SENS:RES:RANG:AUTO ON") # set automatic range - - elif measurement_mode=="4 wires": - self.pyvisa_resource.write(":SENS:FUNC 'FRES'") - self.pyvisa_resource.write(":SENS:FRES:RANG:AUTO ON") # set automatic range - - - - self.pyvisa_resource.write(":DISP:DIG MAX") # Query largest allowable display resolutio - self.pyvisa_resource.write(":DISP:ENAB ON") # This command is used to enable and disable the front panel display circuitry. When disabled, the instrument operates at a higher speed. - self.pyvisa_resource.write("INIT:CONT ON") # able continuous triggering - - if offset_compensation: - self.pyvisa_resource.write(":SENS:FRES:OCOM ON") # enable offset compensation - else: - self.pyvisa_resource.write(":SENS:FRES:OCOM OFF") - - if autozero: - self.pyvisa_resource.write(":SENS:FRES:AZER ON") # enable auto-zero - else: - self.pyvisa_resource.write(":SENS:FRES:AZER OFF") - - self.pyvisa_resource.write(":SENS:FRES:NPLC %.1f"%nplc) # set NPLC. For a PLC of 1, the integration period would be 1/50 (for 50Hz line power) which is 20 msec - - - def read_single(self): - data=self.pyvisa_resource.query("READ?") - return float(data) - - def set_source(self,value): - if self.source_mode=="current": - self.pyvisa_resource.write(":SOUR:CURR %.2E"%value) #set output voltage - elif self.source_mode=="voltage": - self.pyvisa_resource.write(":SOUR:VOLT %.2E"%value) #set output voltage - - - def set_output(self,output_state="ON"): - self.pyvisa_resource.write(":OUTP %s"%output_state) - - diff --git a/equipment_control/k4200.py b/equipment_control/k4200.py index 72aaf7a145a1af698f7a19c12791596714f628e8..76c251cae53ac95c5975644d0a999fe38e69aeed 100644 --- a/equipment_control/k4200.py +++ b/equipment_control/k4200.py @@ -10,8 +10,9 @@ class k4200(equipment.equipment): company="Keysight" url="https://www.tek.com/en/products/keithley/4200a-scs-parameter-analyzer" - def initialize(self, mode="voltage sweep",number_channel=4,smu_bias={"SMU2":0,"SMU3":0,"SMU4":0}, - smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6},sweep_param={"start":0,"stop":0,"step":0}, + def initialize(self, smu_type={"SMU1":"voltage","SMU2":"voltage","SMU3":"common","SMU4":"common"}, smu_used={"SMU1":"on","SMU2":"on","SMU3":"on","SMU4":"on"}, + smu_master=1,smu_bias={"SMU1":0,"SMU2":0,"SMU3":0,"SMU4":0}, + smu_compliance={"SMU1":1e-6,"SMU2":1e-6,"SMU3":1e-6,"SMU4":1e-6},sweep_param={"start":0,"stop":0,"step":0},sweep_type="linear", integration_mode="IT1",delay_time=0,hold_time=0): @@ -19,8 +20,10 @@ class k4200(equipment.equipment): mode: - "voltage sweep": voltage sweep with SMU1 and current measurements on all the SMUs """ - self.mode=mode - self.number_channel=number_channel + self.smu_type=smu_type + self.sweep_type=sweep_type + self.smu_used=smu_used + self.smu_master=smu_master self.sweep_param=sweep_param self.smu_compliance=smu_compliance self.smu_bias=smu_bias @@ -28,69 +31,119 @@ class k4200(equipment.equipment): self.delay_time=delay_time self.hold_time=hold_time - self.set_connection_parameter_dic({"write_termination":'\r\n',"read_termination":'\r\n',"send_end":True}) + index_measurement_type={"sweep":1, "constant":3} + index_smu_type={"voltage":1, "current":2, "common":3} try: self.pyvisa_resource.write("BC") # clear all buffer. self.pyvisa_resource.write("DR1") # This command enables or disables service request for data ready when communications is set to GPIB. self.pyvisa_resource.write("EC 1") # This command sets the condition to exit the test if compliance is reached. - if mode =="voltage sweep": - self.length_data=int(abs((sweep_param["stop"]-sweep_param["start"])/sweep_param["step"])) - self.pyvisa_resource.write("DE") # DE: Accesses SMU channel definition page. - - self.pyvisa_resource.write("CH1, 'V1', 'I1', 1, 1") # 1/2/3: voltage/current/Common 1/2/3: VAR1/VAR2/constant - - for i in range(number_channel-1): - self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', 1, 3"%(i+2,i+2,i+2)) + self.pyvisa_resource.write("DE") # DE: Accesses SMU channel definition page. + + self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', %d, %d"%(smu_master,smu_master,smu_master,index_smu_type[smu_type["SMU%d"%smu_master]],index_measurement_type["sweep"])) # 1/2/3: voltage/current/Common 1/2/3: VAR1/VAR2/constant + + for smu_index in range(4): + if (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="off": + self.pyvisa_resource.write("CH%d"%(smu_index+1)) + elif (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="on": + self.pyvisa_resource.write("CH%d, 'V%d', 'I%d', %d, %d"%(smu_index+1,smu_index+1,smu_index+1,index_smu_type[smu_type["SMU%d"%(smu_index+1)]],index_measurement_type["constant"])) - self.pyvisa_resource.write("SS")# Accesses source setup page - self.pyvisa_resource.write("VR1, %s, %s, %s, %s"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],sweep_param["compliance"])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance - self.pyvisa_resource.write("VC2, %.2f, %s"%(smu_bias[0],smu_compliance[0])) - self.pyvisa_resource.write("VC3, %.2f, %s"%(smu_bias[1],smu_compliance[1])) - self.pyvisa_resource.write("VC4, %.2f, %s"%(smu_bias[2],smu_compliance[2])) + self.pyvisa_resource.write("SS")# Accesses source setup page + if smu_type["SMU%d"%smu_master]=="voltage": + if sweep_type=="linear": + self.pyvisa_resource.write("VR1, %.6E, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],smu_compliance["SMU%d"%smu_master])) # VR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif sweep_type=="log": + self.pyvisa_resource.write("VR2, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],smu_compliance["SMU%d"%smu_master])) # VR2 for log sweep of VAR1 source function, vmin, vmax, compliance + elif smu_type["SMU%d"%smu_master]=="current": + if sweep_type=="linear": + self.pyvisa_resource.write("IR1, %.6E, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],sweep_param["step"],smu_compliance["SMU%d"%smu_master])) # IR1 for linear sweep of VAR1 source function, vmin, vmax,vstep, compliance + elif sweep_type=="log": + self.pyvisa_resource.write("IR2, %.6E, %.6E, %.6E"%(sweep_param["start"],sweep_param["stop"],smu_compliance["SMU%d"%smu_master])) # IR2 for log sweep of VAR1 source function, vmin, vmax, compliance - self.pyvisa_resource.write("HT %f"%hold_time) # Sets a hold time that delays the start of a sweep - self.pyvisa_resource.write("DT %f"%delay_time) # delay time: Sets the time to wait between when the output voltage is set and when the measurement is made in a sweep. - self.pyvisa_resource.write(integration_mode) # integration time, IT1/IT2/IT3 : short/medium/long + for smu_index in range(4): + if (smu_index+1!=smu_master) and smu_used["SMU%d"%(smu_index+1)]=="on": + if smu_type["SMU%d"%(smu_index+1)]=="voltage": + self.pyvisa_resource.write("VC%d, %.2f, %.6E"%(smu_index+1,smu_bias["SMU%d"%(smu_index+1)],smu_compliance["SMU%d"%(smu_index+1)])) + elif smu_type["SMU%d"%(smu_index+1)]=="current": + self.pyvisa_resource.write("IC%d, %.2f, %.6E"%(smu_index+1,smu_bias["SMU%d"%(smu_index+1)],smu_compliance["SMU%d"%(smu_index+1)])) - self.pyvisa_resource.write("RS 7") # This command sets the measurement resolution for all channels of a SM in number of bits - self.pyvisa_resource.write("RG 1, 10E-12") # This command sets the measurement resolution for all channels of a SM in number of bits - self.pyvisa_resource.write("RG 2, 10E-12") # This command sets the lowest current range of the SMU to be used when measuring. - - self.pyvisa_resource.write("SM") - self.pyvisa_resource.write("DM2") - self.pyvisa_resource.write("LI 'I1','I2','I3','I4'") + self.pyvisa_resource.write("RS 7") # This command sets the measurement resolution for all channels of a SM in number of bits + self.pyvisa_resource.write("RG 1, 10E-12") # This command sets the measurement resolution for all channels of a SM in number of bits + self.pyvisa_resource.write("RG 2, 10E-12") # This command sets the lowest current range of the SMU to be used when measuring. + +# ============================================================================= +# self.pyvisa_resource.write("SM") +# self.pyvisa_resource.write("DM1") +# self.pyvisa_resource.write("XN '%s%d', 1, %.1f, %.1f"%(smu_type["SMU%d"%smu_master][0].upper(),smu_master,sweep_param["start"],sweep_param["stop"])) +# +# list_display="" +# for smu_index in range(4): +# if self.smu_used["SMU%d"%(smu_index+1)]=="on": +# if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": +# self.pyvisa_resource.write("YA '%s%d', 3, 1e-15, 1e-6"%("I",smu_index+1)) +# elif self.smu_type["SMU%d"%(smu_index+1)]=="current": +# self.pyvisa_resource.write("YA '%s%d', 3, 1e-15, 1e-6"%("V",smu_index+1)) +# ============================================================================= + self.pyvisa_resource.write("SM") + self.pyvisa_resource.write("DM2") + list_display="" + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + list_display+=",'%s%d'"%("I",smu_index+1) + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + list_display+=",'%s%d'"%("V",smu_index+1) + + self.pyvisa_resource.write("LI %s"%list_display[1:]) except pyvisa.VisaIOError: print("/!\ VisaIOError : timeout expired") self.pyvisa_resource.close() - return {"mode":mode, "number_channels":number_channel, "sweep_param":sweep_param} + return 42 def launch_measurements(self): + number_channel=0 + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + number_channel+=1 + sweep_list=np.round(np.arange(self.sweep_param["start"],self.sweep_param["stop"]+self.sweep_param["step"],self.sweep_param["step"]),6) + N_sweep=len(sweep_list) + data=np.zeros((N_sweep,number_channel+1)) + data[:,0]=sweep_list + + self.pyvisa_resource.write("MD") # This command controls measurements. self.pyvisa_resource.write("ME1") # Run a single trigger test and store readings in a cleared buffer: 1 - time.sleep(10) - N=self.length_data - - if self.mode=="voltage sweep": - v_list=np.round(np.arange(self.sweep_param["start"],self.sweep_param["stop"]+self.sweep_param["step"],self.sweep_param["step"]),6) - - data=np.zeros((N,self.number_channel)) - data[:,0]=v_list - - count=0 - while (count<N): - data_ch1=np.float32(self.pyvisa_resource.query("RD 'I1', %d"%(count+1))) - if (data_ch1!=0.): - data[count,1]=data_ch1 - for i in range(self.number_channel-1): - data[count,i+2]=np.float32(self.pyvisa_resource.query("RD 'I%d', %d"%(i+2,count+1))) - count+=1 - time.sleep(0.1) - return data + time.sleep(1) + j=0 + while (j<N_sweep): + if self.smu_type["SMU%d"%(self.smu_master)]=="voltage": + data_master=np.float32(self.pyvisa_resource.query("RD 'I%d', %d"%(self.smu_master,j+1))) + elif self.smu_type["SMU%d"%(self.smu_master)]=="current": + data_master=np.float32(self.pyvisa_resource.query("RD 'V%d', %d"%(self.smu_master,j+1))) + if (data_master!=0.): + i=0 + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + i+=1 + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + data[j,i]=np.float32(self.pyvisa_resource.query("RD 'I%d', %d"%(smu_index+1,j+1)))# Read measurements + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + data[j,i]=np.float32(self.pyvisa_resource.query("RD 'V%d', %d"%(smu_index+1,j+1)))# Read measurements + + j+=1 + time.sleep(0.1) + header="%s%d"%(self.smu_type["SMU%d"%self.smu_master][0].upper(),self.smu_master) + for smu_index in range(4): + if self.smu_used["SMU%d"%(smu_index+1)]=="on": + if self.smu_type["SMU%d"%(smu_index+1)]=="voltage": + header+=", %s%d"%("I",smu_index+1) + elif self.smu_type["SMU%d"%(smu_index+1)]=="current": + header+=", %s%d"%("V",smu_index+1) + return data, header \ No newline at end of file diff --git a/equipment_control/kal100.py b/equipment_control/kal100.py new file mode 100644 index 0000000000000000000000000000000000000000..d865a498613177662b4583f52761b31a9a23d646 --- /dev/null +++ b/equipment_control/kal100.py @@ -0,0 +1,51 @@ +import equipment_control.equipment as equipment +import time +import serial + +class kal100(equipment.equipment): + + """Class to control KAL100 pressure system""" + model="KAL100" + company="halstrup-walcher" + url="https://www.halstrup-walcher.de/en/products/KAL100.php" + + units_dic={"kPa":0,"Pa":1,"hPa":0} + def __init__(self,port): + self.serial_resource = serial.Serial( + port=port, + baudrate=9600, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS + ) + + def initialize(self,units="kPa",percentage=100, mode_operation="MS", mode_input="MI0"): + + self.serial_resource.write(">PD%d"%self.units_dic[units]) + time.sleep(1) + self.serial_resource.write(">PP%d"%percentage) # always 100% of the target + time.sleep(1) + + self.serial_resource.write("%s"%mode_input) # MI0: Positive P-input, MI1: Negative P-input, MI2: Differential pressure measurement + time.sleep(1) + + self.serial_resource.write("MZ") # mode zeroing + time.sleep(1) + self.serial_resource.write("%s"%mode_operation) #MT: mode test, MZ: mode zeroing, MS: mode target value, MS: mode pressure measurement, + time.sleep(1) + + if mode_operation=="MS": + self.serial_resource.write("PS%3.5f"%0) #MT: mode test, MZ: mode zeroing, MS: mode target value, MS: mode pressure measurement, + time.sleep(1) + + def set_pressure(self,pressure, units="kPa"): + self.serial_resource.write("MS") + time.sleep(1) + self.serial_resource.write(">PD%d"%self.units_dic[units]) + time.sleep(1) + self.serial_resource.write("PS%3.5f"%0) #MT: mode test, MZ: mode zeroing, MS: mode target value, MS: mode pressure measurement, + time.sleep(1) + + def close_connection(self): + self.serial_resource.close() +