import sys sys.path.insert(0, './lib') sys.path.insert(0, '..') #append parent directory import os import configparser import warnings import traceback from interface import * from help import * import hp4155a first_page = page_1() second_page = page_2() third_page = page_3() fourth_page = page_4() fifth_page = page_5() titles = ["SMUs","User Functions","Parameters","Plotting","Save to file"] children = [first_page,second_page,third_page,fourth_page,fifth_page] tab = widgets.Tab() tab.children = children tab.titles = titles display(tab) start = widgets.Button(description='Start Measurement') ini = widgets.Button(description = 'Import from ini.') output = widgets.Output() display(widgets.HBox([start,ini]),output) device = hp4155a.HP4155a('GPIB0::17::INSTR') def on_start_clicked(b): with output: clear_output() change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = True ini.disabled = True # Reset the device device.reset() # Step 1 create the dictionaries appropriately for every measurement # read general information measurement_mode = third_page[0,0].value measurement_name = fifth_page[0,0].value processing_nr = fifth_page[1,0].value sample_series = fifth_page[2,0].value field = fifth_page[3,0].value dut = fifth_page[4,0].value integration = third_page[0,1].value # we need constant smus for all measurements # Constant Smus cons_smus = [] for j in range(1,5): cons_smus.append(create_dict(value = third_page[21,j].value,comp=third_page[22,j].value)) # 2nd page user_functions = [] #iterate over the rows for i in range(1,7): if second_page[i,0].value!="": # do not save user functions without names user_functions.append( create_dict( name = second_page[i,0].value, unit=second_page[i,1].value, expression = second_page[i,2].value ) ) # Page 4 axes = [] # 0 is x-axis , 1 is y1-axis and 2 is y2-axis for j in range(1,4): #iterate over the column axes.append( create_dict( name = fourth_page[1,j].value, scale = fourth_page[2,j].value, min =fourth_page[3,j].value, max = fourth_page[4,j].value ) ) # Page 5 variables = [] for i in range(8): if fifth_page[6+i,0].value!="": # do not save empty rows variables.append( create_dict( name = fifth_page[6+i,0].value, unit =fifth_page[6+i,1].value ) ) # first sweep if measurement_mode == 'SWEEP': #page 1 smus = [] #iterate over the rows for i in range(1,5): smus.append( create_dict( vname = first_page[i,1].value, iname = first_page[i,2].value, mode = first_page[i,3].value, func = first_page[i,4].value, disabled = first_page[i,5].value ) ) # Page 3 #match hysteris checkbox with the command forwarded to the tool if third_page[9,0].value == True: hyst = 'DOUB' else: hyst = 'SING' var1 = create_dict( start = third_page[4,0].value, stop = third_page[5,0].value, step = third_page[6,0].value, comp = third_page[7,0].value, pcomp =third_page[8,0].value, mode = hyst ) var2 = create_dict( start = third_page[4,1].value, step = third_page[5,1].value, points = third_page[6,1].value, comp = third_page[7,1].value, pcomp=third_page[8,1].value ) vard = create_dict( offset=third_page[4,2].value, ratio = third_page[5,2].value, comp = third_page[7,2].value, pcomp=third_page[8,2].value ) pulse = create_dict( period=third_page[4,3].value, width = third_page[5,3].value, base = third_page[6,3].value ) # Now execute measurement #setup sweep measurement mode device.measurement_mode('SWE') #disable all irrelevant units device.disable_not_smu() # First Setup Smus for i,smu in enumerate(smus): if smu['disabled'] == False: device.setup_smu(i+1,smu) else: #disabled device.smu_disable(i+1) # Setup User Functions for user_function in user_functions: device.user_function(user_function['name'],user_function['unit'],user_function['expression']) # Set the integration time device.integration_time(integration) # Setup VAR1 (always in sweep measurements) device.setup_var1(var1) # device will check for errors # Now set the 3 additional columns if check_sweep_func(smus,'VAR2') == True: device.setup_var2(var2) if check_sweep_func(smus,'VARD') == True: device.setup_vard(vard) if check_sweep_pulse(smus)== True: device.setup_pulse(pulse) # Check for constant SMUs but not grounded cons_smu_numbers = check_sweep_cons(smus) for i, cons_smu in enumerate(cons_smus): if i+1 in cons_smu_numbers: # check if the constant smu was found in the first page func device.setup_cons_smu(i+1,cons_smu) # Now set the axes setup_axes(axes,device) # Set the variables to be saved (This function has an exemption) try: save_variables(axes,variables,device) except Exception as e: error_box(e) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return # Start the measurement device.single_measurement() while device.operation_completed()==False: pass device.autoscaling() # List all errors occured counter,message = device.list_all_errors() if counter>0: error_box(message) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return # Get the data from the device # These are correcly defined and include the plotted ones values = {} for variable in variables: key = variable['name']+"("+variable['unit'] +")" values[key] = device.return_values(variable['name']) plot_results(values,device) # Save results df = pd.DataFrame(values) filename = f"{sample_series}_{field}_{dut}_{measurement_name}_sweep.txt" txt_file = create_file(filename) ini_file = os.path.splitext(txt_file)[0]+'.ini' with open(txt_file,'w') as f: date = str(datetime.today().replace(microsecond=0)) f.write(f"{measurement_name} (sweep) at {date}:"+"\n") f.write("Sample Information\n") f.write(f"Processing Number:{processing_nr}"+"\n") f.write(f"Sample Series:{sample_series}"+"\n") f.write(f"Field:{field}"+"\n") f.write(f"DUT:{dut}"+"\n") f.write("\n") f.write(f"Measurement parameters can be found at: {ini_file}"+"\n") f.write("\nResults\n") df.to_csv(txt_file,sep=" ",mode='a') # export interface to ini file # First the Smus config = configparser.ConfigParser() with open(ini_file,'w') as configfile: config.add_section("THESE ARE THE PARAMETERS OF THE CORRESPONDING MEASUREMENT") config.add_section("THE WHOLE INTERFACE IS SAVED SO FIND WHAT YOU NEED") config.add_section("DO NOT MODIFY THIS FILE") config.add_section(f"MEASUREMENT MODE:{measurement_mode}") config.add_section(f"INTEGRATION TIME:{integration}") # First the smus config.add_section("SMUS") for i, smu in enumerate(smus): config.add_section(f"SMU{i+1}") for key,value in smu.items(): config.set(f"SMU{i+1}",key,str(value)) # Secondly the user functions config.add_section("USER FUNCTIONS") for i, user_function in enumerate(user_functions): config.add_section(f"USER FUNCTION {i+1}") for key,value in user_function.items(): config.set(f"USER FUNCTION {i+1}",key,str(value)) # Then the 3rd page config.add_section("VAR1") for key,value in var1.items(): config.set("VAR1",key,str(value)) config.add_section("VAR2") for key,value in var2.items(): config.set("VAR2",key,str(value)) config.add_section("VARD") for key, value in vard.items(): config.set("VARD",key,str(value)) config.add_section("PULSE") for key,value in pulse.items(): config.set("PULSE",key,str(value)) # Now The constant smus config.add_section('CONSTANT SMUS') for i, cons_smu in enumerate(cons_smus): config.add_section(f"CONSTANT SMU{i+1}") for key, value in cons_smu.items(): config.set(f"CONSTANT SMU{i+1}",key,str(value)) # Page 4 The axes config.add_section('AXES') for i,axis in enumerate(axes): config.add_section(f"AXIS {i+1}") for key,value in axis.items(): config.set(f"AXIS {i+1}",key,str(value)) # Page 5 The varibles config.add_section("SAVED VARIABLES") for i, variable in enumerate(variables): config.add_section(f"VARIABLE {i+1}") for key,value in variable.items(): config.set(f"VARIABLE {i+1}",key,str(value)) config.write(configfile) # Sampling Measurement Mode elif measurement_mode=='SAMPLING': # sampling parameters parameters= create_dict( mode=third_page[12,0].value, interval=third_page[13,0].value, hold=third_page[16,0].value, points=third_page[14,0].value, filter=int(third_page[17,0].value) ) duration = third_page[15,0].value # Set the smus all constant #page 1 smus = [] #iterate over the rows and set the function to constant for i in range(1,5): smus.append( create_dict( vname = first_page[i,1].value, iname = first_page[i,2].value, mode = first_page[i,3].value, func = 'CONS', disabled = first_page[i,5].value ) ) # Now start the measurement device.measurement_mode('SAMP') #disable all irrelevant units device.disable_not_smu() # First Setup Smus for i,smu in enumerate(smus): if smu['disabled'] == False: device.setup_smu(i+1,smu) else: #disabled device.smu_disable(i+1) # Setup User Functions for user_function in user_functions: device.user_function(user_function['name'],user_function['unit'],user_function['expression']) # Set the integration time device.integration_time(integration) # Set the sampling parameters device.setup_sampling(parameters) # Set the total sampling time if duration<= 0: warnings.warn("Non positive measurement duration. Auto Sampling time will be set") device.auto_sampling_time(1) else: device.total_sampling_time(duration) # Setup the constant SMUs cons_smu_numbers = check_cons_smu_samp(smus) for i, cons_smu in enumerate(cons_smus): if i+1 in cons_smu_numbers: # check if the constant smu was found in the first page func device.setup_smu_sampling(i+1,cons_smu) # Now set the axes setup_axes(axes,device) # Set the variables to be saved (This function has an exemption) try: save_variables(axes,variables,device) except Exception as e: error_box(e) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return # Start the measurement device.single_measurement() while device.operation_completed()==False: pass device.autoscaling() # List all errors occured counter,message = device.list_all_errors() if counter>0: error_box(message) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return # Get the data from the device # These are correcly defined and include the plotted ones values = {} for variable in variables: key = variable['name']+"("+variable['unit'] +")" values[key] = device.return_values(variable['name']) plot_results(values,device) # Save results df = pd.DataFrame(values) filename = f"{sample_series}_{field}_{dut}_{measurement_name}_sampling.txt" txt_file = create_file(filename) ini_file = os.path.splitext(txt_file)[0]+'.ini' with open(txt_file,'w') as f: date = str(datetime.today().replace(microsecond=0)) f.write(f"{measurement_name} (sampling) at {date}:"+"\n") f.write("Sample Information\n") f.write(f"Processing Number:{processing_nr}"+"\n") f.write(f"Sample Series:{sample_series}"+"\n") f.write(f"Field:{field}"+"\n") f.write(f"DUT:{dut}"+"\n") f.write("\n") f.write(f"Measurement parameters can be found at: {ini_file}"+"\n") f.write("\nResults\n") df.to_csv(txt_file,sep=" ",mode='a') # export interface to ini file # First the Smus config = configparser.ConfigParser() with open(ini_file,'w') as configfile: config.add_section("THESE ARE THE PARAMETERS OF THE CORRESPONDING MEASUREMENT") config.add_section("THE WHOLE INTERFACE IS SAVED SO FIND WHAT YOU NEED") config.add_section("DO NOT MODIFY THIS FILE") config.add_section(f"MEASUREMENT MODE:{measurement_mode}") config.add_section(f"INTEGRATION TIME:{integration}") # First the smus config.add_section("SMUS") for i, smu in enumerate(smus): config.add_section(f"SMU{i+1}") for key,value in smu.items(): config.set(f"SMU{i+1}",key,str(value)) # Secondly the user functions config.add_section("USER FUNCTIONS") for i, user_function in enumerate(user_functions): config.add_section(f"USER FUNCTION {i+1}") for key,value in user_function.items(): config.set(f"USER FUNCTION {i+1}",key,str(value)) # Then the 3rd page config.add_section('SAMPLING PARAMETERS') for key,value in parameters.items(): config.set('SAMPLING PARAMETERS',key,str(value)) # Sampling time config.set('SAMPLING PARAMETERS','duration',str(duration)) # Now the constant smus config.add_section('CONSTANT SMUS') for i, cons_smu in enumerate(cons_smus): config.add_section(f"CONSTANT SMU{i+1}") for key, value in cons_smu.items(): config.set(f"CONSTANT SMU{i+1}",key,str(value)) # Page 4 The axes config.add_section('AXES') for i,axis in enumerate(axes): config.add_section(f"AXIS {i+1}") for key,value in axis.items(): config.set(f"AXIS {i+1}",key,str(value)) # Page 5 The varibles config.add_section("SAVED VARIABLES") for i, variable in enumerate(variables): config.add_section(f"VARIABLE {i+1}") for key,value in variable.items(): config.set(f"VARIABLE {i+1}",key,str(value)) config.write(configfile) else: # Stress #page 1 smus = [] #iterate over the rows and set the function to constant for i in range(1,5): # Set SYNC non SYNC mode mode= first_page[i,3].value if mode != 'COMM': func = 'SYNC' else: func = 'NSYNC' smus.append( create_dict( name = first_page[i,1].value, mode = mode, func = func, disabled = first_page[i,5].value ) ) # Now define the parameters duration = third_page[15,0].value if duration <= 0: error_box("Stress Time should be positive!") change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return hold_time = third_page[16,0].value filter = int(third_page[17,0].value) # Now start the measurement device.stress_page() device.stress_disable_not_smu() # First Setup Smus for i,smu in enumerate(smus): if smu['disabled'] == False: device.smu_stress(i+1,smu) else: #disabled device.smu_stress_disable(i+1) # Now set the Parameters device.stress_filter(filter) device.stress_hold_time(hold_time) device.stress_time(duration) cons_smu_numbers = check_cons_smu_samp(smus) # works also for sampling for i, cons_smu in enumerate(cons_smus): if i+1 in cons_smu_numbers: # check if the constant smu was found in the first page func device.setup_smu_stress(i+1,cons_smu) # Now start the measurement device.start_stress() while device.operation_completed() == False: pass # List all errors occured counter,message = device.list_all_errors() if counter>0: error_box(message) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return filename = f"{sample_series}_{field}_{dut}_{measurement_name}_stress.txt" txt_file = create_file(filename) ini_file = os.path.splitext(txt_file)[0]+'.ini' with open(txt_file,'w') as f: date = str(datetime.today().replace(microsecond=0)) f.write(f"{measurement_name} (Stress) at {date}:"+"\n") f.write("Sample Information\n") f.write(f"Processing Number:{processing_nr}"+"\n") f.write(f"Sample Series:{sample_series}"+"\n") f.write(f"Field:{field}"+"\n") f.write(f"DUT:{dut}"+"\n") f.write("\n") f.write(f"Measurement parameters can be found at: {ini_file}"+"\n") f.write("\nNo Results Available\n") #export the interface to ini file config = configparser.ConfigParser() with open(ini_file,'w') as configfile: config.add_section("THESE ARE THE PARAMETERS OF THE CORRESPONDING MEASUREMENT") config.add_section("THE WHOLE INTERFACE IS SAVED SO FIND WHAT YOU NEED") config.add_section("DO NOT MODIFY THIS FILE") config.add_section(f"MEASUREMENT MODE:{measurement_mode}") # First the smus config.add_section("SMUS") for i, smu in enumerate(smus): config.add_section(f"SMU{i+1}") for key,value in smu.items(): config.set(f"SMU{i+1}",key,str(value)) config.add_section('PARAMETERS') config.set('PARAMETERS', "STRESS TIME",str(duration)) config.set('PARAMETERS', "HOLD TIME",str(hold_time)) config.set('PARAMETERS', "FILTER",str(filter)) # Now the constant smus config.add_section('CONSTANT SMUS') for i, cons_smu in enumerate(cons_smus): config.add_section(f"CONSTANT SMU{i+1}") for key, value in cons_smu.items(): config.set(f"CONSTANT SMU{i+1}",key,str(value)) config.write(configfile) # End of fuction information_box("Measurement finished!") change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return # just to be sure def on_ini_clicked(b): with output: clear_output() change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = True ini.disabled = True #load values to the interface config = configparser.ConfigParser() try: file = load_ini() except Exception as e: error_box(e) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False return try: # Now we do exactly the opposite thing dictionaries to widgets #read the values from each section config.read(file) # Get the sections sections = config.sections() # Get the measurement Mode measurement_mode = get_mode(sections) # Get the constant smus for j in range(1,5): third_page[21,j].value = config.get(f"CONSTANT SMU{j}",'value') third_page[22,j].value = config.get(f"CONSTANT SMU{j}",'comp') if measurement_mode == 'SWEEP': third_page[0,0].value = measurement_mode third_page[0,1].value = get_integration(sections) # Get the SMU channels for i in range(1,5): first_page[i,1].value = config.get(f"SMU{i}",'vname') first_page[i,2].value = config.get(f"SMU{i}",'iname') first_page[i,3].value = config.get(f"SMU{i}",'mode') first_page[i,4].value = config.get(f"SMU{i}",'func') first_page[i,5].value = eval(config.get(f"SMU{i}",'disabled')) # Get the maximum 6 user functions for i in range(1,7): if f"USER FUNCTION {i}" in sections: second_page[i,0].value = config.get(f"USER FUNCTION {i}",'name') second_page[i,1].value = config.get(f"USER FUNCTION {i}",'unit') second_page[i,2].value = config.get(f"USER FUNCTION {i}",'expression') # Get the Sweep units VAR1,VAR2,VARD, PULSE # VAR1 third_page[4,0].value = config.get('VAR1','start') third_page[5,0].value = config.get('VAR1','stop') third_page[6,0].value = config.get('VAR1','step') third_page[7,0].value = config.get('VAR1','comp') third_page[8,0].value = config.get('VAR1','pcomp') hyst = config.get('VAR1','mode') if hyst == 'SING': third_page[9,0].value = False elif hyst == 'DOUB': third_page[9,0].value = True else: raise Exception("Invalid Hysterisis Mode") # VAR2 third_page[4,1].value = config.get('VAR2','start') third_page[5,1].value = config.get('VAR2','step') third_page[6,1].value = config.get('VAR2','points') third_page[7,1].value = config.get('VAR2','comp') third_page[8,1].value = config.get('VAR2','pcomp') # VARD third_page[4,2].value = config.get('VARD','offset') third_page[5,2].value = config.get('VARD','ratio') third_page[7,2].value = config.get('VARD','comp') third_page[8,2].value = config.get('VARD','pcomp') # PULSE third_page[4,3].value = config.get('PULSE','period') third_page[5,3].value = config.get('PULSE','width') third_page[6,3].value = config.get('PULSE','base') # Get the axes for j in range(1,4): fourth_page[1,j].value = config.get(f"AXIS {j}",'name') fourth_page[2,j].value = config.get(f"AXIS {j}",'scale') fourth_page[3,j].value = config.get(f"AXIS {j}",'min') fourth_page[4,j].value = config.get(f"AXIS {j}",'max') # Get the variables for i in range(8): if f"VARIABLE {i+1}" in sections: fifth_page[6+i,0].value = config.get(f"VARIABLE {i+1}",'name') fifth_page[6+i,1].value = config.get(f"VARIABLE {i+1}",'unit') elif measurement_mode == 'SAMPLING': third_page[0,0].value = measurement_mode third_page[0,1].value = get_integration(sections) # Get the SMU channels for i in range(1,5): first_page[i,1].value = config.get(f"SMU{i}",'vname') first_page[i,2].value = config.get(f"SMU{i}",'iname') first_page[i,3].value = config.get(f"SMU{i}",'mode') first_page[i,4].value = config.get(f"SMU{i}",'func') first_page[i,5].value = eval(config.get(f"SMU{i}",'disabled')) # Get the maximum 6 user functions for i in range(1,7): if f"USER FUNCTION {i}" in sections: second_page[i,0].value = config.get(f"USER FUNCTION {i}",'name') second_page[i,1].value = config.get(f"USER FUNCTION {i}",'unit') second_page[i,2].value = config.get(f"USER FUNCTION {i}",'expression') # Get the sampling Parameters third_page[12,0].value = config.get('SAMPLING PARAMETERS','mode') third_page[13,0].value = config.get('SAMPLING PARAMETERS','interval') third_page[16,0].value = config.get('SAMPLING PARAMETERS','hold') third_page[14,0].value = config.get('SAMPLING PARAMETERS','points') third_page[17,0].value = bool(config.get('SAMPLING PARAMETERS','filter')) third_page[15,0].value = config.get('SAMPLING PARAMETERS','duration') # Get the axes for j in range(1,4): fourth_page[1,j].value = config.get(f"AXIS {j}",'name') fourth_page[2,j].value = config.get(f"AXIS {j}",'scale') fourth_page[3,j].value = config.get(f"AXIS {j}",'min') fourth_page[4,j].value = config.get(f"AXIS {j}",'max') # Get the variables for i in range(8): if f"VARIABLE {i+1}" in sections: fifth_page[6+i,0].value = config.get(f"VARIABLE {i+1}",'name') fifth_page[6+i,1].value = config.get(f"VARIABLE {i+1}",'unit') elif measurement_mode == 'STRESS': third_page[0,0].value = measurement_mode # There is no integration time # Get the SMU channels for i in range(1,5): first_page[i,1].value = config.get(f"SMU{i}",'name') # There is not iname first_page[i,3].value = config.get(f"SMU{i}",'mode') # Function is set automatically first_page[i,5].value = eval(config.get(f"SMU{i}",'disabled')) # Skip The user Functions # Set the Stress parameters third_page[15,0].value = config.get('PARAMETERS','stress time') third_page[16,0].value = config.get('PARAMETERS','hold time') third_page[17,0].value = bool(config.get('PARAMETERS','filter')) # Skip the axes and variables else: raise Exception("MEASUREMENT MODE NOT FOUND!") except Exception as e: error_box(traceback.format_exc()) change_state(first_page,second_page,third_page,fourth_page,fifth_page) start.disabled = False ini.disabled = False start.on_click(on_start_clicked) ini.on_click(on_ini_clicked)