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

Beta Version of Custom SMU for Users

parent 4cdc5434
No related branches found
No related tags found
No related merge requests found
%% Cell type:code id:3f5d53eb-4723-4e65-8d58-22888bcc84b1 tags:
``` python
%run main.py
```
%% Output
File ~\labcode\hp4155\Custom_SMU\main.py:27
ini = widgets.Button(description = 'Import from ini. (Coming Soon)',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto')
^
SyntaxError: '(' was never closed
%% Cell type:code id:b4134f36-9202-45f5-ad20-b71dfc315edd tags:
``` python
```
import tkinter as tk
import tkinter.messagebox
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from datetime import datetime
from tkinter import filedialog
# Check the functionalities of smus VAR1,VAR2 and VARD
def check_sweep_func(smus:list,func:str):
for i, smu in enumerate(smus):
if smu["func"] == func and smu["disabled"]== False:
return True
return False
# Check if there is a pulsed smu for sweep smu
def check_sweep_pulse(smus:list):
for smu in smus:
if "PULSE" in smu["mode"] and smu["disabled"]== False:
return True
return False
# Check if there any constant smus and return their numbers
def check_sweep_cons(smus:list):
cons_smu_numbers = []
for i,smu in enumerate(smus):
if (smu['func']=='CONS' and smu['mode']!='COMM') and smu['disabled']== False: # Non Grounded SMUs
cons_smu_numbers.append(i+1) # for the actual number of smus
return cons_smu_numbers
# Setup the axes in tool
def setup_axes(axes_info:list,device):
axes_plot = ['X','Y1','Y2']
for ax_plot,ax_info in zip(axes_plot,axes_info):
if ax_plot == 'Y2' and ax_info['name'] == "": # Y2 axis can be empty
pass
else:
device.display_variable(ax_plot,ax_info['name'])
device.axis_scale(ax_plot,ax_info['scale'])
device.display_variable_min_max(ax_plot,'MIN',ax_info['min'])
device.display_variable_min_max(ax_plot,'MAX',ax_info['max'])
# Setup the variables to be saved
def save_variables(axes,variables,device):
# condition number one: the plotted variables need to be saved in the file
# Sticter policy with exceptions
# Retrieve the names of the variables
variable_names =[]
for variable in variables:
variable_names.append(variable['name'])
# Retrieve the axes names (variable)
axes_names=[]
for i,ax in enumerate(axes):
if i != 2 and ax['name']!="": # Y2 axis can be left empty
axes_names.append(ax['name'])
# Now Check if axes names are in the variable names
for ax_name in axes_names:
if ax_name not in variable_names:
raise Exception("Plotted Variables should be saved!")
# Send the command to tool
device.variables_to_save(variable_names)
# Now this should work
def error_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.showerror(message=information)
root.destroy()
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()
# We plot results: but we will play with the axes!
def plot_results(values,device):
# convert scale from tool to matplotlib
def get_scale(scale):
if scale == 'LIN':
scale = 'linear'
else:
scale = 'log'
return scale
# Get the names of the plotted variables
x_var = device.get_axis_variable('X')
y1_var = device.get_axis_variable('Y1')
y2_var = device.get_axis_variable('Y2')
# Get the scales of the plotted variables
x_scale = device.get_axis_scale('X')
x_scale = get_scale(x_scale)
y1_scale = device.get_axis_scale('Y1')
y1_scale = get_scale(y1_scale)
y2_scale = device.get_axis_scale('Y2')
y2_scale = get_scale(y2_scale)
# Find the values that will be plotted
for key, results in values.items():
if x_var in key: # check if the substring is contained
x_values = results.copy() # This is a list
x_label = key
elif y1_var in key:
y1_values = results.copy()
y1_label = key
elif y2_var in key and y2_var !="":
y2_values = results.copy()
y2_label = key
# Now lets do the plot
fig,ax1 = plt.subplots()
ax1.set_xlabel(x_label)
ax1.set_ylabel(y1_label,color = 'tab:red') # Yellow Color
ax1.set_xscale(x_scale)
ax1.set_yscale(y1_scale)
ax1.plot(x_values,y1_values,color='tab:red')
ax1.tick_params(axis ='y', labelcolor ='tab:red',which='both')
if y2_var!= "":
# Adding Twin Axes # Blue color
ax2 = ax1.twinx()
ax2.set_ylabel(y2_label,color = 'tab:green')
ax2.set_yscale(y2_scale)
ax2.plot(x_values,y2_values,color='tab:green')
ax2.tick_params(axis ='y', labelcolor ='tab:green',which='both')
display(fig)
# The checks will be corrected later
def create_file(filename):
root = tk.Tk()
root.withdraw()
root.lift() #show window above all other applications
root.attributes("-topmost", True)#window stays above all other applications
file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =filename)
#check if the file path is correct(.txt)
while file.endswith(".txt") == False:
#open again filedialog with error message box
tk.messagebox.showerror(message='invalid filename!')
file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =filename)
root.destroy()
return file
# sampling help functions
def check_cons_smu_samp(smus:list):
cons_smu_numbers = []
for i,smu in enumerate(smus):
if smu['mode']!='COMM' and smu["disabled"]==False: # Non Grounded active SMUs
cons_smu_numbers.append(i+1) # for the actual number of smus
return cons_smu_numbers
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
answer=tk.messagebox.askyesno(message='Do you want to cancel the ini file load?')
if answer == True:
raise Exception("Ini File Operation aborted!")
else:
file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title = "Select ini file")
root.destroy()
return file
# Get measurement mode from ini file
def get_mode(sections):
for section in sections:
if "MEASUREMENT MODE:" in section:
mode = section.split(":")[1]
return mode
raise Exception("Meaurement mode not found ini file!")
def get_integration(sections):
for section in sections:
if "INTEGRATION TIME:" in section:
integration = section.split(":")[1]
return integration
raise Exception("Integration Time not found ini file!")
\ No newline at end of file
import ipywidgets as widgets
from IPython.display import clear_output
from ipywidgets import GridspecLayout,Layout
def create_dict(**widgets):
return widgets
# The smu configuration page
def page_1():
first_page = GridspecLayout(5,6)
#first column
first_page[0,0]= widgets.Label("UNIT",layout=Layout(height='auto', width='auto'))
first_page[1,0] = widgets.Label('SMU1',layout=Layout(height='auto', width='auto'))
first_page[2,0] = widgets.Label('SMU2',layout=Layout(height='auto', width='auto'))
first_page[3,0] = widgets.Label('SMU3',layout=Layout(height='auto', width='auto'))
first_page[4,0] = widgets.Label('SMU4',layout=Layout(height='auto', width='auto'))
#second column voltage name
first_page[0,1]= widgets.Label('VNAME',layout=Layout(height='auto', width='auto'))
for i in range(1,5):
first_page[i,1]= widgets.Text(layout=Layout(height='auto', width='auto'), value =f'V{i}' )
#Third column Iname
first_page[0,2]= widgets.Label('INAME',layout=Layout(height='auto', width='auto'))
for i in range(1,5):
first_page[i,2]= widgets.Text(layout=Layout(height='auto', width='auto'),value = f'I{i}')
#Fourth column mode
options_mode = ['V','I','COMM','VPULSE','IPULSE']
first_page[0,3]= widgets.Label('MODE',layout=Layout(height='auto', width='auto'))
first_page[1,3]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_mode,value = 'COMM') #smu1
first_page[2,3]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_mode,value = 'I') #smu2
first_page[3,3]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_mode,value = 'V') #smu3
first_page[4,3]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_mode,value = 'V') #smu4
#Fifth column function
options_function= ['VAR1','VAR2','VARD','CONS']
first_page[0,4]= widgets.Label('FUNC',layout=Layout(height='auto', width='auto'))
first_page[1,4]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_function,value ='CONS') #smu1
first_page[2,4]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_function,value ='VAR2') #smu2
first_page[3,4]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_function,value ='VAR1') #smu3
first_page[4,4]= widgets.Dropdown(layout=Layout(height='auto', width='auto'),options = options_function,value ='CONS') #smu4
# Sixth column ask if smus are disabled
first_page[0,5] = widgets.Label("DISABLE")
for i in range(1,5):
first_page[i,5]= widgets.Checkbox(layout=Layout(height='auto', width='auto'),value = False,indent = False)
return first_page
#page 2 the user function page
def page_2():
second_page = GridspecLayout(7,3)
# first line (descriptions)
second_page[0,0]= widgets.Label('NAME',layout=Layout(height='auto', width='auto'))
second_page[0,1]= widgets.Label('UNIT',layout=Layout(height='auto', width='auto'))
second_page[0,2]= widgets.Label('DEFINITION',layout=Layout(height='auto', width='auto'))
# Iterate through the lines and columns for text boxes
for i in range(1,7):
for j in range(3):
second_page[i,j] = widgets.Text(layout=Layout(height='auto', width='auto'))
return second_page
#parameters setting
def page_3():
third_page = GridspecLayout(24,5)
# First Line
third_page[0,0]=widgets.Dropdown(options = ['SWEEP','SAMPLING','STRESS'], value = 'SWEEP',description ="MEASUREMENT MODE",layout=Layout(height='auto', width='auto'),style = {'description_width': 'initial'})
third_page[0,1] = widgets.Dropdown(options = ['SHORt','MEDium','LONG'], value = 'MEDium',description ="INTEGRATION TIME",layout=Layout(height='auto', width='auto'),style = {'description_width': 'initial'})
# Second Line
third_page[2,:] = widgets.Label("SWEEP SETUP",layout=Layout(height='auto', width='auto'))
# Third Line
third_page[3,0] = widgets.Label("VAR1",layout=Layout(height='auto', width='auto'))
third_page[3,1] = widgets.Label("VAR2",layout=Layout(height='auto', width='auto'))
third_page[3,2] = widgets.Label("VAR1'",layout=Layout(height='auto', width='auto'))
third_page[3,3] = widgets.Label("SMU PULSE",layout=Layout(height='auto', width='auto'))
# Fourth Line
third_page[4,0] = widgets.FloatText(0, description = 'START',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[4,1] = widgets.FloatText(0, description = 'START',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[4,2] = widgets.FloatText(description = 'OFFSET',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[4,3] = widgets.FloatText(description = 'PERIOD',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
# Fifth line
third_page[5,0] = widgets.FloatText(5,description = 'STOP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[5,1] = widgets.FloatText(500e-6, description = 'STOP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[5,2] = widgets.FloatText(description = 'RATIO',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[5,3] = widgets.FloatText(description = 'WIDTH',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
# Sixth Line
third_page[6,0] = widgets.FloatText(0.1,description = 'STEP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[6,1] = widgets.FloatText(6,description = 'NO OF STEPS',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
#skip 5,2
third_page[6,3] = widgets.FloatText(5,description = 'BASE',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
#Seventh Line
third_page[7,0] = widgets.FloatText(100e-3,description = 'COMPLIANCE',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[7,1] = widgets.FloatText(5,description = 'COMPLIANCE',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[7,2] = widgets.FloatText(description = 'COMPLIANCE',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
#no more pulse
# Eighth Line
third_page[8,0] = widgets.FloatText(0,description = 'POWER COMP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[8,1] = widgets.FloatText(0,description = 'POWER COMP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[8,2] = widgets.FloatText(description = 'POWER COMP',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[9,0] = widgets.Checkbox(False,description = 'HYSTERISIS',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
## Sampling Parameters
third_page[11,:] = widgets.Label("SAMPLING OR STRESS PARAMETERS")
third_page[12,0] = widgets.Dropdown(options=["LINear","L10","L25","L50","THINnedout"], value = 'LINear',description = 'MODE',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[13,0] = widgets.FloatText(2e-3,description = "INITIAL INTERVAL", style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[14,0] = widgets.IntText(1001,description = "NO. OF SAMPLES", style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[15,0] = widgets.FloatText(0,description = "DURATION", style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[16,0] = widgets.FloatText(0,description = "HOLD TIME", style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
third_page[17,0] = widgets.Checkbox(True,description = "FILTER", style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
# Set constant SMU for all measurement in case they are not disabled
third_page[19,:] = widgets.Label("CONSTANT",layout=Layout(height='auto', width='auto'))
third_page[20,0] = widgets.Label("UNIT",layout=Layout(height='auto', width='auto'))
third_page[20,1] = widgets.Label("SMU1",layout=Layout(height='auto', width='auto'))
third_page[20,2] = widgets.Label("SMU2",layout=Layout(height='auto', width='auto'))
third_page[20,3] = widgets.Label("SMU3",layout=Layout(height='auto', width='auto'))
third_page[20,4] = widgets.Label("SMU4",layout=Layout(height='auto', width='auto'))
third_page[21,0] = widgets.Label("SOURCE",layout=Layout(height='auto', width='auto'))
third_page[22,0] = widgets.Label("COMPLIANCE",layout=Layout(height='auto', width='auto'))
for i in range(21,23):
for j in range(1,5):
third_page[i,j] = widgets.FloatText(layout=Layout(height='auto', width='auto'))
return third_page
#display variables
def page_4():
fourth_page = GridspecLayout(5,4)
#first line headers
fourth_page[0,1]= widgets.Label('X',layout=Layout(height='auto', width='auto'))
fourth_page[0,2]= widgets.Label('Y1',layout=Layout(height='auto', width='auto'))
fourth_page[0,3]= widgets.Label('Y2',layout=Layout(height='auto', width='auto'))
#first column
fourth_page[1,0] = widgets.Label('NAME',layout=Layout(height='auto', width='auto'))
fourth_page[2,0] = widgets.Label('SCALE',layout=Layout(height='auto', width='auto'))
fourth_page[3,0] = widgets.Label('MIN',layout=Layout(height='auto', width='auto'))
fourth_page[4,0] = widgets.Label('MAX',layout=Layout(height='auto', width='auto'))
#iterate through the second line (NAME)
fourth_page[1,1]=widgets.Text(layout=Layout(height='auto', width='auto'),value = 'V3')
fourth_page[1,2]=widgets.Text(layout=Layout(height='auto', width='auto'),value = 'I3')
fourth_page[1,3]=widgets.Text(layout=Layout(height='auto', width='auto'))
#Iterate through the third line (scale)
options_scale = ['LIN','LOG']
for j in range(1,4):
fourth_page[2,j] = widgets.Dropdown(value = 'LIN',options = options_scale, layout=Layout(height='auto', width='auto'),)
#iterate throuh the last 2 lines(min-max)
for j in range(1,4):
fourth_page[3,j] = widgets.FloatText(value = 0) #min
fourth_page[4,1]=widgets.FloatText(value = 1) #max X-axis
fourth_page[4,2]=widgets.FloatText(value = 0.1) #max Y1-axis
fourth_page[4,3]=widgets.FloatText(value = 0) #max Y2-axis
return fourth_page
def page_5():
fifth_page = GridspecLayout(14,2)
fifth_page[0,0] = widgets.Text(description = 'MEASUREMENT NAME',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
fifth_page[1,0] = widgets.Text(description ='PROCESSING NR.',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
fifth_page[2,0] = widgets.Text(description ='SAMPLE SERIES',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
fifth_page[3,0] = widgets.Text(description ='FIELD',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
fifth_page[4,0] = widgets.Text(description ='DUT',style = {'description_width': 'initial'},layout=Layout(height='auto', width='auto'))
fifth_page[5,0] = widgets.Label("VARIABLES TO SAVE",layout=Layout(height='auto', width='auto'))
fifth_page[5,1] = widgets.Label("UNIT",layout=Layout(height='auto', width='auto'))
for i in range(8):
for j in range(2):
fifth_page[6+i,j] = widgets.Text(layout=Layout(height='auto', width='auto'))
return fifth_page
#change state off the grid
def change_state(*grids):
for grid in grids:
for i in range(grid.n_rows):
for j in range(grid.n_columns):
try:
grid[i,j].disabled = not grid[i,j].disabled
except:
pass
This diff is collapsed.
...@@ -22,17 +22,38 @@ class HP4155a(object): ...@@ -22,17 +22,38 @@ class HP4155a(object):
command = f":PAGE:STR:SMU{number}:MODE {smu['mode']};FUNC {smu['func']};NAME {repr(smu['name'])}" command = f":PAGE:STR:SMU{number}:MODE {smu['mode']};FUNC {smu['func']};NAME {repr(smu['name'])}"
self.inst.write(command) self.inst.write(command)
def setup_smu_stress(self,number:int,smu:dict):
command =f":PAGE:STR:SET:CONS:SMU{number} {smu['value']}" command =f":PAGE:STR:SET:CONS:SMU{number} {smu['value']}"
self.inst.write(command) self.inst.write(command)
command = f":PAGE:STR:SET:CONS:SMU{number}:COMP {smu['comp']}" command = f":PAGE:STR:SET:CONS:SMU{number}:COMP {smu['comp']}"
self.inst.write(command) self.inst.write(command)
def smu_stress_disable(self,number:int):
command = f":PAGE:STR:SMU{number}:DIS"
self.inst.write(command)
def stress_filter(self,status:int):
command = f":PAGE:STR:SET:FILT {status}"
self.inst.write(command)
def stress_hold_time(self,time:float):
command = f":PAGE:STR:SET:HTIM {time}"
self.inst.write(command)
#set the stess time in seconds #set the stess time in seconds
def stress_time(self,time:float): def stress_time(self,time:float):
command = f":PAGE:STR:SET:DUR {time}" command = f":PAGE:STR:SET:DUR {time}"
self.inst.write(command) self.inst.write(command)
def stress_disable_not_smu(self):
self.inst.write(":PAGE:STR:VSU1:DIS")
self.inst.write(":PAGE:STR:VSU2:DIS")
def stress_smu_disable(self,number:int):
command = f":PAGE:STR:SMU{number}:DIS"
self.inst.write(command)
#start stress operation #start stress operation
def start_stress(self): def start_stress(self):
self.inst.write(":PAGE:SCON:STR") self.inst.write(":PAGE:SCON:STR")
...@@ -60,6 +81,16 @@ class HP4155a(object): ...@@ -60,6 +81,16 @@ class HP4155a(object):
while code != 0: while code != 0:
code,_ = self.error() code,_ = self.error()
def list_all_errors(self):
counter = 0
error_code, error_message = self.error()
message = f"{error_code},{error_message}"+"\n"
while error_code!=0:
counter = counter + 1
error_code, error_message = self.error()
message = message + f"{error_code},{error_message}"+"\n"
return counter, message
def operation_completed(self): def operation_completed(self):
text = self.inst.query('*OPC?') text = self.inst.query('*OPC?')
text = text.replace('\n','') text = text.replace('\n','')
...@@ -189,6 +220,11 @@ class HP4155a(object): ...@@ -189,6 +220,11 @@ class HP4155a(object):
var_name = self.inst.query(command) var_name = self.inst.query(command)
return var_name.rstrip() #remove \n return var_name.rstrip() #remove \n
def get_axis_scale(self,axis):
command = f":PAGE:DISP:GRAP:{axis}:SCAL?"
scale = self.inst.query(command)
return scale.rstrip()
def autoscaling(self): def autoscaling(self):
self.inst.write(":PAGE:GLIS:SCAL:AUTO ONCE") self.inst.write(":PAGE:GLIS:SCAL:AUTO ONCE")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment