Browse Source

Rework of yaml log of processing steps. The log is now a flow of steps, any of which can be repeated. Additionally, plotting of the harmonic modelling has been changed to frequency domain.

tags/1.6.1
Trevor Irons 5 years ago
parent
commit
67c74fc49e
5 changed files with 579 additions and 429 deletions
  1. 133
    108
      akvo/gui/akvoGUI.py
  2. 324
    233
      akvo/gui/main.ui
  3. 39
    33
      akvo/tressel/harmonic.py
  4. 82
    54
      akvo/tressel/mrsurvey.py
  5. 1
    1
      setup.py

+ 133
- 108
akvo/gui/akvoGUI.py View File

17
 """
17
 """
18
 
18
 
19
 import matplotlib
19
 import matplotlib
20
-#matplotlib.use("QT4Agg")
20
+matplotlib.use("QT5Agg")
21
 from PyQt5 import QtCore, QtGui, QtWidgets
21
 from PyQt5 import QtCore, QtGui, QtWidgets
22
 
22
 
23
 import numpy as np
23
 import numpy as np
81
     def __init__(self):
81
     def __init__(self):
82
         self.Akvo_VERSION = version
82
         self.Akvo_VERSION = version
83
         self.Import = OrderedDict() # {}
83
         self.Import = OrderedDict() # {}
84
-        self.Processing = OrderedDict() 
84
+        self.Processing = [] # OrderedDict() 
85
+        self.Stacking = OrderedDict() 
85
     #def __init__(self, node):
86
     #def __init__(self, node):
86
     #    self.Akvo_VERSION = node["version"]
87
     #    self.Akvo_VERSION = node["version"]
87
     #    self.Import = OrderedDict( node["Import"] ) # {}
88
     #    self.Import = OrderedDict( node["Import"] ) # {}
88
     #    self.Processing = OrderedDict( node["Processing"] ) 
89
     #    self.Processing = OrderedDict( node["Processing"] ) 
89
     def __repr__(self):
90
     def __repr__(self):
90
         return "%s(name=%r, Akvo_VERSION=%r, Import=%r, Processing=%r)" % (
91
         return "%s(name=%r, Akvo_VERSION=%r, Import=%r, Processing=%r)" % (
91
-            #self.__class__.__name__, self.Akvo_VERSION, self.Import, self.Processing )
92
-            self.__class__.__name__, self.Akvo_VERSION, self.Import, OrderedDict(self.Processing) ) 
93
-            #self.__class__.__name__, self.Akvo_VERSION, self.Import, OrderedDict(self.Processing)) 
92
+            self.__class__.__name__, self.Akvo_VERSION, self.Import, self.Processing, self.Stacking )
93
+            #self.__class__.__name__, self.Akvo_VERSION, self.Import, OrderedDict(self.Processing) ) 
94
     
94
     
95
 try:    
95
 try:    
96
     import thread 
96
     import thread 
141
         self.ui.lcdNumberTauDelay.setEnabled(0)
141
         self.ui.lcdNumberTauDelay.setEnabled(0)
142
         self.ui.lcdNumberNQ.setEnabled(0)
142
         self.ui.lcdNumberNQ.setEnabled(0)
143
 
143
 
144
-        #MAK 20170126: add in a list to hold processing steps
145
         self.logText = []      
144
         self.logText = []      
146
 
145
 
147
-        ####################
148
-        # Make connections #
149
-        ####################
146
+        #######################
147
+        ##################### #
148
+        ## Make connections # #
149
+        ##################### #
150
+        #######################
150
 
151
 
151
-        # Menu items 
152
+        ##############
153
+        # Menu items #
154
+        ##############
152
         self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset)
155
         self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset)
153
         self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess)
156
         self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess)
154
         self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess)
157
         self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess)
156
         self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess)
159
         self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess)
157
         self.ui.actionAboutAkvo.triggered.connect(self.about)
160
         self.ui.actionAboutAkvo.triggered.connect(self.about)
158
 
161
 
159
-        # Buttons
162
+        ###########
163
+        # Buttons #
164
+        ###########
160
 #         #QtCore.QObject.connect(self.ui.fullWorkflowPushButton, QtCore.SIGNAL("clicked()"), self.preprocess )
165
 #         #QtCore.QObject.connect(self.ui.fullWorkflowPushButton, QtCore.SIGNAL("clicked()"), self.preprocess )
161
         self.ui.loadDataPushButton.pressed.connect(self.loadRAW) 
166
         self.ui.loadDataPushButton.pressed.connect(self.loadRAW) 
162
         self.ui.sumDataGO.pressed.connect( self.sumDataChans )
167
         self.ui.sumDataGO.pressed.connect( self.sumDataChans )
812
 
817
 
813
         self.YamlNode.Import = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Import)
818
         self.YamlNode.Import = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Import)
814
         self.YamlNode.Processing = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Processing)
819
         self.YamlNode.Processing = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Processing)
815
-        self.Log() 
820
+        self.YamlNode.Stacking = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Stacking)
821
+        self.Log()
822
+ 
816
             #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False)  )
823
             #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False)  )
817
         #except KeyError:
824
         #except KeyError:
818
         #    pass
825
         #    pass
1128
                 self.ui.mplwidget))
1135
                 self.ui.mplwidget))
1129
 
1136
 
1130
     def calcQ(self):
1137
     def calcQ(self):
1131
-        if "Calc Q" not in self.YamlNode.Processing.keys():
1138
+        if "Calc Q" not in self.YamlNode.Stacking.keys():
1132
             #print("In CalcQ", yaml.dump(self.YamlNode.Processing)  )
1139
             #print("In CalcQ", yaml.dump(self.YamlNode.Processing)  )
1133
-            self.YamlNode.Processing["Calc Q"] = True
1140
+            self.YamlNode.Stacking["Calc Q"] = True
1134
             #print( yaml.dump(self.YamlNode.Processing)  )
1141
             #print( yaml.dump(self.YamlNode.Processing)  )
1135
             self.Log()
1142
             self.Log()
1136
         else:
1143
         else:
1145
                 self.ui.mplwidget))
1152
                 self.ui.mplwidget))
1146
 
1153
 
1147
     def harmonicModel(self):
1154
     def harmonicModel(self):
1148
-
1149
-        if "Harmonic modelling" not in self.YamlNode.Processing.keys():
1150
-            self.YamlNode.Processing["Harmonic modelling"] = {}
1151
-            self.YamlNode.Processing["Harmonic modelling"]["NF"] = str( self.ui.NHarmonicsFreqsSpin.value() ) 
1152
-            self.YamlNode.Processing["Harmonic modelling"]["Segments"] = str( self.ui.NSegments.value() ) 
1153
-            self.YamlNode.Processing["Harmonic modelling"]["f0K1"] = str( self.ui.f0K1Spin.value() )
1154
-            self.YamlNode.Processing["Harmonic modelling"]["f0KN"] = str( self.ui.f0KNSpin.value() )
1155
-            self.YamlNode.Processing["Harmonic modelling"]["f0Ks"] = str( self.ui.f0KsSpin.value() )
1156
-            self.YamlNode.Processing["Harmonic modelling"]["f0"] = str( self.ui.f0Spin.value() )
1157
-            if self.ui.NHarmonicsFreqsSpin.value() > 1:
1158
-                self.YamlNode.Processing["Harmonic modelling"]["f1K1"] = str( self.ui.f1K1Spin.value() )
1159
-                self.YamlNode.Processing["Harmonic modelling"]["f1KN"] = str( self.ui.f1KNSpin.value() )
1160
-                self.YamlNode.Processing["Harmonic modelling"]["f1Ks"] = str( self.ui.f1KsSpin.value() )
1161
-                self.YamlNode.Processing["Harmonic modelling"]["f1"] = str( self.ui.f1Spin.value() )
1162
-            self.Log()
1163
-        #else:
1164
-        #    err_msg = "Harmonic modelling noise cancellation has already been applied!"
1165
-        #    reply = QtWidgets.QMessageBox.critical(self, 'Error', 
1166
-        #        err_msg) 
1167
-        #    return 
1168
-
1155
+        
1169
         self.lock("harmonic noise modelling")
1156
         self.lock("harmonic noise modelling")
1157
+        
1158
+        Harm = OrderedDict()
1159
+        Harm["STEP"] = "Harmonic modelling"
1160
+        Harm["NF"] = str( self.ui.NHarmonicsFreqsSpin.value() ) 
1161
+        Harm["Segments"] = str( self.ui.NSegments.value() ) 
1162
+        Harm["Proc. ref."] = self.ui.harmRef.isChecked() 
1163
+        
1164
+        
1165
+        if self.ui.searchAll.currentText() == "All":
1166
+            Harm["search"] = self.ui.searchAll.currentText()
1167
+            Search = False  
1168
+        else:
1169
+            #Harm["search"] = self.ui.searchAll.currentText() 
1170
+            Harm["search"] = str(self.ui.Nsearch.value()) 
1171
+            Search = self.ui.Nsearch.value() 
1172
+        if self.ui.boundsCheck.isChecked():
1173
+            Harm["Bounds"] = str(self.ui.bounds.value()) 
1174
+            Bounds = self.ui.bounds.value() 
1175
+        else:
1176
+            Harm["Bounds"] = self.ui.boundsCheck.isChecked() 
1177
+            Bounds = 0
1178
+
1179
+        Harm["f0K1"] = str( self.ui.f0K1Spin.value() )
1180
+        Harm["f0KN"] = str( self.ui.f0KNSpin.value() )
1181
+        Harm["f0Ks"] = str( self.ui.f0KsSpin.value() )
1182
+        Harm["f0"] = str( self.ui.f0Spin.value() )
1183
+        if self.ui.NHarmonicsFreqsSpin.value() > 1:
1184
+            Harm["f1K1"] = str( self.ui.f1K1Spin.value() )
1185
+            Harm["f1KN"] = str( self.ui.f1KNSpin.value() )
1186
+            Harm["f1Ks"] = str( self.ui.f1KsSpin.value() )
1187
+            Harm["f1"] = str( self.ui.f1Spin.value() )
1188
+        self.YamlNode.Processing.append(Harm)
1189
+        self.Log()
1170
 
1190
 
1171
         thread.start_new_thread(self.RAWDataProc.harmonicModel, \
1191
         thread.start_new_thread(self.RAWDataProc.harmonicModel, \
1172
                 ( \
1192
                 ( \
1180
                  self.ui.f1K1Spin.value(), \
1200
                  self.ui.f1K1Spin.value(), \
1181
                  self.ui.f1KNSpin.value(), \
1201
                  self.ui.f1KNSpin.value(), \
1182
                  self.ui.f1KsSpin.value(), \
1202
                  self.ui.f1KsSpin.value(), \
1203
+                 Search, \
1204
+                 Bounds, \
1205
+                 self.ui.harmRef.isChecked(), \
1183
                  self.ui.plotHarmonic.isChecked(), \
1206
                  self.ui.plotHarmonic.isChecked(), \
1184
                  self.ui.mplwidget \
1207
                  self.ui.mplwidget \
1185
                 ) \
1208
                 ) \
1187
 
1210
 
1188
     def FDSmartStack(self):
1211
     def FDSmartStack(self):
1189
 
1212
 
1190
-        if "TD stack" not in self.YamlNode.Processing.keys():
1191
-            self.YamlNode.Processing["TD stack"] = {}
1192
-            self.YamlNode.Processing["TD stack"]["outlier"] = str( self.ui.outlierTestCB.currentText() ) 
1193
-            self.YamlNode.Processing["TD stack"]["cutoff"] = str( self.ui.MADCutoff.value() )
1213
+        if "TD stack" not in self.YamlNode.Stacking.keys():
1214
+            self.YamlNode.Stacking["TD stack"] = {}
1215
+            self.YamlNode.Stacking["TD stack"]["outlier"] = str( self.ui.outlierTestCB.currentText() ) 
1216
+            self.YamlNode.Stacking["TD stack"]["cutoff"] = str( self.ui.MADCutoff.value() )
1194
             self.Log()
1217
             self.Log()
1195
         else:
1218
         else:
1196
             err_msg = "TD noise cancellation has already been applied!"
1219
             err_msg = "TD noise cancellation has already been applied!"
1205
                 self.ui.mplwidget))
1228
                 self.ui.mplwidget))
1206
 
1229
 
1207
     def adaptFilter(self):
1230
     def adaptFilter(self):
1208
-
1209
-        if "TD noise cancellation" not in self.YamlNode.Processing.keys():
1210
-            self.YamlNode.Processing["TD noise cancellation"] = {}
1211
-            self.YamlNode.Processing["TD noise cancellation"]["n_Taps"] = str(self.ui.MTapsSpinBox.value())
1212
-            self.YamlNode.Processing["TD noise cancellation"]["lambda"] = str(self.ui.adaptLambdaSpinBox.value())
1213
-            self.YamlNode.Processing["TD noise cancellation"]["truncate"] = str(self.ui.adaptTruncateSpinBox.value())
1214
-            self.YamlNode.Processing["TD noise cancellation"]["mu"] = str(self.ui.adaptMuSpinBox.value()) 
1215
-            self.YamlNode.Processing["TD noise cancellation"]["PCA"] = str(self.ui.PCAComboBox.currentText())
1216
-            self.Log()
1217
-        else:
1218
-            err_msg = "TD noise cancellation has already been applied!"
1219
-            reply =QtWidgets.QMessageBox.critical(self, 'Error', err_msg) 
1220
-            #return 
1221
         
1231
         
1222
         self.lock("TD noise cancellation filter")
1232
         self.lock("TD noise cancellation filter")
1233
+        
1234
+        # Log processing 
1235
+        Adapt = OrderedDict()
1236
+        Adapt["STEP"] = "TD noise cancellation"
1237
+        Adapt["n_Taps"] = str(self.ui.MTapsSpinBox.value())
1238
+        Adapt["lambda"] = str(self.ui.adaptLambdaSpinBox.value())
1239
+        Adapt["truncate"] = str(self.ui.adaptTruncateSpinBox.value())
1240
+        Adapt["mu"] = str(self.ui.adaptMuSpinBox.value()) 
1241
+        Adapt["PCA"] = str(self.ui.PCAComboBox.currentText())
1242
+        self.YamlNode.Processing.append(Adapt)
1243
+        self.Log( )
1244
+
1223
         thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
1245
         thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
1224
                 (self.ui.MTapsSpinBox.value(), \
1246
                 (self.ui.MTapsSpinBox.value(), \
1225
                 self.ui.adaptLambdaSpinBox.value(), \
1247
                 self.ui.adaptLambdaSpinBox.value(), \
1230
 
1252
 
1231
     def sumDataChans(self): 
1253
     def sumDataChans(self): 
1232
 
1254
 
1233
-        if "Data sum" not in self.YamlNode.Processing.keys():
1234
-            self.YamlNode.Processing["Data sum"] = True
1235
-            self.Log()
1236
-        else:
1237
-            err_msg = "Data channels have already been summed!"
1238
-            reply =QtWidgets.QMessageBox.critical(self, 'Error', 
1239
-                err_msg) 
1240
-            return 
1241
-
1242
         self.lock("Summing data channels")
1255
         self.lock("Summing data channels")
1256
+        
1257
+        Sum = OrderedDict()
1258
+        Sum["STEP"] = "Channel sum"
1259
+        self.YamlNode.Processing.append(Sum)
1260
+        self.Log( )
1261
+
1243
         self.dataChan = [self.dataChan[0]]
1262
         self.dataChan = [self.dataChan[0]]
1244
         self.ui.sumDataBox.setEnabled(False)    
1263
         self.ui.sumDataBox.setEnabled(False)    
1245
         thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) )
1264
         thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) )
1253
                 self.ui.mplwidget))
1272
                 self.ui.mplwidget))
1254
 
1273
 
1255
     def bandPassFilter(self):
1274
     def bandPassFilter(self):
1256
-        if "Bandpass filter" not in self.YamlNode.Processing.keys():
1257
-            self.YamlNode.Processing["Bandpass filter"] = {}
1258
-            self.YamlNode.Processing["Bandpass filter"]["central_nu"] = str(self.ui.CentralVSpinBox.value())
1259
-            self.YamlNode.Processing["Bandpass filter"]["passband"] = str(self.ui.passBandSpinBox.value())
1260
-            self.YamlNode.Processing["Bandpass filter"]["stopband"] = str(self.ui.stopBandSpinBox.value()) 
1261
-            self.YamlNode.Processing["Bandpass filter"]["gpass"] = str(self.ui.gpassSpinBox.value())
1262
-            self.YamlNode.Processing["Bandpass filter"]["gstop"] = str(self.ui.gstopSpinBox.value())
1263
-            self.YamlNode.Processing["Bandpass filter"]["type"] = str(self.ui.fTypeComboBox.currentText())
1264
-            self.Log()
1265
-        else:
1266
-            err_msg = "Bandpass filter has already been applied!"
1267
-            reply =QtWidgets.QMessageBox.critical(self, 'Error', 
1268
-                err_msg) 
1269
-            return 
1275
+        
1270
         self.lock("bandpass filter")        
1276
         self.lock("bandpass filter")        
1277
+        
1278
+        # Log processing 
1279
+        Band = OrderedDict()
1280
+        Band["STEP"] = "Bandpass filter"
1281
+        Band["central_nu"] = str(self.ui.CentralVSpinBox.value())
1282
+        Band["passband"] = str(self.ui.passBandSpinBox.value())
1283
+        Band["stopband"] = str(self.ui.stopBandSpinBox.value()) 
1284
+        Band["gpass"] = str(self.ui.gpassSpinBox.value())
1285
+        Band["gstop"] = str(self.ui.gstopSpinBox.value())
1286
+        Band["type"] = str(self.ui.fTypeComboBox.currentText())
1287
+        self.YamlNode.Processing.append(Band)
1288
+        self.Log( )
1289
+
1271
         nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
1290
         nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
1272
         self.ui.lcdTotalDeadTime.display( nv )
1291
         self.ui.lcdTotalDeadTime.display( nv )
1273
         thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
1292
         thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
