From 36de4fcf677bd7d8843571ca1d035f77d1b1b913 Mon Sep 17 00:00:00 2001 From: unknown <asoalexandros@gmail.com> Date: Fri, 21 Mar 2025 12:40:27 +0100 Subject: [PATCH] Stress and Sampling modes added! --- hp4155/Custom_SMU/lib/help.py | 10 + hp4155/Custom_SMU/main.py | 366 ++++++++++++++++++++++--- hp4155/Custom_SMU/test_interface.ipynb | 31 ++- 3 files changed, 359 insertions(+), 48 deletions(-) diff --git a/hp4155/Custom_SMU/lib/help.py b/hp4155/Custom_SMU/lib/help.py index 2b96c4c..ac3295b 100644 --- a/hp4155/Custom_SMU/lib/help.py +++ b/hp4155/Custom_SMU/lib/help.py @@ -163,6 +163,16 @@ def create_file(filename): root.destroy() return file +# sampling help functions + +def check_cons_smu_samp(smus:list): + cons_smu_numbers = [] + for i,smu in enumerate(smus): + if smu['mode']!='COMM': # Non Grounded SMUs + cons_smu_numbers.append(i+1) # for the actual number of smus + + return cons_smu_numbers + \ No newline at end of file diff --git a/hp4155/Custom_SMU/main.py b/hp4155/Custom_SMU/main.py index d27315e..c93e5bc 100644 --- a/hp4155/Custom_SMU/main.py +++ b/hp4155/Custom_SMU/main.py @@ -3,6 +3,7 @@ sys.path.insert(0, './lib') sys.path.insert(0, '..') #append parent directory import os import configparser +import warnings from interface import * from help import * @@ -31,6 +32,7 @@ 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) # Reset the device @@ -52,7 +54,43 @@ def on_start_clicked(b): 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]!="": # 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': @@ -71,21 +109,8 @@ def on_start_clicked(b): ) - # 2nd page - user_functions = [] - #iterate over the rows - for i in range(1,7): - if second_page[i,0]!="": # 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 3 - #match hysteris checkbox with the command forwarded to the tool if third_page[9,0].value == True: hyst = 'DOUB' @@ -119,30 +144,6 @@ def on_start_clicked(b): width = third_page[5,3].value, base = third_page[6,3].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 - ) - ) # Now execute measurement @@ -223,20 +224,20 @@ def on_start_clicked(b): # Save results df = pd.Dataframe(values) - filename = f"{sample_series}_{field}_{dut}_{measurement_name}_sweep.txt" + filename = f"{sample_series}_{field}_{dut}_{measurement_name}.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} at {date}:"+"\n") + f.write(f"{measurement_name} (sweep) at {date}:"+"\n") f.write("Sample Information\n") f.write(f"Processing Number:{proceccing_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 arameters can be found at: {ini_file}"+"\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') @@ -313,11 +314,290 @@ def on_start_clicked(b): interval=third_page[13,0].value, hold=third_page[16,0].value, points=third_page[14,0].value, - filter=third_page[17,0].value + filter=int(third_page[17,0].value) ) duration = third_page[13,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_sampling(smus) + for i, cons_smu in enumerate(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) + + # Set integration time + device.intergration_time(integration_time) + + + # 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) + 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>1: + error_box(message) + change_state(first_page,second_page,third_page,fourth_page,fifth_page) + return + + + # Get the data from the device + # These are correcly defined and include the plotted ones + values = {} + for variable in variables: + key = f"{variable['name']} ({variable['unit']})" + values[key] = device.return_data(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} (sampling) at {date}:"+"\n") + f.write("Sample Information\n") + f.write(f"Processing Number:{proceccing_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,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,value) + + # Then the 3rd page + config.add_section('SAMPLING PARAMETERS') + for key,value in parameters.items(): + config.set('SAMPLING PARAMETERS',key,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,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,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,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[13,0].value + if duration <= 0: + error_box("Stress Time should be positive!") + change_state(first_page,second_page,third_page,fourth_page,fifth_page) + 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.hold_time(hold_time) + device.stress_time(duration) + + cons_smu_numbers = check_cons_smu_sampling(smus) # works also for sampling + for i, cons_smu in enumerate(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>1: + error_box(message) + change_state(first_page,second_page,third_page,fourth_page,fifth_page) + return + + 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} (Stress) at {date}:"+"\n") + f.write("Sample Information\n") + f.write(f"Processing Number:{proceccing_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,value) + + config.add_section('PARAMETERS') + config.set('PARAMETERS', "STRESS TIME",duration) + config.set('PARAMETERS', "HOLD TIME",hold_time) + config.set('PARAMETERS', "FILTER",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,value) + config.write(configfile) + + # End of fuction + information_box("Measurement finished!") + change_state(first_page,second_page,third_page,fourth_page,fifth_page) + return # just to be sure + + + start.on_click(on_start_clicked) diff --git a/hp4155/Custom_SMU/test_interface.ipynb b/hp4155/Custom_SMU/test_interface.ipynb index 34839db..e660df2 100644 --- a/hp4155/Custom_SMU/test_interface.ipynb +++ b/hp4155/Custom_SMU/test_interface.ipynb @@ -2,14 +2,14 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "8c823003-1b29-4ece-a0cb-e693a1cd0402", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "6427bccee9fd48e58312921affdeb9b3", + "model_id": "8d3ae4e04b93409d9e2c2ae411d086e3", "version_major": 2, "version_minor": 0 }, @@ -23,7 +23,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "a34bc4bbbc7f44eb8a20a124af8cc604", + "model_id": "13e68e30196f47168d03fe727bf4c898", "version_major": 2, "version_minor": 0 }, @@ -37,7 +37,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "06a413304448487fad402f1b345badb1", + "model_id": "73798f7b542a425f99b55e1c38154150", "version_major": 2, "version_minor": 0 }, @@ -79,9 +79,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "aae3eef8-c2d2-424a-8b10-230f7d8cd67a", "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "int(True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8b4ed5c-3f37-4d87-b77a-a4003b9b271d", + "metadata": {}, "outputs": [], "source": [] } -- GitLab