Initial commit #2

This commit is contained in:
Matthias@Dell 2023-04-07 18:14:15 +02:00
parent 7c5dca87c9
commit 4b28a3b475
10 changed files with 768 additions and 136 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__
.ipynb_checkpoints

View File

@ -1,6 +1,21 @@
from os import listdir, path
def add_zeros(v: int, digits=3):
"""
return v as string, add leading zeros if len(str(v)) < digits
"""
s = str(v)
return '0' * (max(digits - len(s), 0)) + s
def get_next_filename(basename, directory=".", digits=3):
"""
get the next filename (without extenstion).
example:
basename = file
directory has file001, file002, file004
-> return file005
"""
files = listdir(directory)
files.sort()
files.reverse()
@ -11,14 +26,8 @@ def get_next_filename(basename, directory=".", digits=3):
try:
number = int(file.split('.')[0].strip(basename))
if number < lowest_number: continue
lowest_number = number
except ValueError:
continue
return basename + add_zeros(lowest_number)

20
keithley.py Normal file
View File

@ -0,0 +1,20 @@
import pyvisa
def init_keithley(beep_success=True):
rm = pyvisa.ResourceManager('@py')
resources = rm.list_resources()
if len(resources) < 1:
raise Exception("No resources found.")
elif len(resources) == 1:
print(f"Opening Resource {resources[0]}")
keithley = rm.open_resource(resources[0])
if beep_success: keithley.write("beeper.beep(0.5, 1000)")
return keithley
elif len(resources) > 1:
print(f"Resources: {resources}")
instr = int(input("Select an instrument (0-based index)"))
keithley = rm.open_resource(resources[instr])
if beep_success: keithley.write("beeper.beep(0.5, 1000)")
return keithley

70
keithley_interactive.py Normal file
View File

@ -0,0 +1,70 @@
"""
run this before using this library:
ipython -i keithley_interactive.py
"""
import numpy as np
import matplotlib.pyplot as plt
from sys import exit
settings = {
"filename": "measurement",
"interval": 0.01,
"beep": True,
}
# global variable for the instrument returned by pyvisa
k = None
def measure():
global k, settings
pass
def monitor():
"""
Monitor the voltage with matplotlib.
@details:
- Resets the buffers
- Opens a matplotlib window and takes measurements depending on settings["interval"]
- Waits for the user to press a key
You can take the data from the buffer afterwards, using TODO
"""
data = []
for _ in range(1000):
# data.append(tuple(float(v) for v in instr.query("print(smua.measure.v())").strip('\n').split('\t')))
data.append(np.random())
# print(i, data[-1])
# clear_output(wait=True)
plt.plot(data)
plt.show()
sleep(settings["interval"])
pass
def save_csv():
global k, settings
"""
Saves the contents of nvbuffer1 as csv
"""
pass
def help():
print("""
""")
def init():
global k, settings
print("""Interactive Keithley-Shell for TENG measurements.
Version 1.0
---
Enter 'help()' for a list of commands""")
from keithley import init_keithley
try:
k = init_keithley(beep_success=settings["beep"])
except Exception as e:
print(e)
exit()

118
main.py
View File