1274
                 (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
1293
                 (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
1275
 
1294
 
1276
     def downsample(self):
1295
     def downsample(self):
1296
+
1277
         self.lock("resampling")
1297
         self.lock("resampling")
1278
-        
1279
-        if "Resample" not in self.YamlNode.Processing.keys():
1280
-            self.YamlNode.Processing["Resample"] = {}
1281
-            self.YamlNode.Processing["Resample"]["downsample factor"] = [] 
1282
-            self.YamlNode.Processing["Resample"]["truncate length"] = []  
1283
-        self.YamlNode.Processing["Resample"]["downsample factor"].append( str(self.ui.downSampleSpinBox.value() ) )
1284
-        self.YamlNode.Processing["Resample"]["truncate length"].append(  str( self.ui.truncateSpinBox.value() ) )
1298
+
1299
+        # Log processing 
1300
+        Resample = OrderedDict() 
1301
+        Resample["STEP"] = "Resample"
1302
+        Resample["downsample factor"] = str(self.ui.downSampleSpinBox.value())
1303
+        Resample["truncate length"] = str(self.ui.truncateSpinBox.value()) 
1304
+        self.YamlNode.Processing.append(Resample)
1285
         self.Log( )
1305
         self.Log( )
1286
         
1306
         
1287
         thread.start_new_thread(self.RAWDataProc.downsample, \
1307
         thread.start_new_thread(self.RAWDataProc.downsample, \
1295
         method = ['trf','dogbox','lm'][int(self.ui.QDMethod.currentIndex())]
1315
         method = ['trf','dogbox','lm'][int(self.ui.QDMethod.currentIndex())]
1296
         loss = ['linear','soft_l1','cauchy','huber'][int(self.ui.QDLoss.currentIndex())]         
1316
         loss = ['linear','soft_l1','cauchy','huber'][int(self.ui.QDLoss.currentIndex())]         
1297
 
1317
 
1298
-
1299
         # allow overwrite of Quad Det.    
1318
         # allow overwrite of Quad Det.    
1300
-        self.YamlNode.Processing["Quadrature detection"] = {}
1301
-        self.YamlNode.Processing["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
1302
-        self.YamlNode.Processing["Quadrature detection"]["method"] = method 
1303
-        self.YamlNode.Processing["Quadrature detection"]["loss"] = loss
1319
+        self.YamlNode.Stacking["Quadrature detection"] = {}
1320
+        self.YamlNode.Stacking["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
1321
+        self.YamlNode.Stacking["Quadrature detection"]["method"] = method 
1322
+        self.YamlNode.Stacking["Quadrature detection"]["loss"] = loss
1304
         self.Log()
1323
         self.Log()
1305
 
1324
 
1306
         #if "Quadrature detection" not in self.YamlNode.Processing.keys():
1325
         #if "Quadrature detection" not in self.YamlNode.Processing.keys():
1330
 
1349
 
1331
     def gateIntegrate(self):
1350
     def gateIntegrate(self):
1332
         
1351
         
1333
-        if "Gate integrate" not in self.YamlNode.Processing.keys():
1334
-            self.YamlNode.Processing["Gate integrate"] = {}
1335
-        self.YamlNode.Processing["Gate integrate"]["gpd"] = str(self.ui.GPDspinBox.value( ) )
1352
+        if "Gate integrate" not in self.YamlNode.Stacking.keys():
1353
+            self.YamlNode.Stacking["Gate integrate"] = {}
1354
+        self.YamlNode.Stacking["Gate integrate"]["gpd"] = str(self.ui.GPDspinBox.value( ) )
1336
         self.Log()
1355
         self.Log()
1337
  
1356
  
1338
         self.lock("gate integration")
1357
         self.lock("gate integration")
1361
         self.ui.lcdNumberFilterOrder.display(bord)
1380
         self.ui.lcdNumberFilterOrder.display(bord)
1362
         self.ui.lcdNumberFTauDead.display(1e3*fe)
1381
         self.ui.lcdNumberFTauDead.display(1e3*fe)
1363
         self.ui.bandPassGO.setEnabled(1)
1382
         self.ui.bandPassGO.setEnabled(1)
1383
+
1384
+        ################################################################
1364
         # Hack for MacOS to force refresh of group box and plot
1385
         # Hack for MacOS to force refresh of group box and plot
1386
+        # this has an undesirable effect that it causes the groupbox to 'jump' up
1387
+        # TODO come up with a better solution  
1365
         self.ui.mplwidget.hide()
1388
         self.ui.mplwidget.hide()
1366
         self.ui.mplwidget.show()
1389
         self.ui.mplwidget.show()
1367
         self.ui.BandPassBox.hide()
1390
         self.ui.BandPassBox.hide()
1369
  
1392
  
1370
     def windowFilter(self):
1393
     def windowFilter(self):
1371
         
1394
         
1372
-        if "Window filter" not in self.YamlNode.Processing.keys():
1373
-            self.YamlNode.Processing["Window filter"] = {}
1374
-            self.YamlNode.Processing["Window filter"]["type"] = str(self.ui.windowTypeComboBox.currentText()) 
1375
-            self.YamlNode.Processing["Window filter"]["width"] = str(self.ui.windowBandwidthSpinBox.value()) 
1376
-            self.YamlNode.Processing["Window filter"]["centre"] = str(self.ui.CentralVSpinBox.value() )
1377
-            self.Log()
1378
-        else:
1379
-            err_msg = "FD window has already been applied!"
1380
-            reply =QtWidgets.QMessageBox.critical(self, 'Error', 
1381
-                err_msg) 
1382
-            return 
1383
         self.lock("window filter")
1395
         self.lock("window filter")
1384
         
1396
         
1397
+        # Log processing 
1398
+        Window = OrderedDict()
1399
+        Window["STEP"] = "Window filter"
1400
+        Window["type"] = str(self.ui.windowTypeComboBox.currentText()) 
1401
+        Window["width"] = str(self.ui.windowBandwidthSpinBox.value()) 
1402
+        Window["centre"] = str(self.ui.CentralVSpinBox.value() )
1403
+        Window["trim"] = str(self.ui.windowTrim.isChecked())
1404
+        self.YamlNode.Processing.append(Window)
1405
+        self.Log( )
1406
+        
1407
+        if self.ui.windowTrim.isChecked():
1408
+            nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdWinDead.value()
1409
+            self.ui.lcdTotalDeadTime.display( nv )
1410
+        
1385
         thread.start_new_thread(self.RAWDataProc.windowFilter, \
1411
         thread.start_new_thread(self.RAWDataProc.windowFilter, \
1386
                 (str(self.ui.windowTypeComboBox.currentText()), \
1412
                 (str(self.ui.windowTypeComboBox.currentText()), \
1387
                 self.ui.windowBandwidthSpinBox.value(), \
1413
                 self.ui.windowBandwidthSpinBox.value(), \
1388
                 self.ui.CentralVSpinBox.value(), \
1414
                 self.ui.CentralVSpinBox.value(), \
1415
+                self.ui.windowTrim.isChecked(), \
1389
                 self.ui.mplwidget))
1416
                 self.ui.mplwidget))
1390
 
1417
 
1391
     def designFDFilter(self):
1418
     def designFDFilter(self):
1392
-#         thread.start_new_thread(self.RAWDataProc.computeWindow, ( \
1393
-#                 "Pulse 1",
1394
-#                 self.ui.windowBandwidthSpinBox.value(), \
1395
-#                 self.ui.CentralVSpinBox.value(), \
1396
-#                 str(self.ui.windowTypeComboBox.currentText()), \
1397
-#                 self.ui.mplwidget ))
1398
 
1419
 
1399
         mPulse = "None"
1420
         mPulse = "None"
1400
         if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
1421
         if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
1401
             mPulse = u"Pulse 1"
1422
             mPulse = u"Pulse 1"
1402
         elif u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
1423
         elif u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
1403
             mPulse = u"Pulse 2"
1424
             mPulse = u"Pulse 2"
1404
-        a,b,c,d,dead = self.RAWDataProc.computeWindow( \
1425
+        a,b,c,d,dead,ndead = self.RAWDataProc.computeWindow( \
1405
                 mPulse,
1426
                 mPulse,
1406
                 self.ui.windowBandwidthSpinBox.value(), \
1427
                 self.ui.windowBandwidthSpinBox.value(), \
1407
                 self.ui.CentralVSpinBox.value(), \
1428
                 self.ui.CentralVSpinBox.value(), \
1409
                 self.ui.mplwidget )
1430
                 self.ui.mplwidget )
1410
 
1431
 
1411
         self.ui.lcdWinDead.display(dead)
1432
         self.ui.lcdWinDead.display(dead)
1433
+
1434
+        ################################################################
1412
         # Hack for MacOS to force refresh of group box and plot
1435
         # Hack for MacOS to force refresh of group box and plot
1436
+        # this has an undesirable effect that it causes the groupbox to 'jump' up
1437
+        # TODO come up with a better solution  
1413
         self.ui.mplwidget.hide()
1438
         self.ui.mplwidget.hide()
1414
         self.ui.mplwidget.show()
1439
         self.ui.mplwidget.show()
1415
         self.ui.windowFilterGroupBox.hide()
1440
         self.ui.windowFilterGroupBox.hide()

+ 324
- 233
akvo/gui/main.ui View File

355
                <bool>true</bool>
355
                <bool>true</bool>
356
               </property>
356
               </property>
357
               <layout class="QGridLayout" name="gridLayout_5">
357
               <layout class="QGridLayout" name="gridLayout_5">
358
-               <item row="0" column="0">
359
-                <widget class="QLabel" name="label_3">
360
-                 <property name="text">
361
-                  <string>Truncate [ms]</string>
362
-                 </property>
363
-                </widget>
364
-               </item>
365
                <item row="0" column="1">
358
                <item row="0" column="1">
366
                 <widget class="QSpinBox" name="truncateSpinBox">
359
                 <widget class="QSpinBox" name="truncateSpinBox">
367
                  <property name="maximumSize">
360
                  <property name="maximumSize">
381
                  </property>
374
                  </property>
382
                 </widget>
375
                 </widget>
383
                </item>
376
                </item>
384
-               <item row="1" column="0">
385
-                <widget class="QLabel" name="label_12">
377
+               <item row="0" column="0">
378
+                <widget class="QLabel" name="label_3">
386
                  <property name="text">
379
                  <property name="text">
387
-                  <string>Downsample factor</string>
380
+                  <string>Truncate [ms]</string>
388
                  </property>
381
                  </property>
389
                 </widget>
382
                 </widget>
390
                </item>
383
                </item>
407
                  </property>
400
                  </property>
408
                 </widget>
401
                 </widget>
409
                </item>
402
                </item>
403
+               <item row="1" column="0">
404
+                <widget class="QLabel" name="label_12">
405
+                 <property name="text">
406
+                  <string>Downsample factor</string>
407
+                 </property>
408
+                </widget>
409
+               </item>
410
                <item row="1" column="2">
410
                <item row="1" column="2">
411
                 <widget class="QPushButton" name="downSampleGO">
411
                 <widget class="QPushButton" name="downSampleGO">
412
                  <property name="styleSheet">
412
                  <property name="styleSheet">
466
                <bool>true</bool>
466
                <bool>true</bool>
467
               </property>
467
               </property>
468
               <layout class="QGridLayout" name="gridLayout_6">
468
               <layout class="QGridLayout" name="gridLayout_6">
469
-               <item row="4" column="1">
470
-                <widget class="QLCDNumber" name="lcdWinDead">
471
-                 <property name="sizePolicy">
472
-                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
473
-                   <horstretch>0</horstretch>
474
-                   <verstretch>0</verstretch>
475
-                  </sizepolicy>
469
+               <item row="4" column="0">
470
+                <widget class="QLabel" name="label_55">
471
+                 <property name="text">
472
+                  <string>dead time [ms]</string>
476
                  </property>
473
                  </property>
474
+                </widget>
475
+               </item>
476
+               <item row="1" column="3">
477
+                <widget class="QPushButton" name="fdDesignPushButton">
477
                  <property name="styleSheet">
478
                  <property name="styleSheet">
478
-                  <string notr="true">#lcdWinDead {
479
-color: green;
480
-background: black;
481
-}
482
-
483
-#lcdWinDead:disabled {
484
-color: grey;
485
-background: dark grey;
486
-}</string>
479
+                  <string notr="true"/>
487
                  </property>
480
                  </property>
488
-                 <property name="segmentStyle">
489
-                  <enum>QLCDNumber::Flat</enum>
481
+                 <property name="text">
482
+                  <string>design</string>
490
                  </property>
483
                  </property>
491
                 </widget>
484
                 </widget>
492
                </item>
485
                </item>
526
                  </property>
519
                  </property>
527
                 </widget>
520
                 </widget>
528
                </item>
521
                </item>
529
-               <item row="0" column="0">
530
-                <widget class="QLabel" name="label_45">
531
-                 <property name="text">
532
-                  <string>Type</string>
522
+               <item row="4" column="1">
523
+                <widget class="QLCDNumber" name="lcdWinDead">
524
+                 <property name="sizePolicy">
525
+                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
526
+                   <horstretch>0</horstretch>
527
+                   <verstretch>0</verstretch>
528
+                  </sizepolicy>
529
+                 </property>
530
+                 <property name="styleSheet">
531
+                  <string notr="true">#lcdWinDead {
532
+color: green;
533
+background: black;
534
+}
535
+
536
+#lcdWinDead:disabled {
537
+color: grey;
538
+background: dark grey;
539
+}</string>
540
+                 </property>
541
+                 <property name="segmentStyle">
542
+                  <enum>QLCDNumber::Flat</enum>
533
                  </property>
543
                  </property>
534
                 </widget>
544
                 </widget>
535
                </item>
545
                </item>
536
-               <item row="4" column="0">
537
-                <widget class="QLabel" name="label_55">
546
+               <item row="0" column="0">
547
+                <widget class="QLabel" name="label_45">
538
                  <property name="text">
548
                  <property name="text">
539
-                  <string>dead time [ms]</string>
549
+                  <string>Type</string>
540
                  </property>
550
                  </property>
541
                 </widget>
551
                 </widget>
542
                </item>
552
                </item>
564
                  </item>
574
                  </item>
565
                 </widget>
575
                 </widget>
566
                </item>
576
                </item>
567
-               <item row="1" column="3">
568
-                <widget class="QPushButton" name="fdDesignPushButton">
569
-                 <property name="styleSheet">
570
-                  <string notr="true"/>
577
+               <item row="0" column="3">
578
+                <widget class="QCheckBox" name="windowTrim">
579
+                 <property name="toolTip">
580
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sets whether or not the dead time will be trimmed from the beginning and end of the signal. When doing a cascade of filters, users may wish to hold off on edge effect removal. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
571
                  </property>
581
                  </property>
572
                  <property name="text">
582
                  <property name="text">
573
-                  <string>design</string>
583
+                  <string>Trim dead time </string>
584
+                 </property>
585
+                 <property name="checked">
586
+                  <bool>true</bool>
574
                  </property>
587
                  </property>
575
                 </widget>
588
                 </widget>
576
                </item>
589
                </item>
1021
                <bool>true</bool>
1034
                <bool>true</bool>
1022
               </property>
1035
               </property>
1023
               <layout class="QGridLayout" name="gridLayout_9">
1036
               <layout class="QGridLayout" name="gridLayout_9">
1024
-               <item row="0" column="0">
1025
-                <widget class="QLabel" name="label_26">
1037
+               <item row="12" column="0">
1038
+                <widget class="QLabel" name="label_34">
1026
                  <property name="text">
1039
                  <property name="text">
1027
-                  <string>N freqs</string>
1040
+                  <string>First harmonic 2</string>
1028
                  </property>
1041
                  </property>
1029
                 </widget>
1042
                 </widget>
1030
                </item>
1043
                </item>
1031
-               <item row="0" column="1">
1032
-                <widget class="QSpinBox" name="NHarmonicsFreqsSpin">
1033
-                 <property name="minimum">
1034
-                  <number>1</number>
1044
+               <item row="1" column="0">
1045
+                <widget class="QLabel" name="label_49">
1046
+                 <property name="text">
1047
+                  <string>N segments</string>
1035
                  </property>
1048
                  </property>
1036
-                 <property name="maximum">
1037
-                  <number>2</number>
1049
+                </widget>
1050
+               </item>
1051
+               <item row="17" column="2">
1052
+                <widget class="QPushButton" name="harmonicGO">
1053
+                 <property name="layoutDirection">
1054
+                  <enum>Qt::LeftToRight</enum>
1038
                  </property>
1055
                  </property>
1039
-                 <property name="value">
1040
-                  <number>1</number>
1056
+                 <property name="styleSheet">
1057
+                  <string notr="true">#harmonicGO {background: green;}
1058
+#harmonicGO:disabled{background: black;}</string>
1059
+                 </property>
1060
+                 <property name="text">
1061
+                  <string>GO</string>
1041
                  </property>
1062
                  </property>
1042
                 </widget>
1063
                 </widget>
1043
                </item>
1064
                </item>
1044
-               <item row="5" column="1">
1045
-                <widget class="QSpinBox" name="f0KNSpin">
1046
-                 <property name="minimum">
1047
-                  <number>2</number>
1048
-                 </property>
1049
-                 <property name="value">
1050
-                  <number>40</number>
1065
+               <item row="13" column="0">
1066
+                <widget class="QLabel" name="label_35">
1067
+                 <property name="text">
1068
+                  <string>Last harmonic 2</string>
1051
                  </property>
1069
                  </property>
1052
                 </widget>
1070
                 </widget>
1053
                </item>
1071
                </item>
1054
-               <item row="4" column="1">
1055
-                <widget class="QSpinBox" name="f0K1Spin">
1072
+               <item row="14" column="1">
1073
+                <widget class="QSpinBox" name="f1KsSpin">
1056
                  <property name="minimum">
1074
                  <property name="minimum">
1057
                   <number>1</number>
1075
                   <number>1</number>
1058
                  </property>
1076
                  </property>
1059
                  <property name="maximum">
1077
                  <property name="maximum">
1060
-                  <number>50</number>
1078
+                  <number>3</number>
1079
+                 </property>
1080
+                </widget>
1081
+               </item>
1082
+               <item row="11" column="1">
1083
+                <widget class="QDoubleSpinBox" name="f1Spin">
1084
+                 <property name="maximum">
1085
+                  <double>25000.000000000000000</double>
1061
                  </property>
1086
                  </property>
1062
                  <property name="value">
1087
                  <property name="value">
1063
-                  <number>1</number>
1088
+                  <double>60.000000000000000</double>
1064
                  </property>
1089
                  </property>
1065
                 </widget>
1090
                 </widget>
1066
                </item>
1091
                </item>
1067
-               <item row="12" column="2">
1068
-                <widget class="QLCDNumber" name="lcdf0NK2">
1069
-                 <property name="styleSheet">
1070
-                  <string notr="true">#lcdf0NK2 { 
1071
-color: green;
1072
-background: black;
1073
-}
1074
-
1075
-#lcdf0NK2:disabled {
1076
-color: grey;
1077
-background: dark grey;
1078
-}</string>
1092
+               <item row="17" column="1">
1093
+                <widget class="QCheckBox" name="plotHarmonic">
1094
+                 <property name="text">
1095
+                  <string>Plot</string>
1079
                  </property>
