diff --git a/hp4155/ADU for double gate devices/double_gate_ADU.py b/hp4155/ADU for double gate devices/double_gate_ADU.py deleted file mode 100644 index 6ad6963a9d0ff0d3f379b3202f13f561ecf2a386..0000000000000000000000000000000000000000 --- a/hp4155/ADU for double gate devices/double_gate_ADU.py +++ /dev/null @@ -1,326 +0,0 @@ -import sys -sys.path.insert(0, './lib') -sys.path.insert(0, '..') #append parent directory - - -from interface import * -from help import * -from measurements import * -import configparser - -# Create the grids -#create the information grid -style = {'description_width': 'initial'} -sample = information_box_new() - - -###end of sampling information####################################### - -# move checkboxes outside of the tabs -transfer_check,integration_transfer,transfer_gates = header('Transfer Curve',"MEDium") -output_check,integration_output,output_gates = header('Output Curve',"SHORt") -gatediode_check,integration_gatediode,_=header('Gatediode',"MEDium") - -checkboxes = widgets.HBox([transfer_check,output_check,gatediode_check]) -display(checkboxes) - -#transfer -Vds_transfer_widgets,Vds_transfer = secondary('VDS',0.05,0.95,1,1e-2) -Vtg_transfer_widgets,Vtg_transfer = primary('VTG',-5,0.01,5,1e-3) -Vbg_transfer_widgets,Vbg_transfer = synchronous('VBG',-15,0.1,15,1e-3) -replot_transfer_widgets,replot_transfer = replot() -transfer_box = widgets.VBox([integration_transfer,transfer_gates,Vds_transfer_widgets,Vtg_transfer_widgets,Vbg_transfer_widgets,replot_transfer_widgets]) - - -#output -Vds_output_widgets,Vds_output = primary('VDS',0,0.01,5,1e-2) -Vtg_output_widgets,Vtg_output = secondary('VTG',-5,2,5,1e-3) -Vbg_output_widgets,Vbg_output = additional_secondary('VBG',-15,5,15,1e-3) -replot_output_widgets,replot_output = replot() - -output_box = widgets.VBox([integration_output,output_gates,Vds_output_widgets,Vtg_output_widgets,Vbg_output_widgets,replot_output_widgets]) - - -#GateDiodde -terminal = widgets.Dropdown( - options = ['VTG','VBG'], - description = 'Selected Gate:', - value ='VTG', - style= {'description_width': 'initial'} -) -Vg_gatediode_widgets,Vg_gatediode=primary('VG',-5,0.05,5,1e-3) -replot_gatediode_widgets,replot_gatediode = replot() -gatediode_box = widgets.VBox([integration_gatediode,terminal,Vg_gatediode_widgets,replot_gatediode_widgets]) - - -#the tab widget -children = [transfer_box,output_box,gatediode_box] -titles = ["Transfer","Output","Gatediode"] -tab = widgets.Tab() -tab.children = children -tab.titles = titles - -display(tab) - -button = widgets.Button(description ='Start Measurement') -output = widgets.Output() - -export_ini_button = widgets.Button(description = 'Export as ini') -import_ini_button = widgets.Button(description='Import from ini') -replot_button = widgets.Button(description = 'Replot',disabled = True) - -all_widgets =[transfer_gates,output_gates,button,transfer_check,integration_transfer,output_check,integration_output,gatediode_check,integration_gatediode,terminal,export_ini_button,import_ini_button] - -add_widgets_to_list(sample,all_widgets) -add_widgets_to_list(Vds_transfer,all_widgets) -add_widgets_to_list(Vtg_transfer,all_widgets) -add_widgets_to_list(Vbg_transfer,all_widgets) -add_widgets_to_list(Vds_output,all_widgets) -add_widgets_to_list(Vtg_output,all_widgets) -add_widgets_to_list(Vbg_output,all_widgets) -add_widgets_to_list(Vg_gatediode,all_widgets) - -add_widgets_to_list(replot_transfer,all_widgets) -add_widgets_to_list(replot_output,all_widgets) -add_widgets_to_list(replot_gatediode,all_widgets) - -line = widgets.HBox([button,import_ini_button,export_ini_button,replot_button]) -display(line,output) -device = hp4155a.HP4155a('GPIB0::17::INSTR') - -df_transfer =pd.DataFrame() -df_output =pd.DataFrame() -df_gatediode = pd.DataFrame() - -points_transfer = 0 -points_output = 0 -points_gatediode = 0 - -def on_start_clicked(b): - with output: - global df_transfer,df_output,df_gatediode,points_transfer,points_output - clear_output() - replot_button.disabled = True - #disable all widgets - disable_widgets(all_widgets) - - #reset replotting columns - replot_transfer['x_variable'].options = [] - replot_transfer['y_variable'].options = [] - replot_output['x_variable'].options= [] - replot_output['y_variable'].options = [] - replot_gatediode['x_variable'].options = [] - replot_gatediode['y_variable'].options = [] - - Setup(device) #setup the device - - if transfer_check.value == True: - match transfer_gates.value: - case 'VTG' if check_values(Vtg_transfer,'primary') and check_values(Vds_transfer,'secondary'): - df_transfer,points_transfer = Transfer_VTG(Vtg_transfer,Vds_transfer,integration_transfer.value,sample,device) - replot_transfer['x_variable'].options = df_transfer.columns.tolist() - replot_transfer['y_variable'].options = df_transfer.columns.tolist() - replot_transfer['x_variable'].value = 'VTG/V' - replot_transfer['y_variable'].value = 'IDmm/uA/um' - case 'VBG' if check_values(Vbg_transfer,'primary') and check_values(Vds_transfer,'secondary'): - df_transfer,points_transfer = Transfer_VBG(Vbg_transfer,Vds_transfer,integration_transfer.value,sample,device) - replot_transfer['x_variable'].options = df_transfer.columns.tolist() - replot_transfer['y_variable'].options = df_transfer.columns.tolist() - replot_transfer['x_variable'].value = 'VBG/V' - replot_transfer['y_variable'].value = 'IDmm/uA/um' - case 'BOTH' if check_values(Vbg_transfer,'synchronous') and check_values(Vds_transfer,'secondary') and check_values(Vtg_transfer,'primary'): - df_transfer,points_transfer = Transfer_BOTH(Vtg_transfer,Vbg_transfer,Vds_transfer,integration_transfer.value,sample,device) - replot_transfer['x_variable'].options = df_transfer.columns.tolist() - replot_transfer['y_variable'].options = df_transfer.columns.tolist() - replot_transfer['x_variable'].value = 'VBG/V' - replot_transfer['y_variable'].value = 'IDmm/uA/um' - case _ : - information_box("Transfer Measurement skipped due to invalid parameters") - df_transfer = pd.DataFrame() - points_transfer = 0 - - if output_check.value == True: - match output_gates.value: - case 'VTG' if check_values(Vds_output,'primary') and check_values(Vtg_output,'secondary'): - df_output,points_output = Output_VTG(Vds_output,Vtg_output,integration_output.value,sample,device) - replot_output['x_variable'].options = df_output.columns.tolist() - replot_output['y_variable'].options = df_output.columns.tolist() - replot_output['x_variable'].value = 'VDS/V' - replot_output['y_variable'].value = 'IDmm/uA/um' - case 'VBG' if check_values(Vds_output,'primary') and check_values(Vbg_output,'secondary'): - df_output,points_output = Output_VBG(Vds_output,Vbg_output,integration_output.value,sample,device) - replot_output['x_variable'].options = df_output.columns.tolist() - replot_output['y_variable'].options = df_output.columns.tolist() - replot_output['x_variable'].value = 'VDS/V' - replot_output['y_variable'].value = 'IDmm/uA/um' - case 'BOTH' if check_values(Vds_output,'primary') and check_values(Vtg_output,'secondary') and check_values(Vbg_output,'secondary'): - df_output,points_output = Output_BOTH(Vds_output,Vtg_output,Vbg_output,integration_output.value,sample,device) - replot_output['x_variable'].options = df_output.columns.tolist() - replot_output['y_variable'].options = df_output.columns.tolist() - replot_output['x_variable'].value = 'VDS/V' - replot_output['y_variable'].value = 'IDmm/uA/um' - case _ : - information_box("Output Measurement skipped due to invalid parameters") - df_output = pd.DataFrame() - points_output = 0 - - - if gatediode_check.value == True: - match terminal.value: - case 'VTG' if check_values(Vg_gatediode,'primary'): - df_gatediode = Gatediode_VTG(Vg_gatediode,integration_gatediode.value,sample,device) - replot_gatediode['x_variable'].options = df_gatediode.columns.tolist() - replot_gatediode['y_variable'].options = df_gatediode.columns.tolist() - replot_gatediode['x_variable'].value = 'VTG/V' - replot_gatediode['y_variable'].value = 'ITGmm/uA/um' - case 'VBG' if check_values(Vg_gatediode,'primary'): - df_gatediode = Gatediode_VBG(Vg_gatediode,integration_gatediode.value,sample,device) - replot_gatediode['x_variable'].options = df_gatediode.columns.tolist() - replot_gatediode['y_variable'].options = df_gatediode.columns.tolist() - replot_gatediode['x_variable'].value = 'VBG/V' - replot_gatediode['y_variable'].value = 'IBGmm/uA/um' - case _ : - information_box("Gatediode Measurement skipped due to invalid parameters") - df_gatediode = pd.DataFrame() - - information_box("Measurement finished!") - enable_widgets(all_widgets) - replot_button.disabled = False - - -def on_export_ini_clicked(b): - with output: - disable_widgets(all_widgets) - config = configparser.ConfigParser() - default_filename = 'ADU_double_gate.ini' - file = save_as_ini(default_filename) - with open(file,'w') as configfile: - config.add_section('ALL VALUES ARE IN SI-UNITS!') - config.add_section('IT IS RECOMMENDED TO CHANGE THE INI FILE FROM THE INTERFACE AND DO NOT CHANGE ANY VALUES MANUALLY') - - # Transfer curve - config.add_section('Transfer') - config.set('Transfer','Integration',integration_transfer.value) - - config.add_section("Vtg_transfer") - for parameter,widget in Vtg_transfer.items(): - config.set('Vtg_transfer',parameter,str(widget.value)) - - config.add_section("Vbg_transfer") - for parameter,widget in Vbg_transfer.items(): - config.set('Vbg_transfer',parameter,str(widget.value)) - - config.add_section('Vds_transfer') - for parameter,widget in Vds_transfer.items(): - config.set('Vds_transfer',parameter,str(widget.value)) - - #output - config.add_section('Output') - config.set('Output','Integration',integration_output.value) - - config.add_section("Vtg_output") - for parameter,widget in Vtg_output.items(): - config.set('Vtg_output',parameter,str(widget.value)) - - config.add_section("Vbg_output") - for parameter,widget in Vbg_output.items(): - config.set('Vbg_output',parameter,str(widget.value)) - - config.add_section('Vds_output') - for parameter,widget in Vds_output.items(): - config.set('Vds_output',parameter,str(widget.value)) - - # Gatediode - config.add_section('Gatediode') - config.set('Gatediode','Integration',integration_gatediode.value) - - config.add_section("Vg_gatediode") - for parameter,widget in Vg_gatediode.items(): - config.set('Vg_gatediode',parameter,str(widget.value)) - - config.write(configfile) - enable_widgets(all_widgets) - - -def on_import_ini_clicked(b): - with output: - disable_widgets(all_widgets) - #load values to the interface - config = configparser.ConfigParser() - file = load_ini() - #read the values from each section - try: - config.read(file) - - #transfer curve - integration_transfer.value = config.get('Transfer', "integration") - for parameter,widget in Vtg_transfer.items(): - widget.value = config.get('Vtg_transfer',parameter) - for parameter,widget in Vds_transfer.items(): - widget.value = config.get('Vds_transfer',parameter) - for parameter,widget in Vbg_transfer.items(): - widget.value = config.get('Vbg_transfer',parameter) - - #output curve - integration_output.value = config.get('Output','integration') - for parameter,widget in Vtg_output.items(): - widget.value = config.get('Vtg_output',parameter) - for parameter,widget in Vds_output.items(): - widget.value = config.get('Vds_output',parameter) - for parameter,widget in Vbg_output.items(): - widget.value = config.get('Vbg_output',parameter) - - # gatediode - integration_gatediode.value = config.get('Gatediode','integration') - for parameter,widget in Vg_gatediode.items(): - widget.value = config.get('Vg_gatediode',parameter) - - information_box("all parameters loaded succesfully") - except Exception as error: - if type(error).__name__ =='NoSectionError': - information_box(f"{error}.Explanation: Section(header) [section] does not exist. Create a new ini file or compare it with functional ini files!") - elif type(error).__name__=='NoOptionError': - information_box(f'{error}.Explanation: The variable name before the equal sign is not recognized. Create a new ini file or compare it with functional ini files!') - elif type(error).__name__ == 'TraitError': - information_box(f'{error}.Explanation: Invalid Parameter Setting. Check if you set an invalid value!') - elif type(error).__name__ =="DuplicateOptionError": - information_box(f"{error}. Explaination: The section contains the setted parameter more than once!") - else: - information_box(f"A {type(error).__name__} has occurred. Create A new ini file") - enable_widgets(all_widgets) - -def on_replot_button_clicked(b): - with output: - global df_transfer,df_output,df_gatediode,points_transfer,points_output - clear_output() - disable_widgets(all_widgets) - replot_button.disabled = True - - # plot transfer - replot_results(replot_transfer,df_transfer,points_transfer,'Transfer Results') - - #plot output - replot_results(replot_output,df_output,points_output,'Output Results') - - # plot gatediode - replot_results(replot_gatediode,df_gatediode,1,'Gatediode Results') - - enable_widgets(all_widgets) - replot_button.disabled = False - - - -button.on_click(on_start_clicked) -import_ini_button.on_click(on_import_ini_clicked) -export_ini_button.on_click(on_export_ini_clicked) -replot_button.on_click(on_replot_button_clicked) - - - - - - - - - - diff --git a/hp4155/ADU for double gate devices/double_gate_ADU_interface.ipynb b/hp4155/ADU for double gate devices/double_gate_ADU_interface.ipynb deleted file mode 100644 index dfe2a4b133047677268ae680c30520540e5abdb1..0000000000000000000000000000000000000000 --- a/hp4155/ADU for double gate devices/double_gate_ADU_interface.ipynb +++ /dev/null @@ -1,114 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "51b012d0-95b0-41c2-81bb-2205f3c53be2", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "2638bd63af444e68994918696154d12c", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(VBox(children=(Label(value='Sample Information', layout=Layout(height='auto', width='50%'), sty…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b591d6385eff426fbba4cf45c8b30a61", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(Checkbox(value=True, description='Transfer Curve', indent=False), Checkbox(value=True, descript…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "28df52400d24479b8527781d9ff59a7b", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Tab(children=(VBox(children=(Dropdown(description='Integration Time', index=1, layout=Layout(height='auto', wi…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c143972b5b3d40d3a3347c486c760d38", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(Button(description='Start Measurement', style=ButtonStyle()), Button(description='Import from i…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "72efd18ffe784d928e3a49f403080dd0", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%run double_gate_ADU.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "329c0c76-4194-4805-ab3f-fe9f55f79eea", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/hp4155/ADU for double gate devices/lib/help.py b/hp4155/ADU for double gate devices/lib/help.py deleted file mode 100644 index 6e32487381dfe7c126fd8fc59c17d9b655ce4e2f..0000000000000000000000000000000000000000 --- a/hp4155/ADU for double gate devices/lib/help.py +++ /dev/null @@ -1,218 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -import time -from datetime import datetime - -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox -import copy - -import pandas as pd - -#Get dataframe from results -def get_dataframe_from_results(dictionary): - # creating a shallow copy - dictionary_copy = copy.copy(dictionary) - for old_key in dictionary_copy.keys(): - if old_key[0]=='I': - new_key = old_key+"/A" - else: #V - new_key = old_key + "/V" - dictionary[new_key] = dictionary.pop(old_key) - - df = pd.DataFrame(dictionary) - return df -def number_of_points(dict): - try: - diff = dict['stop'].value - dict['start'].value - ratio = abs(diff/dict['step'].value) - points = int(ratio+1) - - except ZeroDivisionError: - points = 1 - - #the programm crashed because for secondary step we had no problem setting start = stop and then it was dividing by zero - - if points>128: - points = 128 - return points - -def check_values(dictionary,function): - valid = True - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - if function =='primary': - if abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting - valid = False - tkinter.messagebox.showerror(message="Invalid parameter setting!") - - if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity - dictionary['step'].value =(-1)*dictionary['step'].value - - elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0: - dictionary['step'].value = (-1)*dictionary['step'].value - - else: - pass - - if function == 'secondary': - if dictionary['start'].value == dictionary['stop'].value: - pass - elif abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting - valid = False - tkinter.messagebox.showerror(message="Invalid parameter setting!") - if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity - dictionary['step'].value =(-1)*dictionary['step'].value - - elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0: - dictionary['step'].value = (-1)*dictionary['step'].value - - if function == 'synchronous': - pass - - if valid == True: - #check compliance - comp = dictionary['comp'].value - start = dictionary['start'].value - stop = dictionary['stop'].value - - if abs(comp)*max(abs(start),abs(stop))>2: - dictionary["comp"].value=np.sign(comp)*2/max(abs(start),abs(stop)) - - root.destroy() - return valid - -def add_widgets_to_list(source_dictionary,target_list): - for widget in source_dictionary.values(): - target_list.append(widget) - -def change_state(widgets_list): - for widget in widgets_list: - widget.disabled = not widget.disabled - -def enable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = False - -def disable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = True - -def information_box(information): - #open dialog and hide the main window - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #display meaagebox - tkinter.messagebox.showinfo(message=information) - root.destroy() - -#normalization factor to is for both normalizations 10**6/width mA/mm = uA/um = 10**(-6)A/um (returned from the tool) -def normalization_factor(width): - factor = 10**6/width - return factor - - -def save_as_ini(default_filename): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".ini") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename) - root.destroy() - return file - -def load_ini(): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - - file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title ='Select ini file') - while file.endswith(".ini") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title = "Select ini file") - root.destroy() - return file - -# function to return ratio and offset for synchronous sweep measurement -def calculate_line(VTG,VBG): - ratio = (VBG['stop'].value-VBG['start'].value)/(VTG['stop'].value-VTG['start'].value) - offset = VBG['start'].value-ratio*VTG['start'].value - return ratio,offset - - -# replot results -def replot_results(replot_dict,df,points,title): - try: - if len(df.columns.tolist())!=0 and replot_dict['check'].value==True: # Measurement is done - fig,ax = plt.subplots(figsize=(10,6)) - - #Retrieve the columns - x_col = replot_dict['x_variable'].value - y_col = replot_dict['y_variable'].value - - #Scale and Absolute Values - - if replot_dict['x_scale'].value=='linear': - x = np.array_split(df[x_col],points) - else: - x = np.array_split(df[x_col].abs(),points) - ax.set_xscale('log') - - if replot_dict['y_scale'].value=='linear': - y = np.array_split(df[y_col],points) - else: - y = np.array_split(df[y_col].abs(),points) - ax.set_yscale('log') - - # check auto limits - if replot_dict['x_auto'].value== False and replot_dict['x_max'].value > replot_dict['x_min'].value: - ax.set_xlim([replot_dict['x_min'].value,replot_dict['x_max'].value]) - - if replot_dict['y_auto'].value== False and replot_dict['y_max'].value > replot_dict['y_min'].value: - ax.set_ylim([replot_dict['y_min'].value,replot_dict['y_max'].value]) - - # Now set the label - ax.set_xlabel(x_col) - ax.set_ylabel(y_col) - - #And Plot - for i in range(points): - ax.plot(x[i],y[i]) - - fig.suptitle(title, fontweight ="bold") - display(fig) - except: - information_box("reploting failed please try again") - - - - - - - - - - - \ No newline at end of file diff --git a/hp4155/ADU for double gate devices/lib/interface.py b/hp4155/ADU for double gate devices/lib/interface.py deleted file mode 100644 index f3d0cf808cec1d7ca185abf87e3e9095825f2af0..0000000000000000000000000000000000000000 --- a/hp4155/ADU for double gate devices/lib/interface.py +++ /dev/null @@ -1,301 +0,0 @@ -import ipywidgets as widgets -from ipywidgets import GridspecLayout,Layout -from IPython.display import clear_output -import sys -import os - -width = "50%" -height = 'auto' -style = {'description_width': 'initial'} -floatbox_width = "80%" - -def header(name,integration): - style = {'description_width': 'initial'} - options_integration=["SHORt","MEDium","LONG"] - - check=widgets.Checkbox( - description = name, - value = True, - indent = False - ) - integration= widgets.Dropdown( - options=options_integration, - value=integration,description='Integration Time', - style =style, - layout=Layout(height='auto', width="30%") - ) - - select =widgets.Dropdown( - options = ['VTG','VBG',"BOTH"], - description = 'Sweeping Gates:', - value ='BOTH', - style= {'description_width': 'initial'} - ) - - return check, integration ,select - - -def primary(name,start,step,stop,comp): - primary_grid = GridspecLayout(4,4) - primary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto')) - primary_grid[:,3].style.font_weight = 'bold' - - - #first line - primary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto')) - primary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto')) - primary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto')) - - #second line - primary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - primary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width)) - primary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - - #third line - primary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto')) - primary_grid[2,1] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'))#mind the gap - primary_grid[2,2] =widgets.Label("Hysterisis",layout=Layout(height='auto', width='auto'))#mind the gap - - #fourth line - primary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width)) - primary_grid[3,1]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap - primary_grid[3,2]=widgets.Dropdown(options=['SINGle','DOUBle'],value='SINGle',layout=Layout(height='auto', width=floatbox_width))#mind the gap - - - parameters = { - 'start': primary_grid[1,0], - 'step': primary_grid[1,1], - 'stop': primary_grid[1,2], - 'comp': primary_grid[3,0], - 'hyst':primary_grid[3,2], - 'pcomp':primary_grid[3,1] - } - return primary_grid,parameters - -def secondary(name,start,step,stop,comp): - secondary_grid = GridspecLayout(4,4) - secondary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto')) - secondary_grid[:,3].style.font_weight = 'bold' - - #first line - secondary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto')) - secondary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto')) - secondary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto')) - - #second line - secondary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - - #third line - secondary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto')) - secondary_grid[2,2] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'))#mind the gap - - #fourth line - secondary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[3,2]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap - - parameters = { - 'start': secondary_grid[1,0], - 'step': secondary_grid[1,1], - 'stop':secondary_grid[1,2], - 'comp':secondary_grid[3,0], - 'pcomp':secondary_grid[3,2] - } - - - return secondary_grid,parameters - - -def information_box_new(): - width = '90%' - sample_information=widgets.Label("Sample Information",layout=Layout(height=height, width='50%')) - sample_information.style.font_weight='bold' - information_grid=GridspecLayout(3,2) - - for i in range(3): - for j in range(2): - if i ==2 and j == 1: - continue - elif i == 2 and j == 0: - information_grid[i,j]=widgets.BoundedFloatText( - value=100, - min=1e-3, - max=sys.float_info.max,step=1, - layout=Layout(height=height, width=width) - ) - else: - information_grid[i,j]=widgets.Text(layout=Layout(height=height, width=width)) - - information_grid[0,0].description = "Processing-Nr:" - information_grid[1,0].description = "Sample:" - information_grid[2,0].description = "Device Width(um):" - information_grid[0,1].description = "Field(XYY):" - information_grid[1,1].description = "Device:" - - for i in range(3): - for j in range(2): - if i ==2 and j == 1: - continue - information_grid[i,j].style = style - - - - config = widgets.Label("SMU Configuration",layout=Layout(height='auto', width='auto')) - smu1 = widgets.Label("SMU1:Top Gate",layout=Layout(height='auto', width='auto')) - smu2 = widgets.Label("SMU2:Drain",layout=Layout(height='auto', width='auto')) - smu3 = widgets.Label("SMU3:Back Gate",layout=Layout(height='auto', width='auto')) - smu4 = widgets.Label("SMU4:Source(Ground)",layout=Layout(height='auto', width='auto')) - - config.style.font_weight='bold' - - - vbox2 = widgets.VBox([config,smu1,smu2,smu3,smu4]) - vbox1=widgets.VBox([sample_information,information_grid]) - display(widgets.HBox([vbox1,vbox2])) - - information = { - 'processing_number': information_grid[0,0], - 'sample' : information_grid[1,0], - 'field': information_grid[0,1], - 'device':information_grid[1,1], - 'width': information_grid[2,0] - } - - return information - -def synchronous(name,start,step,stop,comp): - synchronous_grid = GridspecLayout(4,4) - synchronous_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto')) - synchronous_grid[:,3].style.font_weight = 'bold' - - - #first line - synchronous_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto')) - synchronous_grid[0,1]=widgets.Label("Step(V)(Only 1 Gate)",layout=Layout(height='auto', width='auto'),style = style) - synchronous_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto')) - - #second line - synchronous_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - synchronous_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width)) - synchronous_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - - #third line - synchronous_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto')) - synchronous_grid[2,1] =widgets.Label("Power Compliance(W)(0=OFF)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap - synchronous_grid[2,2] =widgets.Label("Hysterisis(Only 1 gate)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap - - #fourth line - synchronous_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width)) - synchronous_grid[3,1]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap - synchronous_grid[3,2]=widgets.Dropdown(options=['SINGle','DOUBle'],value='SINGle',layout=Layout(height='auto', width=floatbox_width))#mind the gap - - - parameters = { - 'start': synchronous_grid[1,0], - 'stop': synchronous_grid[1,2], - 'comp': synchronous_grid[3,0], - 'pcomp':synchronous_grid[3,1], - 'step': synchronous_grid[1,1], - 'hyst': synchronous_grid[3,2] - } - return synchronous_grid,parameters - -def additional_secondary(name,start,step,stop,comp): - secondary_grid = GridspecLayout(4,4) - secondary_grid[:,3]=widgets.Label(name,layout=Layout(height='auto', width='auto')) - secondary_grid[:,3].style.font_weight = 'bold' - - #first line - secondary_grid[0,0]=widgets.Label("Start(V)",layout=Layout(height='auto', width='auto')) - secondary_grid[0,1]=widgets.Label("Step(V)",layout=Layout(height='auto', width='auto')) - secondary_grid[0,2]=widgets.Label("Stop(V)",layout=Layout(height='auto', width='auto')) - - #second line - secondary_grid[1,0]=widgets.BoundedFloatText(value=start,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[1,1]=widgets.BoundedFloatText(value=step,min=-200,max=200,step=1,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[1,2]=widgets.BoundedFloatText(value=stop,min=-100,max=100,step=1,layout=Layout(height='auto', width=floatbox_width)) - - #third line - secondary_grid[2,0]=widgets.Label("Compliance(A)",layout=Layout(height='auto', width='auto')) - secondary_grid[2,2] =widgets.Label("Power Compliance(W)(0=OFF)(Only 1 Gate)",layout=Layout(height='auto', width='auto'),style = style)#mind the gap - - #fourth line - secondary_grid[3,0]=widgets.BoundedFloatText(value=comp,min=-0.1,max=0.1,step=0.01,layout=Layout(height='auto', width=floatbox_width)) - secondary_grid[3,2]=widgets.BoundedFloatText(value=0,min=0,max=2,step=0.1,layout=Layout(height='auto', width=floatbox_width))#mind the gap - - parameters = { - 'start': secondary_grid[1,0], - 'step': secondary_grid[1,1], - 'stop':secondary_grid[1,2], - 'comp':secondary_grid[3,0], - 'pcomp':secondary_grid[3,2] - } - return secondary_grid,parameters - -def replot(): - replot_grid = GridspecLayout(7,2) - - replot_grid[0,0]= widgets.Checkbox( - description = "Replot", - value = False, - indent = False, - ) - - replot_grid[1,0] = widgets.Label('X-axis',layout=Layout(height='auto', width='auto')) - replot_grid[1,1] = widgets.Label('Y-axis',layout=Layout(height='auto', width='auto')) - - for i in range(2): - replot_grid[2,i]= widgets.Dropdown( - options = [], - description = "Variable:", - layout=Layout(height='auto', width=floatbox_width), - ) - - replot_grid[3,i] = widgets.FloatText( - value = None, - description = 'min:', - layout=Layout(height='auto', width=floatbox_width), - - ) - - replot_grid[4,i] = widgets.FloatText( - value = None, - description = 'max:', - layout=Layout(height='auto', width=floatbox_width), - - ) - - replot_grid[5,i] = widgets.Dropdown( - description = 'scale:', - options =['linear','log'], - value = 'linear', - layout=Layout(height='auto', width=floatbox_width), - - ) - - replot_grid[6,i]= widgets.Checkbox( - description = "Autolimits", - value = True, - style = style, - ) - replot_dict ={ - 'x_variable':replot_grid[2,0], - 'x_min':replot_grid[3,0], - 'x_max':replot_grid[4,0], - 'x_scale':replot_grid[5,0], - 'x_auto':replot_grid[6,0], - 'y_variable': replot_grid[2,1], - 'y_min':replot_grid[3,1], - 'y_max':replot_grid[4,1], - 'y_scale':replot_grid[5,1], - 'y_auto':replot_grid[6,1], - 'check': replot_grid[0,0] - - } - return replot_grid, replot_dict - - - - - \ No newline at end of file diff --git a/hp4155/ADU for double gate devices/lib/measurements.py b/hp4155/ADU for double gate devices/lib/measurements.py deleted file mode 100644 index c2feb303d61391bc3425603f5aa1ce83784c0aa6..0000000000000000000000000000000000000000 --- a/hp4155/ADU for double gate devices/lib/measurements.py +++ /dev/null @@ -1,1115 +0,0 @@ -# New measurements file for ADU - -# The new measurements will have the smus configuration as a parameter and written from the interface - -import sys -sys.path.insert(0, '..') #append parent directory - -import hp4155a -from help import * -from decimal import Decimal - -def Setup(device): - device.reset() - - #setup sweep measurement mode - device.measurement_mode('SWE') - - #disable all irrelevant units - device.disable_not_smu() - -# Transfer only VTG -def Transfer_VTG(VTG,VDS,integration,sample,device): - smu1 = device.smu_dict() - smu1.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2') - smu3 = device.smu_dict() - smu3.update(vname = 'VBG',iname='IBG',mode = 'COMM',func = 'CONS') - smu4 = device.smu_dict() - smu4.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VTG['hyst'].value, - start=VTG['start'].value, - stop=VTG['stop'].value, - step=VTG['step'].value, - comp =VTG['comp'].value, - pcomp=VTG['pcomp'].value - ) - - device.setup_var1(var1) - - points = number_of_points(VDS) - - var2=device.var2_dict() - var2.update( - start=VDS['start'].value, - step=VDS['step'].value, - points=points, - comp=VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var2(var2) - - device.integration_time(integration) - device.display_variable('X','VTG') - device.display_variable('Y1','ID') - device.display_variable('Y2','ITG') - - variables_list =["VTG","ITG","VDS","ID"] - device.variables_to_save(variables_list) - - device.single_measurement() - while device.operation_completed()==False: - pass - - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = np.array_split(df["VTG/V"],points) - y = np.array_split(df["IDmm/uA/um"].abs(),points) - labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels - - ax1.set_xlabel('$V_{TG} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - ax1.set_yscale('log') - - for i in range(points): - ax1.plot(x[i],y[i],label = f"VDS:{round(labels[i],3)} V") - - # Adding title - fig.suptitle('Transfer Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_TOP_GATE_U.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Transfer Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VTG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VTG from {VTG['start'].value}V to {VTG['stop'].value}V with step {VTG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - if VTG['pcomp'].value==0: - f.write(f"Top Gate Current Compliance/A:{VTG['comp'].value}"+"\n") - else: - f.write(f"Top Gate Power Compliance/A:{VTG['pcomp'].value}"+"\n") - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - f.write(f'Integration Time:{integration}'+"\n") - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - -# Transfer only VBG -def Transfer_VBG(VBG,VDS,integration,sample,device): - smu1 = device.smu_dict() - smu1.update(vname = 'VTG',iname='ITG',mode = 'COMM',func='CONS') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2') - smu3 = device.smu_dict() - smu3.update(vname = 'VBG',iname='IBG',mode = 'V',func = 'VAR1') - smu4 = device.smu_dict() - smu4.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VBG['hyst'].value, - start=VBG['start'].value, - stop=VBG['stop'].value, - step=VBG['step'].value, - comp =VBG['comp'].value, - pcomp=VBG['pcomp'].value - ) - - device.setup_var1(var1) - - points = number_of_points(VDS) - - var2=device.var2_dict() - var2.update( - start=VDS['start'].value, - step=VDS['step'].value, - points=points, - comp=VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var2(var2) - - device.integration_time(integration) - device.display_variable('X','VBG') - device.display_variable('Y1','ID') - device.display_variable('Y2','IBG') - - variables_list =["VBG","IBG","VDS","ID"] - device.variables_to_save(variables_list) - - device.single_measurement() - while device.operation_completed()==False: - pass - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = np.array_split(df["VBG/V"],points) - y = np.array_split(df["IDmm/uA/um"].abs(),points) - labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels - - ax1.set_xlabel('$V_{BG} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - ax1.set_yscale('log') - - for i in range(points): - ax1.plot(x[i],y[i],label = f"VDS:{round(labels[i],3)} V") - - # Adding title - fig.suptitle('Transfer Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_BACK_GATE_U.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Transfer Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VBG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VBG from {VBG['start'].value}V to {VBG['stop'].value}V with step {VBG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - #calculate the values - if VBG['pcomp'].value==0: - f.write(f"Back Gate Current Compliance/A:{VBG['comp'].value}"+"\n") - else: - f.write(f"Back Gate Power Compliance/A:{VBG['pcomp'].value}"+"\n") - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - - -def Transfer_BOTH(VTG,VBG,VDS,integration,sample,device): - smu1 = device.smu_dict() - smu1.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2') - smu3 = device.smu_dict() - smu3.update(vname = 'VBG',iname='IBG',mode = 'V',func = 'VARD') - smu4 = device.smu_dict() - smu4.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VTG['hyst'].value, - start=VTG['start'].value, - stop=VTG['stop'].value, - step=VTG['step'].value, - comp =VTG['comp'].value, - pcomp=VTG['pcomp'].value - ) - - device.setup_var1(var1) - - points = number_of_points(VDS) - - var2=device.var2_dict() - var2.update( - start=VDS['start'].value, - step=VDS['step'].value, - points=points, - comp=VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var2(var2) - - #calculate parameters for VARD - ratio,offset = calculate_line(VTG,VBG) - - # update VBG step - VBG["step"].value = Decimal(str(ratio)) * Decimal(str(VTG["step"].value)) - - vard = device.vard_dict() - vard.update( - offset = offset, - ratio = ratio, - comp = VBG["comp"].value, - pcomp = VBG["pcomp"].value - ) - device.setup_vard(vard) - - device.integration_time(integration) - device.display_variable('X','VTG') - device.display_variable('Y1','ID') - device.display_variable('Y2','ITG') - - variables_list =["VBG","IBG","VDS","ID","VTG","ITG"] - device.variables_to_save(variables_list) - - device.single_measurement() - while device.operation_completed()==False: - pass - - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x1 = np.array_split(df["VBG/V"],points) - y = np.array_split(df["IDmm/uA/um"].abs(),points) - x2 = np.array_split(df["VTG/V"],points) - labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels - - ax1.set_xlabel('$V_{BG} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - ax1.set_yscale('log') - - for i in range(points): - ax1.plot(x1[i],y[i],label = f"VDS:{round(labels[i],3)} V") - - # add opposite x axis - ax2 = ax1.twiny() - ax2.set_xlabel('$V_{TG} (V)$') - - for i in range(points): - ax2.plot(x2[i],y[i]) - - # Adding title - fig.suptitle('Transfer Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_BOTH_GATES_U.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Transfer Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gates:VBG,VTG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VBG from {VBG['start'].value}V to {VBG['stop'].value}V with step {VBG['step'].value}V"+"\n") - f.write(f"VTG from {VTG['start'].value}V to {VTG['stop'].value}V with step {VTG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - #calculate the values - if VBG['pcomp'].value==0: - f.write(f"Back Gate Current Compliance/A:{VBG['comp'].value}"+"\n") - else: - f.write(f"Back Gate Power Compliance/A:{VBG['pcomp'].value}"+"\n") - - if VTG['pcomp'].value==0: - f.write(f"Top Gate Current Compliance/A:{VTG['comp'].value}"+"\n") - else: - f.write(f"Top Gate Power Compliance/A:{VTG['pcomp'].value}"+"\n") - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - -# Output with VTG -def Output_VTG(VDS,VTG,integration,sample,device): - smu1=device.smu_dict() - smu1.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR2') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR1') - smu3= device.smu_dict() - smu3.update(vname='VBG',iname='IBG',mode = 'COMM',func='CONS') - smu4 = device.smu_dict() - smu4.update(vname='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VDS['hyst'].value, - start=VDS['start'].value, - stop=VDS['stop'].value, - step=VDS['step'].value, - comp =VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var1(var1) - - points = number_of_points(VTG) - - var2=device.var2_dict() - var2.update( - start=VTG['start'].value, - step=VTG['step'].value, - points=points, - comp=VTG['comp'].value, - pcomp=VTG['pcomp'].value - ) - device.setup_var2(var2) - - device.integration_time(integration) - device.display_variable('X','VDS') - device.display_variable('Y1','ID') - device.display_variable('Y2','ITG') - - variables_list = ['VDS','ID','VTG','ITG'] - device.variables_to_save(variables_list) - - device.single_measurement() - - while device.operation_completed()==False: - pass - - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # plot results - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= df["ID/A"]*norm - df["ITGmm/uA/um"]= df["ITG/A"]*norm - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = np.array_split(df["VDS/V"],points) - y = np.array_split(df["IDmm/uA/um"],points) - labels =np.mean(np.array_split(df["VTG/V"],points),axis = 1) # VDS values for labels - - ax1.set_xlabel('$V_{DS} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - - for i in range(points): - ax1.plot(x[i],y[i],label = f"VTG:{round(labels[i],3)} V") - - # Adding title - fig.suptitle('Output Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - #save Results - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_TOP_GATE_A.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Output Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VTG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VTG from {VTG['start'].value}V to {VTG['stop'].value}V with step {VTG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - #calculate the values - if VTG['pcomp'].value==0: - f.write(f"Top Gate Current Compliance/A:{VTG['comp'].value}"+"\n") - else: - f.write(f"Top Gate Power Compliance/A:{VTG['pcomp'].value}"+"\n") - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - -#Output VBG -def Output_VBG(VDS,VBG,integration,sample,device): - smu1=device.smu_dict() - smu1.update(vname ='VTG',iname = 'ITG',mode = 'COMM',func='CONS') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR1') - smu3= device.smu_dict() - smu3.update(vname='VBG',iname='IBG',mode = 'V',func = 'VAR2') - smu4 = device.smu_dict() - smu4.update(vname='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VDS['hyst'].value, - start=VDS['start'].value, - stop=VDS['stop'].value, - step=VDS['step'].value, - comp =VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var1(var1) - - points = number_of_points(VBG) - - var2=device.var2_dict() - var2.update( - start=VBG['start'].value, - step=VBG['step'].value, - points=points, - comp=VBG['comp'].value, - pcomp=VBG['pcomp'].value - ) - device.setup_var2(var2) - - device.integration_time(integration) - device.display_variable('X','VDS') - device.display_variable('Y1','ID') - device.display_variable('Y2','IBG') - - variables_list = ['VDS','ID','VBG','IBG'] - device.variables_to_save(variables_list) - - device.single_measurement() - - while device.operation_completed()==False: - pass - - device.autoscaling() - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # plot results - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = np.array_split(df["VDS/V"],points) - y = np.array_split(df["IDmm/uA/um"],points) - labels_VBG =np.mean(np.array_split(df["VBG/V"],points),axis = 1) # VDS values for labels - - ax1.set_xlabel('$V_{DS} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - - for i in range(points): - ax1.plot(x[i],y[i],label = f"VBG:{round(labels_VBG[i],3)} V") - - # Adding title - fig.suptitle('Output Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - #save Results - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_BACK_GATE_A.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Output Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VBG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VBG from {VBG['start'].value}V to {VBG['stop'].value}V with step {VBG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - #calculate the values - if VBG['pcomp'].value==0: - f.write(f"Back Gate Current Compliance/A:{VBG['comp'].value}"+"\n") - else: - f.write(f"Back Gate Power Compliance/A:{VBG['pcomp'].value}"+"\n") - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - -# Output both -def Output_BOTH(VDS,VTG,VBG,integration,sample,device): - smu1=device.smu_dict() - smu1.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR2') - smu2 = device.smu_dict() - smu2.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR1') - smu3= device.smu_dict() - smu3.update(vname='VBG',iname='IBG',mode = 'V',func = 'CONS') - smu4 = device.smu_dict() - smu4.update(vname='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.setup_smu(2,smu2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VDS['hyst'].value, - start=VDS['start'].value, - stop=VDS['stop'].value, - step=VDS['step'].value, - comp =VDS['comp'].value, - pcomp=VDS['pcomp'].value - ) - - device.setup_var1(var1) - - points_VTG = number_of_points(VTG) - - var2=device.var2_dict() - var2.update( - start=VTG['start'].value, - step=VTG['step'].value, - points=points_VTG, - comp=VTG['comp'].value, - pcomp=VTG['pcomp'].value - ) - device.setup_var2(var2) - - - points_VBG = number_of_points(VBG) - values_VBG = np.linspace(VBG["start"].value,VBG["stop"].value,num = points_VBG,endpoint= True) - - device.integration_time(integration) - device.display_variable('X','VDS') - device.display_variable('Y1','ID') - device.display_variable('Y2','ITG') - - variables_list = ['VDS','ID','VBG','IBG','VTG','ITG'] - device.variables_to_save(variables_list) - - for i , value in enumerate(values_VBG): - cons = device.cons_smu_dict() - cons.update(comp = VBG['comp'].value,value = value) - device.setup_cons_smu(3,cons) - - if i == 0: - device.single_measurement() - else: - device.append_measurement() - - while device.operation_completed()==False: - pass - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # plot results - points = points_VTG*points_VBG # number of curves - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = np.array_split(df["VDS/V"],points) - y = np.array_split(df["IDmm/uA/um"],points) - labels_VBG =np.mean(np.array_split(df["VBG/V"],points),axis = 1) # VBG values for labels - labels_VTG = np.mean(np.array_split(df["VTG/V"],points),axis = 1) - - ax1.set_xlabel('$V_{DS} (V)$') - ax1.set_ylabel('$I_{D} (uA/um)$') - - for i in range(points): - ax1.plot(x[i],y[i],label = f"VBG:{round(labels_VBG[i],3)} V , VTG:{round(labels_VTG[i],3)} V") - - # Adding title - fig.suptitle('Output Curve', fontweight ="bold") - fig.legend(loc='outside right upper') - #fig.tight_layout() - - display(fig) - - #save Results - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_BOTH_GATES_A.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Output Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gates:VBG,VTG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VBG from {VBG['start'].value}V to {VBG['stop'].value}V with step {VBG['step'].value}V"+"\n") - f.write(f"VTG from {VTG['start'].value}V to {VTG['stop'].value}V with step {VTG['step'].value}V"+"\n") - f.write(f"VDS from {VDS['start'].value}V to {VDS['stop'].value}V with step {VDS['step'].value}V"+"\n") - - - #calculate the values - f.write(f"Back Gate Current Compliance/A:{VBG['comp'].value}"+"\n") - - if VTG['pcomp'].value==0: - f.write(f"Top Gate Current Compliance/A:{VTG['comp'].value}"+"\n") - else: - f.write(f"Top Gate Power Compliance/A:{VTG['pcomp'].value}"+"\n") - - - if VDS['pcomp'].value == 0: - f.write(f"Drain Current Compliance/A:{VDS['comp'].value}"+"\n") - else: - f.write(f"Drain Power Compliance/A:{VDS['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df,points - - -def Gatediode_VTG(VTG,integration,sample,device): - smu1=device.smu_dict() - smu1.update(vname ='VTG',iname = 'ITG',mode = 'V',func='VAR1') - smu4 = device.smu_dict() - smu4.update(vname='VS',iname = 'IS',mode = 'COMM',func='CONS') - - device.setup_smu(1,smu1) - device.smu_disable(2) - device.smu_disable(3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VTG['hyst'].value, - start=VTG['start'].value, - stop=VTG['stop'].value, - step=VTG['step'].value, - comp =VTG['comp'].value, - pcomp=VTG['pcomp'].value - ) - device.setup_var1(var1) - - device.integration_time(integration) - - variables_list = ['VTG','ITG'] - device.variables_to_save(variables_list) - device.display_variable('X','VTG') - device.display_variable('Y1','ITG') - - device.single_measurement() - - while device.operation_completed()==False: - pass - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # plot results - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = df["VTG/V"] - y = df["ITGmm/uA/um"].abs() - - ax1.set_xlabel('$V_{TG} (V)$') - ax1.set_ylabel('$I_{TG} (uA/um)$') - ax1.set_yscale('log') - - ax1.plot(x,y) - - # Adding title - fig.suptitle('Gatediode Curve', fontweight ="bold") - #fig.tight_layout() - - display(fig) - - #save Results - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_TOP_GATE_D.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Gatediode Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VTG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VTG from {VTG['start'].value}V to {VTG['stop'].value}V with step {VTG['step'].value}V"+"\n") - - #calculate the values - if VTG['pcomp'].value==0: - f.write(f"Top Gate Current Compliance/A:{VTG['comp'].value}"+"\n") - else: - f.write(f"Top Gate Power Compliance/A:{VTG['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df - -def Gatediode_VBG(VBG,integration,sample,device): - smu3=device.smu_dict() - smu3.update(vname ='VBG',iname = 'IBG',mode = 'V',func='VAR1') - smu4 = device.smu_dict() - smu4.update(vname='VS',iname = 'IS', mode='COMM',func='CONS') - - device.smu_disable(1) - device.smu_disable(2) - device.setup_smu(3,smu3) - device.setup_smu(4,smu4) - - var1 = device.var1_dict() - var1.update( - mode=VBG['hyst'].value, - start=VBG['start'].value, - stop=VBG['stop'].value, - step=VBG['step'].value, - comp =VBG['comp'].value, - pcomp=VBG['pcomp'].value - ) - device.setup_var1(var1) - - device.integration_time(integration) - - variables_list = ['VBG','IBG'] - device.variables_to_save(variables_list) - - - device.display_variable('X','VBG') - device.display_variable('Y1','IBG') - - device.single_measurement() - while device.operation_completed()==False: - pass - - device.autoscaling() - - values = dict([(variable,device.return_values(variable)) for variable in variables_list]) - df = get_dataframe_from_results(values) - - # plot results - - # calculate normalization factor - norm = normalization_factor(sample["width"].value) - - # Append the normalized current - df["IBGmm/uA/um"]= (df["IBG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float') - - # Plot normalized Results VTG-IDmm - fig,ax1= plt.subplots(figsize=(10,6),layout='constrained') - - x = df["VBG/V"] - y = df["IBGmm/uA/um"].abs() - - ax1.set_xlabel('$V_{BG} (V)$') - ax1.set_ylabel('$I_{BG} (uA/um)$') - ax1.set_yscale('log') - - ax1.plot(x,y) - - # Adding title - fig.suptitle('Gatediode Curve', fontweight ="bold") - #fig.tight_layout() - - display(fig) - - #save Results - # Save the results - default_filename = f"{sample['sample'].value}_{sample['field'].value}_{sample['device'].value}_BACK_GATE_D.txt" - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename) - - root.destroy() - - with open(file,'w') as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Gatediode Curve at {date}"+"\n") - f.write(f"Series:{sample['processing_number'].value}"+"\n") - f.write(f"Sample:{sample['sample'].value}"+"\n") - f.write(f"Field:{sample['field'].value}"+"\n") - f.write(f"Device:{sample['device'].value}"+"\n") - f.write(f"Device Width/um:{sample['width'].value}"+"\n") - f.write("Sweeping Gate:VBG"+"\n\n") - - f.write('Parameters\n') - f.write(f"VBG from {VBG['start'].value}V to {VBG['stop'].value}V with step {VBG['step'].value}V"+"\n") - - #calculate the values - if VBG['pcomp'].value==0: - f.write(f"Back Gate Current Compliance/A:{VBG['comp'].value}"+"\n") - else: - f.write(f"Back Gate Power Compliance/A:{VBG['pcomp'].value}"+"\n") - - f.write(f'Integration Time:{integration}'+"\n") - - f.write("\nResults\n") - - df.to_csv(file,sep=" ",mode='a') - return df \ No newline at end of file diff --git a/hp4155/memristor (Version 1.0)/help.py b/hp4155/memristor (Version 1.0)/help.py deleted file mode 100644 index 918cc46ea79d3996a5edfae986545c0374bef776..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 1.0)/help.py +++ /dev/null @@ -1,353 +0,0 @@ -""" -This is a python file containing all the important functions for memristor measurement - -Available Functions - -measurements in the HP4155a -plot results -create data frame -ini file decoder -enabing and disabling widgets for jupyter(lists) -""" - -import sys -sys.path.insert(0, '..') #append parent directory - -import module -import matplotlib.pyplot as plt - -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox - -import numpy as np -from IPython.display import display, clear_output -import pandas as pd -from datetime import datetime -import ipywidgets as widgets -import time -import os - - -#double sweep from start to stop and then from start to stop -def sweep(start,stop,step,comp,integration,device): - device.measurement_mode('SWE') - - #changed smu2 is source and 4 is ground - #smu2 is constant and common - device.smu_mode_meas(4,'COMM') - device.smu_function_sweep(4,'CONS') - - #smu4 is VAR1 and V - device.smu_mode_meas(2,'V') - device.smu_function_sweep(2,'VAR1') - - device.integration_time(integration) - - #define double sweep - device.var1_mode('DOUB') - - #start stop step and comp - device.start_value_sweep(start) - #time.sleep(5) - device.stop_value_sweep(stop) - #time.sleep(5) - device.step_sweep(step) - #time.sleep(5) - device.comp('VAR1',comp) - - #display variables - device.display_variable('X','V2') - device.display_variable('Y1','I2') - - #execute measurement - device.single_measurement() - while device.operation_completed()==False: - pass - - device.autoscaling() - - #return values - V=device.return_data('V2') - I=device.return_data('I2') - - #convert the list to np.array to return the absolute values for the logarithmic scale - V = np.array(V) - I = np.array(I) - - #return all values to the function - return V, I - -#sampling check -def sampling_check(voltage,device): - - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.number_of_points(5) - device.integration_time('MED') - device.initial_interval(2e-3) - device.filter_status('OFF') - - #remove total sampling time - device.auto_sampling_time('ON') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - pass - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - R_mean = np.average(R) - return R_mean - except: - return 0 - -#new (retention) -def retention(voltage,period,duration,device): - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.initial_interval(period) - - device.total_sampling_time(duration) - - if int(duration/period)+1<=10001: - device.number_of_points(int(duration/period)+1) - else: - device.number_of_points('MAX') - device.integration_time('MED') - device.filter_status('OFF') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - pass - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - return TIME,R - except: - return 0,0 - - -#plot sweep results -def plot_sweep(x,y,title): - #plot results - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle(title) - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - ax1.plot(x,y) - ax2.plot(x,np.absolute(y)) - plt.tight_layout() - plt.show() - -def plot_retention(x,y): - fig, ax = plt.subplots() - fig.suptitle('Retention') - ax.set(xlabel='time(s)',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - ax.set_xscale('linear') - plt.plot(x,y) - plt.show() - -def create_data_frame(x,y): - header = ['V(V)','ABSV(V)',"I(A)",'ABSI(A)',"R(Ohm)"] - data = {header[0]:x,header[1]:np.absolute(x),header[2]:y,header[3]:np.absolute(y),header[4]:np.divide(x,y)} - df = pd.DataFrame(data) - #print(df) - return df - -def create_retention_data_frame(x,y): - header = ['Time(s)','R(Ohm)'] - data = {header[0]:x,header[1]:y} - df = pd.DataFrame(data) - return df - - -#write results to file -def write_to_file(file,title,df): - with open(file,'a') as f: - f.write(title) - f.write("\n") - f.write(df.to_string()) - f.write("\n\n") - -#### new functions ############## -def change_state(widgets_list): - for widget in widgets_list: - widget.disabled = not widget.disabled - -def enable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = False - -#a check values function -def check_values(step,set_voltage,reset_voltage): - valid = True - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - if step > abs(set_voltage) or step > abs(reset_voltage) or step==0:#invalid parameter setting - valid = False - tkinter.messagebox.showerror(message="Invalid parameter setting!") - - #now if the set-reset voltages have the same polarity show a warning - elif set_voltage*reset_voltage>0: - valid = tk.messagebox.askokcancel(message="Set-Reset voltages have the same polarity. Continue?") - - else: - pass - - root.destroy() - return valid - - -def information_box(information): - #open dialog and hide the main window - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #display meaagebox - tkinter.messagebox.showinfo(message=information) - root.destroy() - -#choose directory to save measurement results -#and check if you have access -def check_writable(folder): - filename = "test.txt" - file = os.path.join(folder,filename) - - #protection against removing existing file in python - i=1 - while os.path.exists(file): - filename=f"test{i}.txt" - file = os.path.join(folder,filename) - try: - with open(file,'a'): - writable = True - os.remove(file) - except: - writable = False - information_box(f"{folder} is not writable!") - - return writable - -def choose_folder(): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #choose nonemty folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check if writable in a while loop - writable=check_writable(folder) - - while writable == False: - #choose a correct folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check writable if not repeat - writable=check_writable(folder) - - root.destroy() - return folder - - - -#create or append to file a new measurement(now locally) we dont need that anymore!!! -def create_remote_file(sample_series,field,DUT,folder): - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file=os.path.join(folder,filename)#the whole file with location - date = str(datetime.today().replace(microsecond=0)) - - #check loop (once the return is called the function is over) - while True: - try:#you cannot write in every directory - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - return file - except: - information_box(f"You cannot write in the directory: {folder}!") - #again - folder=choose_folder() - file=os.path.join(folder,filename)#the whole file with location - - -#write the header -def write_header(file,sample_series,field,DUT): - date = str(datetime.today().replace(microsecond=0)) - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - -""" -New function (UPLOAD RESULTS) -IMPORTANT FOR ALL MEASUREMENTS -THE RESULTS ARE MOVED FROM SOURCE FILE TO TARGET FILE EVEN LOCALLY -""" - -def upload_results(source_file,target_file,target_file_dir): - while True: - try: - with (open(source_file,'r') as source,open(target_file,'a') as target): - target.write(source.read()) - os.remove(source_file) - return source_file,target_file,target_file_dir - except: - information_box(f"{target_file} is no longer accessible. Please change directory") - target_file_dir = choose_folder() - filename = os.path.basename(target_file) - target_file =os.path.join(target_file_dir,filename) - #and then try again - - - \ No newline at end of file diff --git a/hp4155/memristor (Version 1.0)/memristor.py b/hp4155/memristor (Version 1.0)/memristor.py deleted file mode 100644 index f092234bc04d217a20b9b7f318cdb9822790e118..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 1.0)/memristor.py +++ /dev/null @@ -1,495 +0,0 @@ -### this is the new memrstor measurement (set and reset as many times as the user wants and full sweeps with a button) -from help import * -import ipywidgets as widgets -from keyboard import add_hotkey,remove_hotkey - - - - - -#additional variables -first = True #first measurement -""" -This is not anymore the first time you start a measurement but the first time you write a header -""" - -file = None #complete filename with path -#first_sampling = True #indicates first sampling for set and reset buttons because we cannot add two at each button -#we dont need this variable anymore - - -#create temporary file to store the results localy -temp_file= os.path.join(os.getcwd(),'tempfile.txt') - -# the three naming fields - -sample_series= widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'sample series:', - style = {'description_width': 'initial'} - ) - -field = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'Field:', - style = {'description_width': 'initial'}, - ) - -DUT = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'DUT:', - style = {'description_width': 'initial'}, - ) - -#start new measurement button(new sample) -new=widgets.Button(description='next sample') - -#choose a new folder button -new_folder = widgets.Button(description='change folder') - - -horizontal = widgets.HBox([sample_series,new]) -horizontal3= widgets.HBox([DUT,new_folder]) -all_text_boxes = widgets.VBox([horizontal,field,horizontal3]) - - - -#first series of parameters -step = widgets.BoundedFloatText( - value=0.01, - min=0, - max=100, - step=0.01, - description='Step(V):', -) - -integration_time=widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - #style = {'description_width': 'initial'}, -) - -sampling=widgets.Checkbox(description='sampling check') - -#align the widgets horizontaly -line0=widgets.HBox([step,integration_time,sampling]) - - - -# THE BUTTONS -#create buttons as it shown in the how_buttons_look -set=widgets.Button(description='SET') -reset=widgets.Button(description='RESET') -full=widgets.Button(description='full sweep') -number = widgets.BoundedIntText(value=1,min=1,max=sys.maxsize,step=1,description='full sweeps:',disabled=False) #number of measuremts for the full sweep -retention_button=widgets.Button(description='retention') - - -#parameter boxes -Vset=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description= 'Comp(A):', -) - -#parameter buttons -Vreset=widgets.BoundedFloatText( - value=-1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vreset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description='Comp(A):', -) - -Vretention=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=1, - description='Voltage(V):', -) - -period=widgets.BoundedFloatText( - value=1, - min=2e-3, - max=65.535, - step=1, - description='Period(s):', -) - -duration=widgets.BoundedFloatText( - value=60, - min=60e-6, - max=1e11, - step=1, - description='Duration(s):', -) - -#align a button with a checkbox or integer bounded texts horizontaly -line1 = widgets.HBox([set,Vset,CC_vset]) -line2 = widgets.HBox([reset,Vreset,CC_vreset]) -line3 = widgets.HBox([full,number]) -line4 = widgets.HBox([retention_button,Vretention,period,duration]) - -#pack them into a single vertical box -all = widgets.VBox([line1,line2,line3,line4]) -output = widgets.Output() - - -#help lists for changing state of the buttons -information = [sample_series,field,DUT] -buttons = [set,reset,full,new,new_folder,retention_button] -parameters = [Vset,CC_vset,Vreset,CC_vreset,step,integration_time,number,sampling,Vretention,period,duration] - - -#connect to the device -device = module.HP4155a('GPIB0::17::INSTR') -device.reset() - -#disable all irrelevant units for the measurement -#smu1 and smu3 are disabled -device.smu_disable_sweep(1) -device.smu_disable_sweep(3) - -#disable vmus and vsus -device.disable_vsu(1) -device.disable_vsu(2) -device.disable_vmu(1) -device.disable_vmu(2) - -# R user function -device.user_function('R','OHM','V2/I2') - -#choose folder directory -folder=choose_folder() - - -#display all at the end -display(all_text_boxes) -print() -display(line0) -print() - -#display the buttons -display(all,output) -""" the above is what happens when the programm starts all the rest have to be written into button trigger functions""" - -def on_set_button_clicked(b): - global first,folder,file,temp_file - with output: - #disable buttons - change_state(buttons) - change_state(parameters) - - clear_output() - - #during first button press - if first == True: - change_state(information)#disable all widgets that are relevant about the information of the sample - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False - - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - if valid == True: - if sampling.value == True: #do sampling set before set process(100mV) - R_mean = sampling_check(0.1,device) - print(f"Average Resistance(Sampling Check):{R_mean} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) - plot_sweep(V12,I12,'SET') - df = create_data_frame(V12,I12) - print(df) - title = f"SET Memristor:"+"\n\n"+f"Set Voltage={Vset.value}V"+"\n"+f"current compliance={CC_vset.value}A"+"\n" - write_to_file(temp_file,title,df) - - if sampling.value == True: #do sampling set after set process(10mV) - R_mean = sampling_check(0.01,device) - print(f"Average Resistance(Sampling Check):{R_mean} Ohm") - first_sampling = False - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - #show messagebox - information_box("Measurement finished!") - - change_state(buttons) - change_state(parameters) - -def on_reset_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - - clear_output() - - #during first button press - if first == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - if valid == True: - - if sampling.value == True: #do sampling set before reset process(10mV) - R_mean = sampling_check(0.01,device) - print(f"Average Resistance(Sampling Check):{R_mean} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) - plot_sweep(V34,I34,'RESET') - df = create_data_frame(V34,I34) - print(df) - title =f"RESET Memristor:"+"\n\n"+f"Reset Voltage={Vreset.value}V"+"\n"+f"current compliance={CC_vreset.value}A"+"\n" - write_to_file(temp_file,title,df) - - if sampling.value == True: #do sampling set after reset process(100mV) - R_mean = sampling_check(0.1,device) - print(f"Average Resistance(Sampling Check):{R_mean} Ohm") - first_sampling = False - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - #show messagebox - information_box("Measurement finished!") - - change_state(buttons) - change_state(parameters) - -def on_full_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - - clear_output() - - #during first button press - if first == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - if valid == True: - with open(temp_file,'a') as f: - f.write(f"{number.value} full sweeps with parameters:") - f.write("\n") - f.write(f"Set Voltage = {Vset.value}V") - f.write("\n") - f.write(f"Current compliance set = {CC_vset.value}A") - f.write("\n") - f.write(f"Reset Voltage = {Vreset.value}V") - f.write("\n") - f.write(f"Current compliance reset = {CC_vreset.value}A") - f.write("\n\n") - - - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle('FULL SWEEP') - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - stop = False - - def break_loop(): - nonlocal stop - stop = True - #help list with the resistances - resistances = [] - - add_hotkey("esc",break_loop) - #execute number of measurements - for i in range(number.value):#here it is easier to implement the sampling checks - if sampling.value == True: #before set(100mv) - R_mean = sampling_check(0.1,device) - resistances.append(R_mean) - - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) #set - - #after set/before set - if sampling.value == True: #before set(10mv) - R_mean = sampling_check(0.01,device) - resistances.append(R_mean) - - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) #reset - - #no reason to do check at the end because the next loop will do that - - #butterfly curve - V=np.concatenate((V12,V34)) - I=np.concatenate((I12,I34)) - - #create data frame and save to file - df = create_data_frame(V,I) - f.write(f"{i+1} Iteration") - f.write("\n") - f.write(df.to_string()) - f.write("\n\n") - - - #plot results - ax1.plot(V,I) - ax2.plot(V,np.absolute(I)) - fig.tight_layout() - - #update plot - clear_output() - display(fig) - #plt.show() - print(df) - - #check for loop termination - if stop == True: - information_box("Endurance stopped after esc!") - f.write("endurance stopped!\n\n") - break - else: - information_box("Endurance completed!") - f.write("endurance completed!\n\n") - - remove_hotkey('esc') - stop = False - - #plot resistances if sampling value == True or len(resistances) !=0 - if len(resistances)!=0: - indexes = np.arange(1,len(resistances)+1) - resistances = np.array(resistances) - - plt.figure().clear() - fig, ax = plt.subplots() - - fig.suptitle('Resistance') - ax.set(xlabel='Index',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - plt.scatter(indexes,resistances) - plt.show() - print(len(resistances)) - print(indexes) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - change_state(buttons) - change_state(parameters) - -#move to next sample -def on_new_sample_button_clicked(b): - global first - with output: - #the if is to ensure that is not pressed many times - #just in case the user presses anything - change_state(buttons) - change_state(parameters) - - first = True - #change_state(information) not anymore creating changing state but enabling the widgets - enable_widgets(information) - sample_series.value='' - field.value='' - DUT.value='' - - #enable again - change_state(buttons) - change_state(parameters) - -#new_folder clicked -def on_new_folder_button_clicked(b): - global folder,file,first - with output: - change_state(buttons) #just to be sure - change_state(parameters) - - folder = choose_folder()#choose new folder - #file = create_file(sample_series,field,DUT,folder) #and create the new file (creates multiple headers!!!) - first = True #that will write header if the directory is the same as the previous one! - change_state(buttons) - change_state(parameters) - -def on_retention_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - clear_output() - - #during first button press - if first == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - #execute measurement - t,R=retention(Vretention.value,period.value,duration.value,device) - plot_retention(t,R) - df=create_retention_data_frame(t,R) - title =f"Retention Memristor:"+"\n\n"+f"Voltage={Vretention.value}V"+"\n"+f"period={period.value}s"+"\n"+f"duration={duration.value}s"+"\n" - - write_to_file(temp_file,title,df) - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - #show messagebox - information_box("Measurement finished!") - - change_state(buttons) - change_state(parameters) - -#link buttons with functions -set.on_click(on_set_button_clicked) -reset.on_click(on_reset_button_clicked) -full.on_click(on_full_button_clicked) -new.on_click(on_new_sample_button_clicked) -new_folder.on_click(on_new_folder_button_clicked) -retention_button.on_click(on_retention_button_clicked) diff --git a/hp4155/memristor (Version 1.0)/memristor_buttons.ipynb b/hp4155/memristor (Version 1.0)/memristor_buttons.ipynb deleted file mode 100644 index 498d56188be934b35876166f0d05103f25f69943..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 1.0)/memristor_buttons.ipynb +++ /dev/null @@ -1,114 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "df99f5a2-80af-4892-8633-33177239e444", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "a20406ad111145a8804514f54e9079eb", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Text(value='', description='sample series:', placeholder='Enter text here:', sty…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f8ebfdb43fdd4d3eabc6e482baa6dcf1", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(BoundedFloatText(value=0.01, description='Step(V):', step=0.01), Dropdown(description='Integrat…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b22d980d9eb444cf966c7c30bd02c59a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Button(description='SET', style=ButtonStyle()), BoundedFloatText(value=1.0, desc…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4b511a4dec9a47fc8f0572a7b8c7a112", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%run memristor.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9613a247-7ebb-46b8-ae8f-5d4ba21e5d43", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/hp4155/memristor (Version 2.0)/help.py b/hp4155/memristor (Version 2.0)/help.py deleted file mode 100644 index c57d751cb6473e514711fec7132bb75c69500af2..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 2.0)/help.py +++ /dev/null @@ -1,359 +0,0 @@ -""" -This is a python file containing all the important functions for memristor measurement - -Available Functions - -measurements in the HP4155a -plot results -create data frame -ini file decoder -enabing and disabling widgets for jupyter(lists) -""" - -import sys -sys.path.insert(0, '..') #append parent directory - -import module -import matplotlib.pyplot as plt - -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox - -import numpy as np -from IPython.display import display, clear_output -import pandas as pd -from datetime import datetime -import ipywidgets as widgets -import time -import os - - -#double sweep from start to stop and then from start to stop -def sweep(start,stop,step,comp,integration,device): - device.measurement_mode('SWE') - - #changed smu2 is source and 4 is ground - #smu2 is constant and common - device.smu_mode_meas(4,'COMM') - device.smu_function_sweep(4,'CONS') - - #smu4 is VAR1 and V - device.smu_mode_meas(2,'V') - device.smu_function_sweep(2,'VAR1') - - device.integration_time(integration) - - #define double sweep - device.var1_mode('DOUB') - - #start stop step and comp - device.start_value_sweep(start) - #time.sleep(5) - device.stop_value_sweep(stop) - #time.sleep(5) - - if start < stop and step < 0 : - step = -step - elif start > stop and step > 0 : - step = -step - - device.step_sweep(step) - #time.sleep(5) - device.comp('VAR1',comp) - - #display variables - device.display_variable('X','V2') - device.display_variable('Y1','I2') - - #execute measurement - device.single_measurement() - while device.operation_completed()==False: - time.sleep(2) - - device.autoscaling() - - #return values - V=device.return_data('V2') - I=device.return_data('I2') - - #convert the list to np.array to return the absolute values for the logarithmic scale - V = np.array(V) - I = np.array(I) - - #return all values to the function - return V, I - -#sampling check -def sampling_check(voltage,device): - - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.number_of_points(5) - device.integration_time('MED') - device.initial_interval(2e-3) - device.filter_status('OFF') - - #remove total sampling time - device.auto_sampling_time('ON') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - time.sleep(2) - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - R_mean = np.average(R) - return R_mean - except: - return 0 - -#new (retention) -def retention(voltage,period,duration,device): - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.initial_interval(period) - - device.total_sampling_time(duration) - - if int(duration/period)+1<=10001: - device.number_of_points(int(duration/period)+1) - else: - device.number_of_points('MAX') - device.integration_time('MED') - device.filter_status('OFF') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - time.sleep(2) - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - return TIME,R - except: - return 0,0 - - -#plot sweep results -def plot_sweep(x,y,title): - #plot results - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle(title) - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - ax1.plot(x,y) - ax2.plot(x,np.absolute(y)) - plt.tight_layout() - plt.show() - -def plot_retention(x,y): - fig, ax = plt.subplots() - fig.suptitle('Retention') - ax.set(xlabel='time(s)',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - ax.set_xscale('linear') - plt.plot(x,y) - plt.show() - -def create_data_frame(x,y): - header = ['V(V)','ABSV(V)',"I(A)",'ABSI(A)',"R(Ohm)"] - data = {header[0]:x,header[1]:np.absolute(x),header[2]:y,header[3]:np.absolute(y),header[4]:np.divide(x,y)} - df = pd.DataFrame(data) - #print(df) - return df - -def create_retention_data_frame(x,y): - header = ['Time(s)','R(Ohm)'] - data = {header[0]:x,header[1]:y} - df = pd.DataFrame(data) - return df - - -#write results to file -def write_to_file(file,title,df): - with open(file,'a') as f: - f.write(title) - f.write("\n") - f.write(df.to_string()) - f.write("\n\n") - -#### new functions ############## -def change_state(widgets_list): - for widget in widgets_list: - widget.disabled = not widget.disabled - -def enable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = False - -#a check values function -def check_values(step,set_voltage,reset_voltage): - valid = True - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - if step > abs(set_voltage) or step > abs(reset_voltage) or step==0:#invalid parameter setting - valid = False - tkinter.messagebox.showerror(message="Invalid parameter setting!") - - #now if the set-reset voltages have the same polarity show a warning - elif set_voltage*reset_voltage>0: - valid = tk.messagebox.askokcancel(message="Set-Reset voltages have the same polarity. Continue?") - - else: - pass - - root.destroy() - return valid - - -def information_box(information): - #open dialog and hide the main window - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #display meaagebox - tkinter.messagebox.showinfo(message=information) - root.destroy() - -#choose directory to save measurement results -#and check if you have access -def check_writable(folder): - filename = "test.txt" - file = os.path.join(folder,filename) - - #protection against removing existing file in python - i=1 - while os.path.exists(file): - filename=f"test{i}.txt" - file = os.path.join(folder,filename) - try: - with open(file,'a'): - writable = True - os.remove(file) - except: - writable = False - information_box(f"{folder} is not writable!") - - return writable - -def choose_folder(): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #choose nonemty folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check if writable in a while loop - writable=check_writable(folder) - - while writable == False: - #choose a correct folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check writable if not repeat - writable=check_writable(folder) - - root.destroy() - return folder - - - -#create or append to file a new measurement(now locally) we dont need that anymore!!! -def create_remote_file(sample_series,field,DUT,folder): - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file=os.path.join(folder,filename)#the whole file with location - date = str(datetime.today().replace(microsecond=0)) - - #check loop (once the return is called the function is over) - while True: - try:#you cannot write in every directory - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - return file - except: - information_box(f"You cannot write in the directory: {folder}!") - #again - folder=choose_folder() - file=os.path.join(folder,filename)#the whole file with location - - -#write the header -def write_header(file,sample_series,field,DUT): - date = str(datetime.today().replace(microsecond=0)) - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - -""" -New function (UPLOAD RESULTS) -IMPORTANT FOR ALL MEASUREMENTS -THE RESULTS ARE MOVED FROM SOURCE FILE TO TARGET FILE EVEN LOCALLY -""" - -def upload_results(source_file,target_file,target_file_dir): - while True: - try: - with (open(source_file,'r') as source,open(target_file,'a') as target): - target.write(source.read()) - os.remove(source_file) - return source_file,target_file,target_file_dir - except: - information_box(f"{target_file} is no longer accessible. Please change directory") - target_file_dir = choose_folder() - filename = os.path.basename(target_file) - target_file =os.path.join(target_file_dir,filename) - #and then try again - - - \ No newline at end of file diff --git a/hp4155/memristor (Version 2.0)/memristor.py b/hp4155/memristor (Version 2.0)/memristor.py deleted file mode 100644 index e8b6297bd3a2a81a780e9b022c844292d58a90c2..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 2.0)/memristor.py +++ /dev/null @@ -1,543 +0,0 @@ -### this is the new memrstor measurement (set and reset as many times as the user wants and full sweeps with a button) -from help import * -import ipywidgets as widgets -from keyboard import add_hotkey,remove_hotkey - - - - - -#additional variables -first = True #first measurement -""" -This is not anymore the first time you start a measurement but the first time you write a header -""" - -file = None #complete filename with path -#first_sampling = True #indicates first sampling for set and reset buttons because we cannot add two at each button -#we dont need this variable anymore - - -#create temporary file to store the results localy -temp_file= os.path.join(os.getcwd(),'tempfile.txt') - -# the three naming fields - -sample_series= widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'sample series:', - style = {'description_width': 'initial'} - ) - -field = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'Field:', - style = {'description_width': 'initial'}, - ) - -DUT = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'DUT:', - style = {'description_width': 'initial'}, - ) - -#start new measurement button(new sample) -new=widgets.Button(description='next sample') - -#choose a new folder button -new_folder = widgets.Button(description='change folder') - - -horizontal = widgets.HBox([sample_series,new]) -horizontal3= widgets.HBox([DUT,new_folder]) -all_text_boxes = widgets.VBox([horizontal,field,horizontal3]) - - - -#first series of parameters -step = widgets.BoundedFloatText( - value=0.01, - min=0, - max=100, - step=0.01, - description='Step(V):', -) - -integration_time=widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - #style = {'description_width': 'initial'}, -) - -sampling=widgets.Checkbox(description='sampling check') - -#align the widgets horizontaly -line0=widgets.HBox([step,integration_time,sampling]) - - - -# THE BUTTONS -#create buttons as it shown in the how_buttons_look -set=widgets.Button(description='SET') -reset=widgets.Button(description='RESET') -full=widgets.Button(description='full sweep') -number = widgets.BoundedIntText(value=1,min=1,max=sys.maxsize,step=1,description='full sweeps:',disabled=False) #number of measuremts for the full sweep -retention_button=widgets.Button(description='retention') - - -#parameter boxes -Vset=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description= 'Comp(A):', -) - -#parameter buttons -Vreset=widgets.BoundedFloatText( - value=-1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vreset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description='Comp(A):', -) - -Vretention=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=1, - description='Voltage(V):', -) - -period=widgets.BoundedFloatText( - value=1, - min=2e-3, - max=65.535, - step=1, - description='Period(s):', -) - -duration=widgets.BoundedFloatText( - value=60, - min=60e-6, - max=1e11, - step=1, - description='Duration(s):', -) - -#align a button with a checkbox or integer bounded texts horizontaly -line1 = widgets.HBox([set,Vset,CC_vset]) -line2 = widgets.HBox([reset,Vreset,CC_vreset]) -line3 = widgets.HBox([full,number]) -line4 = widgets.HBox([retention_button,Vretention,period,duration]) - -#pack them into a single vertical box -all = widgets.VBox([line1,line2,line3,line4]) -output = widgets.Output() - - -#help lists for changing state of the buttons -information = [sample_series,field,DUT] -buttons = [set,reset,full,new,new_folder,retention_button] -parameters = [Vset,CC_vset,Vreset,CC_vreset,step,integration_time,number,sampling,Vretention,period,duration] - - -#connect to the device -device = module.HP4155a('GPIB0::17::INSTR') -device.reset() - -#disable all irrelevant units for the measurement -#smu1 and smu3 are disabled -device.smu_disable_sweep(1) -device.smu_disable_sweep(3) - -#disable vmus and vsus -device.disable_vsu(1) -device.disable_vsu(2) -device.disable_vmu(1) -device.disable_vmu(2) - -# R user function -device.user_function('R','OHM','V2/I2') - -#choose folder directory -folder=choose_folder() - - -#display all at the end -display(all_text_boxes) -print() -display(line0) -print() - -#display the buttons -display(all,output) -""" the above is what happens when the programm starts all the rest have to be written into button trigger functions""" - -def on_set_button_clicked(b): - global first,folder,file,temp_file - with output: - #disable buttons - change_state(buttons) - change_state(parameters) - - #lock the device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - change_state(information)#disable all widgets that are relevant about the information of the sample - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False - - if valid == True: - if sampling.value == True: #do sampling set before set process(100mV) - R_mean_before = sampling_check(0.1,device) - R_mean_before = round(R_mean_before,1)#round 1 decimal point - print(f"Average Resistance(Sampling Check):{R_mean_before:e} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) - plot_sweep(V12,I12,'SET') - df = create_data_frame(V12,I12) - print(df) - - - if sampling.value == True: #do sampling set after set process(10mV) - R_mean_after = sampling_check(0.01,device) - R_mean_after = round(R_mean_after,1) - print(f"Average Resistance(Sampling Check):{R_mean_after:e} Ohm") - first_sampling = False - - title = f"SET Memristor:"+"\n\n"+f"Set Voltage={Vset.value}V"+"\n"+f"current compliance={CC_vset.value}A"+"\n" - if sampling.value == True: - title = title + f"R(Ohm) Before/After"+"\n"+f"{R_mean_before} {R_mean_after}"+"\n" - write_to_file(temp_file,title,df) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #show messagebox - information_box("Measurement finished!") - - #unlock device - device.inst.unlock() - - change_state(buttons) - change_state(parameters) - -def on_reset_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - - #lock device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - if valid == True: - if sampling.value == True: #do sampling set before reset process(10mV) - R_mean_before = sampling_check(0.01,device) - R_mean_before = round(R_mean_before,1)#round 1 decimal point - print(f"Average Resistance(Sampling Check):{R_mean_before:e} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) - plot_sweep(V34,I34,'RESET') - df = create_data_frame(V34,I34) - print(df) - - if sampling.value == True: #do sampling set after reset process(100mV) - R_mean_after = sampling_check(0.1,device) - R_mean_after = round(R_mean_after,1) - print(f"Average Resistance(Sampling Check):{R_mean_after:e} Ohm") - first_sampling = False - - title =f"RESET Memristor:"+"\n\n"+f"Reset Voltage={Vreset.value}V"+"\n"+f"current compliance={CC_vreset.value}A"+"\n" - if sampling.value == True: - title = title + f"R(Ohm) Before/After"+"\n"+f"{R_mean_before} {R_mean_after}"+"\n" - write_to_file(temp_file,title,df) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #show messagebox - information_box("Measurement finished!") - - #unlock device - device.inst.unlock() - - change_state(buttons) - change_state(parameters) - -def on_full_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - - # lock device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - - if valid == True: - with open(temp_file,'a') as f: - f.write(f"{number.value} full sweeps with parameters:") - f.write("\n") - f.write(f"Set Voltage = {Vset.value}V") - f.write("\n") - f.write(f"Current compliance set = {CC_vset.value}A") - f.write("\n") - f.write(f"Reset Voltage = {Vreset.value}V") - f.write("\n") - f.write(f"Current compliance reset = {CC_vreset.value}A") - f.write("\n\n") - - - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle('FULL SWEEP') - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - stop = False - - def break_loop(): - nonlocal stop - stop = True - #help list with the resistances - resistances = [] - - add_hotkey("esc",break_loop) - #execute number of measurements - for i in range(number.value):#here it is easier to implement the sampling checks - if sampling.value == True: #before set(100mv) - R_mean_init = sampling_check(0.1,device) - R_mean_init = round(R_mean_init,1) - resistances.append(R_mean_init) - - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) #set - - #after set/before set - if sampling.value == True: #before set(10mv) - R_mean_set = sampling_check(0.01,device) - R_mean_set = round(R_mean_set,1) - resistances.append(R_mean_set) - - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) #reset - - #no reason to do check at the end because the next loop will do that(not anymore) more sampling checks - - #after reset - if sampling.value == True:#-0.1V - R_mean_reset = sampling_check(-0.1,device) - R_mean_reset = round(R_mean_reset,1) - resistances.append(R_mean_reset) - - - #butterfly curve - V=np.concatenate((V12,V34)) - I=np.concatenate((I12,I34)) - - #create data frame and save to file - df = create_data_frame(V,I) - f.write(f"{i+1} Iteration") - f.write("\n") - if sampling.value == True: - f.write(f"R(Ohm) INIT/SET/RESET"+"\n"+f"{R_mean_init} {R_mean_set} {R_mean_reset}"+"\n") - f.write(df.to_string()) - f.write("\n\n") - - - #plot results - ax1.plot(V,I) - ax2.plot(V,np.absolute(I)) - fig.tight_layout() - - #update plot - clear_output() - display(fig) - #plt.show() - print(df) - - #check for loop termination - if stop == True: - information_box("Endurance stopped after esc!") - f.write("endurance stopped!\n\n") - break - else: - information_box("Endurance completed!") - f.write("endurance completed!\n\n") - - remove_hotkey('esc') - stop = False - - #plot resistances if sampling value == True or len(resistances) !=0 - if len(resistances)!=0: - indexes = np.arange(1,len(resistances)+1) - resistances = np.array(resistances) - - plt.figure().clear() - fig, ax = plt.subplots() - - fig.suptitle('Resistance') - ax.set(xlabel='Index',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - plt.scatter(indexes,resistances) - plt.show() - #print(len(resistances)) - #print(indexes) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #unlock the device - device.inst.unlock() - - change_state(buttons) - change_state(parameters) - -#move to next sample -def on_new_sample_button_clicked(b): - global first - with output: - #the if is to ensure that is not pressed many times - #just in case the user presses anything - change_state(buttons) - change_state(parameters) - - first = True - #change_state(information) not anymore creating changing state but enabling the widgets - enable_widgets(information) - #sample_series.value='' - #field.value='' - DUT.value='' - - #enable again - change_state(buttons) - change_state(parameters) - -#new_folder clicked -def on_new_folder_button_clicked(b): - global folder,file,first - with output: - change_state(buttons) #just to be sure - change_state(parameters) - - folder = choose_folder()#choose new folder - #file = create_file(sample_series,field,DUT,folder) #and create the new file (creates multiple headers!!!) - first = True #that will write header if the directory is the same as the previous one! - change_state(buttons) - change_state(parameters) - -def on_retention_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - - device.inst.lock_excl() - - clear_output() - - #during first button press - if first == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - #execute measurement - t,R=retention(Vretention.value,period.value,duration.value,device) - plot_retention(t,R) - df=create_retention_data_frame(t,R) - title =f"Retention Memristor:"+"\n\n"+f"Voltage={Vretention.value}V"+"\n"+f"period={period.value}s"+"\n"+f"duration={duration.value}s"+"\n" - - write_to_file(temp_file,title,df) - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - #show messagebox - information_box("Measurement finished!") - - device.inst.unlock() - - change_state(buttons) - change_state(parameters) - -#link buttons with functions -set.on_click(on_set_button_clicked) -reset.on_click(on_reset_button_clicked) -full.on_click(on_full_button_clicked) -new.on_click(on_new_sample_button_clicked) -new_folder.on_click(on_new_folder_button_clicked) -retention_button.on_click(on_retention_button_clicked) diff --git a/hp4155/memristor (Version 2.0)/memristor_buttons.ipynb b/hp4155/memristor (Version 2.0)/memristor_buttons.ipynb deleted file mode 100644 index ddfec87750fa4d2d2e7f892cfa1d7ef71be78a88..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 2.0)/memristor_buttons.ipynb +++ /dev/null @@ -1,114 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "df99f5a2-80af-4892-8633-33177239e444", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "867d912290bc4089ab98083476c64723", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Text(value='', description='sample series:', placeholder='Enter text here:', sty…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "93d35a24b3474362912ad3626c5d3065", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(BoundedFloatText(value=0.01, description='Step(V):', step=0.01), Dropdown(description='Integrat…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "92dbe8ccf22f4fa0b8b3fb00003a4416", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Button(description='SET', style=ButtonStyle()), BoundedFloatText(value=1.0, desc…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ab54e647d9f74958b4211dd8f95b8041", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%run memristor.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "076a9132-edc2-4ae5-8a7f-c8a179473952", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/hp4155/memristor (Version 3.0)/help.py b/hp4155/memristor (Version 3.0)/help.py deleted file mode 100644 index 96851a571213a3cd22a0c6fd695a73d2efe7f485..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 3.0)/help.py +++ /dev/null @@ -1,443 +0,0 @@ -""" -This is a python file containing all the important functions for memristor measurement - -Available Functions - -measurements in the HP4155a -plot results -create data frame -ini file decoder -enabing and disabling widgets for jupyter(lists) -""" - -import sys -sys.path.insert(0, '..') #append parent directory - -import module -import matplotlib.pyplot as plt - -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox - -import numpy as np -from IPython.display import display, clear_output -import pandas as pd -from datetime import datetime -import ipywidgets as widgets -import time -import os - - -#these are the quick sampling checks -def test_contacts(): - device = module.HP4155a('GPIB0::17::INSTR') - - smu = [1,2,3,4] - for i in range(1,4): # iterate through smus 1-4 - for j in range(4,i,-1): - """ - We have the following pairs in order - 1-4,1-3,1-2,2-4,2-3,3-4 - """ - device.reset() - - device.measurement_mode('SAMP') - device.sampling_mode('LIN') - device.number_of_points(1) - device.integration_time('MED') - device.initial_interval(2e-3) - device.filter_status('OFF') - #remove total sampling time - device.auto_sampling_time('ON') - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - - device.smu_mode_meas(i,'V') #one smu is measuring - device.smu_mode_meas(j,'COMM') #one smu is ground - - #set voltage and compliance - device.constant_smu_sampling(i,0.01) - device.constant_smu_comp(i,'MAX') - - #smus to remove - smu_disable = smu.copy() - smu_disable.remove(i) - smu_disable.remove(j) - - for number in smu_disable: - device.smu_disable_sweep(number) - - device.display_variable('X','@TIME') - device.display_variable('Y1',f'I{i}') - device.single_measurement() - while device.operation_completed() == False: - time.sleep(2) - - device.autoscaling() - V = device.return_data(f'V{i}') - I = device.return_data(f'I{i}') - R = V[0]/I[0] - print(f"R{i}{j}:{R} Ohm") - #print(f"Contact check of smu{i} and smu{j} failed!") - - del device - - - -#double sweep from start to stop and then from start to stop -def sweep(start,stop,step,comp,integration,device): - device.measurement_mode('SWE') - - #changed smu2 is source and 4 is ground - #smu2 is constant and common - device.smu_mode_meas(4,'COMM') - device.smu_function_sweep(4,'CONS') - - #smu4 is VAR1 and V - device.smu_mode_meas(2,'V') - device.smu_function_sweep(2,'VAR1') - - device.integration_time(integration) - - #define double sweep - device.var1_mode('DOUB') - - #start stop step and comp - device.start_value_sweep(start) - #time.sleep(5) - device.stop_value_sweep(stop) - #time.sleep(5) - - if start < stop and step < 0 : - step = -step - elif start > stop and step > 0 : - step = -step - - device.step_sweep(step) - #time.sleep(5) - device.comp('VAR1',comp) - - #display variables - device.display_variable('X','V2') - device.display_variable('Y1','I2') - - #execute measurement - device.single_measurement() - while device.operation_completed()==False: - time.sleep(2) - - device.autoscaling() - - #return values - V=device.return_data('V2') - I=device.return_data('I2') - - #convert the list to np.array to return the absolute values for the logarithmic scale - V = np.array(V) - I = np.array(I) - - #return all values to the function - return V, I - -#sampling check -def sampling_check(voltage,device): - - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.number_of_points(5) - device.integration_time('MED') - device.initial_interval(2e-3) - device.filter_status('OFF') - - #remove total sampling time - device.auto_sampling_time('ON') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - time.sleep(2) - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - R_mean = np.average(R) - return R_mean - except: - return 0 - -#new (retention) -def retention(voltage,period,duration,device): - device.measurement_mode('SAMP') - - device.smu_mode_meas(2,'V') - device.smu_mode_meas(4,'COMM') - - #set voltage and compliance - device.constant_smu_sampling(2,voltage) - device.constant_smu_comp(2,'MAX') - - device.sampling_mode('LIN') - device.initial_interval(period) - - device.total_sampling_time(duration) - - if int(duration/period)+1<=10001: - device.number_of_points(int(duration/period)+1) - else: - device.number_of_points('MAX') - device.integration_time('MED') - device.filter_status('OFF') - - device.display_variable('X','@TIME') - device.display_variable('Y1','R') - device.single_measurement() - while device.operation_completed() == False: - time.sleep(2) - - device.autoscaling() - try: - TIME = device.return_data('@TIME') - R = device.return_data('R') - TIME = np.array(TIME) - R = np.array(R) - return TIME,R - except: - return 0,0 - - -#plot sweep results -def plot_sweep(x,y,title): - #plot results - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle(title) - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - ax1.plot(x,y) - ax2.plot(x,np.absolute(y)) - plt.tight_layout() - plt.show() - -def plot_retention(x,y): - fig, ax = plt.subplots() - fig.suptitle('Retention') - ax.set(xlabel='time(s)',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - ax.set_xscale('linear') - plt.plot(x,y) - plt.show() - -def create_data_frame(x,y): - header = ['V(V)','ABSV(V)',"I(A)",'ABSI(A)',"R(Ohm)"] - data = {header[0]:x,header[1]:np.absolute(x),header[2]:y,header[3]:np.absolute(y),header[4]:np.divide(x,y)} - df = pd.DataFrame(data) - #print(df) - return df - -def create_retention_data_frame(x,y): - header = ['Time(s)','R(Ohm)'] - data = {header[0]:x,header[1]:y} - df = pd.DataFrame(data) - return df - - -#write results to file -def write_to_file(file,title,df): - with open(file,'a') as f: - f.write(title) - f.write("\n") - f.write(df.to_string()) - f.write("\n\n") - -#### new functions ############## -def disable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = True - -def change_state(widgets_list): - for widget in widgets_list: - widget.disabled = not widget.disabled - -def enable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = False - -#a check values function -def check_values(step,set_voltage,reset_voltage): - valid = True - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - if step > abs(set_voltage) or step > abs(reset_voltage) or step==0:#invalid parameter setting - valid = False - tkinter.messagebox.showerror(message="Invalid parameter setting!") - - #now if the set-reset voltages have the same polarity show a warning - elif set_voltage*reset_voltage>0: - valid = tk.messagebox.askokcancel(message="Set-Reset voltages have the same polarity. Continue?") - - else: - pass - - root.destroy() - return valid - - -def information_box(information): - #open dialog and hide the main window - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #display meaagebox - tkinter.messagebox.showinfo(message=information) - root.destroy() - -#choose directory to save measurement results -#and check if you have access -def check_writable(folder): - filename = "test.txt" - file = os.path.join(folder,filename) - - #protection against removing existing file in python - i=1 - while os.path.exists(file): - filename=f"test{i}.txt" - file = os.path.join(folder,filename) - try: - with open(file,'a'): - writable = True - os.remove(file) - except: - writable = False - information_box(f"{folder} is not writable!") - - return writable - -def choose_folder(): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #choose nonemty folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check if writable in a while loop - writable=check_writable(folder) - - while writable == False: - #choose a correct folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check writable if not repeat - writable=check_writable(folder) - - root.destroy() - return folder - - - -#create or append to file a new measurement(now locally) we dont need that anymore!!! -def create_remote_file(sample_series,field,DUT,folder): - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file=os.path.join(folder,filename)#the whole file with location - date = str(datetime.today().replace(microsecond=0)) - - #check loop (once the return is called the function is over) - while True: - try:#you cannot write in every directory - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - return file - except: - information_box(f"You cannot write in the directory: {folder}!") - #again - folder=choose_folder() - file=os.path.join(folder,filename)#the whole file with location - - -#write the header -def write_header(file,sample_series,field,DUT): - date = str(datetime.today().replace(microsecond=0)) - with open(file,'a') as f: - title = f"Memristor Measurement"+"\n\n"+f"Sample series:{sample_series.value}" +"\n"+f"field:{field.value}"+"\n"+f"DUT:{DUT.value}"+"\n"+f"Date:{date}"+"\n\n" - f.write(title) - -""" -New function (UPLOAD RESULTS) -IMPORTANT FOR ALL MEASUREMENTS -THE RESULTS ARE MOVED FROM SOURCE FILE TO TARGET FILE EVEN LOCALLY -""" - -def upload_results(source_file,target_file,target_file_dir): - while True: - try: - with (open(source_file,'r') as source,open(target_file,'a') as target): - target.write(source.read()) - os.remove(source_file) - return source_file,target_file,target_file_dir - except: - information_box(f"{target_file} is no longer accessible. Please change directory") - target_file_dir = choose_folder() - filename = os.path.basename(target_file) - target_file =os.path.join(target_file_dir,filename) - #and then try again - - -#setup device for regular memristor measurement -def setup_memristor(): - #connect to the device - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - - #disable all irrelevant units for the measurement - #smu1 and smu3 are disabled - device.smu_disable_sweep(1) - device.smu_disable_sweep(3) - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - - # R user function - device.user_function('R','OHM','V2/I2') - - return device \ No newline at end of file diff --git a/hp4155/memristor (Version 3.0)/help_pulse.py b/hp4155/memristor (Version 3.0)/help_pulse.py deleted file mode 100644 index ce69d42678070a3ececb8519c5050cef52678813..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 3.0)/help_pulse.py +++ /dev/null @@ -1,439 +0,0 @@ -import sys -sys.path.insert(0, '..') #append parent directory - -import ipywidgets as widgets -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox -import os -from datetime import datetime -import matplotlib.pyplot as plt -import numpy as np -import module -import time -import pandas as pd -from IPython.display import display, clear_output - -#widgets interactivity - -def add_widgets_to_list(source_dictionary,target_list): - for widget in source_dictionary.values(): - target_list.append(widget) - - -def check_pulse(dictionary): - #check if number of pulses is ok - if dictionary['pulses'].value < 0: - dictionary['pulses'].value = -dictionary['pulses'].value - elif dictionary['pulses'].value==0: - dictionary['pulses'].value = 1 - else: - pass - - # Restriction: pulse period ≥ pulse width + 4 ms - if dictionary['period'].value < dictionary['width'].value+4e-3: - dictionary['period'].value = dictionary['width'].value+4e-3 - - -#sweep pulse measurement -def sweep_meas(dict): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.smu_disable_sweep(1) - device.smu_disable_sweep(3) - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - - device.measurement_mode("SWE") - device.smu_function_sweep(2,"VAR1") - device.smu_mode_meas(4,"COMMON") - device.smu_function_sweep(4,"CONS") - - device.smu_mode_meas(2,"VPULSE") - device.start_value_sweep(dict["start"].value) - device.stop_value_sweep(dict["stop"].value) - - #define the number of steps given specific pulses - - step = (dict["stop"].value-dict["start"].value)/(dict["pulses"].value-1) - device.step_sweep(step) - - device.comp("VAR1",dict["comp"].value) - - device.display_variable("X","V2") - device.display_variable("Y1",'I2') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - - device.pulse_base(dict["base"].value) - device.pulse_width(dict["width"].value) - device.pulse_period(dict["period"].value) - device.integration_time(dict["integration"].value) - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I2") - V_i=device.return_data("V2") - R_i = np.divide(V_i,I_i) - - - expected_time = dict["period"].value*dict["pulses"].value - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def plot_sweep_pulse(values): - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("V(V)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(values[0],np.abs(values[1]),color=color) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(values[0],np.abs(values[2]),color = color) - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - ax2.set_yscale('log') - - fig.suptitle("Sweep Pulse Measurement Results") - - plt.show() - -def save_sweep(folder,sample_dict,values,times,sweep_dict): - filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt" - - file = os.path.join(folder,filename) - - with open(file,"a") as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Sweep Pulse Measurement at {date}"+"\n") - f.write(f"period(s):{sweep_dict['period'].value}"+"\n") - f.write(f"width(s):{sweep_dict['width'].value}"+"\n") - f.write(f"base value(V):{sweep_dict['base'].value}"+"\n") - f.write(f"execution time(s):{times[0]}"+"\n") - f.write(f"expected time(s):{times[1]}"+"\n") - f.write(f"number of pulses:{sweep_dict['pulses'].value}"+"\n") - f.write(f"current compliance(A):{sweep_dict['comp'].value}"+"\n") - f.write(f"voltage:{sweep_dict['start'].value}V to {sweep_dict['stop'].value}V"+"\n") - f.write(f"integration time:{sweep_dict['integration'].value}"+"\n\n") - - zipped = list(zip(values[0],values[1], values[2])) - df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)']) - - f.write("Results Sweep Pulse:\n") - f.write(df.to_string()) - f.write("\n\n\n") - -def constant_meas(dict): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.user_function('V','V','V2') - device.user_function('I','A','I2') - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - device.smu_disable_sweep(1) - #device.smu_disable_sweep(3) - - device.measurement_mode("SWE") - device.smu_mode_meas(2,"VPULSE") - device.smu_function_sweep(2,'CONS') - device.smu_mode_meas(4,"COMM") - device.smu_function_sweep(2,"CONS") - device.smu_function_sweep(4,'CONS') - - #smu 3 is used to define the number of pulses not contacted - device.smu_mode_meas(3,'V') - device.smu_function_sweep(3,"VAR1") - - device.start_value_sweep(0) - device.stop_value_sweep(10) - - #define the number of steps given specific pulses - step = 10/(dict["pulses"].value-1) - device.step_sweep(step) - - device.comp("VAR1","MAX") - device.const_comp(2,dict["comp"].value) - - device.cons_smu_value(2,dict["voltage"].value) - - device.display_variable("X","@INDEX") - device.display_variable("Y1",'I') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - device.range_mode(3,"AUTO") - - device.pulse_base(dict["base"].value) - device.pulse_width(dict["width"].value) - device.pulse_period(dict["period"].value) - device.integration_time(dict["integration"].value) - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I") - V_i=device.return_data("V") - R_i = np.divide(V_i,I_i) - - - expected_time = dict["period"].value*dict["pulses"].value - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def plot_constant_pulse(values): - index =[] - for i in range(len(values[0])): - index.append(i+1) - - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("Index(Pulse number)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(index,np.abs(values[1]),color=color,label = "Voltage(V):"+str(min(values[0]))) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(index,np.abs(values[2]),color=color) - ax2.set_yscale('log') - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - - fig.suptitle("Constant Pulse Measurement Results") - ax1.set_title("Voltage:"+str(min(values[0]))+"V") - - plt.show() - -def save_constant(folder,sample_dict,values,times,cons_dict): - filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt" - - file = os.path.join(folder,filename) - - with open(file,"a") as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Constant Pulse Measurement at {date}"+"\n") - f.write(f"period(s):{cons_dict['period'].value}"+"\n") - f.write(f"width(s):{cons_dict['width'].value}"+"\n") - f.write(f"base value(V):{cons_dict['base'].value}"+"\n") - f.write(f"execution time(s):{times[0]}"+"\n") - f.write(f"expected time(s):{times[1]}"+"\n") - f.write(f"number of pulses:{cons_dict['pulses'].value}"+"\n") - f.write(f"current compliance(A):{cons_dict['comp'].value}"+"\n") - f.write(f"constant voltage:{cons_dict['voltage'].value}V"+"\n") - f.write(f"integration time:{cons_dict['integration'].value}"+"\n\n") - - zipped = list(zip(values[0],values[1], values[2])) - df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)']) - - f.write("Results Constant Pulse:\n") - f.write(df.to_string()) - f.write("\n\n\n") - -import ipywidgets as widgets - -#sample interface - -style = {'description_width': 'initial'} - -def constant_pulse(): - voltage = widgets.BoundedFloatText( - value = 10, - min = -100, - max = 100, - step = 1, - description = 'Constant Voltage(V):', - style=style, - ) - - comp = widgets.BoundedFloatText( - value = 0.1, - min = -0.1, - max = 0.1, - step = 0.01, - description = 'Compliance(A):', - style=style, - ) - - pulses = widgets.IntText( - value = 100, - description = 'Number of Pulses:', - style=style, - ) - period = widgets.BoundedFloatText( - value = 5e-3, - min = 5e-3, - max = 1, - step = 5e-3, - description ='Pulse Period(s):', - style=style, - - ) - width = widgets.BoundedFloatText( - value = 5e-4, - min = 5e-4, - max = 1e-1, - step= 5e-4, - description ='Pulse Width(s):', - style=style, - ) - base = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Base Voltage(V):', - style=style - ) - - integration =widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - style=style - ) - - pulse_parameters = widgets.VBox([pulses,period,width,base]) - smu_parameters = widgets.VBox([voltage,comp,integration]) - - constant_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters]) - constant_pulse_dict = { - 'voltage': voltage, - 'comp':comp, - 'pulses':pulses, - 'period':period, - 'width':width, - 'base':base, - 'integration':integration - } - return constant_pulse_widgets,constant_pulse_dict - -def sweep_pulse(): - start_voltage = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Start Voltage(V):', - style=style, - ) - stop_voltage = widgets.BoundedFloatText( - value = 15, - min = -100, - max = 100, - step = 1, - description = 'Stop Voltage(V):', - style=style, - ) - - comp = widgets.BoundedFloatText( - value = 0.1, - min = -0.1, - max = 0.1, - step = 0.01, - description = 'Compliance(A):', - style=style, - ) - - pulses = widgets.IntText( - value = 100, - description = 'Number of Pulses:', - style=style, - ) - period = widgets.BoundedFloatText( - value = 5e-3, - min = 5e-3, - max = 1, - step = 5e-3, - description ='Pulse Period(s):', - style=style, - - ) - width = widgets.BoundedFloatText( - value = 5e-4, - min = 5e-4, - max = 1e-1, - step= 5e-4, - description ='Pulse Width(s):', - style=style, - ) - base = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Base Voltage(V):', - style=style - ) - - integration =widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - style=style - ) - - pulse_parameters = widgets.VBox([pulses,period,width,base]) - smu_parameters = widgets.VBox([start_voltage,stop_voltage,comp,integration]) - - sweep_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters]) - sweep_pulse_dict = { - 'start': start_voltage, - 'stop':stop_voltage, - 'comp':comp, - 'pulses':pulses, - 'period':period, - 'width':width, - 'base':base, - 'integration':integration - } - return sweep_pulse_widgets,sweep_pulse_dict - - diff --git a/hp4155/memristor (Version 3.0)/memristor.py b/hp4155/memristor (Version 3.0)/memristor.py deleted file mode 100644 index 9b4fc48bcadc25da28f066293e23d6cf7dfa970d..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 3.0)/memristor.py +++ /dev/null @@ -1,643 +0,0 @@ -### this is the new memrstor measurement (set and reset as many times as the user wants and full sweeps with a button) -from help import * -import ipywidgets as widgets -from keyboard import add_hotkey,remove_hotkey - -# pulsed libraries -from help_pulse import * - -#additional variables -first = True #first measurement -""" -This is not anymore the first time you start a measurement but the first time you write a header -""" - -file = None #complete filename with path -#first_sampling = True #indicates first sampling for set and reset buttons because we cannot add two at each button -#we dont need this variable anymore - - -#create temporary file to store the results localy -temp_file= os.path.join(os.getcwd(),'tempfile.txt') - -# the three naming fields - -sample_series= widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'sample series:', - style = {'description_width': 'initial'} - ) - -field = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'Field:', - style = {'description_width': 'initial'}, - ) - -DUT = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'DUT:', - style = {'description_width': 'initial'}, - ) - -#start new measurement button(new sample) -new=widgets.Button(description='next sample') - -#choose a new folder button -new_folder = widgets.Button(description='change folder') - - -horizontal = widgets.HBox([sample_series,new]) -horizontal3= widgets.HBox([DUT,new_folder]) -all_text_boxes = widgets.VBox([horizontal,field,horizontal3]) - - - -#first series of parameters -step = widgets.BoundedFloatText( - value=0.01, - min=0, - max=100, - step=0.01, - description='Step(V):', -) - -integration_time=widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - #style = {'description_width': 'initial'}, -) - -sampling=widgets.Checkbox(description='sampling check') - -#align the widgets horizontaly -line0=widgets.HBox([step,integration_time,sampling]) - - - -# THE BUTTONS -#create buttons as it shown in the how_buttons_look -set=widgets.Button(description='SET') -reset=widgets.Button(description='RESET') -full=widgets.Button(description='FULL SWEEP') -number = widgets.BoundedIntText(value=1,min=1,max=sys.maxsize,step=1,description='full sweeps:',disabled=False) #number of measuremts for the full sweep -retention_button=widgets.Button(description='RETENTION') -contact_check = widgets.Button(description = 'CONTACT CHECK') - - -#parameter boxes -Vset=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description= 'Comp(A):', -) - -#parameter buttons -Vreset=widgets.BoundedFloatText( - value=-1, - min=-100, - max=100, - step=0.1, - description='Voltage(V):', -) - -#parameter buttons -CC_vreset=widgets.BoundedFloatText( - value=1e-3, - min=-0.1, - max=0.1, - step=0.01, - description='Comp(A):', -) - -Vretention=widgets.BoundedFloatText( - value=1, - min=-100, - max=100, - step=1, - description='Voltage(V):', -) - -period=widgets.BoundedFloatText( - value=1, - min=2e-3, - max=65.535, - step=1, - description='Period(s):', -) - -duration=widgets.BoundedFloatText( - value=60, - min=60e-6, - max=1e11, - step=1, - description='Duration(s):', -) - -#align a button with a checkbox or integer bounded texts horizontaly -line1 = widgets.HBox([set,Vset,CC_vset]) -line2 = widgets.HBox([reset,Vreset,CC_vreset]) -line3 = widgets.HBox([full,number]) -line4 = widgets.HBox([retention_button,Vretention,period,duration]) - -#pack them into a single vertical box -all = widgets.VBox([line0,line1,line2,line3,line4]) -output = widgets.Output() - - -#help lists for changing state of the buttons -information = [sample_series,field,DUT] -buttons = [set,reset,full,new,new_folder,retention_button,contact_check] -parameters = [Vset,CC_vset,Vreset,CC_vreset,step,integration_time,number,sampling,Vretention,period,duration] - -#choose folder directory -folder=choose_folder() - - -#display all at the end -display(all_text_boxes) -print() - -display(contact_check) -print() - -cons_widgets,cons_dict = constant_pulse() -sweep_widgets,sweep_dict = sweep_pulse() - -sweep_button = widgets.Button(description = "SWEEP PULSE") -cons_button = widgets.Button(description = "CONSTANT PULSE") - - -children = [all,widgets.VBox([sweep_widgets,sweep_button]),widgets.VBox([cons_widgets,cons_button])] -titles = ["Regular","Sweep Pulse","Constant Pulse"] -tab = widgets.Tab() -tab.children = children -tab.titles = titles - -display(tab,output) - -all_widgets = [sweep_button,cons_button] -add_widgets_to_list(cons_dict,all_widgets) -add_widgets_to_list(sweep_dict,all_widgets) - -#display the buttons -""" the above is what happens when the programm starts all the rest have to be written into button trigger functions""" - -def on_contact_check_clicked(b): - with output: - clear_output(wait = True) - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - - test_contacts() - - information_box("Contact Check Completed") - - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - -def on_set_button_clicked(b): - global first,folder,file,temp_file - with output: - #disable buttons - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - - device = setup_memristor() - - #lock the device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - change_state(information)#disable all widgets that are relevant about the information of the sample - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False - - if valid == True: - if sampling.value == True: #do sampling set before set process(100mV) - R_mean_before = sampling_check(0.1,device) - R_mean_before = round(R_mean_before,1)#round 1 decimal point - print(f"Average Resistance(Sampling Check):{R_mean_before:e} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) - plot_sweep(V12,I12,'SET') - df = create_data_frame(V12,I12) - print(df) - - - if sampling.value == True: #do sampling set after set process(10mV) - R_mean_after = sampling_check(0.01,device) - R_mean_after = round(R_mean_after,1) - print(f"Average Resistance(Sampling Check):{R_mean_after:e} Ohm") - first_sampling = False - - title = f"SET Memristor:"+"\n\n"+f"Set Voltage={Vset.value}V"+"\n"+f"current compliance={CC_vset.value}A"+"\n" - if sampling.value == True: - title = title + f"R(Ohm) Before/After"+"\n"+f"{R_mean_before} {R_mean_after}"+"\n" - write_to_file(temp_file,title,df) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #show messagebox - information_box("Measurement finished!") - - #unlock device - device.inst.unlock() - - del device - - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - -def on_reset_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - - device = setup_memristor() - - #lock device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - if valid == True: - if sampling.value == True: #do sampling set before reset process(10mV) - R_mean_before = sampling_check(0.01,device) - R_mean_before = round(R_mean_before,1)#round 1 decimal point - print(f"Average Resistance(Sampling Check):{R_mean_before:e} Ohm") - first_sampling = False - - #execute measurement,plot results and save them - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) - plot_sweep(V34,I34,'RESET') - df = create_data_frame(V34,I34) - print(df) - - if sampling.value == True: #do sampling set after reset process(100mV) - R_mean_after = sampling_check(0.1,device) - R_mean_after = round(R_mean_after,1) - print(f"Average Resistance(Sampling Check):{R_mean_after:e} Ohm") - first_sampling = False - - title =f"RESET Memristor:"+"\n\n"+f"Reset Voltage={Vreset.value}V"+"\n"+f"current compliance={CC_vreset.value}A"+"\n" - if sampling.value == True: - title = title + f"R(Ohm) Before/After"+"\n"+f"{R_mean_before} {R_mean_after}"+"\n" - write_to_file(temp_file,title,df) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #show messagebox - information_box("Measurement finished!") - - #unlock device - device.inst.unlock() - - del device - - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - -def on_full_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - - device= setup_memristor() - - # lock device - device.inst.lock_excl() - - clear_output() - - #check values - valid = check_values(step.value,Vset.value,Vreset.value) - - #during first button press - if first == True and valid == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - - if valid == True: - with open(temp_file,'a') as f: - f.write(f"{number.value} full sweeps with parameters:") - f.write("\n") - f.write(f"Set Voltage = {Vset.value}V") - f.write("\n") - f.write(f"Current compliance set = {CC_vset.value}A") - f.write("\n") - f.write(f"Reset Voltage = {Vreset.value}V") - f.write("\n") - f.write(f"Current compliance reset = {CC_vreset.value}A") - f.write("\n\n") - - - plt.figure().clear() - fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis - fig.suptitle('FULL SWEEP') - ax1.set_title('Linear I') - ax1.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_title('Logarithmic I') - ax2.set(xlabel='Voltage(V)',ylabel='Current(A)') - ax2.set_yscale('log') - - stop = False - - def break_loop(): - nonlocal stop - stop = True - #help list with the resistances - resistances = [] - - add_hotkey("esc",break_loop) - #execute number of measurements - for i in range(number.value):#here it is easier to implement the sampling checks - if sampling.value == True: #before set(100mv) - R_mean_init = sampling_check(0.1,device) - R_mean_init = round(R_mean_init,1) - resistances.append(R_mean_init) - - V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) #set - - #after set/before set - if sampling.value == True: #before set(10mv) - R_mean_set = sampling_check(0.01,device) - R_mean_set = round(R_mean_set,1) - resistances.append(R_mean_set) - - V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) #reset - - #no reason to do check at the end because the next loop will do that(not anymore) more sampling checks - - #after reset - if sampling.value == True:#-0.1V - R_mean_reset = sampling_check(-0.1,device) - R_mean_reset = round(R_mean_reset,1) - resistances.append(R_mean_reset) - - - #butterfly curve - V=np.concatenate((V12,V34)) - I=np.concatenate((I12,I34)) - - #create data frame and save to file - df = create_data_frame(V,I) - f.write(f"{i+1} Iteration") - f.write("\n") - if sampling.value == True: - f.write(f"R(Ohm) INIT/SET/RESET"+"\n"+f"{R_mean_init} {R_mean_set} {R_mean_reset}"+"\n") - f.write(df.to_string()) - f.write("\n\n") - - - #plot results - ax1.plot(V,I) - ax2.plot(V,np.absolute(I)) - fig.tight_layout() - - #update plot - clear_output() - display(fig) - #plt.show() - print(df) - - #check for loop termination - if stop == True: - information_box("Endurance stopped after esc!") - f.write("endurance stopped!\n\n") - break - else: - information_box("Endurance completed!") - f.write("endurance completed!\n\n") - - remove_hotkey('esc') - stop = False - - #plot resistances if sampling value == True or len(resistances) !=0 - if len(resistances)!=0: - indexes = np.arange(1,len(resistances)+1) - resistances = np.array(resistances) - - plt.figure().clear() - fig, ax = plt.subplots() - - fig.suptitle('Resistance') - ax.set(xlabel='Index',ylabel='Resistance(Ohm)') - ax.set_yscale('log') - plt.scatter(indexes,resistances) - plt.show() - #print(len(resistances)) - #print(indexes) - - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - - #unlock the device - device.inst.unlock() - - del device - - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - -#move to next sample -def on_new_sample_button_clicked(b): - global first - with output: - #the if is to ensure that is not pressed many times - #just in case the user presses anything - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - - first = True - #change_state(information) not anymore creating changing state but enabling the widgets - enable_widgets(information) - #sample_series.value='' - #field.value='' - DUT.value='' - - #enable again - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - -#new_folder clicked -def on_new_folder_button_clicked(b): - global folder,file,first - with output: - change_state(buttons) #just to be sure - change_state(parameters) - change_state(all_widgets) - - folder = choose_folder()#choose new folder - #file = create_file(sample_series,field,DUT,folder) #and create the new file (creates multiple headers!!!) - first = True #that will write header if the directory is the same as the previous one! - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - -def on_retention_button_clicked(b): - global first,folder,file,temp_file - with output: - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - - device = setup_memristor() - - device.inst.lock_excl() - - clear_output() - - #during first button press - if first == True: - #disable checkboxes, text fields etc. - change_state(information) - filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt" - file = os.path.join(folder,filename) - #write header to temp_file - write_header(temp_file,sample_series,field,DUT) - first = False #set first to false irrelvant if it is in the if statement or not - - #execute measurement - t,R=retention(Vretention.value,period.value,duration.value,device) - plot_retention(t,R) - df=create_retention_data_frame(t,R) - title =f"Retention Memristor:"+"\n\n"+f"Voltage={Vretention.value}V"+"\n"+f"period={period.value}s"+"\n"+f"duration={duration.value}s"+"\n" - - write_to_file(temp_file,title,df) - #upload results - temp_file,file,folder=upload_results(temp_file,file,folder) - #show messagebox - information_box("Measurement finished!") - - device.inst.unlock() - - del device - - change_state(buttons) - change_state(parameters) - change_state(all_widgets) - - -def on_sweep_button_clicked(b): - with output: - global first - clear_output(wait = True) - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - check_pulse(sweep_dict) - - sample_dict= { - 'series':sample_series, - 'field':field, - 'dut':DUT - } - if first == True: - change_state(information) - first = False - - times,values = sweep_meas(sweep_dict) - plot_sweep_pulse(values) - save_sweep(folder,sample_dict,values,times,sweep_dict) - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - - -def on_constant_button_clicked(b): - with output: - global first - clear_output(wait = True) - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - check_pulse(sweep_dict) - - sample_dict= { - 'series':sample_series, - 'field':field, - 'dut':DUT - } - if first == True: - change_state(information) - first = False - - times,values = constant_meas(cons_dict) - plot_constant_pulse(values) - save_constant(folder,sample_dict,values,times,cons_dict) - change_state(all_widgets) - change_state(buttons) - change_state(parameters) - -#link buttons to widgets (pulsed) -sweep_button.on_click(on_sweep_button_clicked) -cons_button.on_click(on_constant_button_clicked) - -#link buttons with functions -set.on_click(on_set_button_clicked) -reset.on_click(on_reset_button_clicked) -full.on_click(on_full_button_clicked) -new.on_click(on_new_sample_button_clicked) -new_folder.on_click(on_new_folder_button_clicked) -retention_button.on_click(on_retention_button_clicked) -contact_check.on_click(on_contact_check_clicked) diff --git a/hp4155/memristor (Version 3.0)/memristor_buttons.ipynb b/hp4155/memristor (Version 3.0)/memristor_buttons.ipynb deleted file mode 100644 index 0564861132a090398cf808cddd3b309c0bfe584a..0000000000000000000000000000000000000000 --- a/hp4155/memristor (Version 3.0)/memristor_buttons.ipynb +++ /dev/null @@ -1,114 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "df99f5a2-80af-4892-8633-33177239e444", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8e42e33b13b94bc28d51ac3879635a83", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Text(value='', description='sample series:', placeholder='Enter text here:', sty…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b645be04ed3040d5bfa6ab024e5dd698", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Button(description='CONTACT CHECK', style=ButtonStyle())" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "382a0395fff84d78b2e3ef2c67f2de6a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Tab(children=(VBox(children=(HBox(children=(BoundedFloatText(value=0.01, description='Step(V):', step=0.01), D…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "1f0a16c6eaf44dce8926c29cff203ec7", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%run memristor.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "076a9132-edc2-4ae5-8a7f-c8a179473952", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/hp4155/memristor pulsed (Version 1.0)/constant_pulse_test.ipynb b/hp4155/memristor pulsed (Version 1.0)/constant_pulse_test.ipynb deleted file mode 100644 index 8cf0475cd6e144b65a48c27c3a4bd4959056d29a..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/constant_pulse_test.ipynb +++ /dev/null @@ -1,95 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from help import *\n", - "\n", - "#set the values here\n", - "const_voltage = 10\n", - "comp = 0.1\n", - "\n", - "#number of pulses \n", - "pulses = 100\n", - "\n", - "# pulse period is in interval 5ms to 1s \n", - "pulse_period = 5e-2\n", - "\n", - "#pulse is in interval 0.5ms to 100ms\n", - "pulse_width = 5e-3\n", - "\n", - "# Restriction: pulse period ≥ pulse width + 4 ms\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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LwD8/PxISkq67nUPDw8GDBjA7NmzGTVqFLNnz2bQoEG4ubldd25iYqKtB7ikgoKCiI2NLXAsNja2QG9yUa/x8PAodq8pSHEqhBBCiP+hKEqxhte1NGjQIJ599lnmz5/P3LlzefLJJ1EUhUaNGrFjx44C5+7YsYP69etf9yz3fEaj8bpe1R07djBy5Ej69u0L5BWaFy9etL3eoEEDcnNzOXToEK1a5U2FOHfuXIFCs2XLlsTExGAwGKhZs2ah97799tuJiYkhKSmpQK8r5BXgXbp0YdWqVezcuZOpU6ded/358+fJysri9ttvL/wbVUTt2rVj48aNBbaZWr9+Pe3atbvpNf+73dR/XXMzMqwvhBBCiArLzc2NwYMH88orrxAdHW2bT/rCCy+wceNGpkyZwpkzZ/jpp5/4+uuvmTRp0g3bqlmzJhs3brQViQD16tVj2bJlHD58mCNHjjB06FCsVqvtmoYNG3L33Xfz+OOPs3fvXg4dOsTjjz+Os7Oz7RGdd999N+3ataNPnz78+eefXLx4kZ07d/Laa6+xf/9+IK849fPzu66ghryN+evWrcvw4cNtUxn+1/bt26lduzZ16tSxHRs+fDivvPJKgfMOHz7M4cOHSU9P59q1axw+fJjw8HDb688++yxr167l008/5dSpU7z99tvs37+fCRMm2M555ZVXGD58uO3zJ554goiICF566SVOnTrFt99+y6JFi3juuedu+L2+qZttMyCEEEKIyq2ibiX1bzt37lQBtVevXgWO528lZTQa1Ro1aqhTp04t8Pr/bve0cuVKtW7duqrBYLBtJXXhwgW1a9euqrOzs1q9enX166+/vm4bpqioKPW+++5THR0d1bCwMHX+/PlqQECAOn36dNs5qamp6tNPP61Wq1ZNNRqNavXq1dVhw4apkZGRtnNeeukldciQIYV+jR988IEKqJ988kmhr997773qhx9+WOBY586d1REjRhQ4xr+2y+J/ts3Kt2jRIrV+/fqqg4OD2qRJE3X16tUFXh8xYoTauXPnAsc2b96stmjRQnVwcFBr166tzp49u9Cc+W72c6f8HVQIIYQQVVBWVhYXLlygVq1ahS7IEcV35coVqlevzoYNG+jevXuRr4uJiaFJkyYcPHiQsLCwIl934sQJunXrxpkzZ/D09CxJ5HJ3s587mXMqhBBCCHELNm3aRHp6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", - "text/plain": [ - "<Figure size 640x480 with 2 Axes>" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "times,values=constant_pulse(const_voltage,comp,pulses,pulse_period,pulse_width)\n", - "plot_constant(values)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Measurement finished!\n" - ] - } - ], - "source": [ - "create_file(measurement=\"Constant Pulse\",period=pulse_period,width=pulse_width,pulses=pulses,times=times,values=values,comp=comp)\n", - "print(\"Measurement finished!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/hp4155/memristor pulsed (Version 1.0)/help.py b/hp4155/memristor pulsed (Version 1.0)/help.py deleted file mode 100644 index bd52bc9d6ba089952b3db5a2c4c75446938ec82d..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/help.py +++ /dev/null @@ -1,246 +0,0 @@ -import sys -sys.path.insert(0, '..') #append parent directory - - -import matplotlib.pyplot as plt -import numpy as np - -import module -import time -import pandas as pd -import tkinter as tk -from tkinter import filedialog - -def sweep_pulse(start,stop,comp,points,width,period): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.smu_disable_sweep(1) - device.smu_disable_sweep(3) - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - - device.measurement_mode("SWE") - device.smu_function_sweep(2,"VAR1") - device.smu_mode_meas(4,"COMMON") - device.smu_function_sweep(4,"CONS") - - device.smu_mode_meas(2,"VPULSE") - device.start_value_sweep(start) - device.stop_value_sweep(stop) - - #define the number of steps given specific pulses - - step = (stop-start)/(points-1) - device.step_sweep(step) - - device.comp("VAR1",comp) - - device.display_variable("X","V2") - device.display_variable("Y1",'I2') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - - device.pulse_base(0) - device.pulse_width(width) - device.pulse_period(period) - device.integration_time("MED") - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I2") - V_i=device.return_data("V2") - R_i = np.divide(V_i,I_i) - - - expected_time = period*int(points) - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def constant_pulse(const,comp,points,period,width): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.user_function('V','V','V2') - device.user_function('I','A','I2') - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - device.smu_disable_sweep(1) - #device.smu_disable_sweep(3) - - device.measurement_mode("SWE") - device.smu_mode_meas(2,"VPULSE") - device.smu_function_sweep(2,'CONS') - device.smu_mode_meas(4,"COMM") - device.smu_function_sweep(2,"CONS") - device.smu_function_sweep(4,'CONS') - - #smu 3 is used to define the number of pulses not contacted - device.smu_mode_meas(3,'V') - device.smu_function_sweep(3,"VAR1") - - device.start_value_sweep(0) - device.stop_value_sweep(10) - - #define the number of steps given specific pulses - step = 10/(points-1) - device.step_sweep(step) - - device.comp("VAR1","MAX") - device.const_comp(2,comp) - - device.cons_smu_value(2,const) - - device.display_variable("X","V") - device.display_variable("Y1",'I') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - device.range_mode(3,"AUTO") - - device.pulse_base(0) - device.pulse_width(width) - device.pulse_period(period) - device.integration_time("MED") - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I") - V_i=device.return_data("V") - R_i = np.divide(V_i,I_i) - - - expected_time = period*int(points) - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def create_file(measurement,period,width,pulses,values,times,comp): - - filename = " " - - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =filename) - - #check if the file path is correct(.txt) - while file.endswith(".txt") == False: - #open again filedialog with error message box - tk.messagebox.showerror(message='invalid filename!') - file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =filename) - root.destroy() - - with open(file,"w") as f: - f.write(f"{measurement}"+"\n") - f.write(f"period(s):{period}"+"\n") - f.write(f"width(s):{width}"+"\n") - f.write(f"execution time(s):{times[0]}"+"\n") - f.write(f"expected time(s):{times[1]}"+"\n") - f.write(f"number of pulses:{pulses}"+"\n") - f.write(f"current compliance(A):{comp}"+"\n\n") - - zipped = list(zip(values[0],values[1], values[2])) - df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)']) - - f.write("Results Pulse:\n") - f.write(df.to_string()) - -def plot_sweep(values): - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("V(V)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(values[0],np.abs(values[1]),color=color) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(values[0],np.abs(values[2]),color = color) - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - ax2.set_yscale('log') - - plt.show() - - -def plot_constant(values): - index =[] - for i in range(len(values[0])): - index.append(i+1) - - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("Index(Pulse number)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(index,np.abs(values[1]),color=color,label = "Voltage(V):"+str(min(values[0]))) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(index,np.abs(values[2]),color=color,label = "Voltage(V):"+str(min(values[0]))) - ax2.set_yscale('log') - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - - fig.legend() - plt.show() - - - - - - - - - - - - diff --git a/hp4155/memristor pulsed (Version 1.0)/help_new.py b/hp4155/memristor pulsed (Version 1.0)/help_new.py deleted file mode 100644 index f2506b8d020f27d8ff5e28dbd01bad51425581fc..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/help_new.py +++ /dev/null @@ -1,352 +0,0 @@ -import sys -sys.path.insert(0, '..') #append parent directory - -import ipywidgets as widgets -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox -import os -from datetime import datetime -import matplotlib.pyplot as plt -import numpy as np -import module -import time -import pandas as pd -from IPython.display import display, clear_output - -#widgets interactivity - -def add_widgets_to_list(source_dictionary,target_list): - for widget in source_dictionary.values(): - target_list.append(widget) - -def change_state(widgets_list): - for widget in widgets_list: - widget.disabled = not widget.disabled - -def enable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = False - -def disable_widgets(widgets_list): - for widget in widgets_list: - widget.disabled = True - -def information_box(information): - #open dialog and hide the main window - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #display meaagebox - tkinter.messagebox.showinfo(message=information) - root.destroy() - -#choose directory to save measurement results -#and check if you have access -def check_writable(folder): - filename = "test.txt" - file = os.path.join(folder,filename) - - #protection against removing existing file in python - i=1 - while os.path.exists(file): - filename=f"test{i}.txt" - file = os.path.join(folder,filename) - try: - with open(file,'a'): - writable = True - os.remove(file) - except: - writable = False - information_box(f"{folder} is not writable!") - - return writable - -def choose_folder(): - root = tk.Tk() - root.withdraw() - root.lift() #show window above all other applications - - root.attributes("-topmost", True)#window stays above all other applications - - #choose nonemty folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check if writable in a while loop - writable=check_writable(folder) - - while writable == False: - #choose a correct folder - folder = tk.filedialog.askdirectory() - - while folder == '': - folder = tk.filedialog.askdirectory() - - #check writable if not repeat - writable=check_writable(folder) - - root.destroy() - return folder - -def check_values(dictionary): - #check if number of pulses is ok - if dictionary['pulses'].value < 0: - dictionary['pulses'].value = -dictionary['pulses'].value - elif dictionary['pulses'].value==0: - dictionary['pulses'].value = 1 - else: - pass - - # Restriction: pulse period ≥ pulse width + 4 ms - if dictionary['period'].value < dictionary['width'].value+4e-3: - dictionary['period'].value = dictionary['width'].value+4e-3 - - -#sweep pulse measurement -def sweep_meas(dict): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.smu_disable_sweep(1) - device.smu_disable_sweep(3) - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - - device.measurement_mode("SWE") - device.smu_function_sweep(2,"VAR1") - device.smu_mode_meas(4,"COMMON") - device.smu_function_sweep(4,"CONS") - - device.smu_mode_meas(2,"VPULSE") - device.start_value_sweep(dict["start"].value) - device.stop_value_sweep(dict["stop"].value) - - #define the number of steps given specific pulses - - step = (dict["stop"].value-dict["start"].value)/(dict["pulses"].value-1) - device.step_sweep(step) - - device.comp("VAR1",dict["comp"].value) - - device.display_variable("X","V2") - device.display_variable("Y1",'I2') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - - device.pulse_base(dict["base"].value) - device.pulse_width(dict["width"].value) - device.pulse_period(dict["period"].value) - device.integration_time(dict["integration"].value) - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I2") - V_i=device.return_data("V2") - R_i = np.divide(V_i,I_i) - - - expected_time = dict["period"].value*dict["pulses"].value - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def plot_sweep(values): - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("V(V)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(values[0],np.abs(values[1]),color=color) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(values[0],np.abs(values[2]),color = color) - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - ax2.set_yscale('log') - - fig.suptitle("Sweep Pulse Measurement Results") - - plt.show() - -def save_sweep(folder,sample_dict,values,times,sweep_dict): - filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt" - - file = os.path.join(folder,filename) - - with open(file,"a") as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Sweep Pulse Measurement at {date}"+"\n") - f.write(f"period(s):{sweep_dict['period'].value}"+"\n") - f.write(f"width(s):{sweep_dict['width'].value}"+"\n") - f.write(f"base value(V):{sweep_dict['base'].value}"+"\n") - f.write(f"execution time(s):{times[0]}"+"\n") - f.write(f"expected time(s):{times[1]}"+"\n") - f.write(f"number of pulses:{sweep_dict['pulses'].value}"+"\n") - f.write(f"current compliance(A):{sweep_dict['comp'].value}"+"\n") - f.write(f"voltage:{sweep_dict['start'].value}V to {sweep_dict['stop'].value}V"+"\n") - f.write(f"integration time:{sweep_dict['integration'].value}"+"\n\n") - - zipped = list(zip(values[0],values[1], values[2])) - df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)']) - - f.write("Results Sweep Pulse:\n") - f.write(df.to_string()) - f.write("\n\n\n") - -def constant_meas(dict): - device = module.HP4155a('GPIB0::17::INSTR') - device.reset() - device.user_function('V','V','V2') - device.user_function('I','A','I2') - - #disable vmus and vsus - device.disable_vsu(1) - device.disable_vsu(2) - device.disable_vmu(1) - device.disable_vmu(2) - device.smu_disable_sweep(1) - #device.smu_disable_sweep(3) - - device.measurement_mode("SWE") - device.smu_mode_meas(2,"VPULSE") - device.smu_function_sweep(2,'CONS') - device.smu_mode_meas(4,"COMM") - device.smu_function_sweep(2,"CONS") - device.smu_function_sweep(4,'CONS') - - #smu 3 is used to define the number of pulses not contacted - device.smu_mode_meas(3,'V') - device.smu_function_sweep(3,"VAR1") - - device.start_value_sweep(0) - device.stop_value_sweep(10) - - #define the number of steps given specific pulses - step = 10/(dict["pulses"].value-1) - device.step_sweep(step) - - device.comp("VAR1","MAX") - device.const_comp(2,dict["comp"].value) - - device.cons_smu_value(2,dict["voltage"].value) - - device.display_variable("X","@INDEX") - device.display_variable("Y1",'I') - - device.range_mode(4,"AUTO") - device.range_mode(2,"AUTO") - device.range_mode(3,"AUTO") - - device.pulse_base(dict["base"].value) - device.pulse_width(dict["width"].value) - device.pulse_period(dict["period"].value) - device.integration_time(dict["integration"].value) - - t0 = time.time() - device.single_measurement() - while device.operation_completed()== False: - pass - - t1 = time.time() - # get the execution time - elapsed_time = t1 - t0 - device.autoscaling() - - I_i=device.return_data("I") - V_i=device.return_data("V") - R_i = np.divide(V_i,I_i) - - - expected_time = dict["period"].value*dict["pulses"].value - - times = (elapsed_time,expected_time) - values = (V_i,I_i,R_i) - - del device - - return times,values - -def plot_constant(values): - index =[] - for i in range(len(values[0])): - index.append(i+1) - - fig, ax1 = plt.subplots() - color = 'tab:red' - - ax1.set_xlabel("Index(Pulse number)") - ax1.set_ylabel("I(A)",color=color) - ax1.set_yscale('log') - - ax1.plot(index,np.abs(values[1]),color=color,label = "Voltage(V):"+str(min(values[0]))) - ax1.tick_params(axis ='y', labelcolor = color,which = 'both') - - # Adding Twin Axes - ax2 = ax1.twinx() - color = 'tab:green' - - ax2.set_ylabel("R(Ohm)",color = color) - ax2.plot(index,np.abs(values[2]),color=color) - ax2.set_yscale('log') - - ax2.tick_params(axis ='y', labelcolor = color,which = 'both') - - fig.suptitle("Constant Pulse Measurement Results") - ax1.set_title("Voltage:"+str(min(values[0]))+"V") - - plt.show() - -def save_constant(folder,sample_dict,values,times,cons_dict): - filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt" - - file = os.path.join(folder,filename) - - with open(file,"a") as f: - date = str(datetime.today().replace(microsecond=0)) - f.write(f"Constant Pulse Measurement at {date}"+"\n") - f.write(f"period(s):{cons_dict['period'].value}"+"\n") - f.write(f"width(s):{cons_dict['width'].value}"+"\n") - f.write(f"base value(V):{cons_dict['base'].value}"+"\n") - f.write(f"execution time(s):{times[0]}"+"\n") - f.write(f"expected time(s):{times[1]}"+"\n") - f.write(f"number of pulses:{cons_dict['pulses'].value}"+"\n") - f.write(f"current compliance(A):{cons_dict['comp'].value}"+"\n") - f.write(f"constant voltage:{cons_dict['voltage'].value}V"+"\n") - f.write(f"integration time:{cons_dict['integration'].value}"+"\n\n") - - zipped = list(zip(values[0],values[1], values[2])) - df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)']) - - f.write("Results Constant Pulse:\n") - f.write(df.to_string()) - f.write("\n\n\n") - diff --git a/hp4155/memristor pulsed (Version 1.0)/interface.py b/hp4155/memristor pulsed (Version 1.0)/interface.py deleted file mode 100644 index 2a234ed9f0a4f6ad8cee77cc6d2ad945cfb6ae16..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/interface.py +++ /dev/null @@ -1,195 +0,0 @@ -import ipywidgets as widgets - -#sample interface - -style = {'description_width': 'initial'} -def sample(): - # the three naming fields - sample_series= widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'sample series:', - style = {'description_width': 'initial'} - ) - - field = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'Field:', - style = {'description_width': 'initial'}, - ) - - DUT = widgets.Text( - value= '', - placeholder ='Enter text here:', - description = 'DUT:', - style = {'description_width': 'initial'}, - ) - - sample_information = widgets.VBox([sample_series,field,DUT]) - - #choose a new folder button - new_folder = widgets.Button(description='change folder') - sample_widgets = widgets.HBox([sample_information,new_folder]) - - sample_dict = { - 'series':sample_series, - 'field':field, - 'dut':DUT, - 'button':new_folder - } - return sample_widgets,sample_dict - - -def constant_pulse(): - voltage = widgets.BoundedFloatText( - value = 10, - min = -100, - max = 100, - step = 1, - description = 'Constant Voltage(V):', - style=style, - ) - - comp = widgets.BoundedFloatText( - value = 0.1, - min = -0.1, - max = 0.1, - step = 0.01, - description = 'Compliance(A):', - style=style, - ) - - pulses = widgets.IntText( - value = 100, - description = 'Number of Pulses:', - style=style, - ) - period = widgets.BoundedFloatText( - value = 5e-3, - min = 5e-3, - max = 1, - step = 5e-3, - description ='Pulse Period(s):', - style=style, - - ) - width = widgets.BoundedFloatText( - value = 5e-4, - min = 5e-4, - max = 1e-1, - step= 5e-4, - description ='Pulse Width(s):', - style=style, - ) - base = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Base Voltage(V):', - style=style - ) - - integration =widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - style=style - ) - - pulse_parameters = widgets.VBox([pulses,period,width,base]) - smu_parameters = widgets.VBox([voltage,comp,integration]) - - constant_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters]) - constant_pulse_dict = { - 'voltage': voltage, - 'comp':comp, - 'pulses':pulses, - 'period':period, - 'width':width, - 'base':base, - 'integration':integration - } - return constant_pulse_widgets,constant_pulse_dict - -def sweep_pulse(): - start_voltage = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Start Voltage(V):', - style=style, - ) - stop_voltage = widgets.BoundedFloatText( - value = 15, - min = -100, - max = 100, - step = 1, - description = 'Stop Voltage(V):', - style=style, - ) - - comp = widgets.BoundedFloatText( - value = 0.1, - min = -0.1, - max = 0.1, - step = 0.01, - description = 'Compliance(A):', - style=style, - ) - - pulses = widgets.IntText( - value = 100, - description = 'Number of Pulses:', - style=style, - ) - period = widgets.BoundedFloatText( - value = 5e-3, - min = 5e-3, - max = 1, - step = 5e-3, - description ='Pulse Period(s):', - style=style, - - ) - width = widgets.BoundedFloatText( - value = 5e-4, - min = 5e-4, - max = 1e-1, - step= 5e-4, - description ='Pulse Width(s):', - style=style, - ) - base = widgets.BoundedFloatText( - value = 0, - min = -100, - max = 100, - step = 1, - description = 'Base Voltage(V):', - style=style - ) - - integration =widgets.Dropdown( - options=['SHORt', 'MEDium', 'LONG'], - value='MEDium', - description='Integration:', - style=style - ) - - pulse_parameters = widgets.VBox([pulses,period,width,base]) - smu_parameters = widgets.VBox([start_voltage,stop_voltage,comp,integration]) - - sweep_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters]) - sweep_pulse_dict = { - 'start': start_voltage, - 'stop':stop_voltage, - 'comp':comp, - 'pulses':pulses, - 'period':period, - 'width':width, - 'base':base, - 'integration':integration - } - return sweep_pulse_widgets,sweep_pulse_dict diff --git a/hp4155/memristor pulsed (Version 1.0)/pulse.py b/hp4155/memristor pulsed (Version 1.0)/pulse.py deleted file mode 100644 index ceb97d2327453b6b7f2ab745260bc516679088d9..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/pulse.py +++ /dev/null @@ -1,71 +0,0 @@ -from interface import * -from help_new import * - -sample_widgets,sample_dict = sample() -display(sample_widgets) -print() -print() - -cons_widgets,cons_dict = constant_pulse() -sweep_widgets,sweep_dict = sweep_pulse() - -children = [sweep_widgets,cons_widgets] -titles = ["Sweep Pulse","Constant Pulse"] -tab = widgets.Tab() -tab.children = children -tab.titles = titles - -display(tab) - -sweep_button = widgets.Button(description = "Sweep Pulse") -cons_button = widgets.Button(description = "Constant Pulse") - -buttons = widgets.HBox([sweep_button,cons_button]) -output = widgets.Output() -display(buttons,output) - -all_widgets = [sweep_button,cons_button] -add_widgets_to_list(sample_dict,all_widgets) -add_widgets_to_list(cons_dict,all_widgets) -add_widgets_to_list(sweep_dict,all_widgets) - -#choose directory -folder = choose_folder() -def on_sweep_button_clicked(b): - with output: - clear_output(wait = True) - change_state(all_widgets) - check_values(sweep_dict) - - times,values = sweep_meas(sweep_dict) - plot_sweep(values) - save_sweep(folder,sample_dict,values,times,sweep_dict) - change_state(all_widgets) - - -def on_constant_button_clicked(b): - with output: - clear_output(wait = True) - change_state(all_widgets) - check_values(sweep_dict) - - times,values = constant_meas(cons_dict) - plot_constant(values) - save_constant(folder,sample_dict,values,times,cons_dict) - change_state(all_widgets) - -#new_folder clicked -def on_new_folder_button_clicked(b): - global folder - with output: - change_state(all_widgets) #just to be sure - folder = choose_folder()#choose new folder - change_state(all_widgets) #just to be sure - - -#link buttons to widgets -sweep_button.on_click(on_sweep_button_clicked) -cons_button.on_click(on_constant_button_clicked) -sample_dict["button"].on_click(on_new_folder_button_clicked) - - \ No newline at end of file diff --git a/hp4155/memristor pulsed (Version 1.0)/pulse_interface.ipynb b/hp4155/memristor pulsed (Version 1.0)/pulse_interface.ipynb deleted file mode 100644 index f02922c2f28088a8db9ab5bb82a5d8b3acd03a3f..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/pulse_interface.ipynb +++ /dev/null @@ -1,109 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "0ddc31ed-e5cd-47fa-9ce1-39d0b446c9f8", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "429a6850b6b84824a523ef99461535cc", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(VBox(children=(Text(value='', description='sample series:', placeholder='Enter text here:', sty…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6030dc009ecf4be59885f71fb1e68ff6", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Tab(children=(HBox(children=(VBox(children=(BoundedFloatText(value=0.0, description='Start Voltage(V):', min=-…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "108bff59d41f4138bddef3d69fd939ff", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(Button(description='Sweep Pulse', style=ButtonStyle()), Button(description='Constant Pulse', st…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "415c38133e4a415b8be88e11e0979d29", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib widget\n", - "%run pulse.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "454fa518-b7d0-43c8-9247-8d5e5c2aa254", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/hp4155/memristor pulsed (Version 1.0)/sweep_pulse_test.ipynb b/hp4155/memristor pulsed (Version 1.0)/sweep_pulse_test.ipynb deleted file mode 100644 index 68eb350983061f19a990689a2db7fcbb93e1f742..0000000000000000000000000000000000000000 --- a/hp4155/memristor pulsed (Version 1.0)/sweep_pulse_test.ipynb +++ /dev/null @@ -1,96 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from help import *\n", - "\n", - "#set the values here\n", - "start_voltage = 0\n", - "stop_voltage = 15\n", - "comp = 0.1\n", - "\n", - "#number of pulses \n", - "pulses = 100\n", - "\n", - "# pulse period is in interval 5ms to 1s \n", - "pulse_period = 5e-3\n", - "\n", - "#pulse is in interval 0.5ms to 100ms\n", - "pulse_width = 5e-4\n", - "\n", - "# Restriction: pulse period ≥ pulse width + 4 ms\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAApAAAAGwCAYAAAAe8VX7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABueklEQVR4nO3dd3gVddrG8e8p6b0QSOggLVRR6VUQXBXX7u6qoBTLG0UsSBOFVYoKFjSKCBbs3VVXQUWqCoI0ISC9JLT0hLTT5v0jEGAhSiDJnCT357pyJWfOnJlnEji5MzPP72cxDMNAREREROQsWc0uQERERESqFgVIERERESkTBUgRERERKRMFSBEREREpEwVIERERESkTBUgRERERKRMFSBEREREpE7vZBXg7l8vFunXrqF27Nlar8raIiEhV4PF4OHz4MBdeeCF2u+JOedN39C+sW7eOTp06mV2GiIiInINff/2VSy65xOwyqh0FyL9Qu3ZtoPgfYGxsrMnViIiIyNk4ePAgnTp1Kvk9LuVLAfIvHL9sHRsbS7169UyuRkRERMpCt59VDH1XRURERKRMFCBFREREpEwUIEuRmJhIfHw8ffr0MbsUEREREa+iAFmKhIQEkpKSWLJkidmliIiIiHgVBUgRERERKRN1YYuIiIh4uUN5hxi3fBwZhRnYrDbuancXAxsNNK0eBUgRERERL2ez2BjTaQwtI1uSVpDGzV/dTM+6PQn0CTSlHgVIERERES9XK7AWtQJrARAdEE24fzg5jhwFSBEREREzHM47zHNrn2NFygoKXYXUD6nPk92fpHV063LZ/ppDa3hz85skpSeRWpDK832fp1+Dfqet9/7W93lz05ukFaTRIrIF4zqNo22ttqettzl9Mx7DQ52gOuVS37lQE42IiIjUWNlF2Qz+djB2i51X+r3CF3//gtEXjybUN/SM6687sg6nx3na8p1ZO0krSDvjawpcBTSPaM6EzhNKrWPB7gU8s/oZ7m5/Nx8N+ojmEc2564e7SC9IP63eCcsn8HjXx8twlOVPAVJERESqrb59+xIfH09iYuIZn3990+vUCarDkz2epG2tttQLqUe3ut2oH1r/tHU9hocpK6cwZtkY3B53yfLd2bsZtnAYX+788oz76FmvJyM7jqRfw9PPOh43P2k+1ze7nmubXUvT8KY81vUxAmwBfL7j85J1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zapVqwgKCmLgwIEUFhZWcqXl48+ONz8/n7Vr1zJx4kTWrl3LZ599xh9//MHVV19tQqXl469+vsd9/vnnrFy5kri4uEqqTKocQypdp06djISEhJLHbrfbiIuLM6ZNm2ZiVZXjyJEjBmAsXbrU7FIqVG5urtGsWTPj+++/N3r37m3cf//9ZpdUIcaMGWP06NHD7DIqzZVXXmkMHTr0lGXXXXedccstt5hUUcUCjM8//7zkscfjMerUqWM888wzJcuysrIMPz8/4/333zehwvL1v8d7Jr/++qsBGHv37q2coipQacebnJxs1K1b19i0aZPRsGFD47nnnqv02sT76QxkJXM4HPz222/079+/ZJnVaqV///788ssvJlZWObKzswGIjIw0uZKKlZCQwJVXXnnKz7k6+vLLL7n44ou58cYbiYmJ4cILL+S1114zu6wK061bNxYtWsS2bdsA2LBhAytWrOBvf/ubyZVVjt27d3Po0KFT/l2HhYXRuXPnGvH+BcXvYRaLhfDwcLNLqRAej4fbbruN0aNH07p1a7PLES9mN7uAmiYtLQ23203t2rVPWV67dm22bt1qUlWVw+PxMGrUKLp3706bNm3MLqfCfPDBB6xdu5bVq1ebXUqF27VrF6+88goPPvgg48ePZ/Xq1YwcORJfX1+GDBlidnnlbuzYseTk5NCyZUtsNhtut5spU6Zwyy23mF1apTh06BDAGd+/jj9XnRUWFjJmzBj++c9/EhoaanY5FeKpp57CbrczcuRIs0sRL6cAKZUmISGBTZs2sWLFCrNLqTD79+/n/vvv5/vvv8ff39/sciqcx+Ph4osvZurUqQBceOGFbNq0idmzZ1fLAPnRRx/x7rvv8t5779G6dWvWr1/PqFGjiIuLq5bHKyc4nU5uuukmDMPglVdeMbucCvHbb7/xwgsvsHbtWiwWi9nliJfTJexKFh0djc1m4/Dhw6csP3z4MHXq1DGpqop377338vXXX7N48WLq1atndjkV5rfffuPIkSN07NgRu92O3W5n6dKlzJo1C7vdjtvtNrvEchUbG0t8fPwpy1q1asW+fftMqqhijR49mrFjx/KPf/yDtm3bctttt/HAAw8wbdo0s0urFMffo2ra+9fx8Lh3716+//77anv2cfny5Rw5coQGDRqUvH/t3buXhx56iEaNGpldnngZBchK5uvry0UXXcSiRYtKlnk8HhYtWkTXrl1NrKxiGIbBvffey+eff86PP/5I48aNzS6pQvXr14/ff/+d9evXl3xcfPHF3HLLLaxfvx6bzWZ2ieWqe/fupw3LtG3bNho2bGhSRRUrPz8fq/XUt02bzYbH4zGposrVuHFj6tSpc8r7V05ODqtWraqW719wIjxu376dH374gaioKLNLqjC33XYbGzduPOX9Ky4ujtGjR7Nw4UKzyxMvo0vYJnjwwQcZMmQIF198MZ06deL5558nLy+PO+64w+zSyl1CQgLvvfce//nPfwgJCSm5TyosLIyAgACTqyt/ISEhp93fGRQURFRUVLW87/OBBx6gW7duTJ06lZtuuolff/2VOXPmMGfOHLNLqxCDBg1iypQpNGjQgNatW7Nu3TqeffZZhg4danZp5ebo0aPs2LGj5PHu3btZv349kZGRNGjQgFGjRvHkk0/SrFkzGjduzMSJE4mLi+Oaa64xr+jz8GfHGxsbyw033MDatWv5+uuvcbvdJe9hkZGR+Pr6mlX2Ofurn+//BmQfHx/q1KlDixYtKrtU8XZmt4HXVC+++KLRoEEDw9fX1+jUqZOxcuVKs0uqEMAZP9544w2zS6s01XkYH8MwjK+++spo06aN4efnZ7Rs2dKYM2eO2SVVmJycHOP+++83GjRoYPj7+xtNmjQxJkyYYBQVFZldWrlZvHjxGf/PDhkyxDCM4qF8Jk6caNSuXdvw8/Mz+vXrZ/zxxx/mFn0e/ux4d+/eXep72OLFi80u/Zz81c/3f2kYHymNxTCq0RQKIiIiIlLhdA+kiIiIiJSJAqSIiIiIlIkCpIiIiIiUiQKkiIiIiJSJAqSIiIiIlIkCpIiIiIiUiQKkiIiIiJSJAqSIiIiIlIkCpIjUKBMnTuTOO+8s02uSkpKoV68eeXl5FVSViEjVogApIlXeoEGDuPzyy8/43PLly7FYLGzcuJFDhw7xwgsvMGHChDK9Lj4+ni5duvDss89W2DGIiFQlCpAiUuUNGzaM77//nuTk5NOee+ONN7j44otp164dc+fOpVu3bjRs2LBMrwO44447eOWVV3C5XBV7MCIiVYACpIhUeVdddRW1atXizTffPGX50aNH+fjjjxk2bBgAH3zwAYMGDSrz6wAuu+wyMjIyWLp0aYUdh4hIVaEAKSJVnt1uZ/Dgwbz55psYhlGy/OOPP8btdvPPf/6TjIwMkpKSuPjii8v0uuN8fX3p0KEDy5cvr5yDEhHxYgqQIlItDB06lJ07d55yhvCNN97g+uuvJywsjH379mEYBnFxcWV63cni4uLYu3dvxR6IiEgVoAApItVCy5Yt6datG6+//joAO3bsYPny5SWXoQsKCgDw9/cv0+tOFhAQQH5+fkUehohIlaAAKSLVxrBhw/j000/Jzc3ljTfeoGnTpvTu3RuA6OhoADIzM8v0upNlZGRQq1atij0IEZEqQAFSRKqNm266CavVynvvvcf8+fMZOnQoFosFgKZNmxIaGkpSUlKZXneyTZs2ceGFF1b4cYiIeDuLcfKd4yIiVdzw4cP57LPPyMnJYd++fafc83j99dfTuHFjZsyYUabXAezZs4cmTZqwe/fukmGARERqKp2BFJFqZdiwYWRmZjJw4MDTQuDw4cP54IMP8Hg8ZXodwPvvv8+AAQMUHkVE0BlIEalBDMOgc+fOPPDAA6cM0fNXHA4HzZo147333qN79+4VWKGISNWgM5AiUmNYLBbmzJlT5tlk9u3bx/jx4xUeRUSO0RlIERERESkTnYEUERERkTJRgBQRERGRMlGAFBEREZEyUYAUERERkTJRgBQRERGRMlGAFBEREZEyUYAUERERkTJRgBQRERGRMlGAFBEREZEy+X/4qf+10nqMkAAAAABJRU5ErkJggg==", - "text/plain": [ - "<Figure size 640x480 with 2 Axes>" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "times,values=sweep_pulse(start=start_voltage,stop=stop_voltage,comp=comp,points=pulses,width=pulse_width,period=pulse_period)\n", - "plot_sweep(values)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Measurement finished!\n" - ] - } - ], - "source": [ - "create_file(measurement=\"Sweep Pulse\",period=pulse_period,width=pulse_width,pulses=pulses,times=times,values=values,comp=comp)\n", - "print(\"Measurement finished!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}