diff --git a/README.md b/README.md index e411cc4..f6a6221 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,8 @@ static.sineval:=sin(2*pi*${FREQ=5}*static.time); ### FFT GUI (FFT and rawdata plots + controls) A simple tool, [ecmcFFTMainGui.py](tools/ecmcFFTMainGui.py), to visualize the calculated spectrum, rawdata and also plugin controls can be found in the tools directory. The GUI connects to the plugin records over pypics framwork. +The gui are included in the ecmccomgui repo: +https://github.com/anderssandstrom/ecmccomgui Example: ecmcFFTMainGui.py help printout ``` diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..9d714a3 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,8 @@ +# FFT tools + +## GUI + +A python gui for vizualization and control of the FFT plugin can be found in the ecmccomgui repo: +https://github.com/anderssandstrom/ecmccomgui + +![ecmcFFTMainGui.py](docs/gui/ecmcFFTMainGui.png) diff --git a/tools/ecmcArrayGui.py b/tools/ecmcArrayGui.py deleted file mode 100644 index d4afa57..0000000 --- a/tools/ecmcArrayGui.py +++ /dev/null @@ -1,131 +0,0 @@ -#************************************************************************* -# Copyright (c) 2020 European Spallation Source ERIC -# ecmc is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -# -# ecmcArrayGui.py -# -# Created on: October 8, 2020 -# Author: Anders Sandström -# -# Plots two waveforms (y vs time) updates for each callback on the y-pv -# -#************************************************************************* - -import sys -import epics -from PyQt5.QtWidgets import * -from PyQt5 import QtWidgets -from PyQt5.QtCore import * -from PyQt5.QtGui import * -import numpy as np -import matplotlib -matplotlib.use("Qt5Agg") -from matplotlib.figure import Figure -from matplotlib.animation import TimedAnimation -from matplotlib.lines import Line2D -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar -import matplotlib.pyplot as plt -import threading - -class comSignal(QObject): - data_signal = pyqtSignal(object) - -class ecmcArrayGui(QtWidgets.QDialog): - def __init__(self,yname=None): - super(ecmcArrayGui, self).__init__() - self.comSignalY = comSignal() - self.comSignalY.data_signal.connect(self.callbackFuncY) - self.pause = 0 - self.spectY = None - self.figure = plt.figure() - self.plotted_line = None - self.ax = None - self.canvas = FigureCanvas(self.figure) - self.toolbar = NavigationToolbar(self.canvas, self) - self.pauseBtn = QPushButton(text = 'pause') - self.pauseBtn.setFixedSize(100, 50) - self.pauseBtn.clicked.connect(self.pauseBtnAction) - self.pauseBtn.setStyleSheet("background-color: green") - self.pvNameY = yname # "IOC_TEST:Plugin-FFT0-Raw-Data-Act" - self.connectPvs() # Epics - self.setGeometry(300, 300, 900, 700) - self.setWindowTitle("ecmc Array plot: " + self.pvNameY) - layout = QVBoxLayout() - layout.addWidget(self.toolbar) - layout.addWidget(self.canvas) - layout.addWidget(self.pauseBtn) - self.setLayout(layout) - return - - def connectPvs(self): - if self.pvNameY is None: - raise RuntimeError("pvname y must not be 'None'") - if len(self.pvNameY)==0: - raise RuntimeError("pvname y must not be ''") - - self.pvY = epics.PV(self.pvNameY) - #print('self.pvY: ' + self.pvY.info) - - self.pvY.add_callback(self.onChangePvY) - QCoreApplication.processEvents() - - def onChangePvY(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - self.comSignalY.data_signal.emit(value) - - def pauseBtnAction(self): - self.pause = not self.pause - if self.pause: - self.pauseBtn.setStyleSheet("background-color: red"); - else: - self.pauseBtn.setStyleSheet("background-color: green"); - self.comSignalY.data_signal.emit(self.spectY) - return - - def callbackFuncY(self, value): - if(np.size(value)) > 0: - self.spectY = value - self.plotSpect() - return - - def plotSpect(self): - if self.pause: - return - - if self.spectY is None: - return - - # create an axis - if self.ax is None: - self.ax = self.figure.add_subplot(111) - - # plot data - if self.plotted_line is not None: - self.plotted_line.remove() - - self.plotted_line, = self.ax.plot(self.spectY, 'b*-') - self.ax.grid(True) - - plt.xlabel('Time []') - plt.ylabel(self.pvNameY +' [' + self.pvY.units + ']') - # refresh canvas - self.canvas.draw() - - self.ax.autoscale(enable=True) - -def printOutHelp(): - print("ecmcArrayGui: Plots waveforms data (updates on data callback). ") - print("python ecmcArrayGui.py ") - print("example: python ecmcArrayGui.py IOC_TEST:Plugin-FFT0-Raw-Data-Act") - -if __name__ == "__main__": - import sys - if len(sys.argv)!=2: - printOutHelp() - sys.exit() - yname=sys.argv[1] - app = QtWidgets.QApplication(sys.argv) - window=ecmcArrayGui(yname=yname) - window.show() - sys.exit(app.exec_()) diff --git a/tools/ecmcFFTGui.py b/tools/ecmcFFTGui.py deleted file mode 100644 index 195e4ef..0000000 --- a/tools/ecmcFFTGui.py +++ /dev/null @@ -1,157 +0,0 @@ -#************************************************************************* -# Copyright (c) 2020 European Spallation Source ERIC -# ecmc is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -# -# ecmcFFTGui.py -# -# Created on: October 6, 2020 -# Author: Anders Sandström -# -# Plots two waveforms (x vs y) updates for each callback on the y-pv -# -#************************************************************************* - -import sys -import epics -from PyQt5.QtWidgets import * -from PyQt5 import QtWidgets -from PyQt5.QtCore import * -from PyQt5.QtGui import * -import numpy as np -import matplotlib -matplotlib.use("Qt5Agg") -from matplotlib.figure import Figure -from matplotlib.animation import TimedAnimation -from matplotlib.lines import Line2D -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar -import matplotlib.pyplot as plt -import threading - -class comSignal(QObject): - data_signal = pyqtSignal(object) - -class ecmcFFTGui(QtWidgets.QDialog): - def __init__(self,xname=None,yname=None): - super(ecmcFFTGui, self).__init__() - self.comSignalX = comSignal() - self.comSignalX.data_signal.connect(self.callbackFuncX) - self.comSignalY = comSignal() - self.comSignalY.data_signal.connect(self.callbackFuncY) - self.pause = 0 - self.spectX = None - self.spectY = None - self.figure = plt.figure() - self.plotted_line = None - self.ax = None - self.canvas = FigureCanvas(self.figure) - self.toolbar = NavigationToolbar(self.canvas, self) - self.pauseBtn = QPushButton(text = 'pause') - self.pauseBtn.setFixedSize(100, 50) - self.pauseBtn.clicked.connect(self.pauseBtnAction) - self.pauseBtn.setStyleSheet("background-color: green"); - self.pvNameY = yname # "IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act" - self.pvNameX = xname # "IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act" - self.connectPvs() # Epics - self.setGeometry(300, 300, 900, 700) - self.setWindowTitle("ecmc FFT plot: " + self.pvNameY + ' vs ' + self.pvNameX) - layout = QVBoxLayout() - layout.addWidget(self.toolbar) - layout.addWidget(self.canvas) - layout.addWidget(self.pauseBtn) - self.setLayout(layout) - return - - def connectPvs(self): - - if self.pvNameX is None: - raise RuntimeError("pvname X must not be 'None'") - if len(self.pvNameX)==0: - raise RuntimeError("pvname X must not be ''") - - if self.pvNameY is None: - raise RuntimeError("pvname y must not be 'None'") - if len(self.pvNameY)==0: - raise RuntimeError("pvname y must not be ''") - - self.pvX = epics.PV(self.pvNameX) - #print('self.pvX: ' + self.pvX.info) - - self.pvY = epics.PV(self.pvNameY) - #print('self.pvY: ' + self.pvY.info) - - self.pvX.add_callback(self.onChangePvX) - self.pvY.add_callback(self.onChangePvY) - QCoreApplication.processEvents() - - def onChangePvX(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - self.comSignalX.data_signal.emit(value) - - def onChangePvY(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - self.comSignalY.data_signal.emit(value) - - def pauseBtnAction(self): - self.pause = not self.pause - if self.pause: - self.pauseBtn.setStyleSheet("background-color: red"); - else: - self.pauseBtn.setStyleSheet("background-color: green"); - self.comSignalY.data_signal.emit(self.spectY) - return - - - def callbackFuncX(self, value): - if(np.size(value)) > 0: - self.spectX = value - self.xDataValid = 1 - return - - def callbackFuncY(self, value): - if(np.size(value)) > 0: - self.spectY = value - self.plotSpect() - return - - def plotSpect(self): - if self.pause: - return - if self.spectX is None: - return - if self.spectY is None: - return - - # create an axis - if self.ax is None: - self.ax = self.figure.add_subplot(111) - - # plot data - if self.plotted_line is not None: - self.plotted_line.remove() - - self.plotted_line, = self.ax.plot(self.spectX,self.spectY, 'b*-') - self.ax.grid(True) - - plt.xlabel(self.pvNameX +' [' + self.pvX.units + ']') - plt.ylabel(self.pvNameY +' [' + self.pvY.units + ']') - # refresh canvas - self.canvas.draw() - - self.ax.autoscale(enable=False) - -def printOutHelp(): - print("ecmcFFTGui: Plots waveforms of FFT data (updates on Y data callback). ") - print("python ecmcFFTGui.py ") - print("example: python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act") - -if __name__ == "__main__": - import sys - if len(sys.argv)!=3: - printOutHelp() - sys.exit() - xname=sys.argv[1] - yname=sys.argv[2] - app = QtWidgets.QApplication(sys.argv) - window=ecmcFFTGui(xname=xname,yname=yname) - window.show() - sys.exit(app.exec_()) diff --git a/tools/ecmcFFTMainGui.py b/tools/ecmcFFTMainGui.py deleted file mode 100644 index ac991a3..0000000 --- a/tools/ecmcFFTMainGui.py +++ /dev/null @@ -1,528 +0,0 @@ -#************************************************************************* -# Copyright (c) 2020 European Spallation Source ERIC -# ecmc is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -# -# ecmcFFTMainGui.py -# -# Created on: October 6, 2020 -# Author: Anders Sandström -# -# Plots two waveforms (x vs y) updates for each callback on the y-pv -# -#************************************************************************* - -import sys -import epics -from PyQt5.QtWidgets import * -from PyQt5 import QtWidgets -from PyQt5.QtCore import * -from PyQt5.QtGui import * -import numpy as np -import matplotlib -matplotlib.use("Qt5Agg") -from matplotlib.figure import Figure -from matplotlib.animation import TimedAnimation -from matplotlib.lines import Line2D -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar -import matplotlib.pyplot as plt -import threading - -# FFT object pvs Plugin-FFT- -# IOC_TEST:Plugin-FFT0-stat -# IOC_TEST:Plugin-FFT0-NFFT x -# IOC_TEST:Plugin-FFT0-Mode-RB x -# IOC_TEST:Plugin-FFT0-SampleRate-Act x -# IOC_TEST:Plugin-FFT0-Enable x -# IOC_TEST:Plugin-FFT0-Trigg x -# IOC_TEST:Plugin-FFT0-Source x -# IOC_TEST:Plugin-FFT0-Raw-Data-Act x -# IOC_TEST:Plugin-FFT0-PreProc-Data-Act -# IOC_TEST:Plugin-FFT0-Spectrum-Amp-Act x -# IOC_TEST:Plugin-FFT0-Spectrum-X-Axis-Act x - - -class comSignal(QObject): - data_signal = pyqtSignal(object) - -class ecmcFFTMainGui(QtWidgets.QDialog): - def __init__(self,prefix=None,fftPluginId=None): - super(ecmcFFTMainGui, self).__init__() - self.offline = False - self.pvPrefixStr = prefix - self.pvPrefixOrigStr = prefix # save for restore after open datafile - self.fftPluginId = fftPluginId - self.fftPluginOrigId = fftPluginId - self.allowSave = False - if prefix is None or fftPluginId is None: - self.offline = True - self.pause = True - self.enable = False - else: - self.buildPvNames() - self.offline = False - self.pause = False - - # Callbacks through signals - self.comSignalSpectX = comSignal() - self.comSignalSpectX.data_signal.connect(self.callbackFuncSpectX) - self.comSignalSpectY = comSignal() - self.comSignalSpectY.data_signal.connect(self.callbackFuncSpectY) - self.comSignalRawData = comSignal() - self.comSignalRawData.data_signal.connect(self.callbackFuncrawData) - self.comSignalEnable = comSignal() - self.comSignalEnable.data_signal.connect(self.callbackFuncEnable) - self.comSignalMode = comSignal() - self.comSignalMode.data_signal.connect(self.callbackFuncMode) - - self.pause = 0 - - # Data - self.spectX = None - self.spectY = None - self.rawdataY = None - self.rawdataX = None - self.enable = None - - self.pvMode = None - - self.createWidgets() - self.connectPvs() - self.setStatusOfWidgets() - - return - - def createWidgets(self): - - self.figure = plt.figure() - self.plottedLineSpect = None - self.plottedLineRaw = None - self.axSpect = None - self.axRaw = None - self.canvas = FigureCanvas(self.figure) - self.toolbar = NavigationToolbar(self.canvas, self) - self.pauseBtn = QPushButton(text = 'pause') - self.pauseBtn.setFixedSize(100, 50) - self.pauseBtn.clicked.connect(self.pauseBtnAction) - self.pauseBtn.setStyleSheet("background-color: green") - self.openBtn = QPushButton(text = 'open data') - self.openBtn.setFixedSize(100, 50) - self.openBtn.clicked.connect(self.openBtnAction) - self.saveBtn = QPushButton(text = 'save data') - self.saveBtn.setFixedSize(100, 50) - self.saveBtn.clicked.connect(self.saveBtnAction) - self.enableBtn = QPushButton(text = 'enable FFT') - self.enableBtn.setFixedSize(100, 50) - self.enableBtn.clicked.connect(self.enableBtnAction) - self.triggBtn = QPushButton(text = 'trigg FFT') - self.triggBtn.setFixedSize(100, 50) - self.triggBtn.clicked.connect(self.triggBtnAction) - self.modeCombo = QComboBox() - self.modeCombo.setFixedSize(100, 50) - self.modeCombo.currentIndexChanged.connect(self.newModeIndexChanged) - self.modeCombo.addItem("CONT") - self.modeCombo.addItem("TRIGG") - - # Fix layout - self.setGeometry(300, 300, 900, 700) - - layoutVert = QVBoxLayout() - layoutVert.addWidget(self.toolbar) - layoutVert.addWidget(self.canvas) - - layoutControl = QHBoxLayout() - layoutControl.addWidget(self.pauseBtn) - layoutControl.addWidget(self.enableBtn) - layoutControl.addWidget(self.triggBtn) - layoutControl.addWidget(self.modeCombo) - layoutControl.addWidget(self.saveBtn) - layoutControl.addWidget(self.openBtn) - - frameControl = QFrame(self) - frameControl.setFixedHeight(70) - frameControl.setLayout(layoutControl) - - - layoutVert.addWidget(frameControl) - self.setLayout(layoutVert) - - def setStatusOfWidgets(self): - self.saveBtn.setEnabled(self.allowSave) - if self.offline: - self.enableBtn.setStyleSheet("background-color: grey") - self.enableBtn.setEnabled(False) - self.pauseBtn.setStyleSheet("background-color: grey") - self.pauseBtn.setEnabled(False) - self.modeCombo.setEnabled(False) - self.triggBtn.setEnabled(False) - self.setWindowTitle("ecmc FFT Main plot: Offline") - else: - self.modeCombo.setEnabled(True) - # Check actual value of pvs - if(self.pvEnable.get()>0): - self.enableBtn.setStyleSheet("background-color: green") - self.enable = True - else: - self.enableBtn.setStyleSheet("background-color: red") - self.enable = False - - self.sourceStr = self.pvSource.get(as_string=True) - self.sampleRate = self.pvSampleRate.get() - self.NFFT = self.pvNFFT.get() - self.mode = self.pvMode.get() - self.modeStr = "NO_MODE" - self.triggBtn.setEnabled(False) # Only enable if mode = TRIGG = 2 - if self.mode == 1: - self.modeStr = "CONT" - self.modeCombo.setCurrentIndex(self.mode-1) # Index starta t zero - - if self.mode == 2: - self.modeStr = "TRIGG" - self.triggBtn.setEnabled(True) - self.modeCombo.setCurrentIndex(self.mode-1) # Index starta t zero - - self.setWindowTitle("ecmc FFT Main plot: prefix=" + self.pvPrefixStr + " , fftId=" + str(self.fftPluginId) + - ", source=" + self.sourceStr + ", rate=" + str(self.sampleRate) + - ", nfft=" + str(self.NFFT)) - - def buildPvNames(self): - # Pv names based on structure: Plugin-FFT- - self.pvNameSpectY = self.buildPvName('Spectrum-Amp-Act') # "IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act" - self.pvNameSpectX = self.buildPvName('Spectrum-X-Axis-Act') # "IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act" - self.pvNameRawDataY = self.buildPvName('Raw-Data-Act') # IOC_TEST:Plugin-FFT0-Raw-Data-Act - self.pvnNameEnable = self.buildPvName('Enable') # IOC_TEST:Plugin-FFT0-Enable - self.pvnNameTrigg = self.buildPvName('Trigg') # IOC_TEST:Plugin-FFT0-Trigg - self.pvnNameSource = self.buildPvName('Source') # IOC_TEST:Plugin-FFT0-Source - self.pvnNameSampleRate = self.buildPvName('SampleRate-Act') # IOC_TEST:Plugin-FFT0-SampleRate-Act - self.pvnNameNFFT = self.buildPvName('NFFT') # IOC_TEST:Plugin-FFT0-NFFT - self.pvnNameMode = self.buildPvName('Mode-RB') # IOC_TEST:Plugin-FFT0-Mode-RB - - def buildPvName(self, suffixname): - return self.pvPrefixStr + 'Plugin-FFT' + str(self.fftPluginId) + '-' + suffixname - - def connectPvs(self): - if self.offline: - return - - if self.pvNameSpectX is None: - raise RuntimeError("pvname X spect must not be 'None'") - if len(self.pvNameSpectX)==0: - raise RuntimeError("pvname X spect must not be ''") - - if self.pvNameSpectY is None: - raise RuntimeError("pvname y spect must not be 'None'") - if len(self.pvNameSpectY)==0: - raise RuntimeError("pvname y spect must not be ''") - - if self.pvNameRawDataY is None: - raise RuntimeError("pvname raw data must not be 'None'") - if len(self.pvNameRawDataY)==0: - raise RuntimeError("pvname raw data must not be ''") - - if self.pvnNameEnable is None: - raise RuntimeError("pvname enable must not be 'None'") - if len(self.pvnNameEnable)==0: - raise RuntimeError("pvname enable must not be ''") - - if self.pvnNameTrigg is None: - raise RuntimeError("pvname trigg must not be 'None'") - if len(self.pvnNameTrigg)==0: - raise RuntimeError("pvname trigg must not be ''") - - if self.pvnNameSource is None: - raise RuntimeError("pvname source must not be 'None'") - if len(self.pvnNameSource)==0: - raise RuntimeError("pvname source must not be ''") - - if self.pvnNameSampleRate is None: - raise RuntimeError("pvname sample rate must not be 'None'") - if len(self.pvnNameSampleRate)==0: - raise RuntimeError("pvname sample rate must not be ''") - - if self.pvnNameNFFT is None: - raise RuntimeError("pvname NFFT must not be 'None'") - if len(self.pvnNameNFFT)==0: - raise RuntimeError("pvname NFFT must not be ''") - - if self.pvnNameMode is None: - raise RuntimeError("pvname mode must not be 'None'") - if len(self.pvnNameMode)==0: - raise RuntimeError("pvname mode must not be ''") - - self.pvSpectX = epics.PV(self.pvNameSpectX) - self.pvSpectY = epics.PV(self.pvNameSpectY) - self.pvRawData = epics.PV(self.pvNameRawDataY) - self.pvEnable = epics.PV(self.pvnNameEnable) - self.pvTrigg = epics.PV(self.pvnNameTrigg) - self.pvSource = epics.PV(self.pvnNameSource) - self.pvSampleRate = epics.PV(self.pvnNameSampleRate) - self.pvNFFT = epics.PV(self.pvnNameNFFT) - self.pvMode = epics.PV(self.pvnNameMode) - self.pvSpectX.add_callback(self.onChangePvSpectX) - self.pvSpectY.add_callback(self.onChangePvSpectY) - self.pvRawData.add_callback(self.onChangePvrawData) - self.pvEnable.add_callback(self.onChangePvEnable) - self.pvMode.add_callback(self.onChangePvMode) - QCoreApplication.processEvents() - - ###### Pv monitor callbacks - def onChangePvMode(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - if self.pause: - return - self.comSignalMode.data_signal.emit(value) - - def onChangePvEnable(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - if self.pause: - return - self.comSignalEnable.data_signal.emit(value) - - def onChangePvSpectX(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - if self.pause: - return - self.comSignalSpectX.data_signal.emit(value) - - def onChangePvSpectY(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - if self.pause: - return - self.comSignalSpectY.data_signal.emit(value) - - def onChangePvrawData(self,pvname=None, value=None, char_value=None,timestamp=None, **kw): - if self.pause: - return - self.comSignalRawData.data_signal.emit(value) - - ###### Signal callbacks - def callbackFuncMode(self, value): - if value < 1 or value> 2: - self.modeStr = "NO_MODE" - print('callbackFuncMode: Error Invalid mode.') - return - - self.mode = value - self.modeCombo.setCurrentIndex(self.mode-1) # Index starta t zero - - if self.mode == 1: - self.modeStr = "CONT" - self.triggBtn.setEnabled(False) # Only enable if mode = TRIGG = 2 - - if self.mode == 2: - self.modeStr = "TRIGG" - self.triggBtn.setEnabled(True) - - return - - def callbackFuncEnable(self, value): - self.enable = value - if self.enable: - self.enableBtn.setStyleSheet("background-color: green") - else: - self.enableBtn.setStyleSheet("background-color: red") - return - - def callbackFuncSpectX(self, value): - if(np.size(value)) > 0: - self.spectX = value - self.xDataValid = 1 - return - - def callbackFuncSpectY(self, value): - if(np.size(value)) > 0: - self.spectY = value - self.plotSpect() - return - - def callbackFuncrawData(self, value): - if(np.size(value)) > 0: - if self.rawdataX is None or np.size(value) != np.size(self.rawdataY): - self.rawdataX = np.arange(-np.size(value)/self.sampleRate, 0, 1/self.sampleRate) - - self.rawdataY = value - self.plotRaw() - return - - ###### Widget callbacks - def pauseBtnAction(self): - self.pause = not self.pause - if self.pause: - self.pauseBtn.setStyleSheet("background-color: red") - else: - self.pvPrefixStr = self.pvPrefixOrigStr # Restore if dataset was opened - self.fftPluginId = self.fftPluginOrigId # Restore if dataset was opened - self.buildPvNames() - - self.pauseBtn.setStyleSheet("background-color: green") - # Retrigger plots with newest values - self.comSignalSpectY.data_signal.emit(self.spectY) - self.comSignalRawData.data_signal.emit(self.rawdataY) - return - - def enableBtnAction(self): - self.enable = not self.enable - self.pvEnable.put(self.enable) - if self.enable: - self.enableBtn.setStyleSheet("background-color: green") - else: - self.enableBtn.setStyleSheet("background-color: red") - return - - def triggBtnAction(self): - self.pvTrigg.put(True) - return - - def newModeIndexChanged(self,index): - if index==0 or index==1: - if not self.offline and self.pvMode is not None: - self.pvMode.put(index+1) - return - - def openBtnAction(self): - if not self.offline: - self.pause = 1 # pause while open if online - self.pauseBtn.setStyleSheet("background-color: red") - QCoreApplication.processEvents() - - fname = QFileDialog.getOpenFileName(self, 'Open file', '.', "Data files (*.npz)") - if fname is None: - return - if np.size(fname) != 2: - return - if len(fname[0])<=0: - return - - npzfile = np.load(fname[0]) - - # verify scope plugin - if npzfile['plugin'] != "FFT": - print ("Invalid data type (wrong plugin type)") - return - - # File valid - self.rawdataX = npzfile['rawdataX'] - self.rawdataY = npzfile['rawdataY'] - self.spectX = npzfile['spectX'] - self.spectY = npzfile['spectY'] - self.sourceStr = str(npzfile['sourceStr']) - self.sampleRate = npzfile['sampleRate'] - self.NFFT = npzfile['NFFT'] - self.mode = npzfile['mode'] - self.pvPrefixStr = str(npzfile['pvPrefixStr']) - self.fftPluginId = npzfile['fftPluginId'] - - self.buildPvNames() - - # trigg draw - self.comSignalMode.data_signal.emit(self.mode) - self.comSignalSpectX.data_signal.emit(self.spectX) - self.comSignalSpectY.data_signal.emit(self.spectY) - self.comSignalRawData.data_signal.emit(self.rawdataY) - - self.setStatusOfWidgets() - return - - def saveBtnAction(self): - fname = QFileDialog.getSaveFileName(self, 'Save file', '.', "Data files (*.npz)") - if fname is None: - return - if np.size(fname) != 2: - return - if len(fname[0])<=0: - return - # Save all relevant data - np.savez(fname[0], - plugin = "FFT", - rawdataX = self.rawdataX, - rawdataY = self.rawdataY, - spectX = self.spectX, - spectY = self.spectY, - sourceStr = self.sourceStr, - sampleRate = self.sampleRate, - NFFT = self.NFFT, - mode = self.mode, - pvPrefixStr = self.pvPrefixStr, - fftPluginId = self.fftPluginId - ) - - - return - - ###### Plotting - def plotSpect(self): - if self.spectX is None: - return - if self.spectY is None: - return - - # create an axis for spectrum - if self.axSpect is None: - self.axSpect = self.figure.add_subplot(212) - - # plot data - if self.plottedLineSpect is not None: - self.plottedLineSpect.remove() - - self.plottedLineSpect, = self.axSpect.plot(self.spectX,self.spectY, 'b*-') - self.axSpect.grid(True) - - if self.offline: # No units offline - self.axSpect.set_xlabel(self.pvNameSpectX) - self.axSpect.set_ylabel(self.pvNameSpectY) - else: - self.axSpect.set_xlabel(self.pvNameSpectX +' [' + self.pvSpectX.units + ']') - self.axSpect.set_ylabel(self.pvNameSpectY +' [' + self.pvSpectY.units + ']') - - # refresh canvas - self.canvas.draw() - self.axSpect.autoscale(enable=False) - - def plotRaw(self): - if self.rawdataY is None: - return - - # create an axis for spectrum - if self.axRaw is None: - self.axRaw = self.figure.add_subplot(211) - - # plot data - if self.plottedLineRaw is not None: - self.plottedLineRaw.remove() - - self.plottedLineRaw, = self.axRaw.plot(self.rawdataX,self.rawdataY, 'b*-') - self.axRaw.grid(True) - - self.axRaw.set_xlabel('Time [s]') - if self.offline: # No units offline - self.axRaw.set_ylabel(self.pvNameRawDataY) - else: - self.axRaw.set_ylabel(self.pvNameRawDataY +' [' + self.pvRawData.units + ']') - - # refresh canvas - self.canvas.draw() - self.allowSave = True - self.axRaw.autoscale(enable=True) - -def printOutHelp(): - print("ecmcFFTMainGui: Plots waveforms of FFT data (updates on Y data callback). ") - print("python ecmcFFTMainGui.py ") - print(": Ioc prefix ('IOC_TEST:')") - print(" : Id of fft plugin ('0')") - print("example : python ecmcFFTMainGui.py 'IOC_TEST:' '0'") - print("Will connect to Pvs: Plugin-FFT-*") - -if __name__ == "__main__": - import sys - prefix = None - fftid = None - if len(sys.argv) == 1: - prefix = None - fftid = None - elif len(sys.argv) == 3: - prefix = sys.argv[1] - fftid = int(sys.argv[2]) - else: - printOutHelp() - sys.exit() - app = QtWidgets.QApplication(sys.argv) - window=ecmcFFTMainGui(prefix=prefix,fftPluginId=fftid) - window.show() - sys.exit(app.exec_()) diff --git a/tools/testdata.npz b/tools/testdata.npz deleted file mode 100644 index 3ae997e..0000000 Binary files a/tools/testdata.npz and /dev/null differ