1096
                  </property>
1080
-                 <property name="segmentStyle">
1081
-                  <enum>QLCDNumber::Flat</enum>
1097
+                 <property name="checked">
1098
+                  <bool>true</bool>
1082
                  </property>
1099
                  </property>
1083
                 </widget>
1100
                 </widget>
1084
                </item>
1101
                </item>
1085
-               <item row="6" column="2">
1086
-                <widget class="QLCDNumber" name="lcdf0NK">
1102
+               <item row="14" column="2">
1103
+                <widget class="QLCDNumber" name="lcdf0NK2">
1087
                  <property name="styleSheet">
1104
                  <property name="styleSheet">
1088
-                  <string notr="true">#lcdf0NK { 
1105
+                  <string notr="true">#lcdf0NK2 { 
1089
 color: green;
1106
 color: green;
1090
 background: black;
1107
 background: black;
1091
 }
1108
 }
1092
 
1109
 
1093
-#lcdf0NK:disabled {
1110
+#lcdf0NK2:disabled {
1094
 color: grey;
1111
 color: grey;
1095
 background: dark grey;
1112
 background: dark grey;
1096
 }</string>
1113
 }</string>
1098
                  <property name="segmentStyle">
1115
                  <property name="segmentStyle">
1099
                   <enum>QLCDNumber::Flat</enum>
1116
                   <enum>QLCDNumber::Flat</enum>
1100
                  </property>
1117
                  </property>
1101
-                 <property name="intValue" stdset="0">
1102
-                  <number>0</number>
1103
-                 </property>
1104
-                </widget>
1105
-               </item>
1106
-               <item row="10" column="0">
1107
-                <widget class="QLabel" name="label_34">
1108
-                 <property name="text">
1109
-                  <string>First harmonic 2</string>
1110
-                 </property>
1111
                 </widget>
1118
                 </widget>
1112
                </item>
1119
                </item>
1113
                <item row="12" column="1">
1120
                <item row="12" column="1">
1114
-                <widget class="QSpinBox" name="f1KsSpin">
1121
+                <widget class="QSpinBox" name="f1K1Spin">
1115
                  <property name="minimum">
1122
                  <property name="minimum">
1116
                   <number>1</number>
1123
                   <number>1</number>
1117
                  </property>
1124
                  </property>
1118
-                 <property name="maximum">
1119
-                  <number>3</number>
1120
-                 </property>
1121
                 </widget>
1125
                 </widget>
1122
                </item>
1126
                </item>
1123
-               <item row="13" column="2">
1124
-                <widget class="Line" name="line_9">
1125
-                 <property name="orientation">
1126
-                  <enum>Qt::Horizontal</enum>
1127
+               <item row="14" column="0">
1128
+                <widget class="QLabel" name="label_41">
1129
+                 <property name="text">
1130
+                  <string>Sub-harmonics</string>
1127
                  </property>
1131
                  </property>
1128
                 </widget>
1132
                 </widget>
1129
                </item>
1133
                </item>
1130
-               <item row="11" column="0">
1131
-                <widget class="QLabel" name="label_35">
1132
-                 <property name="text">
1133
-                  <string>Last harmonic 2</string>
1134
+               <item row="10" column="2">
1135
+                <widget class="Line" name="line_6">
1136
+                 <property name="orientation">
1137
+                  <enum>Qt::Horizontal</enum>
1134
                  </property>
1138
                  </property>
1135
                 </widget>
1139
                 </widget>
1136
                </item>
1140
                </item>
1137
-               <item row="5" column="2">
1138
-                <widget class="QLCDNumber" name="lcdHNF">
1139
-                 <property name="styleSheet">
1140
-                  <string notr="true">#lcdHNF {
1141
-color: green;
1142
-background: black;
1143
-}
1144
-
1145
-#lcdHNF:disabled {
1146
-color: grey;
1147
-background: dark grey;
1148
-}</string>
1141
+               <item row="7" column="1">
1142
+                <widget class="QSpinBox" name="f0KNSpin">
1143
+                 <property name="minimum">
1144
+                  <number>2</number>
1149
                  </property>
1145
                  </property>
1150
-                 <property name="segmentStyle">
1151
-                  <enum>QLCDNumber::Flat</enum>
1146
+                 <property name="value">
1147
+                  <number>40</number>
1152
                  </property>
1148
                  </property>
1153
                 </widget>
1149
                 </widget>
1154
                </item>
1150
                </item>
1155
-               <item row="4" column="2">
1151
+               <item row="6" column="2">
1156
                 <widget class="QLCDNumber" name="lcdH1F">
1152
                 <widget class="QLCDNumber" name="lcdH1F">
1157
                  <property name="styleSheet">
1153
                  <property name="styleSheet">
1158
                   <string notr="true">#lcdH1F {
1154
                   <string notr="true">#lcdH1F {
1170
                  </property>
1166
                  </property>
1171
                 </widget>
1167
                 </widget>
1172
                </item>
1168
                </item>
1173
-               <item row="10" column="2">
1174
-                <widget class="QLCDNumber" name="lcdH1F2">
1175
-                 <property name="styleSheet">
1176
-                  <string notr="true">#lcdH1F2{ 
1177
-color: green;
1178
-background: black;
1179
-}
1180
-
1181
-#lcdH1F2:disabled {
1182
-color: grey;
1183
-background: dark grey;
1184
-}</string>
1185
-                 </property>
1186
-                 <property name="segmentStyle">
1187
-                  <enum>QLCDNumber::Flat</enum>
1169
+               <item row="7" column="0">
1170
+                <widget class="QLabel" name="label_31">
1171
+                 <property name="text">
1172
+                  <string>Last harmonic 1</string>
1188
                  </property>
1173
                  </property>
1189
                 </widget>
1174
                 </widget>
1190
                </item>
1175
                </item>
1191
-               <item row="12" column="0">
1192
-                <widget class="QLabel" name="label_41">
1193
-                 <property name="text">
1194
-                  <string>Sub-harmonics</string>
1176
+               <item row="10" column="1">
1177
+                <widget class="Line" name="line_5">
1178
+                 <property name="orientation">
1179
+                  <enum>Qt::Horizontal</enum>
1195
                  </property>
1180
                  </property>
1196
                 </widget>
1181
                 </widget>
1197
                </item>
1182
                </item>
1198
-               <item row="10" column="1">
1199
-                <widget class="QSpinBox" name="f1K1Spin">
1183
+               <item row="6" column="1">
1184
+                <widget class="QSpinBox" name="f0K1Spin">
1200
                  <property name="minimum">
1185
                  <property name="minimum">
1201
                   <number>1</number>
1186
                   <number>1</number>
1202
                  </property>
1187
                  </property>
1203
-                </widget>
1204
-               </item>
1205
-               <item row="9" column="0">
1206
-                <widget class="QLabel" name="label_27">
1207
-                 <property name="text">
1208
-                  <string>Base freq. 2 </string>
1188
+                 <property name="maximum">
1189
+                  <number>50</number>
1190
+                 </property>
1191
+                 <property name="value">
1192
+                  <number>1</number>
1209
                  </property>
1193
                  </property>
1210
                 </widget>
1194
                 </widget>
1211
                </item>
1195
                </item>
1212
-               <item row="8" column="1">
1213
-                <widget class="Line" name="line_5">
1196
+               <item row="15" column="1">
1197
+                <widget class="Line" name="line_8">
1214
                  <property name="orientation">
1198
                  <property name="orientation">
1215
                   <enum>Qt::Horizontal</enum>
1199
                   <enum>Qt::Horizontal</enum>
1216
                  </property>
1200
                  </property>
1217
                 </widget>
1201
                 </widget>
1218
                </item>
1202
                </item>
1219
-               <item row="8" column="2">
1220
-                <widget class="Line" name="line_6">
1203
+               <item row="2" column="0">
1204
+                <widget class="QLabel" name="label_50">
1205
+                 <property name="text">
1206
+                  <string>Base freq. search </string>
1207
+                 </property>
1208
+                </widget>
1209
+               </item>
1210
+               <item row="10" column="0">
1211
+                <widget class="Line" name="line_4">
1221
                  <property name="orientation">
1212
                  <property name="orientation">
1222
                   <enum>Qt::Horizontal</enum>
1213
                   <enum>Qt::Horizontal</enum>
1223
                  </property>
1214
                  </property>
1224
                 </widget>
1215
                 </widget>
1225
                </item>
1216
                </item>
1226
-               <item row="3" column="1">
1217
+               <item row="4" column="2">
1218
+                <widget class="Line" name="line_2">
1219
+                 <property name="orientation">
1220
+                  <enum>Qt::Horizontal</enum>
1221
+                 </property>
1222
+                </widget>
1223
+               </item>
1224
+               <item row="8" column="0">
1225
+                <widget class="QLabel" name="label_33">
1226
+                 <property name="text">
1227
+                  <string>Sub-harmonics </string>
1228
+                 </property>
1229
+                </widget>
1230
+               </item>
1231
+               <item row="6" column="0">
1232
+                <widget class="QLabel" name="label_11">
1233
+                 <property name="text">
1234
+                  <string>First harmonic 1</string>
1235
+                 </property>
1236
+                </widget>
1237
+               </item>
1238
+               <item row="0" column="1">
1239
+                <widget class="QSpinBox" name="NHarmonicsFreqsSpin">
1240
+                 <property name="minimum">
1241
+                  <number>1</number>
1242
+                 </property>
1243
+                 <property name="maximum">
1244
+                  <number>2</number>
1245
+                 </property>
1246
+                 <property name="value">
1247
+                  <number>1</number>
1248
+                 </property>
1249
+                </widget>
1250
+               </item>
1251
+               <item row="5" column="1">
1227
                 <widget class="QDoubleSpinBox" name="f0Spin">
1252
                 <widget class="QDoubleSpinBox" name="f0Spin">
1228
                  <property name="maximum">
1253
                  <property name="maximum">
1229
                   <double>25000.000000000000000</double>
1254
                   <double>25000.000000000000000</double>
1236
                  </property>
1261
                  </property>
1237
                 </widget>
1262
                 </widget>
1238
                </item>
1263
                </item>
1239
-               <item row="9" column="1">
1240
-                <widget class="QDoubleSpinBox" name="f1Spin">
1241
-                 <property name="maximum">
1242
-                  <double>25000.000000000000000</double>
1264
+               <item row="12" column="2">
1265
+                <widget class="QLCDNumber" name="lcdH1F2">
1266
+                 <property name="styleSheet">
1267
+                  <string notr="true">#lcdH1F2{ 
1268
+color: green;
1269
+background: black;
1270
+}
1271
+
1272
+#lcdH1F2:disabled {
1273
+color: grey;
1274
+background: dark grey;
1275
+}</string>
1243
                  </property>
1276
                  </property>
1244
-                 <property name="value">
1245
-                  <double>60.000000000000000</double>
1277
+                 <property name="segmentStyle">
1278
+                  <enum>QLCDNumber::Flat</enum>
1246
                  </property>
1279
                  </property>
1247
                 </widget>
1280
                 </widget>
1248
                </item>
1281
                </item>
1249
-               <item row="2" column="2">
1250
-                <widget class="Line" name="line_2">
1282
+               <item row="4" column="0">
1283
+                <widget class="Line" name="line_3">
1251
                  <property name="orientation">
1284
                  <property name="orientation">
1252
                   <enum>Qt::Horizontal</enum>
1285
                   <enum>Qt::Horizontal</enum>
1253
                  </property>
1286
                  </property>
1254
                 </widget>
1287
                 </widget>
1255
                </item>
1288
                </item>
1256
-               <item row="15" column="2">
1257
-                <widget class="QPushButton" name="harmonicGO">
1258
-                 <property name="layoutDirection">
1259
-                  <enum>Qt::LeftToRight</enum>
1260
-                 </property>
1261
-                 <property name="styleSheet">
1262
-                  <string notr="true">#harmonicGO {background: green;}
1263
-#harmonicGO:disabled{background: black;}</string>
1289
+               <item row="15" column="0">
1290
+                <widget class="Line" name="line_7">
1291
+                 <property name="orientation">
1292
+                  <enum>Qt::Horizontal</enum>
1264
                  </property>
1293
                  </property>
1294
+                </widget>
1295
+               </item>
1296
+               <item row="11" column="0">
1297
+                <widget class="QLabel" name="label_27">
1265
                  <property name="text">
1298
                  <property name="text">
1266
-                  <string>GO</string>
1299
+                  <string>Base freq. 2 </string>
1267
                  </property>
1300
                  </property>
1268
                 </widget>
1301
                 </widget>
1269
                </item>
1302
                </item>
1270
-               <item row="6" column="1">
1303
+               <item row="8" column="1">
1271
                 <widget class="QSpinBox" name="f0KsSpin">
1304
                 <widget class="QSpinBox" name="f0KsSpin">
1272
                  <property name="toolTip">
1305
                  <property name="toolTip">
1273
                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Would you like to calculate subharmonics? For instance, setting this to 1, will calculate only the exact harmonics, setting this to 2 will calculate 1/2 step subharmonics (i.e. if the baseline frequency is 60 Hz, this will result in calcualtion of 30 Hz subharmonics)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1306
                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Would you like to calculate subharmonics? For instance, setting this to 1, will calculate only the exact harmonics, setting this to 2 will calculate 1/2 step subharmonics (i.e. if the baseline frequency is 60 Hz, this will result in calcualtion of 30 Hz subharmonics)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1283
                  </property>
1316
                  </property>
1284
                 </widget>
1317
                 </widget>
1285
                </item>
1318
                </item>
1286
-               <item row="2" column="1">
1287
-                <widget class="Line" name="line">
1288
-                 <property name="orientation">
1289
-                  <enum>Qt::Horizontal</enum>
1290
-                 </property>
1291
-                </widget>
1292
-               </item>
1293
-               <item row="5" column="0">
1294
-                <widget class="QLabel" name="label_31">
1319
+               <item row="0" column="0">
1320
+                <widget class="QLabel" name="label_26">
1295
                  <property name="text">
1321
                  <property name="text">
1296
-                  <string>Last harmonic 1</string>
1322
+                  <string>N freqs</string>
1297
                  </property>
1323
                  </property>
1298
                 </widget>
1324
                 </widget>
1299
                </item>
1325
                </item>
1300
-               <item row="3" column="0">
1301
-                <widget class="QLabel" name="label_25">
1302
-                 <property name="text">
1303
-                  <string>Base freq. 1</string>
1326
+               <item row="13" column="1">
1327
+                <widget class="QSpinBox" name="f1KNSpin">
1328
+                 <property name="minimum">
1329
+                  <number>2</number>
1330
+                 </property>
1331
+                 <property name="value">
1332
+                  <number>40</number>
1304
                  </property>
1333
                  </property>
1305
                 </widget>
1334
                 </widget>
1306
                </item>
1335
                </item>
1307
-               <item row="11" column="2">
1308
-                <widget class="QLCDNumber" name="lcdHNF2">
1336
+               <item row="8" column="2">
1337
+                <widget class="QLCDNumber" name="lcdf0NK">
1309
                  <property name="styleSheet">
1338
                  <property name="styleSheet">
1310
-                  <string notr="true">#lcdHNF2 { 
1311
- color: green;
1312
- background: black;
1339
+                  <string notr="true">#lcdf0NK { 
1340
+color: green;
1341
+background: black;
1313
 }
1342
 }
1314
 
1343
 
1315
-#lcdHNF2:disabled {
1316
-  color: grey;
1317
-  background: dark grey;
1344
+#lcdf0NK:disabled {
1345
+color: grey;
1346
+background: dark grey;
1318
 }</string>
1347
 }</string>
1319
                  </property>
1348
                  </property>
1320
                  <property name="segmentStyle">
1349
                  <property name="segmentStyle">
1321
                   <enum>QLCDNumber::Flat</enum>
1350
                   <enum>QLCDNumber::Flat</enum>
1322
                  </property>
1351
                  </property>
1323
-                </widget>
1324
-               </item>
1325
-               <item row="11" column="1">
1326
-                <widget class="QSpinBox" name="f1KNSpin">
1327
-                 <property name="minimum">
1328
-                  <number>2</number>
1329
-                 </property>
1330
-                 <property name="value">
1331
-                  <number>40</number>
1352
+                 <property name="intValue" stdset="0">
1353
+                  <number>0</number>
1332
                  </property>
1354
                  </property>
1333
                 </widget>
1355
                 </widget>
1334
                </item>
1356
                </item>
1335
-               <item row="15" column="1">
1336
-                <widget class="QCheckBox" name="plotHarmonic">
1337
-                 <property name="text">
1338
-                  <string>Plot</string>
1357
+               <item row="7" column="2">
1358
+                <widget class="QLCDNumber" name="lcdHNF">
1359
+                 <property name="styleSheet">
1360
+                  <string notr="true">#lcdHNF {
1361
+color: green;
1362
+background: black;
1363
+}
1364
+
1365
+#lcdHNF:disabled {
1366
+color: grey;
1367
+background: dark grey;
1368
+}</string>
1339
                  </property>
1369
                  </property>
1340
-                 <property name="checked">
1341
-                  <bool>true</bool>
1370
+                 <property name="segmentStyle">
1371
+                  <enum>QLCDNumber::Flat</enum>
1342
                  </property>
1372
                  </property>
1343
                 </widget>
1373
                 </widget>
1344
                </item>
1374
                </item>
1345
-               <item row="13" column="1">
1346
-                <widget class="Line" name="line_8">
1375
+               <item row="4" column="1">
1376
+                <widget class="Line" name="line">
1347
                  <property name="orientation">
1377
                  <property name="orientation">
1348
                   <enum>Qt::Horizontal</enum>
1378
                   <enum>Qt::Horizontal</enum>
1349
                  </property>
1379
                  </property>
1350
                 </widget>
1380
                 </widget>
1351
                </item>
1381
                </item>
1352
-               <item row="13" column="0">
1353
-                <widget class="Line" name="line_7">
1354
-                 <property name="orientation">
1355
-                  <enum>Qt::Horizontal</enum>
1382
+               <item row="1" column="1">
1383
+                <widget class="QSpinBox" name="NSegments">
1384
+                 <property name="minimum">
1385
+                  <number>1</number>
1386
+                 </property>
1387
+                 <property name="maximum">
1388
+                  <number>100</number>
1389
+                 </property>
1390
+                 <property name="value">
1391
+                  <number>1</number>
1356
                  </property>
1392
                  </property>
1357
                 </widget>
1393
                 </widget>
1358
                </item>
1394
                </item>
1359
-               <item row="6" column="0">
1360
-                <widget class="QLabel" name="label_33">
1361
-                 <property name="text">
1362
-                  <string>Sub-harmonics </string>
1395
+               <item row="13" column="2">
1396
+                <widget class="QLCDNumber" name="lcdHNF2">
1397
+                 <property name="styleSheet">
1398
+                  <string notr="true">#lcdHNF2 { 
1399
+ color: green;
1400
+ background: black;
1401
+}
1402
+
1403
+#lcdHNF2:disabled {
1404
+  color: grey;
1405
+  background: dark grey;
1406
+}</string>
1407
+                 </property>
1408
+                 <property name="segmentStyle">
1409
+                  <enum>QLCDNumber::Flat</enum>
1363
                  </property>
1410
                  </property>
1364
                 </widget>
1411
                 </widget>
1365
                </item>
1412
                </item>
1366
-               <item row="4" column="0">
1367
-                <widget class="QLabel" name="label_11">
1413
+               <item row="5" column="0">
1414
+                <widget class="QLabel" name="label_25">
1368
                  <property name="text">
1415
                  <property name="text">
1369
-                  <string>First harmonic 1</string>
1416
+                  <string>Base freq. 1</string>
1370
                  </property>
1417
                  </property>
1371
                 </widget>
1418
                 </widget>
1372
                </item>
1419
                </item>
1373
-               <item row="2" column="0">
1374
-                <widget class="Line" name="line_3">
1420
+               <item row="15" column="2">
1421
+                <widget class="Line" name="line_9">
1375
                  <property name="orientation">
1422
                  <property name="orientation">
1376
                   <enum>Qt::Horizontal</enum>
1423
                   <enum>Qt::Horizontal</enum>
1377
                  </property>
1424
                  </property>
1378
                 </widget>
1425
                 </widget>
1379
                </item>
1426
                </item>
1380
-               <item row="8" column="0">
1381
-                <widget class="Line" name="line_4">
1382
-                 <property name="orientation">
1383
-                  <enum>Qt::Horizontal</enum>
1427
+               <item row="2" column="2">
1428
+                <widget class="QSpinBox" name="Nsearch">
1429
+                 <property name="prefix">
1430
+                  <string/>
1384
                  </property>
1431
                  </property>
1385
                 </widget>
1432
                 </widget>
1386
                </item>
1433
                </item>
1387
-               <item row="1" column="1">
1388
-                <widget class="QSpinBox" name="NSegments">
1434
+               <item row="2" column="1">
1435
+                <widget class="QComboBox" name="searchAll">
1436
+                 <property name="toolTip">
1437
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When searching for the fundamental frequency, should the entire ensemble of harmonics be included? Reducing this number can accelerate the algorithm significantly. If a selection other than &amp;quot;All&amp;quot; is chosen, once the fundamental frequency is found, the whole set of harmonics will be included in the modelling.  &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1438
+                 </property>
1439
+                 <item>
1440
+                  <property name="text">
1441
+                   <string>All</string>
1442
+                  </property>
1443
+                 </item>
1444
+                 <item>
1445
+                  <property name="text">
1446
+                   <string>First</string>
1447
+                  </property>
1448
+                 </item>
1449
+                 <item>
1450
+                  <property name="text">
1451
+                   <string/>
1452
+                  </property>
1453
+                 </item>
1454
+                </widget>
1455
+               </item>
1456
+               <item row="3" column="2">
1457
+                <widget class="QDoubleSpinBox" name="bounds">
1458
+                 <property name="toolTip">
1459
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If bounds is selected, this is the variance in the fundamental frequency which will be searched from the &lt;span style=&quot; font-weight:600;&quot;&gt;prior &lt;/span&gt;result. As such, for each record, the fundamental frequency can shift by this much (in either direction) from the prior record. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1460
+                 </property>
1461
+                 <property name="decimals">
1462
+                  <number>3</number>
1463
+                 </property>
1389
                  <property name="minimum">
1464
                  <property name="minimum">
1390
-                  <number>1</number>
1465
+                  <double>0.005000000000000</double>
1391
                  </property>
1466
                  </property>
1392
                  <property name="maximum">
1467
                  <property name="maximum">
1393
-                  <number>100</number>
1468
+                  <double>10.000000000000000</double>
1469
+                 </property>
1470
+                 <property name="singleStep">
1471
+                  <double>0.001000000000000</double>
1394
                  </property>
1472
                  </property>
1395
                  <property name="value">
1473
                  <property name="value">
1396
-                  <number>1</number>
1474
+                  <double>0.125000000000000</double>
1397
                  </property>
1475
                  </property>
1398
                 </widget>
1476
                 </widget>
1399
                </item>
1477
                </item>
1400
-               <item row="1" column="0">
1401
-                <widget class="QLabel" name="label_49">
1478
+               <item row="3" column="1">
1479
+                <widget class="QCheckBox" name="boundsCheck">
1402
                  <property name="text">
1480
                  <property name="text">
1403
-                  <string>N segments</string>
1481
+                  <string>Bounded search</string>
1482
+                 </property>
1483
+                 <property name="checked">
1484
+                  <bool>true</bool>
1485
+                 </property>
1486
+                </widget>
1487
+               </item>
1488
+               <item row="0" column="2">
1489
+                <widget class="QCheckBox" name="harmRef">
1490
+                 <property name="text">
1491
+                  <string>proc ref. channels</string>
1492
+                 </property>
1493
+                 <property name="checked">
1494
+                  <bool>true</bool>
1404
                  </property>
1495
                  </property>
1405
                 </widget>
1496
                 </widget>
1406
                </item>
1497
                </item>
2544
               <rect>
2635
               <rect>
2545
                <x>0</x>
2636
                <x>0</x>
2546
                <y>0</y>
2637
                <y>0</y>
2547
-               <width>96</width>
2548
-               <height>26</height>
2638
+               <width>100</width>
2639
+               <height>30</height>
2549
               </rect>
2640
               </rect>
2550
              </property>
2641
              </property>
2551
              <attribute name="label">
2642
              <attribute name="label">

+ 39
- 33
akvo/tressel/harmonic.py View File

37
     ii =  sN < (3.* np.std(sN))
37
     ii =  sN < (3.* np.std(sN))
38
     return np.linalg.norm( harmonicEuler(sN, fs, t, f0, k1, kN, ks)[ii] ) 
38
     return np.linalg.norm( harmonicEuler(sN, fs, t, f0, k1, kN, ks)[ii] ) 
39
 
39
 
40
-def minHarmonic(sN, fs, t, f0, k1, kN, ks):
40
+def minHarmonic(sN, fs, t, f0, k1, kN, ks, Bounds, Nsearch):
41
     
41
     
42
-    # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
43
-    res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, t, k1, kN, ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
42
+    kNs = kN
43
+    if Nsearch != False:
44
+        kNs = k1+Nsearch    
45
+    if Bounds == 0:
46
+        print("UNbounded search from ", k1, " to ", kNs) # for f0 with fN=10 in search", f0)
47
+        # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
48
+        res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, t, k1, kNs, ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
44
     
49
     
