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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  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.Processing = {}
  53. #self.data = {}
  54. # For going the other way, data import based on Yaml serialization,
  55. def __repr__(self):
  56. return "%s(name=%r, Akvo_VESION=%r, Import=%r, Processing=%r)" % (
  57. self.__class__.__name__, self.Akvo_VERSION, self.Import, self.Processing) #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. if "Saved" not in self.YamlNode.Processing.keys():
  419. self.YamlNode.Processing["Saved"] = []
  420. self.YamlNode.Processing["Saved"].append(datetime.datetime.now().isoformat())
  421. self.Log()
  422. import pickle, os
  423. try:
  424. with open('.akvo.last.path') as f:
  425. fpath = f.readline()
  426. pass
  427. except IOError as e:
  428. fpath = '.'
  429. fdir = os.path.dirname(fpath)
  430. # Pickle the preprocessed data dictionary
  431. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Pickle (*.dmp)")
  432. print(SaveStr)
  433. spath,filen=os.path.split(str(SaveStr[0]))
  434. f = open('.akvo.last.path', 'w')
  435. f.write( str(spath) ) # prompt last file
  436. save = open(SaveStr[0], 'wb')
  437. # Add some extra info
  438. INFO = {}
  439. INFO["pulseType"] = self.RAWDataProc.pulseType
  440. INFO["transFreq"] = self.RAWDataProc.transFreq
  441. INFO["pulseLength"] = self.RAWDataProc.pulseLength
  442. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance
  443. INFO["samp"] = self.RAWDataProc.samp
  444. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  445. INFO["deadTime"] = self.RAWDataProc.deadTime
  446. INFO["transFreq"] = self.RAWDataProc.transFreq
  447. INFO["headerstr"] = str(self.headerstr)
  448. INFO["log"] = yaml.dump( self.YamlNode ) #self.logText #MAK 20170127
  449. print ("YAML NODE", yaml.dump( self.YamlNode ) )
  450. self.RAWDataProc.DATADICT["INFO"] = INFO
  451. pickle.dump(self.RAWDataProc.DATADICT, save)
  452. save.close()
  453. # Export XML file suitable for USGS ScienceBase Data Release
  454. def ExportXML(self):
  455. return 42
  456. def OpenPreprocess(self):
  457. import pickle
  458. try:
  459. with open('.akvo.last.path') as f:
  460. fpath = f.readline()
  461. pass
  462. except IOError as e:
  463. fpath = '.'
  464. #filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', '.')
  465. fpath = QtWidgets.QFileDialog.getOpenFileName(self, 'Open preprocessed file', fpath, r"Pickle Files (*.dmp)")[0]
  466. f = open('.akvo.last.path', 'w')
  467. f.write( str(fpath) ) # prompt last file
  468. self.ui.logTextBrowser.clear()
  469. self.logText = []
  470. if len(fpath) == 0:
  471. return
  472. pfile = open(fpath,'rb')
  473. unpickle = pickle.Unpickler(pfile)
  474. self.connectGMRDataProcessor()
  475. self.RAWDataProc.DATADICT = unpickle.load()
  476. self.RAWDataProc.readHeaderFile(self.RAWDataProc.DATADICT["INFO"]["headerstr"])
  477. self.headerstr = self.RAWDataProc.DATADICT["INFO"]["headerstr"]
  478. self.RAWDataProc.pulseType = self.RAWDataProc.DATADICT["INFO"]["pulseType"]
  479. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  480. self.RAWDataProc.pulseLength = self.RAWDataProc.DATADICT["INFO"]["pulseLength"]
  481. self.RAWDataProc.TuneCapacitance = self.RAWDataProc.DATADICT["INFO"]["TuneCapacitance"]
  482. self.RAWDataProc.samp = self.RAWDataProc.DATADICT["INFO"]["samp"]
  483. self.RAWDataProc.nPulseMoments = self.RAWDataProc.DATADICT["INFO"]["nPulseMoments"]
  484. self.RAWDataProc.deadTime = self.RAWDataProc.DATADICT["INFO"]["deadTime"]
  485. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  486. self.RAWDataProc.dt = 1./self.RAWDataProc.samp
  487. self.dataChan = self.RAWDataProc.DATADICT[ self.RAWDataProc.DATADICT["PULSES"][0] ]["chan"]
  488. # Keep backwards compatibility with prior saved pickles???
  489. #self.ui.logTextBrowser.clear()
  490. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  491. #for a in self.logText:
  492. # self.ui.logTextBrowser.append(str(a))
  493. #self.ui.logTextBrowser
  494. #self.ui.logTextBrowser.clear()
  495. #print ( self.RAWDataProc.DATADICT["INFO"]["log"] )
  496. self.logText = self.RAWDataProc.DATADICT["INFO"]["log"] # YAML
  497. self.YamlNode = yaml.load( self.logText )
  498. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  499. #except KeyError:
  500. # pass
  501. if "Loaded" not in self.YamlNode.Processing.keys():
  502. self.YamlNode.Processing["Loaded"] = []
  503. self.YamlNode.Processing["Loaded"].append(datetime.datetime.now().isoformat())
  504. self.Log()
  505. # If we got this far, enable all the widgets
  506. self.ui.lcdNumberTauPulse1.setEnabled(True)
  507. self.ui.lcdNumberNuTx.setEnabled(True)
  508. self.ui.lcdNumberTuneuF.setEnabled(True)
  509. self.ui.lcdNumberSampFreq.setEnabled(True)
  510. self.ui.lcdNumberNQ.setEnabled(True)
  511. self.ui.headerFileBox.setEnabled(True)
  512. self.ui.inputRAWParametersBox.setEnabled(True)
  513. self.ui.loadDataPushButton.setEnabled(True)
  514. # make plots as you import the dataset
  515. self.ui.plotImportCheckBox.setEnabled(True)
  516. self.ui.plotImportCheckBox.setChecked(True)
  517. # Update info from the header into the GUI
  518. self.ui.pulseTypeTextBrowser.clear()
  519. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  520. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  521. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  522. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  523. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  524. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  525. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  526. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  527. if self.RAWDataProc.pulseType != "FID":
  528. self.ui.lcdNumberTauPulse2.setEnabled(1)
  529. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  530. self.ui.lcdNumberTauDelay.setEnabled(1)
  531. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  532. self.ui.FIDProcComboBox.clear()
  533. if self.RAWDataProc.pulseType == "4PhaseT1":
  534. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  535. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") #, const QVariant & userData = QVariant() )
  536. self.ui.FIDProcComboBox.insertItem(2, "Both") #, const QVariant & userData = QVariant() )
  537. if len( self.RAWDataProc.DATADICT["PULSES"]) == 2:
  538. self.ui.FIDProcComboBox.setCurrentIndex (2)
  539. elif self.RAWDataProc.DATADICT["PULSES"][0] == "Pulse 1":
  540. self.ui.FIDProcComboBox.setCurrentIndex (0)
  541. else:
  542. self.ui.FIDProcComboBox.setCurrentIndex (1)
  543. elif self.RAWDataProc.pulseType == "FID":
  544. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  545. self.ui.FIDProcComboBox.setCurrentIndex (0)
  546. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  547. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  548. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  549. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  550. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  551. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  552. self.enableAll()
  553. def loadRAW(self):
  554. #################################################
  555. # Check to make sure we are ready to process
  556. # Header
  557. if self.RAWDataProc == None:
  558. err_msg = "You need to load a header first."
  559. reply = QtGui.QMessageBox.critical(self, 'Error',
  560. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  561. return
  562. # Stacks
  563. try:
  564. self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]"))
  565. except:
  566. err_msg = "You need to set your stacks correctly.\n" + \
  567. "This should be a Python Numpy interpretable list\n" + \
  568. "of stack indices. For example 1:24 or 1:4,8:24"
  569. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  570. return
  571. # Data Channels
  572. #Chan = np.arange(0,9,1)
  573. try:
  574. self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]"))
  575. except:
  576. #QMessageBox messageBox;
  577. #messageBox.critical(0,"Error","An error has occured !");
  578. #messageBox.setFixedSize(500,200);
  579. #quit_msg = "Are you sure you want to exit the program?"
  580. #reply = QtGui.QMessageBox.question(self, 'Message',
  581. # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  582. err_msg = "You need to set your data channels correctly.\n" + \
  583. "This should be a Python Numpy interpretable list\n" + \
  584. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  585. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  586. "1:3 is not inclusive of 3 and is the same as 1,2 "
  587. reply = QtGui.QMessageBox.critical(self, 'Error',
  588. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  589. return
  590. #############################
  591. # Reference Channels
  592. # TODO make sure no overlap between data and ref channels
  593. self.refChan = np.array( () )
  594. if str(self.ui.refChanLineEdit.text()): # != "none":
  595. try:
  596. self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]"))
  597. except:
  598. err_msg = "You need to set your reference channels correctly.\n" + \
  599. "This should be a Python Numpy interpretable list\n" + \
  600. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  601. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  602. "1:3 is not inclusive of 3 and is the same as 1,2 "
  603. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  604. return
  605. #####################################################
  606. # Load data
  607. self.lock("loading RAW GMR dataset")
  608. if self.RAWDataProc.pulseType == "FID":
  609. self.procThread = thread.start_new_thread(self.RAWDataProc.loadFIDData, \
  610. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  611. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  612. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  613. elif self.RAWDataProc.pulseType == "4PhaseT1":
  614. self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  615. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  616. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  617. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  618. self.YamlNode.Import["GMR Header"] = self.headerstr
  619. self.YamlNode.Import["opened"] = datetime.datetime.now().isoformat()
  620. self.YamlNode.Import["pulse Type"] = str(self.RAWDataProc.pulseType)
  621. self.YamlNode.Import["stacks"] = self.procStacks.tolist()
  622. self.YamlNode.Import["data channels"] = self.dataChan.tolist()
  623. self.YamlNode.Import["reference channels"] = self.refChan.tolist()
  624. self.YamlNode.Import["pulse records"] = str(self.ui.FIDProcComboBox.currentText())
  625. self.YamlNode.Import["instrument dead time"] = (1e-3 * self.ui.DeadTimeSpinBox.value( ))
  626. self.Log ( )
  627. # should be already done
  628. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  629. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  630. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  631. self.ui.ProcessedBox.setEnabled(True)
  632. self.ui.lcdNumberFID1Length.setEnabled(1)
  633. self.ui.lcdNumberFID2Length.setEnabled(1)
  634. self.ui.lcdNumberResampFreq.setEnabled(1)
  635. self.ui.lcdTotalDeadTime.setEnabled(1)
  636. self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) )
  637. #self.ui.lcdNumberFID1Length.display(0)
  638. #self.ui.lcdNumberFID2Length.display(0)
  639. #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  640. self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget)
  641. self.ui.mplwidget.draw()
  642. def Log(self):
  643. #for line in yaml.dump(self.YamlNode, default_flow_style=False):
  644. #for line in nlogText:
  645. # self.ui.logTextBrowser.append( line )
  646. # self.logText.append( line )
  647. self.ui.logTextBrowser.clear()
  648. self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  649. def disable(self):
  650. self.ui.BandPassBox.setEnabled(False)
  651. self.ui.downSampleGroupBox.setEnabled(False)
  652. self.ui.windowFilterGroupBox.setEnabled(False)
  653. # self.ui.despikeGroupBox.setEnabled(False)
  654. self.ui.adaptBox.setEnabled(False)
  655. self.ui.adaptFDBox.setEnabled(False)
  656. self.ui.qCalcGroupBox.setEnabled(False)
  657. self.ui.FDSmartStackGroupBox.setEnabled(False)
  658. self.ui.sumDataBox.setEnabled(False)
  659. self.ui.qdGroupBox.setEnabled(False)
  660. self.ui.gateBox.setEnabled(False)
  661. def enableAll(self):
  662. self.enableDSP()
  663. self.enableQC()
  664. def enableDSP(self):
  665. # Bandpass filter
  666. self.ui.BandPassBox.setEnabled(True)
  667. self.ui.BandPassBox.setChecked(True)
  668. self.ui.bandPassGO.setEnabled(False) # need to design first
  669. self.ui.plotBP.setEnabled(True)
  670. self.ui.plotBP.setChecked(True)
  671. # downsample
  672. self.ui.downSampleGroupBox.setEnabled(True)
  673. self.ui.downSampleGroupBox.setChecked(True)
  674. # window
  675. self.ui.windowFilterGroupBox.setEnabled(True)
  676. self.ui.windowFilterGroupBox.setChecked(True)
  677. # Despike
  678. # self.ui.despikeGroupBox.setEnabled(True)
  679. # self.ui.despikeGroupBox.setChecked(False)
  680. # Adaptive filtering
  681. self.ui.adaptBox.setEnabled(True)
  682. self.ui.adaptBox.setChecked(True)
  683. # FD Adaptive filtering
  684. self.ui.adaptFDBox.setEnabled(True)
  685. self.ui.adaptFDBox.setChecked(True)
  686. # sum group box
  687. try:
  688. if len(self.dataChan) > 1:
  689. self.ui.sumDataBox.setEnabled(True)
  690. self.ui.sumDataBox.setChecked(True)
  691. except:
  692. pass
  693. # Quadrature Detect
  694. self.ui.qdGroupBox.setEnabled(True)
  695. self.ui.qdGroupBox.setChecked(True)
  696. self.enableQC()
  697. def enableQC(self):
  698. # Q calc
  699. self.ui.qCalcGroupBox.setEnabled(True)
  700. self.ui.qCalcGroupBox.setChecked(True)
  701. # FD SmartStack
  702. self.ui.FDSmartStackGroupBox.setEnabled(True)
  703. self.ui.FDSmartStackGroupBox.setChecked(True)
  704. # Quadrature detect
  705. try:
  706. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  707. np.shape(self.RAWDataProc.DATADICT[pulse]["Q"])
  708. self.RAWDataProc.DATADICT["stack"]
  709. self.ui.qdGroupBox.setEnabled(True)
  710. self.ui.qdGroupBox.setChecked(True)
  711. except:
  712. self.ui.qdGroupBox.setEnabled(False)
  713. self.ui.qdGroupBox.setChecked(False)
  714. # Gating
  715. try:
  716. self.RAWDataProc.DATADICT["CA"]
  717. self.ui.gateBox.setEnabled(True)
  718. self.ui.gateBox.setChecked(True)
  719. except:
  720. self.ui.gateBox.setEnabled(False)
  721. self.ui.gateBox.setChecked(False)
  722. def despikeFilter(self):
  723. self.lock("despike filter")
  724. thread.start_new_thread(self.RAWDataProc.despike, \
  725. (self.ui.windowSpinBox.value(), \
  726. self.ui.thresholdSpinBox.value(), \
  727. str(self.ui.replComboBox.currentText()), \
  728. self.ui.rollOnSpinBox.value(), \
  729. self.ui.despikeInterpWinSpinBox.value(),
  730. self.ui.mplwidget))
  731. def calcQ(self):
  732. self.lock("pulse moment calculation")
  733. thread.start_new_thread(self.RAWDataProc.effectivePulseMoment, \
  734. (self.ui.CentralVSpinBox.value(), \
  735. self.ui.mplwidget_2))
  736. def FDSmartStack(self):
  737. self.lock("time-domain smart stack")
  738. nlogText = []
  739. nlogText.append("TD_stack: ")
  740. nlogText.append(" outlier: " + str( self.ui.outlierTestCB.currentText() ) )
  741. nlogText.append(" cutoff: " + str( self.ui.MADCutoff.value() ) )
  742. self.Log(nlogText)
  743. thread.start_new_thread(self.RAWDataProc.TDSmartStack, \
  744. (str(self.ui.outlierTestCB.currentText()), \
  745. self.ui.MADCutoff.value(),
  746. self.ui.mplwidget_2))
  747. def adaptFilter(self):
  748. self.lock("TD noise cancellation filter")
  749. nlogText = []
  750. nlogText.append("TD_noise_cancellation: ")
  751. nlogText.append(" n_Taps: " + str(self.ui.MTapsSpinBox.value()) )
  752. nlogText.append(" lambda: " + str(self.ui.adaptLambdaSpinBox.value()) )
  753. nlogText.append(" truncate: " + str(self.ui.adaptTruncateSpinBox.value()) )
  754. nlogText.append(" mu: " + str(self.ui.adaptMuSpinBox.value()) )
  755. nlogText.append(" PCA: " + str(self.ui.PCAComboBox.currentText()) )
  756. self.Log(nlogText)
  757. thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
  758. (self.ui.MTapsSpinBox.value(), \
  759. self.ui.adaptLambdaSpinBox.value(), \
  760. self.ui.adaptTruncateSpinBox.value(), \
  761. self.ui.adaptMuSpinBox.value(), \
  762. str(self.ui.PCAComboBox.currentText()), \
  763. self.ui.mplwidget))
  764. def sumDataChans(self):
  765. self.lock("Summing data channels")
  766. nlogText = []
  767. nlogText.append("Data_sum: ")
  768. nlogText.append( " summed_channel: " + str(self.dataChan[0]) )
  769. self.Log(nlogText)
  770. self.dataChan = [self.dataChan[0]]
  771. self.ui.sumDataBox.setEnabled(False)
  772. thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) )
  773. def adaptFilterFD(self):
  774. self.lock("FD noise cancellation filter")
  775. thread.start_new_thread(self.RAWDataProc.adaptiveFilterFD, \
  776. (str(self.ui.windowTypeComboBox.currentText()), \
  777. self.ui.windowBandwidthSpinBox.value(), \
  778. self.ui.CentralVSpinBox.value(), \
  779. self.ui.mplwidget))
  780. def bandPassFilter(self):
  781. self.lock("bandpass filter")
  782. nlogText = []
  783. nlogText.append("bandpass_filter: ")
  784. nlogText.append(" central_nu: "+str(self.ui.CentralVSpinBox.value()))
  785. nlogText.append(" passband: "+str(self.ui.passBandSpinBox.value()) )
  786. nlogText.append(" stopband: "+str(self.ui.stopBandSpinBox.value()) )
  787. nlogText.append(" gpass: "+str(self.ui.gpassSpinBox.value()) )
  788. nlogText.append(" gstop: "+str(self.ui.gstopSpinBox.value()) )
  789. nlogText.append(" type: "+str(self.ui.fTypeComboBox.currentText()) )
  790. self.Log(nlogText)
  791. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
  792. self.ui.lcdTotalDeadTime.display( nv )
  793. thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
  794. (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
  795. def downsample(self):
  796. self.lock("resampling")
  797. nlogText = list(['Resample: '])
  798. nlogText.append(" downsample_factor: " + str(self.ui.downSampleSpinBox.value() ) )
  799. nlogText.append(" truncate_length: " + str( self.ui.truncateSpinBox.value() ) )
  800. self.Log(nlogText)
  801. thread.start_new_thread(self.RAWDataProc.downsample, \
  802. (self.ui.truncateSpinBox.value(), \
  803. self.ui.downSampleSpinBox.value(),
  804. self.ui.mplwidget))
  805. def quadDet(self):
  806. self.lock("quadrature detection")
  807. nlogText = []
  808. nlogText.append("quadrature_detection: ")
  809. nlogText.append(" trim: " + str( self.ui.trimSpin.value() ))
  810. #nlogText.append(" representation:" + str( self.ui.QDType.currentText() ))
  811. self.Log(nlogText)
  812. thread.start_new_thread(self.RAWDataProc.quadDet, \
  813. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2))
  814. self.ui.plotQD.setEnabled(True)
  815. def plotQD(self):
  816. self.lock("plot QD")
  817. thread.start_new_thread(self.RAWDataProc.plotQuadDet, \
  818. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2))
  819. def gateIntegrate(self):
  820. self.lock("gate integration")
  821. nlogText = []
  822. nlogText.append("gate_integrate: ")
  823. nlogText.append(" gpd: " + str(self.ui.GPDspinBox.value( ) ))
  824. self.Log(nlogText)
  825. thread.start_new_thread(self.RAWDataProc.gateIntegrate, \
  826. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), self.ui.mplwidget_2))
  827. self.ui.actionExport_Preprocessed_Dataset.setEnabled(True)
  828. self.ui.plotGI.setEnabled(True)
  829. def plotGI(self):
  830. self.lock("plot gate integrate")
  831. thread.start_new_thread(self.RAWDataProc.plotGateIntegrate, \
  832. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), \
  833. self.ui.QDType_2.currentIndex(), self.ui.mplwidget_2))
  834. def designFilter(self):
  835. [bord, fe] = self.RAWDataProc.designFilter( \
  836. self.ui.CentralVSpinBox.value(), \
  837. self.ui.passBandSpinBox.value(), \
  838. self.ui.stopBandSpinBox.value(), \
  839. self.ui.gpassSpinBox.value(), \
  840. self.ui.gstopSpinBox.value(), \
  841. str(self.ui.fTypeComboBox.currentText()),
  842. self.ui.mplwidget)
  843. self.ui.lcdNumberFilterOrder.display(bord)
  844. self.ui.lcdNumberFTauDead.display(1e3*fe)
  845. #self.ui.lcdNumberFilterOrder.display(bord)
  846. self.ui.bandPassGO.setEnabled(1)
  847. # self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  848. def windowFilter(self):
  849. self.lock("window filter")
  850. nlogText = []
  851. nlogText.append("FD_window: ")
  852. nlogText.append(" type: " + str(self.ui.windowTypeComboBox.currentText()) )
  853. nlogText.append(" width: " + str(self.ui.windowBandwidthSpinBox.value()) )
  854. nlogText.append(" centre: " + str(self.ui.CentralVSpinBox.value() ))
  855. self.Log(nlogText)
  856. thread.start_new_thread(self.RAWDataProc.windowFilter, \
  857. (str(self.ui.windowTypeComboBox.currentText()), \
  858. self.ui.windowBandwidthSpinBox.value(), \
  859. self.ui.CentralVSpinBox.value(), \
  860. self.ui.mplwidget))
  861. def designFDFilter(self):
  862. # thread.start_new_thread(self.RAWDataProc.computeWindow, ( \
  863. # "Pulse 1",
  864. # self.ui.windowBandwidthSpinBox.value(), \
  865. # self.ui.CentralVSpinBox.value(), \
  866. # str(self.ui.windowTypeComboBox.currentText()), \
  867. # self.ui.mplwidget ))
  868. a,b,c,d,dead = self.RAWDataProc.computeWindow( \
  869. "Pulse 1",
  870. self.ui.windowBandwidthSpinBox.value(), \
  871. self.ui.CentralVSpinBox.value(), \
  872. str(self.ui.windowTypeComboBox.currentText()), \
  873. self.ui.mplwidget )
  874. self.ui.lcdWinDead.display(dead)
  875. def updateProgressBar(self, percent):
  876. self.ui.barProgress.setValue(percent)
  877. def updateProc(self):
  878. if str(self.ui.FIDProcComboBox.currentText()) == "Pulse 1":
  879. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  880. elif str(self.ui.FIDProcComboBox.currentText()) == "Pulse 2":
  881. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  882. else:
  883. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  884. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  885. self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  886. def doneStatus(self): # unlocks GUI
  887. self.ui.statusbar.clearMessage ( )
  888. self.ui.barProgress.hide()
  889. self.updateProc()
  890. self.enableAll()
  891. def lock(self, string):
  892. self.ui.statusbar.showMessage ( string )
  893. self.ui.barProgress.show()
  894. self.ui.barProgress.setValue(0)
  895. self.disable()
  896. def unlock(self):
  897. self.ui.statusbar.clearMessage ( )
  898. self.ui.barProgress.hide()
  899. self.enableAll()
  900. def done(self):
  901. self.ui.statusbar.showMessage ( "" )
  902. ################################################################
  903. ################################################################
  904. # Boiler plate main function
  905. import pkg_resources
  906. from pkg_resources import resource_string
  907. import matplotlib.image as mpimg
  908. import matplotlib.pyplot as plt
  909. def main():
  910. # splash screen logo
  911. logo = pkg_resources.resource_filename(__name__, 'akvo.png')
  912. logo2 = pkg_resources.resource_filename(__name__, 'akvo2.png')
  913. qApp = QtWidgets.QApplication(sys.argv)
  914. ssplash = False
  915. if ssplash:
  916. pixmap = QtGui.QPixmap(logo)
  917. splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  918. splash.show()
  919. aw = ApplicationWindow()
  920. img=mpimg.imread(logo)
  921. for ax in [ aw.ui.mplwidget ]:
  922. ax.fig.clear()
  923. subplot = ax.fig.add_subplot(111)
  924. ax.fig.patch.set_facecolor( None )
  925. ax.fig.patch.set_alpha( .0 )
  926. subplot.imshow(img)
  927. subplot.xaxis.set_major_locator(plt.NullLocator())
  928. subplot.yaxis.set_major_locator(plt.NullLocator())
  929. ax.draw()
  930. if ssplash:
  931. splash.showMessage("Loading modules")
  932. splash.finish(aw)
  933. #time.sleep(1)
  934. aw.setWindowTitle("Akvo v"+str(version))
  935. aw.show()
  936. qApp.setWindowIcon(QtGui.QIcon(logo2))
  937. sys.exit(qApp.exec_())
  938. if __name__ == "__main__":
  939. main()