Skip to content
Snippets Groups Projects
Commit 2e102b0c authored by Alexandros Asonitis's avatar Alexandros Asonitis
Browse files

clean up release branch

parent 5ea8648e
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 6650 deletions
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)
%% Cell type:code id:51b012d0-95b0-41c2-81bb-2205f3c53be2 tags:
``` python
%run double_gate_ADU.py
```
%% Output
%% Cell type:code id:329c0c76-4194-4805-ab3f-fe9f55f79eea tags:
``` python
```
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
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
This diff is collapsed.
"""
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
### 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)
%% Cell type:code id:df99f5a2-80af-4892-8633-33177239e444 tags:
``` python
%run memristor.py
```
%% Output
%% Cell type:code id:9613a247-7ebb-46b8-ae8f-5d4ba21e5d43 tags:
``` python
```
"""
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
### 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)
%% Cell type:code id:df99f5a2-80af-4892-8633-33177239e444 tags:
``` python
%run memristor.py
```
%% Output
%% Cell type:code id:076a9132-edc2-4ae5-8a7f-c8a179473952 tags:
``` python
```
"""
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
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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment