Surface NMR processing and inversion GUI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

akvoGUI.py 47KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. #/usr/bin/env python
  2. import sys
  3. import readline
  4. try:
  5. from akvo.gui.main_ui import Ui_MainWindow
  6. uicerr = False
  7. except: # Fallback
  8. from akvo.gui.mainui import Ui_MainWindow
  9. uicerr = """
  10. USING THE DEFAULT GUI FILES, AKVO MAY NOT WORK CORRECTLY!
  11. See INSTALL.txt for details regarding GUI configuration
  12. if you are encountering problems.
  13. Clicking ignore will prevent this warning from showing
  14. each time you launch Akvo.
  15. """
  16. import matplotlib
  17. #matplotlib.use("QT4Agg")
  18. from PyQt5 import QtCore, QtGui, QtWidgets
  19. import numpy as np
  20. import time
  21. import os
  22. from copy import deepcopy
  23. from matplotlib.backends.backend_qt4 import NavigationToolbar2QT #as NavigationToolbar
  24. import datetime, time
  25. import yaml
  26. from akvo.tressel import mrsurvey
  27. import pkg_resources # part of setuptools
  28. version = pkg_resources.require("Akvo")[0].version
  29. # Writes out numpy arrays into Eigen vectors as serialized by Lemma
  30. class MatrixXr(yaml.YAMLObject):
  31. yaml_tag = u'!MatrixXr'
  32. def __init__(self, name, hp, ac, attacks):
  33. self.name = name
  34. self.hp = hp
  35. self.ac = ac
  36. self.attacks = attacks
  37. def __repr__(self):
  38. return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)
  39. class VectorXr(yaml.YAMLObject):
  40. yaml_tag = r'VectorXr'
  41. def __init__(self, array):
  42. self.size = np.shape(array)[0]
  43. self.data = array.tolist()
  44. def __repr__(self):
  45. # Converts to numpy array on import
  46. return "np.array(%r)" % (self.data)
  47. try:
  48. import thread
  49. except ImportError:
  50. import _thread as thread #Py3K compatibility
  51. class MyPopup(QtWidgets.QWidget):
  52. def __init__(self, name):
  53. super().__init__()
  54. self.name = name
  55. self.initUI()
  56. def initUI(self):
  57. lblName = QtWidgets.QLabel(self.name, self)
  58. class ApplicationWindow(QtWidgets.QMainWindow):
  59. def __init__(self):
  60. QtWidgets.QMainWindow.__init__(self)
  61. self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
  62. akvohome = os.path.expanduser("~") + "/.akvo"
  63. if not os.path.exists(akvohome):
  64. os.makedirs(akvohome)
  65. self.ui = Ui_MainWindow()
  66. self.ui.setupUi(self)
  67. if uicerr != False and not os.path.exists(akvohome+"/pyuic-warned"):
  68. reply = QtGui.QMessageBox.warning(self, 'Warning', uicerr, QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ignore)
  69. if reply == 1024: # "0x400" in hex
  70. pass
  71. elif reply == 1048576: # "0x100000" in hex
  72. warn = open( akvohome+"/pyuic-warned" ,"w" )
  73. warn.write("Gui files were not compiled locally using pyuic! Further warnings have been supressed")
  74. warn.close()
  75. self.RAWDataProc = None
  76. # initialise some stuff
  77. self.ui.lcdNumberTauPulse2.setEnabled(0)
  78. self.ui.lcdNumberTauPulse1.setEnabled(0)
  79. self.ui.lcdNumberNuTx.setEnabled(0)
  80. self.ui.lcdNumberTuneuF.setEnabled(0)
  81. self.ui.lcdNumberSampFreq.setEnabled(0)
  82. self.ui.lcdNumberTauDelay.setEnabled(0)
  83. self.ui.lcdNumberNQ.setEnabled(0)
  84. #MAK 20170126: add in a list to hold processing steps
  85. self.logText = []
  86. ####################
  87. # Make connections #
  88. ####################
  89. # Menu items
  90. self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset)
  91. self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess)
  92. self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess)
  93. self.ui.actionExport_Preprocessed_Dataset.setEnabled(False)
  94. self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess)
  95. self.ui.actionAboutAkvo.triggered.connect(self.about)
  96. # Buttons
  97. # #QtCore.QObject.connect(self.ui.fullWorkflowPushButton, QtCore.SIGNAL("clicked()"), self.preprocess )
  98. self.ui.loadDataPushButton.pressed.connect(self.loadRAW)
  99. self.ui.sumDataGO.pressed.connect( self.sumDataChans )
  100. self.ui.bandPassGO.pressed.connect( self.bandPassFilter )
  101. self.ui.filterDesignPushButton.pressed.connect( self.designFilter )
  102. self.ui.fdDesignPushButton.pressed.connect( self.designFDFilter )
  103. self.ui.downSampleGO.pressed.connect( self.downsample )
  104. self.ui.windowFilterGO.pressed.connect( self.windowFilter )
  105. # self.ui.despikeGO.pressed.connect( self.despikeFilter ) # use smart stack instead
  106. self.ui.adaptGO.pressed.connect( self.adaptFilter )
  107. self.ui.adaptFDGO.pressed.connect( self.adaptFilterFD )
  108. self.ui.qdGO.pressed.connect( self.quadDet )
  109. self.ui.gateIntegrateGO.pressed.connect( self.gateIntegrate )
  110. self.ui.calcQGO.pressed.connect( self.calcQ )
  111. self.ui.FDSmartStackGO.pressed.connect( self.FDSmartStack )
  112. self.ui.plotQD.setEnabled(False)
  113. self.ui.plotQD.pressed.connect( self.plotQD )
  114. self.ui.plotGI.setEnabled(False)
  115. self.ui.plotGI.pressed.connect( self.plotGI )
  116. # Add progressbar to statusbar
  117. self.ui.barProgress = QtWidgets.QProgressBar()
  118. self.ui.statusbar.addPermanentWidget(self.ui.barProgress, 0);
  119. self.ui.barProgress.setMaximumSize(100, 16777215);
  120. self.ui.barProgress.hide();
  121. self.ui.mplwidget_navigator.setCanvas(self.ui.mplwidget)
  122. self.ui.mplwidget_navigator_2.setCanvas(self.ui.mplwidget_2)
  123. ##########################################################################
  124. # modelling Table
  125. self.ui.loopTableWidget.setRowCount(40)
  126. self.ui.loopTableWidget.setColumnCount(5)
  127. self.ui.loopTableWidget.setHorizontalHeaderLabels( ["ch. tag", "Northing [m]","Easting [m]","Height [m]", "Radius"] )
  128. self.ui.loopTableWidget.cellChanged.connect(self.cellChanged)
  129. self.ui.loopTableWidget.setDragDropOverwriteMode(False)
  130. self.ui.loopTableWidget.setDragEnabled(True)
  131. self.ui.loopTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  132. ##########################################################################
  133. # layer Table
  134. self.ui.layerTableWidget.setRowCount(80)
  135. self.ui.layerTableWidget.setColumnCount(3)
  136. self.ui.layerTableWidget.setHorizontalHeaderLabels( [r"top [m]", r"bottom [m]", "σ [ Ωm]" ] )
  137. self.ui.layerTableWidget.setDragDropOverwriteMode(False)
  138. self.ui.layerTableWidget.setDragEnabled(True)
  139. self.ui.layerTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  140. pCell = QtWidgets.QTableWidgetItem()
  141. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  142. pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  143. #pCell.setBackground( QtGui.QColor("lightblue").lighter(125) )
  144. pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  145. self.ui.layerTableWidget.setItem(0, 1, pCell)
  146. for ir in range(1, 80):
  147. for ic in range(0, 3):
  148. pCell = QtWidgets.QTableWidgetItem()
  149. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  150. pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  151. pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  152. self.ui.layerTableWidget.setItem(ir, ic, pCell)
  153. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  154. def sigmaCellChanged(self):
  155. self.ui.layerTableWidget.cellChanged.disconnect(self.sigmaCellChanged)
  156. # TODO consider building the model whenever this is called. Would be nice to be able to
  157. # do that. Would require instead dist of T2 I guess.
  158. jj = self.ui.layerTableWidget.currentColumn()
  159. ii = self.ui.layerTableWidget.currentRow()
  160. val = "class 'NoneType'>"
  161. try:
  162. val = eval (str( self.ui.layerTableWidget.item(ii, jj).text() ))
  163. except:
  164. #if jj != 0:
  165. # Error = QtWidgets.QMessageBox()
  166. # Error.setWindowTitle("Error!")
  167. # Error.setText("Non-numeric value encountered")
  168. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  169. return
  170. if jj == 1:
  171. #item.setFlags(QtCore.Qt.ItemIsEnabled)
  172. pCell = self.ui.layerTableWidget.item(ii, jj)
  173. pCell.setBackground( QtGui.QColor("white"))
  174. pCell = self.ui.layerTableWidget.item(ii+1, jj-1)
  175. if str(type(pCell)) == "<class 'NoneType'>":
  176. pCell = QtWidgets.QTableWidgetItem()
  177. pCell.setFlags(QtCore.Qt.ItemIsEnabled)
  178. self.ui.layerTableWidget.setItem(ii+1, jj-1, pCell)
  179. if ii == 0:
  180. pCell.setText(str(val))
  181. #pCell3 = self.ui.layerTableWidget.item(ii+1, jj)
  182. #print ("setting", ii, jj, type(pCell3))
  183. #print ( "setting", ii, jj, type(pCell3))
  184. #pCell3.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  185. #pCell3.setFlags( QtCore.Qt.ItemIsEditable )
  186. elif ii > 0:
  187. val2 = eval (str( self.ui.layerTableWidget.item(ii-1, jj).text() ))
  188. #print ("val2", val2, val, type(val))
  189. #if str(type(pCell)) == "<class 'NoneType'>":
  190. if type(val) == str or val > val2:
  191. pCell.setText(str(val))
  192. else:
  193. Error = QtWidgets.QMessageBox()
  194. Error.setWindowTitle("Error!")
  195. Error.setText("Non-increasing layer detected")
  196. Error.setDetailedText("Each layer interface must be below the one above it.")
  197. Error.exec_()
  198. pCell2 = self.ui.layerTableWidget.item(ii, jj)
  199. pCell2.setText(str(""))
  200. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  201. return
  202. print("I'm here joey")
  203. # enable next layer
  204. pCell4 = self.ui.layerTableWidget.item(ii+1, jj)
  205. pCell4.setBackground( QtGui.QColor("lightblue") ) #.lighter(110))
  206. pCell4.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  207. pCell5 = self.ui.layerTableWidget.item(ii+1, jj+1)
  208. pCell5.setBackground( QtGui.QColor("white"))
  209. pCell5.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  210. print("ii", ii, "jj", jj)
  211. if ii == 0 and jj == 0:
  212. pCell = self.ui.layerTableWidget.item(0, 1)
  213. pCell.setBackground( QtGui.QColor("lightblue")) #.lighter(110) )
  214. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  215. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  216. def cellChanged(self):
  217. # TODO consider building the model whenever this is called. Would be nice to be able to
  218. # do that. Would require instead dist of T2 I guess.
  219. jj = self.ui.loopTableWidget.currentColumn()
  220. ii = self.ui.loopTableWidget.currentRow()
  221. #if self.ui.loopTableWidget.item(ii, jj) == None:
  222. # return
  223. try:
  224. eval (str( self.ui.loopTableWidget.item(ii, jj).text() ))
  225. except:
  226. if jj != 0:
  227. Error = QtWidgets.QMessageBox()
  228. Error.setWindowTitle("Error!")
  229. Error.setText("Non-numeric value encountered")
  230. Error.setDetailedText("Modelling parameters must be able to be cast into numeric values.")
  231. Error.exec_()
  232. self.plotLoops()
  233. def plotLoops(self):
  234. #self.ui.mplwidget_3.fig.clear()
  235. self.ui.mplwidget_3.ax1.clear()
  236. self.ui.mplwidget_3.ax2.clear()
  237. nor = dict()
  238. eas = dict()
  239. dep = dict()
  240. for ii in range( self.ui.loopTableWidget.rowCount() ):
  241. for jj in range( self.ui.loopTableWidget.columnCount() ):
  242. tp = type(self.ui.loopTableWidget.item(ii, jj))
  243. if str(tp) == "<class 'NoneType'>": # ugly hack needed by PySide for some strange reason.
  244. pass #print ("NONE")
  245. else:
  246. if jj == 0:
  247. idx = self.ui.loopTableWidget.item(ii, 0).text()
  248. if idx not in nor.keys():
  249. nor[idx] = list()
  250. eas[idx] = list()
  251. dep[idx] = list()
  252. if jj == 1:
  253. nor[idx].append( eval(self.ui.loopTableWidget.item(ii, 1).text()) )
  254. elif jj == 2:
  255. eas[idx].append( eval(self.ui.loopTableWidget.item(ii, 2).text()) )
  256. elif jj == 3:
  257. dep[idx].append( eval(self.ui.loopTableWidget.item(ii, 3).text()) )
  258. for ii in nor.keys():
  259. try:
  260. self.ui.mplwidget_3.ax1.plot( np.array(nor[ii]), np.array(eas[ii]) )
  261. except:
  262. pass
  263. self.ui.mplwidget_3.draw()
  264. def about(self):
  265. # TODO proper popup with info
  266. #self.w = MyPopup("""About Akvo \n
  267. # Akvo is an open source project developed primarily by Trevor Irons.
  268. #""")
  269. #self.w.setGeometry(100, 100, 400, 200)
  270. #self.w.show()
  271. # Just a splash screen for now
  272. logo = pkg_resources.resource_filename(__name__, 'akvo_about.png')
  273. pixmap = QtGui.QPixmap(logo)
  274. self.splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  275. self.splash.show()
  276. def connectGMRDataProcessor(self):
  277. self.RAWDataProc = mrsurvey.GMRDataProcessor()
  278. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  279. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  280. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  281. self.RAWDataProc.updateProcTrigger.connect(self.updateProc)
  282. def openGMRRAWDataset(self):
  283. try:
  284. with open('.gmr.last.path') as f:
  285. fpath = f.readline()
  286. pass
  287. except IOError as e:
  288. fpath = '.'
  289. self.headerstr = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', fpath)[0] # arg2 = File Type 'All Files (*)'
  290. self.ui.headerFileTextBrowser.clear()
  291. self.ui.headerFileTextBrowser.append(self.headerstr)
  292. if len(self.headerstr) == 0:
  293. return
  294. # clear the processing log
  295. self.ui.logTextBrowser.clear()
  296. self.logText = [] #MAK 20170126
  297. path,filen=os.path.split(str(self.headerstr))
  298. f = open('.gmr.last.path', 'w')
  299. f.write( str(self.headerstr) ) # prompt last file
  300. self.connectGMRDataProcessor()
  301. self.RAWDataProc.readHeaderFile(str(self.headerstr))
  302. # If we got this far, enable all the widgets
  303. self.ui.lcdNumberTauPulse1.setEnabled(True)
  304. self.ui.lcdNumberNuTx.setEnabled(True)
  305. self.ui.lcdNumberTuneuF.setEnabled(True)
  306. self.ui.lcdNumberSampFreq.setEnabled(True)
  307. self.ui.lcdNumberNQ.setEnabled(True)
  308. self.ui.headerFileBox.setEnabled(True)
  309. self.ui.inputRAWParametersBox.setEnabled(True)
  310. self.ui.loadDataPushButton.setEnabled(True)
  311. # make plots as you import the dataset
  312. self.ui.plotImportCheckBox.setEnabled(True)
  313. self.ui.plotImportCheckBox.setChecked(True)
  314. # Update info from the header into the GUI
  315. self.ui.pulseTypeTextBrowser.clear()
  316. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  317. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  318. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  319. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  320. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  321. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  322. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  323. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  324. if self.RAWDataProc.pulseType != "FID":
  325. self.ui.lcdNumberTauPulse2.setEnabled(1)
  326. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  327. self.ui.lcdNumberTauDelay.setEnabled(1)
  328. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  329. self.ui.FIDProcComboBox.clear()
  330. if self.RAWDataProc.pulseType == "4PhaseT1":
  331. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  332. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2")
  333. self.ui.FIDProcComboBox.insertItem(2, "Both")
  334. self.ui.FIDProcComboBox.setCurrentIndex (1)
  335. elif self.RAWDataProc.pulseType == "FID":
  336. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  337. self.ui.FIDProcComboBox.setCurrentIndex (0)
  338. def ExportPreprocess(self):
  339. try:
  340. with open('.akvo.last.yaml.path') as f:
  341. fpath = f.readline()
  342. pass
  343. except IOError as e:
  344. fpath = '.'
  345. fdir = os.path.dirname(fpath)
  346. # Pickle the preprocessed data dictionary
  347. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Processed data (*.yaml)")[0]
  348. spath,filen=os.path.split(str(SaveStr))
  349. f = open('.akvo.last.yaml.path', 'w')
  350. f.write( str(spath) ) # prompt last file
  351. INFO = {}
  352. INFO["headerstr"] = str(self.headerstr)
  353. INFO["pulseType"] = self.RAWDataProc.pulseType
  354. INFO["transFreq"] = self.RAWDataProc.transFreq.tolist()
  355. INFO["pulseLength"] = self.RAWDataProc.pulseLength.tolist()
  356. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance.tolist()
  357. #INFO["samp"] = self.RAWDataProc.samp
  358. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  359. #INFO["deadTime"] = self.RAWDataProc.deadTime
  360. INFO["transFreq"] = self.RAWDataProc.transFreq.tolist()
  361. INFO["processed"] = "Akvo v. 1.0, on " + time.strftime("%d/%m/%Y")
  362. #INFO["log"] = self.logText #MAK 20170128 # TI moved to direct write, this is already YAML compliant
  363. # Pulse current info
  364. ip = 0
  365. INFO["Pulses"] = {}
  366. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  367. qq = []
  368. qv = []
  369. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  370. #for istack in self.RAWDataProc.DATADICT["stacks"]:
  371. # print ("stack q", self.RAWDataProc.DATADICT[pulse]["Q"][ipm,istack-1])
  372. qq.append(np.mean( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]) )
  373. qv.append(np.std( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]/self.RAWDataProc.pulseLength[ip] ))
  374. INFO["Pulses"][pulse] = {}
  375. INFO["Pulses"][pulse]["units"] = "A"
  376. INFO["Pulses"][pulse]["current"] = VectorXr(np.array(qq)/self.RAWDataProc.pulseLength[ip])
  377. INFO["Pulses"][pulse]["variance"] = VectorXr(np.array(qv))
  378. ip += 1
  379. # Data
  380. if self.RAWDataProc.gated == True:
  381. INFO["Gated"] = {}
  382. INFO["Gated"]["abscissa units"] = "ms"
  383. INFO["Gated"]["data units"] = "nT"
  384. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  385. INFO["Gated"][pulse] = {}
  386. INFO["Gated"][pulse]["abscissa"] = VectorXr( self.RAWDataProc.GATEDABSCISSA )
  387. INFO["Gated"][pulse]["windows"] = VectorXr( self.RAWDataProc.GATEDWINDOW )
  388. for ichan in self.RAWDataProc.DATADICT[pulse]["chan"]:
  389. INFO["Gated"][pulse]["Chan. " + str(ichan)] = {}
  390. INFO["Gated"][pulse]["Chan. " + str(ichan)]["STD"] = VectorXr( np.std(self.RAWDataProc.GATED[ichan]["NR"], axis=0) )
  391. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  392. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " CA"] = VectorXr(self.RAWDataProc.GATED[ichan]["CA"][ipm])
  393. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " RE"] = VectorXr(self.RAWDataProc.GATED[ichan]["RE"][ipm])
  394. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IM"] = VectorXr(self.RAWDataProc.GATED[ichan]["IM"][ipm])
  395. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IP"] = VectorXr(self.RAWDataProc.GATED[ichan]["IP"][ipm])
  396. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " NR"] = VectorXr(self.RAWDataProc.GATED[ichan]["NR"][ipm])
  397. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " STD" ] = VectorXr(self.RAWDataProc.GATED[ichan]["SIGMA"][ipm])
  398. # we have gated data
  399. # Window edges
  400. # Window centres
  401. with open(SaveStr, 'w') as outfile:
  402. for line in self.logText:
  403. outfile.write(line+"\n")
  404. yaml.dump(INFO, outfile, default_flow_style=False)
  405. def SavePreprocess(self):
  406. self.Log( ["Saved:" + datetime.datetime.now().isoformat()] )
  407. import pickle, os
  408. try:
  409. with open('.akvo.last.path') as f:
  410. fpath = f.readline()
  411. pass
  412. except IOError as e:
  413. fpath = '.'
  414. fdir = os.path.dirname(fpath)
  415. # Pickle the preprocessed data dictionary
  416. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Pickle (*.dmp)")
  417. print(SaveStr)
  418. spath,filen=os.path.split(str(SaveStr[0]))
  419. f = open('.akvo.last.path', 'w')
  420. f.write( str(spath) ) # prompt last file
  421. save = open(SaveStr[0], 'wb')
  422. # Add some extra info
  423. INFO = {}
  424. INFO["pulseType"] = self.RAWDataProc.pulseType
  425. INFO["transFreq"] = self.RAWDataProc.transFreq
  426. INFO["pulseLength"] = self.RAWDataProc.pulseLength
  427. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance
  428. INFO["samp"] = self.RAWDataProc.samp
  429. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  430. INFO["deadTime"] = self.RAWDataProc.deadTime
  431. INFO["transFreq"] = self.RAWDataProc.transFreq
  432. INFO["headerstr"] = str(self.headerstr)
  433. INFO["log"] = self.logText #MAK 20170127
  434. self.RAWDataProc.DATADICT["INFO"] = INFO
  435. pickle.dump(self.RAWDataProc.DATADICT, save)
  436. save.close()
  437. # Export XML file suitable for USGS ScienceBase Data Release
  438. def ExportXML(self):
  439. return 42
  440. def OpenPreprocess(self):
  441. import pickle
  442. try:
  443. with open('.akvo.last.path') as f:
  444. fpath = f.readline()
  445. pass
  446. except IOError as e:
  447. fpath = '.'
  448. #filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', '.')
  449. fpath = QtWidgets.QFileDialog.getOpenFileName(self, 'Open preprocessed file', fpath, r"Pickle Files (*.dmp)")[0]
  450. f = open('.akvo.last.path', 'w')
  451. f.write( str(fpath) ) # prompt last file
  452. self.ui.logTextBrowser.clear()
  453. self.logText = []
  454. if len(fpath) == 0:
  455. return
  456. pfile = open(fpath,'rb')
  457. unpickle = pickle.Unpickler(pfile)
  458. self.connectGMRDataProcessor()
  459. self.RAWDataProc.DATADICT = unpickle.load()
  460. self.RAWDataProc.readHeaderFile(self.RAWDataProc.DATADICT["INFO"]["headerstr"])
  461. self.headerstr = self.RAWDataProc.DATADICT["INFO"]["headerstr"]
  462. self.RAWDataProc.pulseType = self.RAWDataProc.DATADICT["INFO"]["pulseType"]
  463. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  464. self.RAWDataProc.pulseLength = self.RAWDataProc.DATADICT["INFO"]["pulseLength"]
  465. self.RAWDataProc.TuneCapacitance = self.RAWDataProc.DATADICT["INFO"]["TuneCapacitance"]
  466. self.RAWDataProc.samp = self.RAWDataProc.DATADICT["INFO"]["samp"]
  467. self.RAWDataProc.nPulseMoments = self.RAWDataProc.DATADICT["INFO"]["nPulseMoments"]
  468. self.RAWDataProc.deadTime = self.RAWDataProc.DATADICT["INFO"]["deadTime"]
  469. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  470. self.RAWDataProc.dt = 1./self.RAWDataProc.samp
  471. self.dataChan = self.RAWDataProc.DATADICT[ self.RAWDataProc.DATADICT["PULSES"][0] ]["chan"]
  472. #To keep backwards compatibility with prior saved pickles
  473. try:
  474. self.logText = self.RAWDataProc.DATADICT["INFO"]["log"]
  475. for a in self.logText:
  476. self.ui.logTextBrowser.append(str(a))
  477. except KeyError:
  478. pass
  479. self.Log( ["Loaded:" + datetime.datetime.now().isoformat()] )
  480. # If we got this far, enable all the widgets
  481. self.ui.lcdNumberTauPulse1.setEnabled(True)
  482. self.ui.lcdNumberNuTx.setEnabled(True)
  483. self.ui.lcdNumberTuneuF.setEnabled(True)
  484. self.ui.lcdNumberSampFreq.setEnabled(True)
  485. self.ui.lcdNumberNQ.setEnabled(True)
  486. self.ui.headerFileBox.setEnabled(True)
  487. self.ui.inputRAWParametersBox.setEnabled(True)
  488. self.ui.loadDataPushButton.setEnabled(True)
  489. # make plots as you import the dataset
  490. self.ui.plotImportCheckBox.setEnabled(True)
  491. self.ui.plotImportCheckBox.setChecked(True)
  492. # Update info from the header into the GUI
  493. self.ui.pulseTypeTextBrowser.clear()
  494. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  495. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  496. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  497. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  498. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  499. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  500. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  501. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  502. if self.RAWDataProc.pulseType != "FID":
  503. self.ui.lcdNumberTauPulse2.setEnabled(1)
  504. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  505. self.ui.lcdNumberTauDelay.setEnabled(1)
  506. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  507. self.ui.FIDProcComboBox.clear()
  508. if self.RAWDataProc.pulseType == "4PhaseT1":
  509. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  510. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") #, const QVariant & userData = QVariant() )
  511. self.ui.FIDProcComboBox.insertItem(2, "Both") #, const QVariant & userData = QVariant() )
  512. if len( self.RAWDataProc.DATADICT["PULSES"]) == 2:
  513. self.ui.FIDProcComboBox.setCurrentIndex (2)
  514. elif self.RAWDataProc.DATADICT["PULSES"][0] == "Pulse 1":
  515. self.ui.FIDProcComboBox.setCurrentIndex (0)
  516. else:
  517. self.ui.FIDProcComboBox.setCurrentIndex (1)
  518. elif self.RAWDataProc.pulseType == "FID":
  519. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  520. self.ui.FIDProcComboBox.setCurrentIndex (0)
  521. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  522. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  523. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  524. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  525. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  526. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  527. self.enableAll()
  528. def loadRAW(self):
  529. #################################################
  530. # Check to make sure we are ready to process
  531. # Header
  532. if self.RAWDataProc == None:
  533. err_msg = "You need to load a header first."
  534. reply = QtGui.QMessageBox.critical(self, 'Error',
  535. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  536. return
  537. # Stacks
  538. try:
  539. self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]"))
  540. except:
  541. err_msg = "You need to set your stacks correctly.\n" + \
  542. "This should be a Python Numpy interpretable list\n" + \
  543. "of stack indices. For example 1:24 or 1:4,8:24"
  544. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  545. return
  546. # Data Channels
  547. #Chan = np.arange(0,9,1)
  548. try:
  549. self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]"))
  550. except:
  551. #QMessageBox messageBox;
  552. #messageBox.critical(0,"Error","An error has occured !");
  553. #messageBox.setFixedSize(500,200);
  554. #quit_msg = "Are you sure you want to exit the program?"
  555. #reply = QtGui.QMessageBox.question(self, 'Message',
  556. # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  557. err_msg = "You need to set your data channels correctly.\n" + \
  558. "This should be a Python Numpy interpretable list\n" + \
  559. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  560. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  561. "1:3 is not inclusive of 3 and is the same as 1,2 "
  562. reply = QtGui.QMessageBox.critical(self, 'Error',
  563. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  564. return
  565. #############################
  566. # Reference Channels
  567. # TODO make sure no overlap between data and ref channels
  568. self.refChan = np.array( () )
  569. if str(self.ui.refChanLineEdit.text()): # != "none":
  570. try:
  571. self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]"))
  572. except:
  573. err_msg = "You need to set your reference channels correctly.\n" + \
  574. "This should be a Python Numpy interpretable list\n" + \
  575. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  576. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  577. "1:3 is not inclusive of 3 and is the same as 1,2 "
  578. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  579. return
  580. #####################################################
  581. # Load data
  582. self.lock("loading RAW GMR dataset")
  583. if self.RAWDataProc.pulseType == "FID":
  584. self.procThread = thread.start_new_thread(self.RAWDataProc.loadFIDData, \
  585. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  586. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  587. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  588. elif self.RAWDataProc.pulseType == "4PhaseT1":
  589. self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  590. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  591. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  592. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  593. nlogText = []
  594. nlogText.append( "!<AkvoData>" )
  595. nlogText.append( "Akvo_VERSION: " + str(1.0))
  596. nlogText.append( "Import: " )
  597. nlogText.append( " GMR Header: " + self.headerstr )
  598. nlogText.append( " opened: " + datetime.datetime.now().isoformat() )
  599. nlogText.append( " pulse Type: " + str(self.RAWDataProc.pulseType) )
  600. nlogText.append( " stacks: " + str(self.procStacks) )
  601. nlogText.append( " data channels: " + str(self.dataChan) )
  602. nlogText.append( " reference channels: " + str(self.refChan) )
  603. nlogText.append( " pulse records: " + str(self.ui.FIDProcComboBox.currentText()) )
  604. nlogText.append( " instrument dead time: " + str(1e-3 * self.ui.DeadTimeSpinBox.value( )) )
  605. self.Log ( nlogText )
  606. # should be already done
  607. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  608. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  609. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  610. self.ui.ProcessedBox.setEnabled(True)
  611. self.ui.lcdNumberFID1Length.setEnabled(1)
  612. self.ui.lcdNumberFID2Length.setEnabled(1)
  613. self.ui.lcdNumberResampFreq.setEnabled(1)
  614. self.ui.lcdTotalDeadTime.setEnabled(1)
  615. self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) )
  616. #self.ui.lcdNumberFID1Length.display(0)
  617. #self.ui.lcdNumberFID2Length.display(0)
  618. #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  619. self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget)
  620. self.ui.mplwidget.draw()
  621. def Log(self, nlogText):
  622. for line in nlogText:
  623. self.ui.logTextBrowser.append( line )
  624. self.logText.append( line )
  625. def disable(self):
  626. self.ui.BandPassBox.setEnabled(False)
  627. self.ui.downSampleGroupBox.setEnabled(False)
  628. self.ui.windowFilterGroupBox.setEnabled(False)
  629. # self.ui.despikeGroupBox.setEnabled(False)
  630. self.ui.adaptBox.setEnabled(False)
  631. self.ui.adaptFDBox.setEnabled(False)
  632. self.ui.qCalcGroupBox.setEnabled(False)
  633. self.ui.FDSmartStackGroupBox.setEnabled(False)
  634. self.ui.sumDataBox.setEnabled(False)
  635. self.ui.qdGroupBox.setEnabled(False)
  636. self.ui.gateBox.setEnabled(False)
  637. def enableAll(self):
  638. self.enableDSP()
  639. self.enableQC()
  640. def enableDSP(self):
  641. # Bandpass filter
  642. self.ui.BandPassBox.setEnabled(True)
  643. self.ui.BandPassBox.setChecked(True)
  644. self.ui.bandPassGO.setEnabled(False) # need to design first
  645. self.ui.plotBP.setEnabled(True)
  646. self.ui.plotBP.setChecked(True)
  647. # downsample
  648. self.ui.downSampleGroupBox.setEnabled(True)
  649. self.ui.downSampleGroupBox.setChecked(True)
  650. # window
  651. self.ui.windowFilterGroupBox.setEnabled(True)
  652. self.ui.windowFilterGroupBox.setChecked(True)
  653. # Despike
  654. # self.ui.despikeGroupBox.setEnabled(True)
  655. # self.ui.despikeGroupBox.setChecked(False)
  656. # Adaptive filtering
  657. self.ui.adaptBox.setEnabled(True)
  658. self.ui.adaptBox.setChecked(True)
  659. # FD Adaptive filtering
  660. self.ui.adaptFDBox.setEnabled(True)
  661. self.ui.adaptFDBox.setChecked(True)
  662. # sum group box
  663. try:
  664. if len(self.dataChan) > 1:
  665. self.ui.sumDataBox.setEnabled(True)
  666. self.ui.sumDataBox.setChecked(True)
  667. except:
  668. pass
  669. # Quadrature Detect
  670. self.ui.qdGroupBox.setEnabled(True)
  671. self.ui.qdGroupBox.setChecked(True)
  672. self.enableQC()
  673. def enableQC(self):
  674. # Q calc
  675. self.ui.qCalcGroupBox.setEnabled(True)
  676. self.ui.qCalcGroupBox.setChecked(True)
  677. # FD SmartStack
  678. self.ui.FDSmartStackGroupBox.setEnabled(True)
  679. self.ui.FDSmartStackGroupBox.setChecked(True)
  680. # Quadrature detect
  681. try:
  682. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  683. np.shape(self.RAWDataProc.DATADICT[pulse]["Q"])
  684. self.RAWDataProc.DATADICT["stack"]
  685. self.ui.qdGroupBox.setEnabled(True)
  686. self.ui.qdGroupBox.setChecked(True)
  687. except:
  688. self.ui.qdGroupBox.setEnabled(False)
  689. self.ui.qdGroupBox.setChecked(False)
  690. # Gating
  691. try:
  692. self.RAWDataProc.DATADICT["CA"]
  693. self.ui.gateBox.setEnabled(True)
  694. self.ui.gateBox.setChecked(True)
  695. except:
  696. self.ui.gateBox.setEnabled(False)
  697. self.ui.gateBox.setChecked(False)
  698. def despikeFilter(self):
  699. self.lock("despike filter")
  700. thread.start_new_thread(self.RAWDataProc.despike, \
  701. (self.ui.windowSpinBox.value(), \
  702. self.ui.thresholdSpinBox.value(), \
  703. str(self.ui.replComboBox.currentText()), \
  704. self.ui.rollOnSpinBox.value(), \
  705. self.ui.despikeInterpWinSpinBox.value(),
  706. self.ui.mplwidget))
  707. def calcQ(self):
  708. self.lock("pulse moment calculation")
  709. thread.start_new_thread(self.RAWDataProc.effectivePulseMoment, \
  710. (self.ui.CentralVSpinBox.value(), \
  711. self.ui.mplwidget_2))
  712. def FDSmartStack(self):
  713. self.lock("time-domain smart stack")
  714. nlogText = []
  715. nlogText.append("TD_stack: ")
  716. nlogText.append(" outlier: " + str( self.ui.outlierTestCB.currentText() ) )
  717. nlogText.append(" cutoff: " + str( self.ui.MADCutoff.value() ) )
  718. self.Log(nlogText)
  719. thread.start_new_thread(self.RAWDataProc.TDSmartStack, \
  720. (str(self.ui.outlierTestCB.currentText()), \
  721. self.ui.MADCutoff.value(),
  722. self.ui.mplwidget_2))
  723. def adaptFilter(self):
  724. self.lock("TD noise cancellation filter")
  725. nlogText = []
  726. nlogText.append("TD_noise_cancellation: ")
  727. nlogText.append(" n_Taps: " + str(self.ui.MTapsSpinBox.value()) )
  728. nlogText.append(" lambda: " + str(self.ui.adaptLambdaSpinBox.value()) )
  729. nlogText.append(" truncate: " + str(self.ui.adaptTruncateSpinBox.value()) )
  730. nlogText.append(" mu: " + str(self.ui.adaptMuSpinBox.value()) )
  731. nlogText.append(" PCA: " + str(self.ui.PCAComboBox.currentText()) )
  732. self.Log(nlogText)
  733. thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
  734. (self.ui.MTapsSpinBox.value(), \
  735. self.ui.adaptLambdaSpinBox.value(), \
  736. self.ui.adaptTruncateSpinBox.value(), \
  737. self.ui.adaptMuSpinBox.value(), \
  738. str(self.ui.PCAComboBox.currentText()), \
  739. self.ui.mplwidget))
  740. def sumDataChans(self):
  741. self.lock("Summing data channels")
  742. nlogText = []
  743. nlogText.append("Data_sum: ")
  744. nlogText.append( " summed_channel: " + str(self.dataChan[0]) )
  745. self.Log(nlogText)
  746. self.dataChan = [self.dataChan[0]]
  747. self.ui.sumDataBox.setEnabled(False)
  748. thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) )
  749. def adaptFilterFD(self):
  750. self.lock("FD noise cancellation filter")
  751. thread.start_new_thread(self.RAWDataProc.adaptiveFilterFD, \
  752. (str(self.ui.windowTypeComboBox.currentText()), \
  753. self.ui.windowBandwidthSpinBox.value(), \
  754. self.ui.CentralVSpinBox.value(), \
  755. self.ui.mplwidget))
  756. def bandPassFilter(self):
  757. self.lock("bandpass filter")
  758. nlogText = []
  759. nlogText.append("bandpass_filter: ")
  760. nlogText.append(" central_nu: "+str(self.ui.CentralVSpinBox.value()))
  761. nlogText.append(" passband: "+str(self.ui.passBandSpinBox.value()) )
  762. nlogText.append(" stopband: "+str(self.ui.stopBandSpinBox.value()) )
  763. nlogText.append(" gpass: "+str(self.ui.gpassSpinBox.value()) )
  764. nlogText.append(" gstop: "+str(self.ui.gstopSpinBox.value()) )
  765. nlogText.append(" type: "+str(self.ui.fTypeComboBox.currentText()) )
  766. self.Log(nlogText)
  767. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
  768. self.ui.lcdTotalDeadTime.display( nv )
  769. thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
  770. (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
  771. def downsample(self):
  772. self.lock("resampling")
  773. nlogText = list(['Resample: '])
  774. nlogText.append(" downsample_factor: " + str(self.ui.downSampleSpinBox.value() ) )
  775. nlogText.append(" truncate_length: " + str( self.ui.truncateSpinBox.value() ) )
  776. self.Log(nlogText)
  777. thread.start_new_thread(self.RAWDataProc.downsample, \
  778. (self.ui.truncateSpinBox.value(), \
  779. self.ui.downSampleSpinBox.value(),
  780. self.ui.mplwidget))
  781. def quadDet(self):
  782. self.lock("quadrature detection")
  783. nlogText = []
  784. nlogText.append("quadrature_detection: ")
  785. nlogText.append(" trim: " + str( self.ui.trimSpin.value() ))
  786. #nlogText.append(" representation:" + str( self.ui.QDType.currentText() ))
  787. self.Log(nlogText)
  788. thread.start_new_thread(self.RAWDataProc.quadDet, \
  789. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2))
  790. self.ui.plotQD.setEnabled(True)
  791. def plotQD(self):
  792. self.lock("plot QD")
  793. thread.start_new_thread(self.RAWDataProc.plotQuadDet, \
  794. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2))
  795. def gateIntegrate(self):
  796. self.lock("gate integration")
  797. nlogText = []
  798. nlogText.append("gate_integrate: ")
  799. nlogText.append(" gpd: " + str(self.ui.GPDspinBox.value( ) ))
  800. self.Log(nlogText)
  801. thread.start_new_thread(self.RAWDataProc.gateIntegrate, \
  802. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), self.ui.mplwidget_2))
  803. self.ui.actionExport_Preprocessed_Dataset.setEnabled(True)
  804. self.ui.plotGI.setEnabled(True)
  805. def plotGI(self):
  806. self.lock("plot gate integrate")
  807. thread.start_new_thread(self.RAWDataProc.plotGateIntegrate, \
  808. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), \
  809. self.ui.QDType_2.currentIndex(), self.ui.mplwidget_2))
  810. def designFilter(self):
  811. [bord, fe] = self.RAWDataProc.designFilter( \
  812. self.ui.CentralVSpinBox.value(), \
  813. self.ui.passBandSpinBox.value(), \
  814. self.ui.stopBandSpinBox.value(), \
  815. self.ui.gpassSpinBox.value(), \
  816. self.ui.gstopSpinBox.value(), \
  817. str(self.ui.fTypeComboBox.currentText()),
  818. self.ui.mplwidget)
  819. self.ui.lcdNumberFilterOrder.display(bord)
  820. self.ui.lcdNumberFTauDead.display(1e3*fe)
  821. #self.ui.lcdNumberFilterOrder.display(bord)
  822. self.ui.bandPassGO.setEnabled(1)
  823. # self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  824. def windowFilter(self):
  825. self.lock("window filter")
  826. nlogText = []
  827. nlogText.append("FD_window: ")
  828. nlogText.append(" type: " + str(self.ui.windowTypeComboBox.currentText()) )
  829. nlogText.append(" width: " + str(self.ui.windowBandwidthSpinBox.value()) )
  830. nlogText.append(" centre: " + str(self.ui.CentralVSpinBox.value() ))
  831. self.Log(nlogText)
  832. thread.start_new_thread(self.RAWDataProc.windowFilter, \
  833. (str(self.ui.windowTypeComboBox.currentText()), \
  834. self.ui.windowBandwidthSpinBox.value(), \
  835. self.ui.CentralVSpinBox.value(), \
  836. self.ui.mplwidget))
  837. def designFDFilter(self):
  838. # thread.start_new_thread(self.RAWDataProc.computeWindow, ( \
  839. # "Pulse 1",
  840. # self.ui.windowBandwidthSpinBox.value(), \
  841. # self.ui.CentralVSpinBox.value(), \
  842. # str(self.ui.windowTypeComboBox.currentText()), \
  843. # self.ui.mplwidget ))
  844. a,b,c,d,dead = self.RAWDataProc.computeWindow( \
  845. "Pulse 1",
  846. self.ui.windowBandwidthSpinBox.value(), \
  847. self.ui.CentralVSpinBox.value(), \
  848. str(self.ui.windowTypeComboBox.currentText()), \
  849. self.ui.mplwidget )
  850. self.ui.lcdWinDead.display(dead)
  851. def updateProgressBar(self, percent):
  852. self.ui.barProgress.setValue(percent)
  853. def updateProc(self):
  854. if str(self.ui.FIDProcComboBox.currentText()) == "Pulse 1":
  855. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  856. elif str(self.ui.FIDProcComboBox.currentText()) == "Pulse 2":
  857. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  858. else:
  859. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  860. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  861. self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  862. def doneStatus(self): # unlocks GUI
  863. self.ui.statusbar.clearMessage ( )
  864. self.ui.barProgress.hide()
  865. self.updateProc()
  866. self.enableAll()
  867. def lock(self, string):
  868. self.ui.statusbar.showMessage ( string )
  869. self.ui.barProgress.show()
  870. self.ui.barProgress.setValue(0)
  871. self.disable()
  872. def unlock(self):
  873. self.ui.statusbar.clearMessage ( )
  874. self.ui.barProgress.hide()
  875. self.enableAll()
  876. def done(self):
  877. self.ui.statusbar.showMessage ( "" )
  878. ################################################################
  879. ################################################################
  880. # Boiler plate main function
  881. import pkg_resources
  882. from pkg_resources import resource_string
  883. import matplotlib.image as mpimg
  884. import matplotlib.pyplot as plt
  885. def main():
  886. # splash screen logo
  887. logo = pkg_resources.resource_filename(__name__, 'akvo.png')
  888. logo2 = pkg_resources.resource_filename(__name__, 'akvo2.png')
  889. qApp = QtWidgets.QApplication(sys.argv)
  890. ssplash = False
  891. if ssplash:
  892. pixmap = QtGui.QPixmap(logo)
  893. splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  894. splash.show()
  895. aw = ApplicationWindow()
  896. img=mpimg.imread(logo)
  897. for ax in [ aw.ui.mplwidget ]:
  898. ax.fig.clear()
  899. subplot = ax.fig.add_subplot(111)
  900. ax.fig.patch.set_facecolor( None )
  901. ax.fig.patch.set_alpha( .0 )
  902. subplot.imshow(img)
  903. subplot.xaxis.set_major_locator(plt.NullLocator())
  904. subplot.yaxis.set_major_locator(plt.NullLocator())
  905. ax.draw()
  906. if ssplash:
  907. splash.showMessage("Loading modules")
  908. splash.finish(aw)
  909. #time.sleep(1)
  910. aw.setWindowTitle("Akvo v"+str(version))
  911. aw.show()
  912. qApp.setWindowIcon(QtGui.QIcon(logo2))
  913. sys.exit(qApp.exec_())
  914. if __name__ == "__main__":
  915. main()