diff options
-rw-r--r-- | eitControl.py | 422 | ||||
-rw-r--r-- | example_config.ini | 40 | ||||
-rw-r--r-- | funcGenerator.py | 274 | ||||
-rw-r--r-- | labjackStreamTest.py | 167 | ||||
-rw-r--r-- | rfGen.py | 50 | ||||
-rw-r--r-- | test_rfGenLMX2487.py | 20 | ||||
-rwxr-xr-x | test_serial.py | 47 | ||||
-rwxr-xr-x | test_ue9.py | 10 | ||||
-rw-r--r-- | ue9qol.py | 76 |
9 files changed, 0 insertions, 1106 deletions
diff --git a/eitControl.py b/eitControl.py deleted file mode 100644 index 10832fc..0000000 --- a/eitControl.py +++ /dev/null @@ -1,422 +0,0 @@ -from pyqtgraph.Qt import QtGui, QtCore -import pyqtgraph as pg -from pyqtgraph.dockarea import * -import pyqtgraph.exporters - -import platform -import os -import argparse -import ast - -from threading import Thread - -import time # For sleep, clock, time and perf_counter -from datetime import datetime, timedelta, date - -import numpy as np -import csv - -import ue9qol -from funcGenerator import Sweeper, SinGen, TriangleGen, RampGen, PulseGen, SawGen -import rfGen - -from configparser import ConfigParser, ExtendedInterpolation -config = ConfigParser(interpolation=ExtendedInterpolation(), - converters = {'list': lambda x: [i.strip() for i in x.strip().split('\n')]}) -default_config = """ -[RF] -central_frequency = 6.83468e9 -frequency_span = 100e3 -initial_frequency = 6.834e9 -frequency_export_name = rfFreq - -[DAQ] -# channels to grab and their meaning -ain0 = transmission -ain1 = lockin -ain2 = davll -ain3 = ain3_undefined -# commented out channels will not be processed or stored -# dac0 = dac0_undefined -# dac1 = dac1_undefined2 - -[Plot] -x_axis_data = rfFreq - -[Plot_channels_visibility] -transmission = yes -lockin = yes -davll = yes - -[Plot_channels_colors] -# color specification will be evaluated and should match PyQtGraph.mkColor(args) -# for example -# (R,G,B,Alpha) tuple: example_trace = (255,0,255,100) -# or color name: example_trace = 'g' -transmission = (20,20,20,100) -lockin = (85,170,255,100) -davll = (255,0,255,100) -ain3_undefined = (0,85,255,100) - - -[Save] -save_prefix = eit -data_dir = z:\data.VAMPIRE - -""" - -config.read_string(default_config) -# additional config -config.read("config.ini") - - -class Experiment: - - def __init__(self, root, config, args): - self.root = root - self.config = config - self.save_cnt = 0 - self.tic = 0 - self.newDataIsReady = False - self.xlabel='' - self.channelGraph={} - self.clearData() - self.hardware = {} - self.hardwareSetup(args) - - # now we ready to do gui - self.buttons = {} - self.guiSweeper = Sweeper(self.root, Npoints=10, SweepTime=1, onTicCallbacks=[self.updatePlot]) - self.guiSetup(root) - self.guiSweeper.cmdStart() - - - def hardwareSetup(self,args): - if args.test: - print("Test mode, run with fake hardware") - self.sweeper = Sweeper(self.root, Npoints=100, SweepTime=1, onTicCallbacks=[self.onTic]) - self.hardware['LabJack'] = ue9qol.UE9qolDummy(sweeper=self.sweeper) - self.hardware['rfGen'] = rfGen.rfGenLMX2487Dummy(port='/dev/ttyUSB0', speed=115200, timeout=1) - else: - self.sweeper = Sweeper(self.root, Npoints=500, SweepTime=10, onTicCallbacks=[self.onTic]) - self.hardware['LabJack'] = ue9qol.UE9qol() - if platform.system() == 'Linux': - rf=rfGen.rfGenLMX2487(port='/dev/ttyUSB0', speed=115200, timeout=1) - else: - rf=rfGen.rfGenLMX2487(port='COM5', speed=115200, timeout=1) - self.hardware['rfGen'] = rf - - fCent = self.config['RF'].getfloat('central_frequency', fallback=6.83468e9) - fSpan = self.config['RF'].getfloat('frequency_span', fallback=100e3) - rf_f_init = self.config['RF'].getfloat('initial_frequency', fallback=6.834e9) - self.hardware['rfGen'].setFreq(rf_f_init) - self.rfGenFunc = SawGen(start=0, stop=0, sweeper = self.sweeper, duty_cycle=0.9) - self.rfGenFunc.setCenter(fCent) - self.rfGenFunc.setSpan(fSpan) - - self.funcGen = TriangleGen(start=0, stop=5, sweeper = self.sweeper) - - - def centralFreqValueChanged(self, sb): - v=sb.value() - self.config['RF']['central_frequency'] = str(v) - self.rfGenFunc.setCenter(v) - pass - - def freqSpanValueChanged(self, sb): - v=sb.value() - self.config['RF']['frequency_span'] = str(v) - self.rfGenFunc.setSpan(v) - pass - - def guiSetup(self, root): - self.dockArea = area = DockArea() - d1 = Dock("Global", size=(5,1)) - d2 = Dock("Data", size=(100,100)) - d3 = Dock("RF Gen", size=(1,2)) - dS = Dock("Status", size=(1,2), autoOrientation=False) - dS.setOrientation(o='horizontal') - area.addDock(d1, 'top') - area.addDock(dS, 'bottom', d1) - area.addDock(d2, 'bottom', dS) - area.addDock(d3, 'bottom', d2) - self.root.addWidget(area) - - self.dataPlot = pg.PlotWidget(name='Plot1') - d2.addWidget(self.dataPlot) - self.dataPlot.showGrid(x=True, y=True) - self.dataPlot.addLegend() - self.vLineSweepPosition = vLine = pg.InfiniteLine(angle=90, movable=False, pen='r') - self.dataPlot.addItem(vLine, ignoreBounds=True) - - # global buttons - w1 = pg.LayoutWidget() - bAutoZoom = QtGui.QPushButton('&AutoZoom') - bAutoZoom.clicked.connect(self.autoZoom) - self.buttons["AutoZoom"] = bAutoZoom - bRestart = QtGui.QPushButton('&Restart') - bRestart.clicked.connect(self.restart) - self.buttons["Restart"] = bRestart - bStartStopToggle = QtGui.QPushButton('&Start') - bStartStopToggle.clicked.connect(self.start) - self.buttons["StartStopToggle"] = bStartStopToggle - bSave = QtGui.QPushButton('Sa&ve data') - bSave.clicked.connect(self.saveCmd) - self.buttons["Save"] = bSave - bExit = QtGui.QPushButton('&Exit') - bExit.clicked.connect(exit) - self.buttons["Exit"] = bExit - bSaveConfig = QtGui.QPushButton('Save Con&fig') - bSaveConfig.clicked.connect(self.saveConfigCmd) - self.buttons["SaveConfig"] = bSaveConfig - w1.addWidget(bAutoZoom, row=0, col=0) - w1.addWidget(bRestart, row=0, col=1) - w1.addWidget(bStartStopToggle, row=0, col=2) - w1.addWidget(bSave, row=0, col=3) - w1.addWidget(bSaveConfig, row=0, col=4) - w1.addWidget(bExit, row=0, col=5) - d1.addWidget(w1) - - ## status line - self.statusline = l = QtGui.QLabel("All ok") - dS.addWidget(l, row=1, col=0) - - # RF gen gui - fCent=self.rfGenFunc.getCenter() - fSpan=self.rfGenFunc.getSpan() - spins = [ - ("Central Frequency", - pg.SpinBox(value=fCent, bounds=[6.83e9, 6.84e9], suffix='Hz', siPrefix=True, step=1e3, decimals=10), - self.centralFreqValueChanged), - ("Frequency Span", - pg.SpinBox(value=fSpan, bounds=[1, 10e6], dec=True, step=0.5, suffix='Hz', siPrefix=True, minStep=1), - self.freqSpanValueChanged) - ] - w3 = pg.LayoutWidget() - d3.addWidget(w3) - for text, spin, cb in spins: - l=QtGui.QLabel(text) - w3.addWidget(l) - w3.addWidget(spin) - spin.sigValueChanged.connect(cb) - - def clearData(self): - self.data = {} - # RF generator channels - rf_freq_Name = self.config['RF'].get('frequency_export_name') - self.data[rf_freq_Name] = [] - # DAQ channels - for ch in self.config['DAQ']: - ch_meaning = self.config['DAQ'][ch] - self.data[ch_meaning] = [] - # special channels - self.data['tic'] = [] - self.data['x'] = [] - - - def stop(self): - self.sweeper.cmdStop() - self.buttons["StartStopToggle"].setText("&Continue") - self.buttons["StartStopToggle"].clicked.disconnect() - self.buttons["StartStopToggle"].clicked.connect(self.start) - - def start(self): - self.sweeper.cmdStart() - self.buttons["StartStopToggle"].setText("&Pause") - self.buttons["StartStopToggle"].clicked.disconnect() - self.buttons["StartStopToggle"].clicked.connect(self.stop) - - def restart(self): - self.clearData() - self.sweeper.cmdRestart() - self.buttons["StartStopToggle"].setText("&Pause") - self.buttons["StartStopToggle"].clicked.disconnect() - self.buttons["StartStopToggle"].clicked.connect(self.stop) - - def getNewDataFileName(self, ext="csv"): - data_dir = self.config['Save'].get('data_dir', fallback='unset_data_dir') - if not os.path.exists(data_dir): - os.mkdir(data_dir) - if not os.path.isdir(data_dir): - print(f"ERROR: cannot create directory for data: {data_dir}") - print(f"Will use current dir for storage") - data_dir = "." - - prefix = self.config['Save'].get('save_prefix', fallback='unset_experiment_prefix') - today = date.today() - datestr = today.strftime("%Y%m%d") - self.save_cnt += 1 - - base_name = f"{prefix}_{datestr}_{self.save_cnt:#04}" - file_name = f"{base_name}.{ext}" - data_file = os.path.join(data_dir, file_name) - if os.path.exists(data_file): - data_file = self.getNewDataFileName(ext=ext) - return data_file - - def saveCmd(self): - csv_file = self.getNewDataFileName(ext='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') - msg = f"data saved to {csv_file}" - print(msg) - self.statusline.setText(msg) - - png_file=csv_file.replace(".csv", ".png") - print(f"Picture saved to {png_file}") - plt = self.dataPlot.getPlotItem() - ex = pg.exporters.ImageExporter(plt) - if pg.__version__ == '0.10.0': - # Workaround for PyQtGraph version <= 0.10.0 - # see https://github.com/pyqtgraph/pyqtgraph/issues/538#issuecomment-361405356 - w= int(plt.width()) - h= int(plt.height()) - # the value in setValue need to be different from default - # otherwise it will not be taken - ex.parameters().param('width').setValue(w+1, blockSignal=ex.widthChanged) - ex.parameters().param('height').setValue(h+1, blockSignal=ex.heightChanged) - # now we set actual value - # ex.parameters()['width'] = w - ex.parameters().param('width').setValue(w, blockSignal=ex.widthChanged) - ex.parameters().param('height').setValue(h, blockSignal=ex.heightChanged) - # beware this is bad workaround!!! plot data is misplaced - ex.export(png_file) - - def saveConfigCmd(self): - with open('config.ini', 'w') as configfile: - self.config.write(configfile) - - def onTic(self,swp=None): - start = datetime.now() - if swp is None: - swp = self.sweeper - - # RF generator - rfFreq = self.rfGenFunc.getValue(swp) - self.hardware['rfGen'].setFreq(rfFreq) - # skip data update based on independent variable (rfGen) sweep direction - sweep_direction = self.rfGenFunc.getSweepDirection(swp) - if sweep_direction < .5: - # sweep_direction is either 0 or 1 - # we do no data collection on the backward stroke - return - rf_freq_Name = self.config['RF'].get('frequency_export_name') - self.data[rf_freq_Name].append(rfFreq) - - # global tic counter - tic = self.sweeper.getCnt() - self.data['tic'].append(tic) - - # DAQ - daq0 = self.hardware['LabJack'] - - # dac0 - # dac0 = self.funcGen.getValue(swp) - # dac0 = 0 - # dac0 = self.funcGen.getValue(swp) - # daq0.setOutputCh(0, dac0) - # self.data['dac0'].append(dac0) - - # dac1 - # dac1 = PulseGen(ampl=5, sweeper=swp).getValue() - # dac1 = 0 - # daq0.setOutputCh(1, dac1) - # self.data['dac1'].append(dac1) - - for ch in self.config['DAQ']: - if ch[0:3] == 'ain': - n=int(ch[3:]) - vIn = daq0.getInputCh(n) - ch_meaning = self.config['DAQ'][ch] - self.data[ch_meaning].append( vIn ) - - # X-axis (i.e. independent variable) - x=self.data[self.config['Plot']['x_axis_data']] - x=np.array(x) - fCent = self.rfGenFunc.getCenter() - x=(x-fCent) - self.data['x'] = x - self.dataPlot.setLabel('bottom', 'Frequency offset', units='Hz') - self.dataPlot.setLabel('left', 'Signal', units='V') - - self.newDataIsReady = True - stop = datetime.now() - runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000 - # print("onTic DAQ took %s seconds." % (runTime) ) - - def autoZoom(self): - self.dataPlot.autoRange() - - def updatePlot(self,swp=None): - if self.newDataIsReady: - self.newDataIsReady = False - else: - return - - start = datetime.now() - x = self.data['x'] - for name in self.config['Plot_channels_visibility']: - if not self.config['Plot_channels_visibility'].getboolean(name): - continue - if name not in self.data: - continue - y = self.data[name] - if name not in self.channelGraph: - if name in self.config['Plot_channels_colors']: - color_str = self.config['Plot_channels_colors'][name] - color = ast.literal_eval(color_str) - else: - color = (255,0,0) - self.channelGraph[name]=self.dataPlot.plot(x,y, pen=None, symbol='o', symbolPen=None, symbolBrush=color, symbolSize=5, name=name) - else: - self.channelGraph[name].setData(x,y) - if len(x)>0: - self.vLineSweepPosition.setValue(x[-1]) - # centralFreqFormatted = pg.siFormat(self.fCent, suffix='Hz', precision=4) - # showing trailing zeros is tricky - fCent = self.rfGenFunc.getCenter() - centralFreqFormatted = f"{fCent/1e9:.9f}" - centralFreqFormatted = str.ljust(centralFreqFormatted, 11, '0') + " GHz" - self.dataPlot.setTitle(f"Signals around center frequency {centralFreqFormatted}") - - stop = datetime.now() - runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000 - print("Replot took %s seconds to plot %s points per channel." % (runTime, len(self.data['x'])) ) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Perform EIT based experiment.') - parser.add_argument('--test', '-t', action='store_true', - help='test mode, use fake/dummy hardware') - parser.add_argument('--config-file', '-c', action='append', - help='additional config files, could be used multiple time') - args = parser.parse_args() - - if args.config_file: - for cf in args.config_file: - print("Reading config file: " + cf) - config.read(cf) - - app = QtGui.QApplication([]) - pg.setConfigOption('background', 'w') - pg.setConfigOption('foreground', 'k') - mw = QtGui.QMainWindow() - mw.setWindowTitle('pyqtgraph example: PlotWidget') - mw.resize(800,800) - cw = QtGui.QWidget() - mw.setCentralWidget(cw) - l = QtGui.QVBoxLayout() - cw.setLayout(l) - - mw.show() - - experiment=Experiment(l, config, args) - app.exec() - - diff --git a/example_config.ini b/example_config.ini deleted file mode 100644 index c0fc146..0000000 --- a/example_config.ini +++ /dev/null @@ -1,40 +0,0 @@ -[RF] -central_frequency = 6.83468e9 -frequency_span = 100e3 -initial_frequency = 6.834e9 -frequency_export_name = rfFreq - -[DAQ] -# channels to grab and their meaning -ain0 = transmission -ain1 = lockin -ain2 = davll -ain3 = ain3_undefined -# commented out channels will not be processed or stored -# dac0 = dac0_undefined -# dac1 = dac1_undefined2 - -[Plot] -x_axis_data = rfFreq - -[Plot_channels_visibility] -transmission = yes -lockin = yes -davll = yes - -[Plot_channels_colors] -# color specification will be evaluated and should match PyQtGraph.mkColor(args) -# for example -# (R,G,B,Alpha) tuple: example_trace = (255,0,255,100) -# or color name: example_trace = 'g' -transmission = (20,20,20,100) -lockin = (85,170,255,100) -davll = (255,0,255,100) -ain3_undefined = (0,85,255,100) - - -[Save] -save_prefix = eit -data_dir = z:\data.VAMPIRE - - diff --git a/funcGenerator.py b/funcGenerator.py deleted file mode 100644 index cd33f0b..0000000 --- a/funcGenerator.py +++ /dev/null @@ -1,274 +0,0 @@ -import time # For sleep, clock, time and perf_counter -from datetime import datetime, timedelta -import numpy as np - -try: - from pyqtgraph.Qt import QtCore -except: - pass - -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 setCenterAndSpan(self, center, span): - self.start = center-span/2 - self.stop = center+span/2 - - def setCenter(self, center): - span = self.stop - self.start; - self.setCenterAndSpan(center, span) - - def getCenter(self): - return (self.stop + self.start)/2 - - def setSpan(self, span): - center = (self.stop + self.start)/2 - self.setCenterAndSpan(center, span) - - def getSpan(self): - return self.stop - self.start; - - 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 SawGen(RampGen): - # monotonically goes from start to stop, once reaches stop goes back to start - # does it with duty_cycle, - # i.e duty_cycle*period we go up, the other time we go down - def __init__(self, duty_cycle=0.5, **kwds): - self.duty_cycle = duty_cycle; - super().__init__(**kwds) - - 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() < self.duty_cycle: - return self.start + sweeper.getRelPos()/self.duty_cycle*(self.stop - self.start) - return self.start + (1-sweeper.getRelPos())/(1-self.duty_cycle)*(self.stop - self.start) - def getSweepDirection(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() < self.duty_cycle: - return 1; # increasing value direction - return 0; # decreasing value direction - -class TriangleGen(SawGen): - # monotonically goes from start to stop, once reaches stop goes back to start - # does it with 50% duty cycle, i.e half of period we go up, the other half down - def __init__(self, **kwds): - super().__init__(duty_cycle=0.5, **kwds) - -class PulseGen: - # produce ampl for the first half a period and 0 for the other half - 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: - # main clock sweeper for any function generator - 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.after(0, self.onTic) - - idleTime_mS = round((deadline-stop).seconds * 1000 + (deadline-stop).microseconds/1000) - # print("Will idle for %s" % (idleTime_mS) ) - self.after(idleTime_mS, self.onTic) - - def after(self, idleTime_mS, cmnd): - # this function modelled after Tk.after - # it is execute 'cmnd' after idle time given in mS - # idleTime_mS = 0 means execute immediately - try: - # Tk style - self.widget.after(idleTime_mS, cmnd) - return - except AttributeError: - pass - - try: - # PyQt style - t = QtCore.QTimer() - t.singleShot( idleTime_mS, cmnd ) - return - except NameError: - pass - - raise Exception("Something went horribly wrong: we have no mechanism for Sweeper.after()") - - - 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 - -def testOnTicTk(sweeper): - print( sweeper.getPos() ) - if sweeper.getPos() == sweeper.Npoints: - print("Tk sweeper is done") - sweeper.cmdStop() - sweeper.widget.destroy() - sweeper.widget.quit() - -def testSweeperTk(): - print("test Sweeper with Tk") - root=Tk() - root.geometry("800x600") - root.withdraw(); # do not show window - - Np = 10 - SweepTime = Np - print(f'Test sweeper: you should see a sequence of {Np} numbers updating about every {SweepTime/Np} seconds') - sweeper = Sweeper(root, Npoints=Np, SweepTime=SweepTime, onTicCallbacks=[testOnTicTk]) - sweeper.cmdStart() - - root.mainloop() - -def testOnTicPyQtGraph(sweeper): - print( sweeper.getPos() ) - if sweeper.getPos() == sweeper.Npoints: - print("PyQtGraph sweeper is done") - sweeper.cmdStop() - sweeper.widget.exit() - -def testSweeperPyQtGraph(): - print("test Sweeper with PyQtGraph") - app = QtGui.QApplication([]) - - Np = 10 - SweepTime = Np - print(f'Test sweeper: you should see a sequence of {Np} numbers updating about every {SweepTime/Np} seconds') - sweeper = Sweeper(app, Npoints=Np, SweepTime=SweepTime, onTicCallbacks=[testOnTicPyQtGraph]) - sweeper.cmdStart() - - app.exec() - -if __name__ == '__main__': - try: - from tkinter import Tk - testSweeperTk() - except ModuleNotFoundError: - print("Tk module not found, skipping testSweeperTk") - - try: - from pyqtgraph.Qt import QtGui, QtCore - testSweeperPyQtGraph() - except ModuleNotFoundError: - print("pyqtgraph.Qt module not found, skipping testSweeperPyQtGraph") - print("Done with tests") - diff --git a/labjackStreamTest.py b/labjackStreamTest.py deleted file mode 100644 index c5368ea..0000000 --- a/labjackStreamTest.py +++ /dev/null @@ -1,167 +0,0 @@ -import sys -import traceback -import time # For sleep, clock, time and perf_counter -from datetime import datetime - -import u3 -import u6 -import ue9 - -dacAddress = 5000 # DAC Modbus address - -# MAX_REQUESTS is the number of packets to be read. -MAX_REQUESTS = 75 -# SCAN_FREQUENCY is the scan frequency of stream mode in Hz -SCAN_FREQUENCY = 1000 - -d = None - -############################################################################### -# U3 -# Uncomment these lines to stream from a U3 -############################################################################### -''' -# At high frequencies ( >5 kHz), the number of samples will be MAX_REQUESTS -# times 48 (packets per request) times 25 (samples per packet). -d = u3.U3() - -# To learn the if the U3 is an HV -d.configU3() - -# For applying the proper calibration to readings. -d.getCalibrationData() - -# Set the FIO0 and FIO1 to Analog (d3 = b00000011) -d.configIO(FIOAnalog=3) - -print("Configuring U3 stream") -d.streamConfig(NumChannels=2, PChannels=[0, 1], NChannels=[31, 31], Resolution=3, ScanFrequency=SCAN_FREQUENCY) -''' - -############################################################################### -# U6 -# Uncomment these lines to stream from a U6 -############################################################################### -''' -# At high frequencies ( >5 kHz), the number of samples will be MAX_REQUESTS -# times 48 (packets per request) times 25 (samples per packet). -d = u6.U6() - -# For applying the proper calibration to readings. -d.getCalibrationData() - -print("Configuring U6 stream") - -d.streamConfig(NumChannels=2, ChannelNumbers=[0, 1], ChannelOptions=[0, 0], SettlingFactor=1, ResolutionIndex=1, ScanFrequency=SCAN_FREQUENCY) -''' - -############################################################################### -# UE9 -# Uncomment these lines to stream from a UE9 -############################################################################### -# At 96 Hz or higher frequencies, the number of samples will be MAX_REQUESTS -# times 8 (packets per request) times 16 (samples per packet). -# Currently over ethernet packets per request is 1. -d = ue9.UE9() -#d = ue9.UE9(ethernet=True, ipAddress="192.168.1.209") # Over TCP/ethernet connect to UE9 with IP address 192.168.1.209 - -# For applying the proper calibration to readings. -c=d.getCalibrationData() - -# by evmik -# fixing missing slope for gain '0' -c['AINSlopes']['0']= 0.0000775030 - - -print("Configuring UE9 stream") - -d.streamConfig(NumChannels=4, ChannelNumbers=[0, 1, 2, 3], ChannelOptions=[0, 0, 0, 0], SettlingTime=0, Resolution=12, ScanFrequency=SCAN_FREQUENCY) -''' -''' - -if d is None: - print("""Configure a device first. -Please open streamTest.py in a text editor and uncomment the lines for your device. - -Exiting...""") - sys.exit(0) - -try: - print("Start stream") - d.writeRegister(dacAddress, 2.05) - # d.singleIO(IOType=5, Channel=0, DAC=0) - dacNumber=0 - bits = d.voltageToDACBits(1.4, dacNumber = dacNumber) - out=d.singleIO(IOType=5, Channel=dacNumber, DAC=bits) - print(out) - - d.streamStart() - start = datetime.now() - print("Start time is %s" % start) - - missed = 0 - dataCount = 0 - packetCount = 0 - v=0.1 - - for r in d.streamData(): - # d.writeRegister(dacAddress, 0.05*dataCount) - v=v+0.1 - print(v) - bits = d.voltageToDACBits(v, dacNumber = dacNumber) - out=d.singleIO(IOType=5, Channel=dacNumber, DAC=bits) - if r is not None: - # Our stop condition - if dataCount >= MAX_REQUESTS: - break - - if r["errors"] != 0: - print("Errors counted: %s ; %s" % (r["errors"], datetime.now())) - - if r["numPackets"] != d.packetsPerRequest: - print("----- UNDERFLOW : %s ; %s" % - (r["numPackets"], datetime.now())) - - if r["missed"] != 0: - missed += r['missed'] - print("+++ Missed %s" % r["missed"]) - - if r["firstPacket"] != packetCount % 256: - print("----- Overflow skipping packets : expected %s got %s ; %s" % - (packetCount, r["firstPacket"], datetime.now())) - - # Comment out these prints and do something with r - print("Average of %s AIN0, %s AIN1 readings: %s, %s" % - (len(r["AIN0"]), len(r["AIN1"]), sum(r["AIN0"])/len(r["AIN0"]), sum(r["AIN1"])/len(r["AIN1"]))) - - dataCount += 1 - packetCount += r['numPackets'] - else: - # Got no data back from our read. - # This only happens if your stream isn't faster than the USB read - # timeout, ~1 sec. - print("No data ; %s" % datetime.now()) -except: - print("".join(i for i in traceback.format_exc())) -finally: - stop = datetime.now() - d.streamStop() - print("Stream stopped.\n") - d.close() - - sampleTotal = packetCount * d.streamSamplesPerPacket - - scanTotal = sampleTotal / 2 # sampleTotal / NumChannels - print("%s requests with %s packets per request with %s samples per packet = %s samples total." % - (dataCount, (float(packetCount)/dataCount), d.streamSamplesPerPacket, sampleTotal)) - print("%s samples were lost due to errors." % missed) - sampleTotal -= missed - print("Adjusted number of samples = %s" % sampleTotal) - - runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000 - print("The experiment took %s seconds." % runTime) - print("Actual Scan Rate = %s Hz" % SCAN_FREQUENCY) - print("Timed Scan Rate = %s scans / %s seconds = %s Hz" % - (scanTotal, runTime, float(scanTotal)/runTime)) - print("Timed Sample Rate = %s samples / %s seconds = %s Hz" % - (sampleTotal, runTime, float(sampleTotal)/runTime)) diff --git a/rfGen.py b/rfGen.py deleted file mode 100644 index 3084664..0000000 --- a/rfGen.py +++ /dev/null @@ -1,50 +0,0 @@ -import serial -import io - -import time # For sleep, clock, time and perf_counter -from datetime import datetime, timedelta - -class rfGenLMX2487: - def __init__(self, port='/dev/ttyUSB0', speed=115200, timeout=1, setToDefaults=True): - self.port = port - self.speed = speed - self.timeout = timeout - self.connection = serial.Serial( self.port, self.speed, timeout=self.timeout) - self.log = [] - self.logCapacity = 10 - if setToDefaults: - self.sendSerialCmd("set_lmx2487_board_to_default_state()") - - def add2log(self, text): - self.log.append(text) - while len(self.log) > self.logCapacity: - self.log.pop(0) - - def log2str(self, interval=None): - strOut = "" - for e in self.log: - strOut += e - return strOut - - def sendSerialCmd(self, cmd): - self.connection.write(bytes(cmd+'\r','ascii')) - if "3.4" == serial.__version__: - # older version style - resp = self.connection.read_until(terminator=b'> ') - else: - # new style after 20180616 - resp = self.connection.read_until(expected=b'> ') - resp = resp.decode('utf-8') - self.add2log(resp) - return resp - - def setFreq(self,freq): - cmd_str=f'setFreq({freq:.2f})' - self.sendSerialCmd(cmd_str) - -class rfGenLMX2487Dummy: - def __init__(self, port='/dev/ttyUSB0', speed=115200, timeout=1): - return - - def setFreq(self,freq): - return diff --git a/test_rfGenLMX2487.py b/test_rfGenLMX2487.py deleted file mode 100644 index e87ad79..0000000 --- a/test_rfGenLMX2487.py +++ /dev/null @@ -1,20 +0,0 @@ -from rfGen import rfGenLMX2487 -import numpy as np -import platform - -if platform.system() == 'Linux': - rf=rfGenLMX2487(port='/dev/ttyUSB0', speed=115200, timeout=1) -else: - rf=rfGenLMX2487(port='COM5', speed=115200, timeout=1) - -freqStart = 6.830e9 -freqStop = 6.840e9 -Np = 21 -print(f'We will sweep frequency from {freqStart} to {freqStop} in {Np} points') -for freq in np.linspace(freqStart,freqStop, num=Np, endpoint=True): - print(f'Frequency set to {freq:.2f}') - rf.setFreq(freq) - -print("Printing log") -print(rf.log2str()) - diff --git a/test_serial.py b/test_serial.py deleted file mode 100755 index f88302b..0000000 --- a/test_serial.py +++ /dev/null @@ -1,47 +0,0 @@ -import serial
-import io
-
-import time # For sleep, clock, time and perf_counter
-from datetime import datetime, timedelta
-
-# ser = serial.Serial('COM4', 115200, timeout=1)
-ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
-# ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
-
-# ser.write(b'dofile("bits_converging.lua")\r')
-# ser.write(b'dofile("microwire.lua")\r')
-# ser.write(b'dofile("lmx2487lib.lua")\r')
-# ser.write(b'dofile("Frequency_Settings.lua")\r')
-
-# ser.write(b'settings = initSettings()\r')
-# ser.write(b'settings = set_lmx2487_to_Frequency (startfreq, settings)\r')
-
-
-
-def sendSerialCmd(cmd):
- # start = datetime.now()
- ser.write(bytes(cmd+'\r','ascii'))
- resp = ser.read_until(terminator=b'> ')
- resp = resp.decode('utf-8')
- # print(resp)
- # stop = datetime.now()
- # runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000
- # print("Command: " + cmd + " runtime %s seconds." % (runTime) )
- return resp
-
-sendSerialCmd("print(2+3)")
-
-line = ser.readline()
-print(line)
-
-start = datetime.now()
-# resp = sendSerialCmd("print(node.heap())")
-# resp = sendSerialCmd(""); # empty command
-resp = sendSerialCmd("muSb= tmr.now(); setFreq(6.834e9); muSe =tmr.now(); print(\"execution time: \" .. muSe-muSb .. \" muS\")")
-print(resp)
-stop = datetime.now()
-runTime = (stop-start).seconds + float((stop-start).microseconds)/1000000
-print("runtime %s seconds." % (runTime) )
-
-
-ser.close()
diff --git a/test_ue9.py b/test_ue9.py deleted file mode 100755 index d8a0dff..0000000 --- a/test_ue9.py +++ /dev/null @@ -1,10 +0,0 @@ - -import ue9qol - -daq = ue9qol.UE9qol() - -daq.setOutputCh(0, 0.5) - -v1 = daq.getInputCh(1) -print(f'ch1 = {v1}') - diff --git a/ue9qol.py b/ue9qol.py deleted file mode 100644 index e95fe6b..0000000 --- a/ue9qol.py +++ /dev/null @@ -1,76 +0,0 @@ -import sys -import traceback -import time # For sleep, clock, time and perf_counter -from datetime import datetime -import random - -import u3 -import u6 -import ue9 - -class UE9qol: - - def __init__(self, debug = False, autoOpen = True, **kargs): - #d = ue9.UE9(ethernet=True, ipAddress="192.168.1.209") # Over TCP/ethernet connect to UE9 with IP address 192.168.1.209 - self.daq = ue9.UE9(debug=debug, autoOpen=autoOpen) - - # For applying the proper calibration to readings. - c=self.daq.getCalibrationData() - - # by evmik - # fixing missing slope for gain '0' - c['AINSlopes']['0']= 0.0000775030 - - def getInputCh(self, chNum, BipGain = 8): - # BipGain = 8 -> bipolar range (-5V, +5V) gain 1 - # UE9 default BipGain = 0 -> signal range (0V, +5V) gain 1 - # other BipGain could be: - # 0 = Unipolar Gain 1, 1 = Unipolar Gain 2, - # 2 = Unipolar Gain 4, 3 = Unipolar Gain 8, - # 8 = Bipolar Gain 1 - return self.daq.getAIN(chNum, BipGain = BipGain) - - def setOutputCh(self, chNum=None, volts=None): - if chNum == None or volts == None: - print("setOutputCh needs chNum and volts to be set") - return 0 - bits = self.daq.voltageToDACBits(volts, dacNumber = chNum) - # out is completely bogus for DAC settings in UE9 - out=self.daq.singleIO(IOType=5, Channel=chNum, DAC=bits) - return volts - - def close(self): - self.daq.close() - -class UE9qolDummy: - from funcGenerator import Sweeper, SinGen, TriangleGen, RampGen, PulseGen - # to be used for graphics debugging - def __init__(self, debug = False, autoOpen = True, sweeper=None, **kargs): - self.sweeper = sweeper - # do nothing - return - - def getInputCh(self, chNum): - a =.3 - if chNum == 0: - val = self.SinGen(ampl=a, offset=chNum, sweeper=self.sweeper).getValue() - elif chNum == 1: - val = self.PulseGen(ampl=a, sweeper=self.sweeper).getValue() - val += chNum - elif chNum == 2: - val = self.TriangleGen(start=chNum-a/2, stop=chNum+a/2, sweeper=self.sweeper).getValue() - elif chNum == 3: - val = self.RampGen(start=chNum-a/2, stop=chNum+a/2, sweeper=self.sweeper).getValue() - else: - val = self.SinGen(ampl=.2, offset=chNum, sweeper=self.sweeper).getValue() - val += random.normalvariate(0, 0.01) - return val - - def setOutputCh(self, chNum=None, volts=None): - # do nothing - return - - def close(self): - # do nothing - return - |