diff --git a/equipment_control/__pycache__/equipment.cpython-311.pyc b/equipment_control/__pycache__/equipment.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38619ad18dbf067ef14e2ca29461d31adc447a20 Binary files /dev/null and b/equipment_control/__pycache__/equipment.cpython-311.pyc differ diff --git a/equipment_control/cm110.py b/equipment_control/cm110.py new file mode 100644 index 0000000000000000000000000000000000000000..b7eea32ec424d9222022f0907a54c8f2208d9efd --- /dev/null +++ b/equipment_control/cm110.py @@ -0,0 +1,11 @@ +import equipment +import pyvisa +import time +import numpy as np + +class CM110(equipment.Equipment): + + """Class to control CM110 monochromator""" + model="CM110" + company="Spectral Product" + link="https://www.spectralproducts.com/CM110" diff --git a/equipment_control/dmm.py b/equipment_control/dmm.py new file mode 100644 index 0000000000000000000000000000000000000000..b734264a8277ebbe8690c88b91c20b9e24c02311 --- /dev/null +++ b/equipment_control/dmm.py @@ -0,0 +1,11 @@ +import equipment +import pyvisa +import time +import numpy as np + +class DMM(equipment.Equipment): + + """Class to control DMM multimeter""" + model="DMM7510, DMM6500 or K2000" + company="Keithley" + link="https://www.tek.com/en/products/keithley/benchtop-digital-multimeter" diff --git a/equipment_control/equipment.py b/equipment_control/equipment.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..098c86cf952e98ad0a32fd69fb3c517198807561 100644 --- a/equipment_control/equipment.py +++ b/equipment_control/equipment.py @@ -0,0 +1,57 @@ +import pyvisa +import datetime +import numpy as np +class Equipment(pyvisa.ResourceManager): + + """Base for Equipment classes.""" + + model = "" + company = "" + link = "" + + def __init__(self,rm,address): + self.pyvisa_resource = rm.open_resource(address) + + + def set_connection_parameter(self,key,value): + if key=="timeout": + self.pyvisa_resource.timeout=value + elif key=="write_termination": + self.pyvisa_resource.write_termination=value + elif key=="read_termination": + self.pyvisa_resource.read_termination=value + elif key=="send_end": + self.pyvisa_resource.send_end=value + elif key=="baud_rate": + self.pyvisa_resource.baud_rate =value + + + def set_connection_parameter_dic(self,connection_parameter): + + if isinstance(connection_parameter, dict): + for key, value in connection_parameter.items(): + self.set_connection_parameter(key,value) + else: + print("Please provide a dictionnary as argument.") + + + def close_connection(self): + self.pyvisa_resource.close() + + def write_in_file(self,file_path,data): + + # Create file and header + f = open(file_path, "a") + f.write("%s\n"%(datetime.datetime.now().strftime("%c"))) + + shape=np.shape(data) + + if len(shape)==1: + for i in range(shape[0]): + f.write("%.6f\n"%(data[i])) + elif len(shape)==2: + for i in range(shape[0]): + for j in range(shape[1]): + f.write("%.6f"%(data[i,j])) + f.write("\n") + f.close() diff --git a/equipment_control/hp4145.py b/equipment_control/hp4145.py new file mode 100644 index 0000000000000000000000000000000000000000..eebc0373b1d2fe846cd5e94dfc53023a17484a1f --- /dev/null +++ b/equipment_control/hp4145.py @@ -0,0 +1,118 @@ +import equipment +import pyvisa +import time +import numpy as np + +class HP4145(equipment.Equipment): + + """Class to control HP4145 semiconductor analyzer""" + model="HP4145" + company="Keysight" + link="https://www.keysight.com/dk/en/assets/9018-07935/service-manuals/9018-07935.pdf" + + def initialize_sweep(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}, + integration_mode="IT1",delay_time=0,hold_time=0): + + + """ + mode: + - "voltage sweep": voltage sweep with SMU1 and current measurements on all the SMUs + """ + self.mode=mode + self.number_channel=number_channel + self.sweep_param=sweep_param + self.smu_compliance=smu_compliance + self.smu_bias=smu_bias + self.integration_mode=integration_mode + self.delay_time=delay_time + self.hold_time=hold_time + + self.set_connection_parameter_dic({"timeout":10e3,"write_termination":'\r\n',"read_termination":'\r\n',"send_end":True}) + + 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("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("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'") + # 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") + except pyvisa.VisaIOError: + print("/!\ VisaIOError : timeout expired") + self.pyvisa_resource.close() + + return {"mode":mode, "number_channels":number_channel, "sweep_param":sweep_param} + + def launch_measurements(self): + + N_v=self.length_data + data={} + + if self.integration_mode=="IT1": + Nmax=50 + elif self.integration_mode=="IT2": + Nmax=30 + elif self.integration_mode=="IT3": + 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) + + data=np.zeros((N_v,self.number_channel)) + data[:,0]=v_list + + iteration=int(N_v/Nmax)+1 + index=0 + j=0 + while iteration>0: + v_start=v_list[index] + if index+Nmax>N_v: + v_end=v_list[-1] + else: + v_end=v_list[index+Nmax-1] + + 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: + j+=1 + + index+=Nmax + iteration-=1 + j+=1 + + return data + diff --git a/equipment_control/k24xx.py b/equipment_control/k24xx.py new file mode 100644 index 0000000000000000000000000000000000000000..1126aa967b1d8497692ec3ff118f83e6bef3b8e8 --- /dev/null +++ b/equipment_control/k24xx.py @@ -0,0 +1,11 @@ +import equipment +import pyvisa +import time +import numpy as np + +class K24XX(equipment.Equipment): + + """Class to control K2400 or k2450 SMU""" + model="K2400 or K2450" + company="Keithley" + link="https://www.tek.com/en/products/keithley/digital-multimeter/dmm7510" diff --git a/equipment_control/k4200.py b/equipment_control/k4200.py new file mode 100644 index 0000000000000000000000000000000000000000..c590bfd8c59df121ae73b577b04902c88f883af2 --- /dev/null +++ b/equipment_control/k4200.py @@ -0,0 +1,96 @@ +import equipment +import pyvisa +import time +import numpy as np + +class K4200(equipment.Equipment): + + """Class to control HP4145 semiconductor analyzer""" + model="K4200" + company="Keysight" + link="https://www.tek.com/en/products/keithley/4200a-scs-parameter-analyzer" + + def initialize_sweep(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}, + integration_mode="IT1",delay_time=0,hold_time=0): + + + """ + mode: + - "voltage sweep": voltage sweep with SMU1 and current measurements on all the SMUs + """ + self.mode=mode + self.number_channel=number_channel + self.sweep_param=sweep_param + self.smu_compliance=smu_compliance + self.smu_bias=smu_bias + self.integration_mode=integration_mode + self.delay_time=delay_time + self.hold_time=hold_time + + self.set_connection_parameter_dic({"timeout":10e3,"write_termination":'\r\n',"read_termination":'\r\n',"send_end":True}) + + 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("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("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("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'") + except pyvisa.VisaIOError: + print("/!\ VisaIOError : timeout expired") + self.pyvisa_resource.close() + + return {"mode":mode, "number_channels":number_channel, "sweep_param":sweep_param} + + def launch_measurements(self): + + 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 + + + \ No newline at end of file