from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg from pyqtgraph.dockarea import * from pyqtgraph.exporters import ImageExporter import platform import argparse from threading import Thread import time # For sleep, clock, time and perf_counter from datetime import datetime, timedelta import numpy as np import csv import ue9qol from funcGenerator import Sweeper, SinGen, TriangleGen, RampGen, PulseGen import rfGen class Experiment: def __init__(self, root, args): self.root = root self.tic = 0 self.channelsNames2grab={'tic', 'x','rfFreq','dac0', 'dac1', 'adc0', 'adc1', 'adc2', 'adc3'} self.channelsColor = { 'adc0': 'k', 'adc1': 'c', 'adc2': 'm', 'adc3': 'b', 'dac0': 'w', 'dac1': 'g'} #self.channelsNames2plot={'dac0', 'dac1', 'adc0', 'adc1', 'adc2', 'adc3'} if args.test: self.channelsNames2plot={'adc0', 'adc1', 'adc2', 'adc3'} else: self.channelsNames2plot={'adc0'} self.xChannelName='rfFreq' # can be also 'tic' or any of above self.xlabel='' self.channelGraph={} self.clearData() self.guiSetup(root) self.guiSweeper = Sweeper(self.root, Npoints=10, SweepTime=1, onTicCallbacks=[self.updatePlot]) self.guiSweeper.cmdStart() self.hardware = {} self.sweeper = Sweeper(self.root, Npoints=500, SweepTime=10, onTicCallbacks=[self.onTic]) self.funcGen = TriangleGen(0, 5, sweeper = self.sweeper) fCent=6.83468e9 self.fCent=fCent fSpan=100e3 self.fSpan=fSpan self.rfGenFunc = RampGen(fCent-fSpan/2, fCent+fSpan/2, sweeper = self.sweeper) self.hardwareSetup(args) def hardwareSetup(self,args): if args.test: print("Test mode, run with fake hardware") self.hardware['LabJack'] = ue9qol.UE9qolDummy(sweeper=self.sweeper) self.hardware['rfGen'] = rfGen.rfGenLMX2487Dummy(port='/dev/ttyUSB0', speed=115200, timeout=1) else: 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 def guiSetup(self, root): area = DockArea() d1 = Dock("Controls", size=(5,1)) d2 = Dock("Data", size=(100,100)) area.addDock(d1, 'top') area.addDock(d2, 'bottom', d1) self.root.addWidget(area) self.dataPlot = pg.PlotWidget(name='Plot1') d2.addWidget(self.dataPlot) self.dataPlot.setBackground(None) self.dataPlot.showGrid(x=True, y=True) self.dataPlot.addLegend() w1 = pg.LayoutWidget() bAutoZoom = QtGui.QPushButton('AutoZoom') bAutoZoom.clicked.connect(self.autoZoom) bRestart = QtGui.QPushButton('Restart') bRestart.clicked.connect(self.restart) bStart = QtGui.QPushButton('Start') bStart.clicked.connect(self.start) bStop = QtGui.QPushButton('Stop') bStop.clicked.connect(self.stop) bSave = QtGui.QPushButton('Save data') bSave.clicked.connect(self.saveCmd) bExit = QtGui.QPushButton('Exit') bExit.clicked.connect(exit) w1.addWidget(bAutoZoom, row=0, col=0) w1.addWidget(bRestart, row=0, col=1) w1.addWidget(bStart, row=0, col=2) w1.addWidget(bStop, row=0, col=3) w1.addWidget(bSave, row=0, col=4) w1.addWidget(bExit, row=0, col=5) d1.addWidget(w1) def clearData(self): self.data = {} for ch in self.channelsNames2grab: self.data[ch] = [] 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') try: ex = ImageExporter(self.channelGraph['adc0']) ex.parameters()['width'] = 800 ex.parameters()['height'] = 600 ex.export("snapshot.png") except ZeroDivisionError: print("Early version (0.10.0) of PyQtGraph has bug in exporter. The image file is not generated.") 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) # RF generator rfFreq = self.rfGenFunc.getValue(swp) self.hardware['rfGen'].setFreq(rfFreq) self.data['rfFreq'].append(rfFreq) # 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) # adc0 adc0= daq0.getInputCh(0) # adc0 = SinGen(ampl=4, sweeper=swp).getValue() self.data['adc0'].append( adc0 ) # 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 ) # X-axis (i.e. independent variable) # self.data['x'].append(tic) # self.data['x']=self.data[self.xChannelName] x=self.data[self.xChannelName][-1] x=(x-self.fCent) self.data['x'].append(x) self.dataPlot.setLabel('bottom', 'Frequency offset', units='Hz') self.dataPlot.setLabel('left', 'Signal', units='V') 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): start = datetime.now() x = self.data['x'] for name in self.channelsNames2plot: if name not in self.data: continue y = self.data[name] if name not in self.channelGraph: if name in self.channelsColor: color = self.channelsColor[name] 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) 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__': parser = argparse.ArgumentParser(description='Perform EIT based experiment.') parser.add_argument('--test', '-t', action='store_true', help='test mode, use fake/dummy hardware') args = parser.parse_args() app = QtGui.QApplication([]) 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, args) app.exec()