45
-    #############
46
-    # Reduced N #
47
-    #############
48
-    #print("min 10")
49
-    #res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, t, k1, 10, ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
50
-    
51
-    ########## 
52
-    # Bounds #
53
-    ##########
54
-    #print("bounded search for f0 with 10", f0)
55
-    #bnds = ( (f0-0.125, f0+0.125), )
56
-    #print("len f0", len( [f0,] ))
57
-    #print("len bnds", len(bnds) )
58
-    #res = minimize(harmonicNorm, (f0,), args=(sN, fs, t, k1, kN, ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) # hess=None, bounds=None )
59
-    #res = minimize(harmonicNorm, (f0,), args=(sN, fs, t, k1, 10, ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) # hess=None, bounds=None )
60
-    
61
-    #print(res)
62
-    #print ( "guess", guessf0(  harmonicEuler(sN, fs, t, res.x[0], k1, kN, ks), fs  ) )
50
+    else:
51
+        bnds = ( (f0-Bounds, f0+Bounds), )
52
+        print("bounded ( +-", Bounds, ") search from ", k1, "to", kNs) # for f0 with fN=10 in search", f0)
53
+        res = minimize(harmonicNorm, (f0,), args=(sN, fs, t, k1, kNs, ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) # hess=None, bounds=None )
54
+
63
     return harmonicEuler(sN, fs, t, res.x[0], k1, kN, ks), res.x[0]#[0]
55
     return harmonicEuler(sN, fs, t, res.x[0], k1, kN, ks), res.x[0]#[0]
64
 
56
 
65
 def harmonicEuler2 ( sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks ): 
57
 def harmonicEuler2 ( sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks ): 
70
         fs = sampling frequency
62
         fs = sampling frequency
71
         t = time samples 
63
         t = time samples 
72
         f0 = first base frequency of the sinusoidal noise 
64
         f0 = first base frequency of the sinusoidal noise 
73
-        f0k1 = First harmonic to calulate for f0 
65
+        f0k1 = First harmonic to calula11te for f0 
74
         f0kN = Last base harmonic to calulate for f0
66
         f0kN = Last base harmonic to calulate for f0
75
         f0ks = subharmonics to calculate 
67
         f0ks = subharmonics to calculate 
76
         f1 = second base frequency of the sinusoidal noise 
68
         f1 = second base frequency of the sinusoidal noise 
108
     ii =  sN < (3.* np.std(sN))
100
     ii =  sN < (3.* np.std(sN))
109
     return np.linalg.norm( harmonicEuler2(sN, fs, t, f0[0], f0k1, f0kN, f0ks, f0[1], f1k1, f1kN, f1ks)[ii] ) 
101
     return np.linalg.norm( harmonicEuler2(sN, fs, t, f0[0], f0k1, f0kN, f0ks, f0[1], f1k1, f1kN, f1ks)[ii] ) 
110
 
102
 
111
-def minHarmonic2(sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks):
112
-    
113
-    # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
114
-    #res = minimize(harmonic2Norm, np.array((f0, f1)), args=(sN, fs, t, f0k1, f0kN, f0ks, f1k1,f1kN, f1ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
115
-    
116
-    print("search 10")
117
-    res = minimize(harmonic2Norm, np.array((f0, f1)), args=(sN, fs, t, f0k1, 10, f0ks, f1k1, 10, f1ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
118
-    
119
-    #print(res)
120
-    #print ( "guess", guessf0(harmonicEuler2(sN, fs, t, res.x[0], f0k1, f0kN, f0ks, res.x[1], f1k1, f1kN, f1ks), fs)  )
103
+def minHarmonic2(sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks, Bounds, Nsearch):
104
+
105
+    kNs0 = f0kN
106
+    kNs1 = f1kN
107
+    if Nsearch != False:
108
+        kNs0 = f0k1+Nsearch    
109
+        kNs1 = f1k1+Nsearch    
110
+
111
+    if Bounds == 0:
112
+
113
+        # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
114
+        print("2 UNbounded ( +-", Bounds,") search length ", kNs0, kNs1 ,"for f0", f0, f1)
115
+        res = minimize(harmonic2Norm, np.array((f0, f1)), args=(sN, fs, t, f0k1, f0k1+kNs0, f0ks, f1k1, f1k1+kNs1, f1ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
116
+    else:
117
+        # Bounded
118
+        bnds = ( (f0-Bounds, f0+Bounds),(f1-Bounds, f1+Bounds) )
119
+        print("2 bounded ( +-", Bounds,") search length ", kNs0, kNs1 ,"for f0", f0, f1)
120
+        # L-BFGS-B hess=None, bounds=None )
121
+        res = minimize(harmonic2Norm, ((f0,f1)), args=(sN, fs, t, f0k1, f0k1+kNs0, f0ks, f1k1, f1k1+kNs1, f1ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) 
122
+
121
     return harmonicEuler2(sN, fs, t, res.x[0], f0k1, f0kN, f0ks, res.x[1], f1k1, f1kN, f1ks), res.x[0], res.x[1]#[0]
123
     return harmonicEuler2(sN, fs, t, res.x[0], f0k1, f0kN, f0ks, res.x[1], f1k1, f1kN, f1ks), res.x[0], res.x[1]#[0]
122
 
124
 
123
 def guessf0( sN, fs ):
125
 def guessf0( sN, fs ):
124
     S = np.fft.fft(sN)
126
     S = np.fft.fft(sN)
125
     w = np.fft.fftfreq( len(sN), 1/fs )
127
     w = np.fft.fftfreq( len(sN), 1/fs )
126
     imax = np.argmax( np.abs(S) )
128
     imax = np.argmax( np.abs(S) )
129
+
130
+    #np.save( "sN.npy", S )
131
+    #np.save( "w.npy", w )
132
+    #exit()
127
     #plt.plot( w, np.abs(S) )
133
     #plt.plot( w, np.abs(S) )
128
     #plt.show()
134
     #plt.show()
129
     #print(w)
135
     #print(w)
130
-    #print ( w[imax], w[imax+1] )
136
+    #print ( w[imax], w[imax+1] )esta bien in english
131
     return abs(w[imax])
137
     return abs(w[imax])
132
 
138
 
133
 if __name__ == "__main__":
139
 if __name__ == "__main__":

+ 82
- 54
akvo/tressel/mrsurvey.py View File

536
         #canvas.fig.tight_layout() 
536
         #canvas.fig.tight_layout() 
537
         canvas.draw()
537
         canvas.draw()
538
         self.doneTrigger.emit() 
538
         self.doneTrigger.emit() 
539
-
540
-    #def harmonicModel(self, nF, nK, f0, f1, plot, canvas):
541
     
539
     
542
     def harmonicModel(self, nF, \
540
     def harmonicModel(self, nF, \
543
         f0, f0K1, f0KN, f0Ks, f0ns, \
541
         f0, f0K1, f0KN, f0Ks, f0ns, \
544
         f1, f1K1, f1KN, f1Ks,  \
542
         f1, f1K1, f1KN, f1Ks,  \
543
+        Nsearch, Bounds, procRefs, \
545
         plot, canvas):
544
         plot, canvas):
546
         """ nF = number of base frequencies, must be 1 or 2 
545
         """ nF = number of base frequencies, must be 1 or 2 
547
             f0 = first base frequency  
546
             f0 = first base frequency  
553
             f1K1 = first harmonic to model for second base frequency 
552
             f1K1 = first harmonic to model for second base frequency 
554
             f1KN = last harmonic to model for the second base frequency 
553
             f1KN = last harmonic to model for the second base frequency 
555
             f1Ks = subharmonic spacing for the second base frequency, set to 1 for no subharmonics.
554
             f1Ks = subharmonic spacing for the second base frequency, set to 1 for no subharmonics.
555
+            Nsearch = the number of harmonics to use when determining base frequency 
556
+            bounds = 1/2 the width of the space where baseline frequency will be searched  
557
+            procRefs = should the reference loops be processed as well  
556
             plot = should Akvo plot the results 
558
             plot = should Akvo plot the results 
557
             canvas = mpl plotting axis      
559
             canvas = mpl plotting axis      
558
         """
560
         """
559
         if plot:
561
         if plot:
560
-            canvas.reAx2()
562
+            canvas.reAx2(shy=False)
561
             canvas.ax1.set_ylabel(r"signal [nV]", fontsize=8)
563
             canvas.ax1.set_ylabel(r"signal [nV]", fontsize=8)
562
-            canvas.ax2.set_xlabel(r"time [s]", fontsize=8)
564
+            #canvas.ax2.set_xlabel(r"time [s]", fontsize=8)
563
             canvas.ax2.set_ylabel(r"signal [nV]", fontsize=8)
565
             canvas.ax2.set_ylabel(r"signal [nV]", fontsize=8)
564
-
566
+            canvas.ax2.set_xlabel(r"frequency [Hz]", fontsize=8)
567
+            canvas.ax1.set_yscale('log')
568
+            canvas.ax2.set_yscale('log')
565
         # Data
569
         # Data
566
         iFID = 0
570
         iFID = 0
567
 
571
 
582
                 for ipm in range(self.DATADICT["nPulseMoments"]):
586
                 for ipm in range(self.DATADICT["nPulseMoments"]):
583
                     if plot:
587
                     if plot:
584
                         canvas.softClear()
588
                         canvas.softClear()
585
-                        mmax = 0
586
-                        for ichan in self.DATADICT[pulse]["rchan"]:
587
-                            canvas.ax1.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], alpha=.5) 
588
-                            mmax = max( mmax, np.max(1e9*self.DATADICT[pulse][ichan][ipm][istack])) 
589
+                        mmaxr = 0
590
+                        mmaxd = 0
591
+                        if procRefs: 
592
+                            for ichan in self.DATADICT[pulse]["rchan"]:
593
+                                #canvas.ax1.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], alpha=.5) 
594
+                                #mmaxr = max( mmaxr, np.max(1e9*self.DATADICT[pulse][ichan][ipm][istack])) 
595
+                                ww = np.fft.fftfreq(len(self.DATADICT[pulse][ichan][ipm][istack]), d=self.dt)
596
+                                X = np.fft.rfft(self.DATADICT[pulse][ichan][ipm][istack])
597
+                                canvas.ax1.plot(np.abs(ww[0:len(X)]), np.abs(X), alpha=.5)
598
+                            canvas.ax1.set_prop_cycle(None)
599
+                            #canvas.ax1.set_ylim(-mmaxr, mmaxr) 
589
                         for ichan in self.DATADICT[pulse]["chan"]:
600
                         for ichan in self.DATADICT[pulse]["chan"]:
590
-                            canvas.ax2.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], alpha=.5) 
591
-                            mmax = max( mmax, np.max(1e9*self.DATADICT[pulse][ichan][ipm][istack])) 
592
-                        canvas.ax1.set_prop_cycle(None)
601
+                            #canvas.ax2.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], alpha=.5) 
602
+                            #mmaxd = max( mmaxd, np.max(1e9*self.DATADICT[pulse][ichan][ipm][istack])) 
603
+                            ww = np.fft.fftfreq(len(self.DATADICT[pulse][ichan][ipm][istack]), d=self.dt)
604
+                            X = np.fft.rfft(self.DATADICT[pulse][ichan][ipm][istack])
605
+                            canvas.ax2.plot(np.abs(ww[0:len(X)]), np.abs(X), alpha=.5)
593
                         canvas.ax2.set_prop_cycle(None)
606
                         canvas.ax2.set_prop_cycle(None)
594
-                        canvas.ax1.set_ylim(-mmax, mmax) 
595
-                    for ichan in self.DATADICT[pulse]["rchan"]:
596
-                        if nF == 1:
597
-                            for iseg in range(f0ns):
598
-                                if iseg < f0ns-1:
599
-                                    self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan] = \
600
-                                        harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], \
607
+                        #canvas.ax2.set_ylim(-mmaxd, mmaxd)
608
+                    if procRefs: 
609
+                        for ichan in self.DATADICT[pulse]["rchan"]:
610
+                            if nF == 1:
611
+                                for iseg in range(f0ns):
612
+                                    if iseg < f0ns-1:
613
+                                        self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan] = \
614
+                                            harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], \
601
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
615
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
602
-                                            f0p[ichan], f0K1, f0KN, f0Ks ) 
603
-                                else:
604
-                                    self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan] = \
605
-                                        harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], \
616
+                                            f0p[ichan], f0K1, f0KN, f0Ks, Bounds, Nsearch ) 
617
+                                    else:
618
+                                        self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan] = \
619
+                                            harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], \
606
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
620
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
607
-                                            f0p[ichan], f0K1, f0KN, f0Ks ) 
608
-                        elif nF == 2:
609
-                            for iseg in range(f0ns):
610
-                                if iseg < f0ns-1:
611
-                                    self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan], f1p[ichan] = \
612
-                                        harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg],\
613
-                                     self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
614
-                                     f0p[ichan], f0K1, f0KN, f0Ks,  \
615
-                                     f1p[ichan], f1K1, f1KN, f1Ks ) 
616
-                                else:
617
-                                    self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan], f1p[ichan] = \
618
-                                        harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::],\
619
-                                     self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
620
-                                     f0p[ichan], f0K1, f0KN, f0Ks,  \
621
-                                     f1p[ichan], f1K1, f1KN, f1Ks ) 
622
-                        # plot
623
-                        if plot:
624
-                            canvas.ax1.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], \
621
+                                            f0p[ichan], f0K1, f0KN, f0Ks, Bounds, Nsearch ) 
622
+                            elif nF == 2:
623
+                                for iseg in range(f0ns):
624
+                                    if iseg < f0ns-1:
625
+                                        self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan], f1p[ichan] = \
626
+                                            harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg],\
627
+                                        self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
628
+                                        f0p[ichan], f0K1, f0KN, f0Ks,  \
629
+                                        f1p[ichan], f1K1, f1KN, f1Ks, Bounds, Nsearch ) 
630
+                                    else:
631
+                                        self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan], f1p[ichan] = \
632
+                                            harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::],\
633
+                                        self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
634
+                                        f0p[ichan], f0K1, f0KN, f0Ks,  \
635
+                                        f1p[ichan], f1K1, f1KN, f1Ks, Bounds, Nsearch ) 
636
+                            # plot
637
+                            if plot:
638
+                                #canvas.ax1.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], \
639
+                                #    label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " rchan="  + str(ichan))
640
+                                ww = np.fft.fftfreq(len(self.DATADICT[pulse][ichan][ipm][istack]), d=self.dt)
641
+                                X = np.fft.rfft(self.DATADICT[pulse][ichan][ipm][istack])
642
+                                canvas.ax1.plot(np.abs(ww[0:len(X)]), np.abs(X),\
625
                                 label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " rchan="  + str(ichan))
