aboutsummaryrefslogtreecommitdiff
path: root/eitControl.py
diff options
context:
space:
mode:
authorEugeniy E. Mikhailov <evgmik@gmail.com>2021-04-08 23:47:21 -0400
committerEugeniy E. Mikhailov <evgmik@gmail.com>2021-04-08 23:47:21 -0400
commit1fbf0bb826f88f63e84010c629b2f768f8d5e6cd (patch)
treeeb4b19bcc57c30265e0730626162c0fd5899227f /eitControl.py
parent9c09d346a0120241e1a99537b0b58768f95d1843 (diff)
downloadpyExpControl-1fbf0bb826f88f63e84010c629b2f768f8d5e6cd.tar.gz
pyExpControl-1fbf0bb826f88f63e84010c629b2f768f8d5e6cd.zip
renamed file
Diffstat (limited to 'eitControl.py')
-rw-r--r--eitControl.py368
1 files changed, 368 insertions, 0 deletions
diff --git a/eitControl.py b/eitControl.py
new file mode 100644
index 0000000..23c611e
--- /dev/null
+++ b/eitControl.py
@@ -0,0 +1,368 @@
+import tkinter as tk
+from tkinter import *
+from tkinter import ttk
+
+from threading import Thread
+
+import time # For sleep, clock, time and perf_counter
+from datetime import datetime, timedelta
+
+import numpy as np
+import matplotlib.pyplot as plt
+from matplotlib.figure import Figure
+from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
+
+import csv
+
+import ue9qol
+
+class SinGen:
+ def __init__(self, ampl=1, offset=0, phase=0, sweeper=None):
+ self.ampl = ampl
+ self.phase = phase
+ self.sweeper = sweeper
+ self.offset = offset
+
+ def getValue(self, sweeper=None):
+ if sweeper is None and self.sweeper is None:
+ print("Error: generator needs sweeper")
+ return 0
+ if sweeper is None:
+ sweeper = self.sweeper
+ return self.ampl * np.sin( 2*np.pi*sweeper.getRelPos()) + self.offset
+
+class RampGen:
+ # monotonically goes from start to stop, at final point move to start
+ def __init__(self, start=0, stop=0, sweeper=None):
+ self.start = start
+ self.stop = stop
+ self.sweeper = sweeper
+
+ def getValue(self, sweeper=None):
+ if sweeper is None and self.sweeper is None:
+ print("Error: generator needs sweeper")
+ return 0
+ if sweeper is None:
+ sweeper = self.sweeper
+ return self.start + sweeper.getRelPos()*(self.stop - self.start)
+
+class TriangleGen:
+ # monotonically goes from start to stop, once reaches stop goes back to start
+ def __init__(self, start=0, stop=0, sweeper=None):
+ self.start = start
+ self.stop = stop
+ self.sweeper = sweeper
+
+ def getValue(self, sweeper=None):
+ if sweeper is None and self.sweeper is None:
+ print("Error: generator needs sweeper")
+ return 0
+ if sweeper is None:
+ sweeper = self.sweeper
+ if sweeper.getRelPos() < 0.5:
+ return self.start + 2*sweeper.getRelPos()*(self.stop - self.start)
+ return self.start + 2*(1-sweeper.getRelPos())*(self.stop - self.start)
+
+class PulseGen:
+ # monotonically goes from start to stop, once reaches stop goes back to start
+ def __init__(self, ampl=1, sweeper=None):
+ self.ampl = ampl
+ self.sweeper = sweeper
+
+ def getValue(self, sweeper=None):
+ if sweeper is None and self.sweeper is None:
+ print("Error: generator needs sweeper")
+ return 0
+ if sweeper is None:
+ sweeper = self.sweeper
+ if sweeper.getRelPos() < 0.5:
+ return self.ampl
+ return 0
+
+class Sweeper:
+ def __init__(self, widget, Npoints, SweepTime, onTicCallbacks=[]):
+ # walk from start to stop with Npoints
+ # cnt = 1 corresponds to start
+ # cnt = Npoints corresponds to stop
+ # variables like relVar are relative to the start of the period
+ self.cnt = 0 # onTic will increase it right away
+ self.widget = widget
+ self.Npoints = Npoints
+ self.start = 1
+ self.stop = self.Npoints
+ self.SweepTime = SweepTime
+ self.onTicCallbacks = onTicCallbacks
+ self.isOn = False
+ self.isRestart = True
+ self.isTicRunning = False
+
+ self.span = self.stop - self.start
+ self.center = (self.stop + self.start)/2
+ self.dPos = self.span/(self.Npoints-1)
+ self.dT = self.SweepTime/(self.Npoints-1)
+ self.dTmS = round(self.dT*1000) # dT in milliseconds
+
+ def reset(self):
+ self.cnt = 0 # onTic will increase it right away
+ self.isRestart = False
+ self.startTime = datetime.now()
+
+ def onTic(self):
+ start = datetime.now()
+ deadline = start + timedelta(milliseconds=self.dTmS)
+
+ if not self.isOn:
+ self.isTicRunning = False
+ return
+ self.isTicRunning = True
+ if self.isRestart:
+ self.reset()
+ self.isRestart = False
+ self.incr()
+ for cb in self.onTicCallbacks:
+ cb(self)
+ stop = datetime.now()
+ self.isTicRunning = False
+ if stop > deadline:
+ runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000
+ print("Overrun: Callbacks took %s seconds instead of %s" % (runTime, self.dTmS/1000) )
+ self.widget.after(0, self.onTic)
+
+ idleTime_mS = round((deadline-stop).seconds * 1000 + (deadline-stop).microseconds/1000)
+ # print("Will idle for %s" % (idleTime_mS) )
+ self.widget.after(idleTime_mS, self.onTic)
+
+
+ def cmdRestart(self):
+ self.cnt = 0
+ if self.isOn:
+ self.isRestart = True
+ return
+ self.reset()
+ self.isOn = True
+ self.onTic()
+
+ def cmdStart(self):
+ self.isOn = True
+ self.onTic()
+
+ def cmdStop(self):
+ self.isOn = False
+
+ def incr(self):
+ self.cnt += 1
+ self.updPos()
+
+ def updPos(self):
+ self.relCnt = 1 + ((self.cnt-1) % self.Npoints)
+ self.pos = self.start + self.dPos * (self.relCnt - 1)
+ self.relPos = (self.pos-self.start)/self.span
+
+ def getCnt(self):
+ return self.cnt
+
+ def getRelCnt(self):
+ return self.relCnt
+
+ def getPos(self):
+ return self.pos
+
+ def getRelPos(self):
+ return self.relPos
+
+
+class Experiment:
+
+ def __init__(self, root):
+ self.root = root
+ self.tic = 0
+ self.channelsNames2plot={'dac0', 'dac1', 'adc1', 'adc2', 'adc3', 'adc4'}
+ self.xChannelName='dac0' # can be also 'tic' or any of above
+ self.xlabel='Frequency (Hz)'
+ self.lines2plot={}
+ self.clearData()
+ self.guiSetup(root)
+ self.guiSweeper = Sweeper(self.root, Npoints=2, SweepTime=1, onTicCallbacks=[self.updatePlot])
+ self.guiSweeper.cmdStart()
+ self.hardware = {}
+ # self.hardwareSetup()
+ self.sweeper = Sweeper(self.root, Npoints=100, SweepTime=1, onTicCallbacks=[self.onTic])
+ # self.funcGen = SinGen(2, 2, sweeper = self.sweeper)
+ # self.funcGen = RampGen(0, 5, sweeper = self.sweeper)
+ self.funcGen = TriangleGen(0, 5, sweeper = self.sweeper)
+
+
+
+ def hardwareSetup(self):
+ self.hardware['LabJack'] = ue9qol.UE9qol()
+
+ def guiSetup(self, root):
+ self.cntrlPannel=ttk.LabelFrame(root, text='controls')
+ self.cntrlPannel.pack()
+
+ self.bAutoZoom=Button(self.cntrlPannel,text="AutoZoom",command=self.autoZoom,font=('Arial','24'))
+ self.bAutoZoom.pack(side='left')
+
+ self.bRestart=Button(self.cntrlPannel,text="RESTART",command=self.restart,font=('Arial','24'))
+ self.bRestart.pack(side='left')
+
+ self.bStart=Button(self.cntrlPannel,text="START",command=self.start,font=('Arial','24'))
+ self.bStart.pack(side='left')
+
+ self.bStop=Button(self.cntrlPannel,text="STOP",command=self.stop,font=('Arial','24'))
+ self.bStop.pack(side='left')
+
+ self.bSave=Button(self.cntrlPannel,text="SAVE",command=self.saveCmd,font=('Arial','24'))
+ self.bSave.pack(side='left')
+
+ self.bExit=Button(self.cntrlPannel,text="EXIT",command=exit,font=('Arial','24'))
+ self.bExit.pack(side='left')
+
+ self.dataDisplay=ttk.LabelFrame(root, text='data')
+ self.dataDisplay.pack()
+
+ self.fig=plt.figure(figsize=[32, 24])
+
+ self.ax = self.fig.add_subplot(1,1,1)
+ # self.ax.set_xlim([0,20])
+ # self.ax.set_ylim([0,20])
+ # self.ax.plot([i for i in range(10)],[i for i in range(10)])
+ self.line, = self.ax.plot(self.data['tic'], self.data['adc1'], '.')
+
+ self.canvas = FigureCanvasTkAgg(self.fig, master = self.dataDisplay)
+ self.canvas.draw()
+
+ # placing the canvas on the Tkinter window
+ # self.canvas.get_tk_widget().pack()
+
+ # creating the Matplotlib toolbar
+ self.toolbar = NavigationToolbar2Tk(self.canvas, self.dataDisplay)
+ self.toolbar.update()
+
+ # placing the toolbar on the Tkinter window
+ self.canvas.get_tk_widget().pack()
+
+ def clearData(self):
+ self.data = {}
+ self.data['tic'] = []
+ self.data['x'] = []
+ self.data['dac0'] = []
+ self.data['dac1'] = []
+ self.data['adc1'] = []
+ self.data['adc2'] = []
+ self.data['adc3'] = []
+ self.data['adc4'] = []
+
+ def stop(self):
+ self.sweeper.cmdStop()
+
+ def start(self):
+ self.sweeper.cmdStart()
+
+ def restart(self):
+ self.clearData()
+ self.sweeper.cmdRestart()
+
+ def saveCmd(self):
+ csv_file = 'data.csv'
+ data = self.data
+ try:
+ with open(csv_file, 'w') as csvfile:
+ writer = csv.writer(csvfile)
+ writer.writerow(data.keys())
+ writer.writerows(zip(*data.values()))
+ except IOError:
+ print('I/O error')
+
+ def onTic(self,swp=None):
+ start = datetime.now()
+ if swp is None:
+ swp = self.sweeper
+
+ # global tic counter
+ tic = self.sweeper.getCnt()
+ self.data['tic'].append(tic)
+
+ # DAQ
+ # daq0 = self.hardware['LabJack']
+
+ # dac0
+ dac0 = self.funcGen.getValue(swp)
+ # daq0.setOutputCh(0, out0)
+ self.data['dac0'].append(dac0)
+
+ # dac1
+ dac1 = PulseGen(ampl=5, sweeper=swp).getValue()
+ # daq0.setOutputCh(0, dac1)
+ self.data['dac1'].append(dac1)
+
+ # adc1
+ # adc1= daq0.getInputCh(1)
+ adc1 = SinGen(ampl=1, sweeper=swp).getValue()
+ self.data['adc1'].append( adc1 )
+
+ # adc2
+ # adc2= daq0.getInputCh(2)
+ adc2 = SinGen(ampl=2, sweeper=swp).getValue()
+ self.data['adc2'].append( adc2 )
+
+ # adc3
+ # adc3= daq0.getInputCh(3)
+ adc3 = SinGen(ampl=3, sweeper=swp).getValue()
+ self.data['adc3'].append( adc3 )
+
+ # adc4
+ # adc4= daq0.getInputCh(4)
+ adc4 = SinGen(ampl=4, sweeper=swp).getValue()
+ self.data['adc4'].append( adc4 )
+
+ # X-axis (i.e. independent variable)
+ # self.data['x'].append(tic)
+ self.data['x']=self.data[self.xChannelName]
+
+ stop = datetime.now()
+ runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000
+ # print("onTic DAQ took %s seconds." % (runTime) )
+
+ def autoZoom(self):
+ self.ax.cla()
+ x = self.data['x']
+ for name in self.channelsNames2plot:
+ if name not in self.data:
+ continue
+ y = self.data[name]
+ self.lines2plot[name], = self.ax.plot(x, y, '.', label=name)
+ self.ax.legend()
+ plt.xlabel(self.xlabel)
+ self.canvas.draw()
+
+ def updatePlot(self,swp=None):
+ start = datetime.now()
+ # self.ax.cla()
+ # self.line, = self.ax.plot(self.data['tic'], self.data['adc1'], '.')
+ # t = Thread(target=self.canvas.draw)
+ # self.line.set_data([.1, .2, .3], [.1, .2, .3])
+ x = self.data['x']
+ for name in self.channelsNames2plot:
+ if name not in self.data:
+ continue
+ y = self.data[name]
+ if name in self.lines2plot:
+ ln = self.lines2plot[name]
+ ln.set_data(x, y)
+ self.ax.draw_artist(ln)
+ # self.canvas.update()
+ # self.canvas.draw()
+ self.fig.canvas.flush_events()
+ stop = datetime.now()
+ runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000
+ print("Replot took %s seconds to plot %s points." % (runTime, len(self.data['adc1'])) )
+
+
+if __name__ == '__main__':
+ root=Tk()
+
+ experiment=Experiment(root)
+
+ root.mainloop()
+