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 48KB

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