643
                                 label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " rchan="  + str(ichan))
626
 
644
 
627
                     for ichan in self.DATADICT[pulse]["chan"]:
645
                     for ichan in self.DATADICT[pulse]["chan"]:
628
-                        
629
                         if nF == 1:
646
                         if nF == 1:
630
                             for iseg in range(f0ns):
647
                             for iseg in range(f0ns):
631
                                 if iseg < f0ns-1:
648
                                 if iseg < f0ns-1:
632
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan] = \
649
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], f0p[ichan] = \
633
                                         harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], 
650
                                         harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg], 
634
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
651
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
635
-                                            f0p[ichan], f0K1, f0KN, f0Ks ) 
652
+                                            f0p[ichan], f0K1, f0KN, f0Ks, Bounds, Nsearch ) 
636
                                 else:
653
                                 else:
637
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan] = \
654
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan] = \
638
                                         harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], 
655
                                         harmonic.minHarmonic( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], 
639
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
656
                                             self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
640
-                                            f0p[ichan], f0K1, f0KN, f0Ks )
657
+                                            f0p[ichan], f0K1, f0KN, f0Ks, Bounds, Nsearch )
641
 
658
 
642
                         elif nF == 2:
659
                         elif nF == 2:
643
                             for iseg in range(f0ns):
660
                             for iseg in range(f0ns):
646
                                         harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg],\
663
                                         harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg:(iseg+1)*Nseg],\
647
                                      self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
664
                                      self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg:(iseg+1)*Nseg], \
648
                                      f0p[ichan], f0K1, f0KN, f0Ks,  \
665
                                      f0p[ichan], f0K1, f0KN, f0Ks,  \
649
-                                     f1p[ichan], f1K1, f1KN, f1Ks ) 
666
+                                     f1p[ichan], f1K1, f1KN, f1Ks, Bounds, Nsearch ) 
650
                                 else:
667
                                 else:
651
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan], f1p[ichan] = \
668
                                     self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::], f0p[ichan], f1p[ichan] = \
652
                                         harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::],\
669
                                         harmonic.minHarmonic2( self.DATADICT[pulse][ichan][ipm][istack][iseg*Nseg::],\
653
                                      self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
670
                                      self.samp,  self.DATADICT[pulse]["TIMES"][iseg*Nseg::], \
654
                                      f0p[ichan], f0K1, f0KN, f0Ks,  \
671
                                      f0p[ichan], f0K1, f0KN, f0Ks,  \
655
-                                     f1p[ichan], f1K1, f1KN, f1Ks ) 
672
+                                     f1p[ichan], f1K1, f1KN, f1Ks, Bounds, Nsearch ) 
656
                
673
                
657
                         # plot
674
                         # plot
658
                         if plot:
675
                         if plot:
659
-                            canvas.ax2.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], \
676
+                            #canvas.ax2.plot( self.DATADICT[pulse]["TIMES"], 1e9*self.DATADICT[pulse][ichan][ipm][istack], \
677
+                            #    label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " chan="  + str(ichan))
678
+                            ww = np.fft.fftfreq(len(self.DATADICT[pulse][ichan][ipm][istack]), d=self.dt)
679
+                            X = np.fft.rfft(self.DATADICT[pulse][ichan][ipm][istack])
680
+                            canvas.ax2.plot(np.abs(ww[0:len(X)]), np.abs(X), \
660
                                 label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " chan="  + str(ichan))
681
                                 label = pulse + " ipm=" + str(ipm) + " istack=" + str(istack) + " chan="  + str(ichan))
661
 
682
 
662
                     if plot:
683
                     if plot:
663
-                        canvas.ax1.legend(prop={'size':6}, loc='upper right')
684
+                        if procRefs: 
685
+                            canvas.ax1.legend(prop={'size':6}, loc='upper right')
664
                         canvas.ax2.legend(prop={'size':6}, loc='upper right')
686
                         canvas.ax2.legend(prop={'size':6}, loc='upper right')
665
                         canvas.draw() 
687
                         canvas.draw() 
666
                 
688
                 
1063
                 if phase == 1: # Amp phase
1085
                 if phase == 1: # Amp phase
1064
                     im1 = ax1.pcolormesh( time_sp, QQ, self.DATADICT["CA"][pulse][chan], cmap=dcmap, rasterized=True,
1086
                     im1 = ax1.pcolormesh( time_sp, QQ, self.DATADICT["CA"][pulse][chan], cmap=dcmap, rasterized=True,
1065
                          vmin=-self.DATADICT["CAmax"][pulse] , vmax=self.DATADICT["CAmax"][pulse]  )
1087
                          vmin=-self.DATADICT["CAmax"][pulse] , vmax=self.DATADICT["CAmax"][pulse]  )
1066
-                    im2 = ax2.pcolormesh( time_sp, QQ, self.DATADICT["IP"][pulse][chan], cmap=cmocean.cm.balance, rasterized=True,\
1088
+                    #im2 = ax2.pcolormesh( time_sp, QQ, self.DATADICT["IP"][pulse][chan], cmap=cmocean.cm.balance, rasterized=True,\
1089
+                    im2 = ax2.pcolormesh( time_sp, QQ, self.DATADICT["IP"][pulse][chan], cmap=cmocean.cm.delta, rasterized=True,\
1067
                          vmin=-np.pi, vmax=np.pi)
1090
                          vmin=-np.pi, vmax=np.pi)
1068
                 if phase == 2: # CA NR
1091
                 if phase == 2: # CA NR
1069
                     im1 = ax1.pcolormesh( time_sp, QQ, self.DATADICT["CA"][pulse][chan], cmap=dcmap, rasterized=True,\
1092
                     im1 = ax1.pcolormesh( time_sp, QQ, self.DATADICT["CA"][pulse][chan], cmap=dcmap, rasterized=True,\
2065
     def computeWindow(self, pulse, band, centre, ftype, canvas=None):
2088
     def computeWindow(self, pulse, band, centre, ftype, canvas=None):
2066
         
2089
         
2067
         # Compute window
2090
         # Compute window
2068
-        nd = len(self.DATADICT[pulse][self.DATADICT[pulse]["chan"][0]][0][self.DATADICT["stacks"][0]])
2091
+        nd = len(self.DATADICT[pulse][self.DATADICT[pulse]["chan"][0]][0][self.DATADICT["stacks"][0]]) # num. data 
2069
         fft1 = np.fft.rfft(self.DATADICT[pulse][self.DATADICT[pulse]["chan"][0]][0][self.DATADICT["stacks"][0]])
2092
         fft1 = np.fft.rfft(self.DATADICT[pulse][self.DATADICT[pulse]["chan"][0]][0][self.DATADICT["stacks"][0]])
2070
         freqs   = np.fft.fftfreq(nd, self.dt)
2093
         freqs   = np.fft.fftfreq(nd, self.dt)
2071
         df      = freqs[1] - freqs[0]
2094
         df      = freqs[1] - freqs[0]
2119
             canvas.ax2.set_title("IFFT")
2142
             canvas.ax2.set_title("IFFT")
2120
             canvas.draw()
2143
             canvas.draw()
2121
 
2144
 
2122
-        return [WINDOW, nd, istart, iend, dead]
2145
+        return [WINDOW, nd, istart, iend, dead, ift]
2123
 
2146
 
2124
-    def windowFilter(self, ftype, band, centre, canvas):
2147
+    def windowFilter(self, ftype, band, centre, trunc, canvas):
2125
 
2148
 
2126
         ###############################
2149
         ###############################
2127
         # Window Filter (Ormsby filter http://www.xsgeo.com/course/filt.htm) 
2150
         # Window Filter (Ormsby filter http://www.xsgeo.com/course/filt.htm) 
2128
         # apply window
2151
         # apply window
2129
         iFID = 0
2152
         iFID = 0
2130
         for pulse in self.DATADICT["PULSES"]:
2153
         for pulse in self.DATADICT["PULSES"]:
2131
-            [WINDOW, nd, istart, iend,dead] = self.computeWindow(pulse, band, centre, ftype)
2154
+            [WINDOW, nd, istart, iend, dead, idead] = self.computeWindow(pulse, band, centre, ftype)
2132
             for istack in self.DATADICT["stacks"]:
2155
             for istack in self.DATADICT["stacks"]:
2133
                 for ipm in range(self.DATADICT["nPulseMoments"]):
2156
                 for ipm in range(self.DATADICT["nPulseMoments"]):
2134
                     for ichan in np.append(self.DATADICT[pulse]["chan"], self.DATADICT[pulse]["rchan"]):
2157
                     for ichan in np.append(self.DATADICT[pulse]["chan"], self.DATADICT[pulse]["rchan"]):
2135
                         fft = np.fft.rfft( self.DATADICT[pulse][ichan][ipm][istack]  )
2158
                         fft = np.fft.rfft( self.DATADICT[pulse][ichan][ipm][istack]  )
2136
                         fft *= WINDOW
2159
                         fft *= WINDOW
2137
-                        self.DATADICT[pulse][ichan][ipm][istack] = np.fft.irfft(fft , nd)
2160
+                        if trunc:
2161
+                            self.DATADICT[pulse][ichan][ipm][istack] = np.fft.irfft(fft, nd)[idead:-idead]
2162
+                        else:
2163
+                            self.DATADICT[pulse][ichan][ipm][istack] = np.fft.irfft(fft, nd)
2138
                 
2164
                 
2139
                     percent = (int)(1e2*((float)(iFID*self.DATADICT["nPulseMoments"]+(ipm))/(len(self.DATADICT["PULSES"])*self.nPulseMoments)))
2165
                     percent = (int)(1e2*((float)(iFID*self.DATADICT["nPulseMoments"]+(ipm))/(len(self.DATADICT["PULSES"])*self.nPulseMoments)))
2140
                     self.progressTrigger.emit(percent)  
2166
                     self.progressTrigger.emit(percent)  
2141
                 iFID += 1
2167
                 iFID += 1
2168
+            if trunc:
2169
+                self.DATADICT[pulse]["TIMES"] = self.DATADICT[pulse]["TIMES"][idead:-idead]
2142
 
2170
 
2143
         self.plotFT(canvas, istart, iend)
2171
         self.plotFT(canvas, istart, iend)
2144
         self.doneTrigger.emit() 
2172
         self.doneTrigger.emit() 

+ 1
- 1
setup.py View File

21
     long_description = fh.read()
21
     long_description = fh.read()
22
 
22
 
23
 setup(name='Akvo',
23
 setup(name='Akvo',
24
-      version='1.2.6',
24
+      version='1.2.7',
25
       description='Surface nuclear magnetic resonance workbench',
25
       description='Surface nuclear magnetic resonance workbench',
26
       long_description=long_description,
26
       long_description=long_description,
27
       long_description_content_type='text/markdown',
27
       long_description_content_type='text/markdown',

Loading…
Cancel
Save