@ -1,118 +0,0 @@
import pyvisa
import npyscreen as nps
import
class Keithley(nps.NPSAppManaged):
"""Managed Application. Contains the Praktimatika PKTSession, so that all forms and widgets can access it."""
def onStart(self):
self.version = "alpha 1"
self.settings = {
"print_output": True,
"copy_clip": True,
"dec_sep": ",",
"theme": "Default"
}
self.load_settings()
self.themes = {
"Default": nps.Themes.DefaultTheme,
"Colourful": nps.Themes.ColorfulTheme,
"Elegant": nps.Themes.ElegantTheme,
"Transparent-Light Font": nps.Themes.TransparentThemeLightText,
"Transparent-Dark Font": nps.Themes.TransparentThemeDarkText,
}
theme = nps.Themes.DefaultTheme
if self.settings["theme"] in self.themes:
theme = self.themes[self.settings["theme"]]
nps.setTheme(theme)
# stores a selected ... to be accessible for all forms: (name, value)
self.function = ("", None)
self.variable = ("", None)
self.array = ("", None)
self.constant = ("", None)
self.start = self.addForm("MAIN", StartupMenu, name='Praktimatika Startup')
# self.addForm("start", StartupMenu, name='Praktimatika Startup')
self.home = self.addForm("home", tui_home.HomeMenu, name=f"Praktimatika Home (Version {self.version})")
# APP MENUS
self.f_settings = self.addForm("settings", tui_home.Settings, name="Praktimatika Settings")
self.save = self.addForm("save", SaveMenu, name="Save Praktimatika PKTSession")
self.impor = self.addForm("import", tui_import.ImportMenu, name="Import Arrays from a spreadsheet")
# FUNCTION MENUS
self.func = self.addForm("m_fun", tui_user_functions.UserFuncMenu, name="Function Menu")
self.func_calc = self.addForm("m_fun_calc", tui_user_functions.UserFuncCalc2, name="Calculation Menu")
# BUILTIN FUNCTION MENUS
self.weighted_median = self.addForm("weighted_median", tui_functions.WeightedMedian, name="Weighted Median")
self.error_prop = self.addForm("error_prop", tui_user_functions.ErrorPropagation, name="Error Propagation")
self.curve_fit = self.addForm("curve_fit", tui_user_functions.CurveFit, name="Curve Fitting")
# PLOT MENUS
self.plot = self.addForm("plot", tui_plot.AxesMenu, name="Plot Menu") # remove!
self.pl_fig = self.addForm("pl_fig", tui_plot.FigMenu, name="Plot Menu - Figure")
self.pl_ax = self.addForm("pl_ax", tui_plot.AxesMenu, name="Plot Menu - Axis")
self.pl_pl = self.addForm("pl_pl", tui_plot.PlotMenu, name="Plot Menu - Data")
# Add Menus
self.add_fun = self.addForm("add_fun", tui_add.AddFun, name="Add Functions")
self.edit_fun = self.addForm("edit_fun", tui_add.EditFunc, name="Edit Function")
self.add_arr = self.addForm("add_arr", tui_add.AddArr, name="Add Arrays & Values")
self.save_arr = self.addForm("save_arr", tui_functions.SaveVec, name="Save Array")
# TOOLS
self.latex = self.addForm("latex_table", tui_tools.LatexTable, name="Create Latex Table")
@staticmethod
def exit_app():
if nps.notify_yes_no("Are you sure you want to exit?", title='Exit'):
sys.exit()
#
# Settings
#
def load_settings(self):
try:
with open("keithley.conf", "r") as file:
raw_list = file.readlines()
file.close()
for line in raw_list:
if "#" in line: # ignore commented lines
continue
line = line.replace("\n", "")
temp_list = line.split(" = ")
if temp_list[1] == "True":
temp_list[1] = True
elif temp_list[1] == "False":
temp_list[1] = False
self.settings.update({temp_list[0]: temp_list[1]})
except FileNotFoundError:
nps.notify_confirm("Could not load settings from 'keithley.conf'. File not found.")
except IndexError:
nps.notify_confirm("Could not load settings from 'keithley.conf'. Invalid file structure")
def save_settings(self):
with open("praktimatika.conf", "w") as file:
text = "# Praktimatika Config File. \n" \
"# Content here will be overwritten when the settings are saved.\n"
for key, val in self.settings.items():
text += f"{key} = {val}\n"
file.write(text)
@staticmethod
def show_error(message, exception: BaseException):
"""
Shows an Error Message in an nps.notify_confirm Form
:param message: string, message
:param exception: Exception
:return:
"""
nps.notify_confirm(f"{message}:\n{exception}\nin file {exception.__traceback__.tb_frame.f_code.co_filename}\n"
f"in line {exception.__traceback__.tb_lineno}")
if __name__ == '__main__':
TestApp = Keithley().run()

View File

@ -7,42 +7,117 @@ display.clear()
display.settext('starting')
smua.reset()
smua.measure.autorangev = smua.AUTORANGE_ON
smua.measure.autozero = smua.AUTOZERO_ONCE
smua.source.output = smua.OUTPUT_OFF
-- max 20 V expected
smua.measure.rangev = 20
"""
script_dir = ""
script_dir = "scripts/"
scripts = {
"buffer_reset": "scripts/buffer_reset.lua",
"buffer_reset": "buffer_reset.lua",
"smua_reset": "smua_reset.lua",
}
def run_lua(instr, script_path):
def run_lua(instr, script_path, verbose=False):
with open(script_dir + script_path, "r") as file:
script = file.read()
if verbose: print(f"Running script: {script_dir + script_path}")
instr.write(script)
def measureV(count=100, interval=0.05)
def measure_V(instr, count=100, interval=0.05):
"""
"""
data = []
for i in range(1000):
data.append(tuple(float(v) for v in keithley.query("print(smua.measure.v())").strip('\n').split('\t')))
for _ in range(1000):
data.append(tuple(float(v) for v in instr.query("print(smua.measure.v())").strip('\n').split('\t')))
# print(i, data[-1])
# clear_output(wait=True)
plt.plot(data)
plt.show()
sleep(0.05)
def reset(instr):
run_lua(instr, scripts["smua_reset"], verbose=verbose)
run_lua(instr, scripts["buffer_reset"], verbose=verbose)
def measure_count(instr, V=True, I=True, count=100, interval=0.05, beep_done=True, verbose=True):
"""
take n measurements at dt interval
"""
reset(instr)
f_meas = None
if V and I:
f_meas = "smua.measure.iv(smua.nvbuffer1, smua.nvbuffer2)"
elif V:
f_meas = "smua.measure.v(smua.nvbuffer1)"
elif I:
f_meas = "smua.measure.i(smua.nvbuffer1)"
else:
print("I and/or V needs to be set to True")
return
instr.write(f"smua.measure.count = {count}")
instr.write(f"smua.measure.interval = {interval}")
instr.write(f"smua.source.output = smua.OUTPUT_ON")
instr.write(f_meas)
instr.write(f"smua.source.output = smua.OUTPUT_OFF")
if beep_done:
instr.write("beeper.beep(0.3, 1000)")
def collect_buffer(instr, buffer_nr=1):
"""
get the buffer in double precision binary format as np.array
get the buffer as 2D - np.array
i - ith reading
0: timestamps
1: readings
"""
if buffer_nr == 2: buffername = "smua.nvbuffer2"
else: buffername = "smua.nvbuffer1"
instr.write("format.data = format.DREAL\nformat.byteorder = format.LITTLEENDIAN")
buffer = instr.query_ascii_values(f"printbuffer(1, {buffername}.n, {buffername})", datatype='d', container=np.array)
# instr.write("format.data = format.DREAL\nformat.byteorder = format.LITTLEENDIAN")
# buffer = instr.query_binary_values(f"printbuffer(1, {buffername}.n, {buffername})", datatype='d', container=np.array)
instr.write("format.data = format.ASCII\nformat.asciiprecision = 7")
timestamps = instr.query_ascii_values(f"printbuffer(1, {buffername}.n, {buffername}.timestamps)", container=np.array)
readings = instr.query_ascii_values(f"printbuffer(1, {buffername}.n, {buffername}.readings)", container=np.array)
print(f"readings: {readings}, \ntimestamps: {timestamps}")
buffer = np.vstack((timestamps, readings)).T
return buffer
def event_test_TODO():
# Type of event we want to be notified about
event_type = pyvisa.constants.EventType.service_request
# Mechanism by which we want to be notified
event_mech = pyvisa.constants.EventMechanism.queue
keithley.enable_event(event_type, event_mech)
# Instrument specific code to enable service request
# (for example on operation complete OPC)
keithley.write("*SRE 1")
keithley.write("INIT")
with open("script.lua", "r") as file:
script = file.read()
# for line in script.split('\n'):
# input(line)
# keithley.write(line)
keithley.write(script)
# Wait for the event to occur
response = keithley.wait_on_event(event_type, 1000)
assert response.event.event_type == event_type
assert response.timed_out == False
instr.disable_event(event_type, event_mech)
keithley.query_ascii_values("printbuffer(1, 10, smua.nvbuffer1)", 6)
print(voltages)

498
measurement.ipynb Normal file

File diff suppressed because one or more lines are too long

66
readings.txt Normal file
View File

@ -0,0 +1,66 @@
readings: [ 4.974127e-10 -1.418591e-12 -1.573563e-12 -1.728535e-12 -1.704693e-12
-1.847744e-12 -1.931190e-12 -1.788139e-12 -1.871586e-12 -2.169609e-12
-2.074242e-12 -1.895428e-12 -1.895428e-12 -1.776218e-12 -1.990795e-12
-1.788139e-12 -1.811981e-12 -1.657009e-12 -1.573563e-12 -2.396107e-12
-2.515316e-12 -2.765656e-12 -2.825260e-12 -3.147125e-12 -2.300739e-12
-2.825260e-12 -3.278255e-12 -5.257130e-12 -6.818771e-12 -8.916855e-12
-7.712841e-12 6.437302e-12 -1.142025e-11 -1.206398e-11 -4.649043e-10
-3.427613e-09 -2.460408e-09 -2.340376e-09 -1.306653e-10 1.496077e-11
2.933741e-11 1.953280e-09 8.579970e-10 9.226799e-12 -1.095533e-11
-2.508163e-11 -2.776039e-09 -8.686423e-09 4.935264e-12 1.246929e-11
3.225744e-09 2.814472e-09 1.877034e-09 2.229273e-09 1.713574e-09
8.355618e-10 -4.332781e-10 5.896091e-11 5.762577e-11 8.129537e-09
4.044378e-09 1.771629e-09 7.849216e-10 4.098892e-10 3.390551e-10
2.956390e-10 3.033876e-10 1.716256e-10 1.463890e-11 -5.078316e-12
-6.949902e-12 -8.106232e-12 -6.473065e-12 -4.506111e-12 4.919767e-11
3.052297e-08 1.161162e-08 -9.892106e-09 -3.613818e-09 -5.004287e-09
-2.015829e-11 -4.183054e-11 -1.810908e-10 -2.042532e-10 -3.516316e-10
5.099773e-11 1.921976e-08 -1.256589e-08 -4.242897e-10 -1.358986e-12
-3.445148e-12 -3.838539e-12 -4.184246e-12 -7.402897e-12 -2.840877e-10
-2.872229e-10 -2.730966e-10 -1.134396e-10 -4.376173e-11 -3.576279e-14],
timestamps: [0. 0.05 0.1 0.15 0.2 0.25 0.3 0.35
0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75
0.8 0.85 0.9 0.95 1. 1.05 1.1 1.15
1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55
1.6 1.690891 1.710923 1.75 1.8 1.85 1.9 1.95
2. 2.05 2.1 2.15 2.2 2.25 2.3 2.35
2.420332 2.45 2.5 2.55 2.6 2.65 2.7 2.75
2.820553 2.890843 2.910875 2.95 3. 3.05 3.1 3.15
3.2 3.25 3.3 3.35 3.4 3.45 3.5 3.55
3.6 3.65 3.7 3.75 3.8 3.85 3.9 3.95
4. 4.05 4.1 4.15 4.2 4.25 4.3 4.35
4.4 4.45 4.5 4.55 4.6 4.65 4.7 4.75
4.8 4.85 4.9 4.95 ]
readings: [-1.556139e-01 -1.663574e-01 -1.621783e-01 -1.685456e-01 -1.634915e-01
-1.711711e-01 -1.661170e-01 -1.711710e-01 -1.665548e-01 -1.742343e-01
-1.669925e-01 -1.724839e-01 -1.674302e-01 -1.733590e-01 -1.669922e-01
-1.729215e-01 -1.687431e-01 -1.772979e-01 -1.770578e-01 -1.829874e-01
-1.674301e-01 -1.606676e-01 -1.437982e-01 -1.322218e-01 -1.140394e-01
-1.151545e-01 -9.478331e-02 -6.351433e-02 -2.557993e-04 6.995752e-02
1.734703e-01 1.487249e-01 1.095815e-01 1.079751e+01 1.263197e+01
1.362582e+01 1.300827e+01 1.259473e+01 1.025542e+01 3.997076e+00
-9.946833e+00 -1.482129e+01 -1.399363e+01 -1.326294e+01 -1.132879e+01
-5.142632e+00 1.148345e+01 1.378293e+01 -3.400979e-01 -9.995720e-01
-1.749203e+00 -1.385303e+00 -1.056456e+00 -1.082226e+00 -8.675261e-01
-7.083023e-01 8.988955e-02 4.139638e+00 -6.590693e+00 -1.697538e+01
-1.556470e+01 -1.461764e+01 -1.392116e+01 -1.365366e+01 -1.351573e+01
-1.343544e+01 -1.343307e+01 -1.329787e+01 -1.297363e+01 -1.218130e+01
-1.076091e+01 -8.683739e+00 -6.708155e+00 -5.400786e+00 -7.245429e+00
-1.917886e+01 -1.436163e+01 1.541487e+01 1.495236e+01 1.484173e+01
1.273334e+01 1.251023e+01 1.266481e+01 1.274583e+01 1.290255e+01
1.080429e+01 -1.518563e+01 1.614336e+01 1.317309e+01 1.189001e+01
1.109593e+01 1.094126e+01 1.113482e+01 1.139770e+01 1.268495e+01
1.251639e+01 1.248731e+01 1.230242e+01 1.220341e+01 1.181950e+01],
timestamps: [0. 0.05 0.1 0.15 0.2 0.25 0.3 0.35
0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75
0.8 0.85 0.9 0.95 1. 1.05 1.1 1.15
1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55
1.6 1.690891 1.710923 1.75 1.8 1.85 1.9 1.95
2. 2.05 2.1 2.15 2.2 2.25 2.3 2.35
2.420332 2.45 2.5 2.55 2.6 2.65 2.7 2.75
2.820553 2.890843 2.910875 2.95 3. 3.05 3.1 3.15
3.2 3.25 3.3 3.35 3.4 3.45 3.5 3.55
3.6 3.65 3.7 3.75 3.8 3.85 3.9 3.95
4. 4.05 4.1 4.15 4.2 4.25 4.3 4.35
4.4 4.45 4.5 4.55 4.6 4.65 4.7 4.75
4.8 4.85 4.9 4.95 ]

View File

@ -1,3 +1,4 @@
-- reset both buffers and set to append mode
smua.nvbuffer1.clear()
smua.nvbuffer1.fillmode = smua.FILL_ONCE
smua.nvbuffer1.appendmode = 1
@ -7,4 +8,3 @@ smua.nvbuffer2.clear()
smua.nvbuffer2.fillmode = smua.FILL_ONCE
smua.nvbuffer2.appendmode = 1
smua.nvbuffer2.collecttimestamps = 1

10
scripts/smua_reset.lua Normal file
View File

@ -0,0 +1,10 @@
-- reset smua
smua.reset()
smua.measure.autorangev = smua.AUTORANGE_ON
smua.measure.autozero = smua.AUTOZERO_ONCE
-- set output to 0A DC
smua.source.output = smua.OUTPUT_OFF
smua.source.func = smua.OUTPUT_DCAMPS
smua.source.leveli = smua.OUTPUT_OFF
-- smua.measure.rangev = 20