CalibrationUpdater.py 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. import time
  2. import os
  3. import math
  4. import numpy as np
  5. from numpy.polynomial.polynomial import polyval
  6. import h5py
  7. import traceback
  8. import csv
  9. import warnings
  10. from scipy.optimize import curve_fit
  11. from scipy.stats import chisquare
  12. from scipy.stats import chi2_contingency
  13. from scipy.special import erfc, erf
  14. import datetime
  15. import pyqtgraph as pg
  16. from PyQt4 import QtGui, QtCore, QtSvg
  17. import matplotlib
  18. matplotlib.use("Qt4Agg")
  19. #matplotlib.use("Agg")
  20. import matplotlib.pyplot as plt
  21. try:
  22. #for KCG
  23. from ... import config
  24. from ...config import colours, coloursTrans
  25. from .. import kcgwidget as kcgw
  26. from .CalibrationHandle import theCalibration
  27. from .constants import KARA
  28. from .TimeScan import TimeScan
  29. except:
  30. #for Analysis GUI
  31. import config
  32. from config import colours, coloursTrans
  33. import kcgwidget as kcgw
  34. from CalibrationHandle import theCalibration
  35. from constants import KARA
  36. from TimeScan import TimeScan
  37. LINEAR = 0
  38. GAUSS = 1
  39. GAUSSB = 2
  40. EGAUSSC= 3
  41. EGAUSS = 4
  42. EGAUSSB= 5
  43. SKEW = 6
  44. SINUS = 7
  45. import shutil
  46. def sinus(x,a,b,c,d):
  47. return a*np.sin(b*x*(2*np.pi)+d)+c
  48. class CalibrationUpdater(kcgw.KCGWidgets):
  49. """
  50. The Timescan result plot subwindow.
  51. """
  52. def __init__(self, timeScan, parent=None, bunch=0, workingChannels=[0,1,2,3,4,5,6,7]):
  53. super(CalibrationUpdater, self).__init__()
  54. # ------[ Variable declaration ]------------
  55. self.parent=parent
  56. self.adc_number = 8
  57. self.timeScan = timeScan # Data to plot
  58. self.calibId = self.timeScan.calibId
  59. self.originalnotplotted = True
  60. self.running = False
  61. theCalibration.setHandle(self.calibId)
  62. self.grpX = theCalibration.grpX
  63. self.grpY = theCalibration.grpY
  64. self.workingChannels = workingChannels
  65. # -------[ Create structure ]----------
  66. self.outerLayout = QtGui.QVBoxLayout() # Outermost layout of this window
  67. self.setLayout(self.outerLayout)
  68. self.settingsLayout = QtGui.QGridLayout()
  69. lineindex = 0
  70. fileName = self.timeScan.fileName
  71. if fileName is None:
  72. fileName = 'Last Measurement'
  73. self.text_label = QtGui.QLabel('selected Timescan: ' + fileName)
  74. self.settingsLayout.addWidget(self.text_label, lineindex, 0,1,2)
  75. lineindex +=1
  76. self.text_label = QtGui.QLabel('selected CalibrationFile: ' + self.calibId)
  77. self.settingsLayout.addWidget(self.text_label, lineindex, 0,1,2)
  78. lineindex +=1
  79. self.text_label = QtGui.QLabel('select type: ')
  80. self.settingsLayout.addWidget(self.text_label, lineindex, 0)
  81. self.comboBox = QtGui.QComboBox(self)
  82. self.comboBox.addItem("Peak Positive") #0
  83. self.comboBox.addItem("Peak Negative") #1
  84. self.comboBox.addItem("500MHz") #2
  85. self.settingsLayout.addWidget(self.comboBox, lineindex, 1)
  86. #lineindex +=1
  87. self.text_label = QtGui.QLabel('select Fit: ')
  88. self.settingsLayout.addWidget(self.text_label, lineindex, 2)
  89. self.fitSelect = QtGui.QComboBox(self)
  90. self.fitSelect.addItem("Exponential mod Gauss") #3
  91. self.fitSelect.addItem("Exponential mod Gauss V2") #4
  92. self.fitSelect.addItem("skew Gauss") #5
  93. self.settingsLayout.addWidget(self.fitSelect, lineindex, 3)
  94. lineindex +=1
  95. self.useFirst = QtGui.QSpinBox()
  96. self.useFirst.setRange(0, 1000)
  97. self.useFirst.setSingleStep(1)
  98. self.useFirst.setValue(0)
  99. self.settingsLayout.addWidget(QtGui.QLabel('use first data as Baseline'), lineindex, 0)
  100. self.settingsLayout.addWidget(self.useFirst, lineindex, 1)
  101. lineindex += 1
  102. self.multiBunchSelector = self.createSpinbox(0,184, start_value=bunch, interval=1, connect=self.on_updateBunch)
  103. self.multiBunchSelectorLabel = self.createLabel('Bunch Selection:')
  104. self.settingsLayout.addWidget(self.multiBunchSelectorLabel, lineindex, 0)
  105. self.settingsLayout.addWidget(self.multiBunchSelector, lineindex, 1)
  106. if self.timeScan.multibunch == False:
  107. self.multiBunchSelector.hide()
  108. self.multiBunchSelectorLabel.hide()
  109. lineindex += 1
  110. self.adcCheckBox = []
  111. self.adc_checkbox_layout = QtGui.QHBoxLayout()
  112. self.group = QtGui.QButtonGroup()
  113. self.group.setExclusive(False)
  114. #print(self.workingChannels)
  115. for i in range(self.adc_number):
  116. self.adcCheckBox.append(self.createCheckbox(text="ADC "+str(i+1), connect=self.changeWorking))
  117. self.adc_checkbox_layout.addWidget(self.adcCheckBox[i])
  118. self.group.addButton(self.adcCheckBox[i], i+1)
  119. if i in self.workingChannels:
  120. self.adcCheckBox[i].setChecked(True)
  121. else:
  122. self.adcCheckBox[i].setChecked(False)
  123. self.groupWidget = QtGui.QWidget()
  124. self.groupWidget.setLayout(self.adc_checkbox_layout)
  125. self.settingsLayout.addWidget(self.groupWidget, lineindex,0,1,4)
  126. lineindex +=1
  127. self.okay_btn = QtGui.QPushButton("Run")
  128. self.okay_btn.setStyleSheet("padding: 15px;")
  129. self.okay_btn.clicked.connect(self.on_okay)
  130. self.settingsLayout.addWidget(self.okay_btn, lineindex, 0)
  131. self.okay_btn = QtGui.QPushButton("Save")
  132. self.okay_btn.setStyleSheet("padding: 15px;")
  133. self.okay_btn.clicked.connect(self.on_save)
  134. self.settingsLayout.addWidget(self.okay_btn, lineindex, 1)
  135. self.cancel_btn = QtGui.QPushButton("Cancel")
  136. self.cancel_btn.setStyleSheet("padding: 15px;")
  137. self.cancel_btn.clicked.connect(self.on_cancel)
  138. self.settingsLayout.addWidget(self.cancel_btn, lineindex, 2)
  139. #######################
  140. self.plotLayout = QtGui.QHBoxLayout()
  141. self.plotWidget1 = QtGui.QWidget()
  142. self.plotlayout1= QtGui.QGridLayout() # Main Layout to hold the most elements in this window
  143. self.all_plot_widget = pg.PlotWidget(title="original")
  144. self.plotlayout1.addWidget(self.all_plot_widget, 0, 0)
  145. self.plotWidget1.setLayout(self.plotlayout1)
  146. self.plotWidget2 = QtGui.QWidget()
  147. self.plotlayout2 = QtGui.QGridLayout() # Main Layout to hold the most elements in this window
  148. self.calibrated_plot = pg.PlotWidget(title="calibrated")
  149. self.plotlayout2.addWidget(self.calibrated_plot, 0, 0)
  150. self.plotWidget2.setLayout(self.plotlayout2)
  151. self.plotLayout.addWidget(self.plotWidget1)
  152. self.plotLayout.addWidget(self.plotWidget2)
  153. # -- Create Parameter Adjust
  154. self.blocking = True
  155. self.parameterLayout = QtGui.QGridLayout()
  156. lineindex = 0
  157. self.adcBaselineBox = []
  158. self.parameterLayout.addWidget(self.createLabel('baseline'), lineindex,0)
  159. for i in range(self.adc_number):
  160. self.adcBaselineBox.append(self.createInput(text="", connect=self.update))
  161. self.parameterLayout.addWidget(self.adcBaselineBox[i], lineindex, i+1)
  162. lineindex += 1
  163. #self.adc_offset_layout.addWidget(self.createLabel('ADC '+ str(i+1)))
  164. #self.adc_offset_layout.addWidget(self.adcOffsetBox[i])
  165. self.adcScalingBox = []
  166. self.parameterLayout.addWidget(self.createLabel('scaling'), lineindex,0)
  167. for i in range(self.adc_number):
  168. self.adcScalingBox.append(self.createInput(text="", connect=self.update))
  169. self.parameterLayout.addWidget(self.adcScalingBox[i], lineindex, i+1)
  170. lineindex += 1
  171. self.adcOffsetBox = []
  172. self.parameterLayout.addWidget(self.createLabel('offset (ps)'), lineindex,0)
  173. for i in range(self.adc_number):
  174. self.adcOffsetBox.append(self.createInput(text="", connect=self.update))
  175. self.parameterLayout.addWidget(self.adcOffsetBox[i], lineindex, i+1)
  176. lineindex += 1
  177. self.outerLayout.addLayout(self.settingsLayout)
  178. self.outerLayout.addLayout(self.plotLayout)
  179. self.outerLayout.addLayout(self.parameterLayout)
  180. self.blocking = False
  181. self.setWindowTitle("CalibrationUpdater")
  182. self.plot()
  183. self.displayParameter()
  184. def on_okay(self, param):
  185. if not self.running:
  186. self.old_id = self.calibId
  187. self.calibId += '.new'
  188. self.timeScan.calibId = self.calibId
  189. shutil.copy(self.old_id, self.calibId)
  190. theCalibration.openFile(self.calibId, write=True)
  191. self.grpX = theCalibration.grpX
  192. self.grpY = theCalibration.grpY
  193. self.running = True
  194. self.runCalibration()
  195. def on_save(self, param):
  196. if self.running:
  197. theCalibration.closeHandle(self.calibId)
  198. theCalibration.closeHandle(self.old_id)
  199. ctr=0
  200. filelist = np.sort(os.listdir(os.path.dirname(self.old_id)))
  201. for file in filelist:
  202. if '.old' in file:
  203. if int(file[-2:]) >= ctr:
  204. ctr = int(file[-2:])+1
  205. #print('rename')
  206. os.rename(self.old_id, self.old_id+'.old{:02d}'.format(ctr))
  207. os.rename(self.calibId, self.old_id)
  208. self.calibId = self.old_id
  209. theCalibration.openFile(self.calibId, force=True)
  210. self.timeScan.calibId = self.calibId
  211. self.running = False
  212. pass
  213. def on_cancel(self, param):
  214. self.close()
  215. pass
  216. def on_updateBunch(self, param):
  217. self.originalnotplotted = True
  218. self.plot()
  219. def changeWorking(self, param):
  220. self.workingChannels = []
  221. for i in range(self.adc_number):
  222. if self.adcCheckBox[i].isChecked():
  223. self.workingChannels.append(i)
  224. #print(self.workingChannels)
  225. self.originalnotplotted = True
  226. self.plot()
  227. def displayParameter(self):
  228. self.blocking = True
  229. for i in self.workingChannels:
  230. try:
  231. popt = self.grpY[str(i)][0]
  232. self.adcBaselineBox[i].setText('{:.3f}'.format(popt[0]))
  233. self.adcScalingBox[i].setText('{:.3f}'.format(popt[1]))
  234. self.adcOffsetBox[i].setText('{:.3f}'.format(self.grpX[str(i)]['offset'][()]*1e12))
  235. except:
  236. pass
  237. self.blocking = False
  238. def update(self):
  239. if not self.running:
  240. return
  241. if self.blocking:
  242. return
  243. for i in self.workingChannels:
  244. #print(self.adcOffsetBox[i].text())
  245. #print(self.grpY[str(i)][0])
  246. self.grpY[str(i)][...] = [[float(str(self.adcBaselineBox[i].text())), float(str(self.adcScalingBox[i].text()))]]
  247. self.grpX[str(i)]['offset'][...] = float(str(self.adcOffsetBox[i].text()))*1e-12
  248. #print(i, self.grpY[str(i)][0], self.grpX[str(i)]['offset'][()])
  249. pass
  250. self.plot()
  251. def plot(self):
  252. """
  253. Plot Data
  254. :return: -
  255. """
  256. self.processbarWidget = WaitingWidget(self)
  257. if self.originalnotplotted:
  258. self.originalnotplotted = False
  259. self.all_plot_widget.plotItem.clear()
  260. for i in self.workingChannels:
  261. try:
  262. scanx, scany, scane = self.timeScan.getScanOverTime(i, False, False, bunch=self.multiBunchSelector.value())
  263. self.all_plot_widget.plotItem.plot(scanx, scany, pen=None, symbolPen=pg.mkPen(colours[i]), symbolSize=4, pxMode=True, symbolBrush=pg.mkBrush(colours[i]), downsample=200)
  264. except:
  265. pass
  266. self.calibrated_plot.plotItem.clear()
  267. for i in self.workingChannels:
  268. try:
  269. scanx, scany, scane = self.timeScan.getScanOverTime(i, True, True, force=i==0, bunch=self.multiBunchSelector.value())
  270. sorter = np.argsort(scanx)
  271. scanx = scanx[sorter]
  272. scany = scany[sorter]
  273. N=3
  274. scanyAvg = np.convolve(scany, np.ones((N,))/N, mode='valid')
  275. self.calibrated_plot.plotItem.plot(scanx, scany, pen=None, symbolPen=pg.mkPen(colours[i]), symbolSize=4, pxMode=True, symbolBrush=pg.mkBrush(colours[i]), downsample=200)
  276. self.calibrated_plot.plotItem.plot(scanx[1:-1], scanyAvg, pen=pg.mkPen(colours[i]), downsample=200)
  277. except:
  278. pass
  279. self.processbarWidget.close()
  280. self.processbarWidget = None
  281. self.show()
  282. self.setFocus()
  283. ##################################################################################
  284. def closeEvent(self, event):
  285. """
  286. Event handler for closing this window
  287. """
  288. #reopen file so that it is in read only mode
  289. if self.running:
  290. theCalibration.closeHandle(self.calibId)
  291. self.timeScan.calibId = self.old_id
  292. self.calibId = self.old_id
  293. theCalibration.openFile(self.calibId, force=True)
  294. if self.processbarWidget is not None:
  295. self.processbarWidget.close()
  296. if self.parent is not None:
  297. self.parent.updater = None
  298. # .d8888b. 888 .d8888b. 888 d8b 888 888 d8b
  299. # d88P Y88b 888 d88P Y88b 888 Y8P 888 888 Y8P
  300. # 888 888 888 888 888 888 888 888
  301. # 888 .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. 888 8888b. 888 888 88888b. 888d888 8888b. 888888 888 .d88b. 88888b.
  302. # 888 88888 d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b 888 "88b 888 888 888 "88b 888P" "88b 888 888 d88""88b 888 "88b
  303. # 888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888
  304. # Y88b d88P Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b d88P 888 888 888 888 888 d88P 888 888 888 Y88b. 888 Y88..88P 888 888
  305. # "Y8888P88 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y8888P" "Y888888 888 888 88888P" 888 "Y888888 "Y888 888 "Y88P" 888 888
  306. #
  307. #
  308. #
  309. def runCalibration(self):
  310. typ = self.comboBox.currentIndex()
  311. fittype = self.fitSelect.currentIndex()+EGAUSS
  312. useFirst = self.useFirst.value()
  313. #print(typ, fittype, useFirst)
  314. if typ in [0,1]: #Peak
  315. self.updateY(typ, fittype, useFirst)
  316. elif typ == 2: #500MHz
  317. self.updateX()
  318. #self.generateMap(fh)
  319. pass
  320. pass
  321. # Y88b d88P .d8888b. 888 d8b 888 888 d8b
  322. # Y88b d88P d88P Y88b 888 Y8P 888 888 Y8P
  323. # Y88o88P 888 888 888 888 888
  324. # Y888P 888 8888b. 888 888 88888b. 888d888 8888b. 888888 888 .d88b. 88888b.
  325. # 888 888 "88b 888 888 888 "88b 888P" "88b 888 888 d88""88b 888 "88b
  326. # 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888
  327. # 888 Y88b d88P 888 888 888 888 888 d88P 888 888 888 Y88b. 888 Y88..88P 888 888
  328. # 888 "Y8888P" "Y888888 888 888 88888P" 888 "Y888888 "Y888 888 "Y88P" 888 888
  329. #
  330. #
  331. #
  332. def updateY(self, isNegativ=0, fittype=EGAUSSB, useFirst=0):
  333. try:
  334. self.generateYCalibration(theCalibration.fileHandle, isNegativ, fittype, useFirst)
  335. except:
  336. print('error Calibrating Y')
  337. traceback.print_exc()
  338. #self.generateMap(fh)
  339. self.displayParameter()
  340. self.plot()
  341. def generateYCalibration(self, fh, isNegativ=0, fittype=EGAUSSB, useFirst=0):
  342. print('start Y Calibration')
  343. grpY = fh['y']
  344. grpX = fh['x']
  345. fitFun = lambda x: x
  346. phase0 = 0.0
  347. A0 =0.0
  348. for i in range(self.timeScan.adcNumber):
  349. try:
  350. grpX[str(i)]['offset'][...] = 0
  351. except:
  352. try:
  353. grpX[str(i)]['offset'] = 0
  354. except:
  355. pass
  356. for i in range(self.timeScan.adcNumber):
  357. print(i,'-----------------------------')
  358. baseline = 0.0
  359. if i not in self.workingChannels:
  360. grpY[str(i)][...] = np.array([[0.0,1.0]])
  361. #grpY.create_dataset(str(i), data=np.array([[0.0,1.0]]))
  362. #grpX[str(i)]['offset'] = 0
  363. continue
  364. try:
  365. #scanx = self.prepareX(data, grpX['d330'], grpX['d25'], grpX['d3'], grpX[str(i)]['330'], grpX[str(i)]['25'], grpX[str(i)]['3'], zero25B=grpX['d25b_zero'], cal25B=grpX[str(i)]['25b'])
  366. scanx, scany, scane = self.timeScan.getScanOverTime(i, True, False, force=i==0, bunch=self.multiBunchSelector.value())
  367. if useFirst:
  368. y = scany[np.argsort(scanx)]
  369. baseline = np.mean(y[:useFirst])
  370. print('baseline ', baseline)
  371. #print(scanx.shape, scany.shape)
  372. popt, perr, fitFun, pcov, label, x = self.doFit(scanx, scany, fittype, baseline=baseline, findMin=isNegativ)
  373. phase, A = self.findMax(scanx, popt, fitFun, findMin=isNegativ)
  374. except:
  375. #try:
  376. # popt, perr, fitFun, pcov, label, x = self.doFit(scanx, scany[i], EGAUSSB, baseline=baseline)
  377. # phase, A = self.findMax(scanx, popt, fitFun, findMin=isNegativ)
  378. #except:
  379. try:
  380. grpY[str(i)][...] = np.array([[0.0,1.0]])
  381. except:
  382. print(i)
  383. traceback.print_exc()
  384. grpY[str(i)] = np.array([[0.0,1.0]])
  385. traceback.print_exc()
  386. print(i,' not fit')
  387. continue
  388. if phase0 == 0:
  389. phase0 = phase
  390. grpX[str(i)]['offset'][...] = phase0 - phase
  391. #print(phase, A, popt[4])
  392. A -= popt[4]
  393. if A0 == 0:
  394. A0 = A
  395. if isNegativ:
  396. A *= -1
  397. #print(phase, phase0 - phase, A)
  398. try:
  399. grpY[str(i)][...] = data=np.array([[popt[4], A/A0]], dtype=np.float64)
  400. grpY['{}popt'.format(i)][...] = popt
  401. grpY['{}baseline'.format(i)][...] = baseline
  402. except:
  403. grpY[str(i)] = data=np.array([[popt[4], A/A0]], dtype=np.float64)
  404. grpY['{}popt'.format(i)] = popt
  405. grpY['{}baseline'.format(i)] = baseline
  406. print('generateYCalibration done')
  407. # Y88b d88P .d8888b. 888 d8b 888 888 d8b
  408. # Y88b d88P d88P Y88b 888 Y8P 888 888 Y8P
  409. # Y88o88P 888 888 888 888 888
  410. # Y888P 888 8888b. 888 888 88888b. 888d888 8888b. 888888 888 .d88b. 88888b.
  411. # d888b 888 "88b 888 888 888 "88b 888P" "88b 888 888 d88""88b 888 "88b
  412. # d88888b 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888
  413. # d88P Y88b Y88b d88P 888 888 888 888 888 d88P 888 888 888 Y88b. 888 Y88..88P 888 888
  414. # d88P Y88b "Y8888P" "Y888888 888 888 88888P" 888 "Y888888 "Y888 888 "Y88P" 888 888
  415. #
  416. #
  417. #
  418. def updateX(self):
  419. try:
  420. self.generateXCalibration(theCalibration.fileHandle)
  421. self.generateMap(theCalibration.fileHandle)
  422. except:
  423. print('error Calibrating X')
  424. traceback.print_exc()
  425. return
  426. print('all Done')
  427. self.displayParameter()
  428. self.plot()
  429. #self.plotWidget.finetune(peakScanFile, self.fileHandle)
  430. def generateXCalibration(self, fh):
  431. grpX = fh['x']
  432. self.processbarWidget = ProcesbarWidget(self, True)
  433. valmax = 100
  434. val = 0
  435. verbose = False
  436. doPlots = False
  437. try:
  438. grpX['d330'][...] = 334
  439. grpX['d25'][...] = 23
  440. grpX['d3'][...] = 3
  441. grpX['d25b'][...] = 23
  442. grpX['d25b_zero'][...] = 4
  443. except:
  444. grpX['d330'] = 334
  445. grpX['d25'] = 23
  446. grpX['d3'] = 3
  447. grpX['d25b'] = 23
  448. grpX['d25b_zero'] = 4
  449. stepswith25 = 13
  450. stepswith3 = 32
  451. zero25 = 0
  452. steps = [0,1,3,4,6,7]
  453. data = self.timeScan.scanData
  454. adc = self.timeScan.adcNumber
  455. ### X Calibration:
  456. print('i | A | F | b | phi')
  457. phase0 = 0
  458. for i in range(adc):
  459. if i in [4,5]:
  460. continue
  461. self.processbarWidget.update(val/valmax*1000)
  462. val += 1
  463. try:
  464. adcgrp = grpX[str(i)]
  465. except:
  466. adcgrp = grpX.create_group(str(i))
  467. cal33 = None
  468. cal25 = None
  469. cal3 = None
  470. popt0 = None
  471. popt = 0
  472. fitx0 = 0
  473. phase = 0
  474. for iteration in range(1):
  475. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'],cal33,cal25,cal3, zero25B=grpX['d25b_zero'])
  476. fitx = scanx
  477. popt, perr = self.fit500(fitx[::32], scany[i][::32])
  478. phase = popt[3]/(2*np.pi)/popt[1]#1e3#*1e9
  479. if popt0 is None:
  480. popt0 = popt
  481. fitx0 = fitx
  482. if i == 0:
  483. phase0 = phase
  484. self.processbarWidget.update(val/valmax*1000)
  485. val += 1
  486. print(i, popt, phase0 -phase, iteration)
  487. ######################################
  488. # Calib 330ps
  489. print('Calib 330ps')
  490. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'], defaultB=False, zero25B=grpX['d25b_zero'])
  491. if verbose:
  492. print(scanx.shape)
  493. print(scany.shape)
  494. print(len(data[0]))
  495. tmp = np.ones((14,stepswith25,stepswith3))
  496. for j in range(len(data[0])):
  497. #data[0][j][2] ist 330ps; [][][3] ist 25ps; [][][4] ist 3ps; [][][6] ist 25ps FCM2
  498. if int(data[0][j][3]) == zero25 and int(data[0][j][4]) == 0 and int(data[0][j][6]) == int(grpX['d25b_zero'][()]):
  499. tmp[int(data[0][j][2])][int(data[0][j][3])][int(data[0][j][4])] = self.findDeltaX(scanx[j], scany[i][j], 0.1, popt, 1)
  500. dat33 = tmp[:,zero25,0]
  501. cal33 = dat33[np.where(dat33[:] != 1)]*1e12
  502. if verbose: print('call33 {}'.format(cal33))
  503. self.processbarWidget.update(val/valmax*1000)
  504. val += 1
  505. # Plot
  506. if doPlots:
  507. plt.figure()
  508. if iteration > 0:
  509. plt.plot(np.sort(fitx0), sinus(np.sort(fitx0),*popt0))
  510. plt.plot(np.sort(fitx), sinus(np.sort(fitx),*popt))
  511. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'], zero25B=grpX['d25b_zero'])
  512. plt.plot(scanx[::33*stepswith25], scany[i][::33*stepswith25], '.', label='{} org'.format(iteration))
  513. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'], cal33, zero25B=grpX['d25b_zero'])
  514. plt.plot(scanx[::33*stepswith25], scany[i][::33*stepswith25], 'x', label='{} x'.format(iteration))
  515. plt.legend()
  516. #plt.show()
  517. ######################################
  518. # Calib 25ps
  519. print('Calib 25ps')
  520. data2 = self.selectScan(data, steps)
  521. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], cal33, defaultB=False, zero25B=grpX['d25b_zero'])
  522. tmp = np.ones((14,stepswith25,stepswith3))
  523. l = len(data2[0])
  524. for j in range(len(data2[0])):
  525. if int(data2[0][j][4]) == 0 and int(data2[0][j][6]) == grpX['d25b_zero'][()]:
  526. if j%2 == 0:
  527. self.processbarWidget.update(val/valmax*1000, (j*1.0)/l*1000.0)
  528. tmp[int(data2[0][j][2])][int(data2[0][j][3])][int(data2[0][j][4])] = self.findDeltaX(scanx[j], scany[i][j], 0.5, popt,1)
  529. dat25 = tmp[steps,:,0]
  530. dat25 = dat25[np.where(dat25[:,0] != 1)]*1e12
  531. cal25 = np.mean(dat25,0)
  532. if verbose: print('cal25 {}'.format(cal25))
  533. self.processbarWidget.update(val/valmax*1000)
  534. val += 1
  535. # Plot
  536. if doPlots:
  537. plt.figure()
  538. if iteration > 0:
  539. plt.plot(np.sort(fitx0), sinus(np.sort(fitx0),*popt0))
  540. plt.plot(np.sort(fitx), sinus(np.sort(fitx),*popt))
  541. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], zero25B=grpX['d25b_zero'])
  542. plt.plot(scanx[::33], scany[i][::33], '1', label='org {}'.format(iteration))
  543. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], cal33, zero25B=grpX['d25b_zero'])
  544. plt.plot(scanx[::33], scany[i][::33], '2', label='cal330 {}'.format(iteration))
  545. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], cal33, cal25, zero25B=grpX['d25b_zero'])
  546. plt.plot(scanx[::33], scany[i][::33], '3', label='cal 330+25 {}'.format(iteration))
  547. plt.legend()
  548. #plt.show()
  549. self.processbarWidget.update(val/valmax*1000)
  550. val += 1
  551. ######################################
  552. # Calib 3ps
  553. print('Calib 3ps')
  554. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], cal33, defaultB=False, zero25B=grpX['d25b_zero'])
  555. tmp = np.ones((14,stepswith25,stepswith3))
  556. l = len(data2[0])
  557. for j in range(len(data2[0])-1):
  558. if int(data2[0][j][2]) in steps and int(data2[0][j][6]) == grpX['d25b_zero'][()]:
  559. if j%8 == 0:
  560. self.processbarWidget.update(val/valmax*1000, (j*1.0)/l*1000.0)
  561. tmp[int(data2[0][j][2])][int(data2[0][j][3])][int(data2[0][j][4])] = self.findDeltaX(scanx[j], scany[i][j], 1, popt,1)
  562. dat3 = tmp[steps,:12,:]
  563. dat3 = dat3[np.where(dat3[:,0,1] != 1)]*1e12
  564. if len(dat3) == 0:
  565. cal3 = np.zeros(stepswith3)
  566. else:
  567. cal3 = np.mean(np.mean(dat3, 0),0)
  568. if verbose: print(cal3.shape)
  569. print('done')
  570. if doPlots:
  571. print('plot')
  572. plt.figure()
  573. if iteration > 0:
  574. plt.plot(np.sort(fitx0), sinus(np.sort(fitx0),*popt0))
  575. plt.plot(np.sort(fitx), sinus(np.sort(fitx),*popt))
  576. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'], zero25B=grpX['d25b_zero'])
  577. plt.plot(scanx, scany[i], '1', label='org {}'.format(iteration))
  578. scanx, scany = self.prepareScan(data, grpX['d330'], grpX['d25'], grpX['d3'], cal33, cal25, cal3, zero25B=grpX['d25b_zero'])
  579. plt.plot(scanx, scany[i], '3', label='cal33+25+3 {}'.format(iteration))
  580. plt.legend()
  581. plt.plot()
  582. self.processbarWidget.update(val/valmax*1000)
  583. val += 1
  584. #Iteration End
  585. if doPlots:
  586. plt.show()
  587. try:
  588. adcgrp['fit_popt'][...] = popt
  589. adcgrp['fit_perr'][...] = perr
  590. adcgrp['330'][...] = cal33
  591. adcgrp['25'][...] = cal25
  592. adcgrp['3'][...] = cal3
  593. except:
  594. adcgrp['offset'] = phase0 - phase
  595. adcgrp['fit_popt'] = popt
  596. adcgrp['fit_perr'] = perr
  597. adcgrp.create_dataset('330', data=cal33)
  598. adcgrp.create_dataset('25', data=cal25)
  599. adcgrp.create_dataset('3', data=cal3)
  600. self.processbarWidget.update(val/valmax*1000)
  601. val += 1
  602. ######################################
  603. # Calib 25ps FMC2
  604. dat25b=np.zeros(8)
  605. if i < 4: #only to be done for ADC1-4 on FMC2
  606. print('Calib FMC2')
  607. scanx, scany = self.prepareScan(data2, grpX['d330'], grpX['d25'], grpX['d3'], cal33, cal25, cal3, defaultB=False, zero25B=grpX['d25b_zero'])
  608. tmp = np.zeros(12)
  609. ctr = np.zeros(12)
  610. for j in range(len(data2[0])):
  611. if int(data2[0][j][6]) != grpX['d25b_zero']:
  612. if j%2 == 0:
  613. self.processbarWidget.update(val/valmax*1000, (j*1.0)/l*1000.0)
  614. tmp[int(data2[0][j][6])] += self.findDeltaX(scanx[j], scany[i][j], 1, popt,1)
  615. ctr[int(data2[0][j][6])] += 1
  616. dat25b = tmp[np.where(tmp != 1)]*1e12
  617. ctr[np.where(ctr==0)] += 1
  618. dat25b = dat25b/ctr
  619. tmp[grpX['d25b_zero']] = 0
  620. try:
  621. adcgrp['25b'][...] = dat25b
  622. except:
  623. adcgrp.create_dataset('25b', data=dat25b)
  624. if self.processbarWidget is not None:
  625. self.processbarWidget.close()
  626. self.processbarWidget = None
  627. #############################
  628. ### Generate time Map
  629. def generateMap(self, fh):
  630. print('generateMap')
  631. grpX = fh['x']
  632. self.processbarWidget = ProcesbarWidget(self)
  633. val = 0
  634. valmax = 8*8*13 #*32*9
  635. delays = np.zeros((8, 8, 13, 32, 9))
  636. for adc in range(8):
  637. for c33 in range(0,7+1):
  638. for c25 in range(13):
  639. for f in range(32):
  640. for c25b in range(9):
  641. x = c33*grpX['d330'][()] + c25*grpX['d25'][()] + f*grpX['d3'][()]
  642. if adc < 4:
  643. x -= (c25b - grpX['d25b_zero'][()]) * grpX['d25b'][()]
  644. x = x*1e-12
  645. if adc in [4,5]:
  646. delays[adc][c33][c25][f][c25b] = x
  647. continue
  648. corr= (grpX[str(adc)]['330'][c33] +
  649. grpX[str(adc)]['25'][c25] +
  650. grpX[str(adc)]['3'][f])
  651. if adc < 4:
  652. corr += grpX[str(adc)]['25b'][c25b][()]
  653. corr = corr*1e-12
  654. #corr += grpX[str(adc)]['offset'][()]
  655. x += corr
  656. delays[adc][c33][c25][f][c25b] = x
  657. if self.processbarWidget is not None:
  658. self.processbarWidget.update(val/valmax*1000)
  659. val +=1
  660. try:
  661. grpX['map'][...] = delays
  662. except:
  663. processbarWidgetgrpX['map'] = delays
  664. if self.processbarWidget is not None:
  665. self.processbarWidget.close()
  666. self.processbarWidget = None
  667. print('done')
  668. """
  669. # 888 888 888 8888888888 888 d8b
  670. # 888 888 888 888 888 Y8P
  671. # 888 888 888 888 888
  672. # 8888888888 .d88b. 888 88888b. .d88b. 888d888 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
  673. # 888 888 d8P Y8b 888 888 "88b d8P Y8b 888P" 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
  674. # 888 888 88888888 888 888 888 88888888 888 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
  675. # 888 888 Y8b. 888 888 d88P Y8b. 888 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
  676. # 888 888 "Y8888 888 88888P" "Y8888 888 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
  677. # 888
  678. # 888
  679. # 888
  680. """
  681. def prepareX(self, data, a=330,b=25,c=3, cal33=None, cal25=None, cal3=None, steps=[0,3,6,9,12], zero25B=4, cal25B=None):
  682. if cal33 is None:
  683. scanx = np.array([val[2]*a + val[3]*b + val[4]*c + (zero25B - val[6])*b + (cal25B[int(val[6])] if cal25B is not None else 0) for val in data[0]])*1e-12
  684. elif cal25 is None:
  685. scanx = np.array([val[2]*a+cal33[int(val[2])] + val[3]*b + val[4]*c + (zero25B - val[6])*b + (cal25B[int(val[6])] if cal25B is not None else 0) for val in data[0]])*1e-12
  686. elif cal3 is None:
  687. scanx = np.array([val[2]*a+cal33[int(val[2])] +
  688. val[3]*b+cal25[int(val[3])] + val[4]*c + (zero25B - val[6])*b + (cal25B[int(val[6])] if cal25B is not None else 0) for val in data[0]])*1e-12
  689. else:
  690. scanx = np.array([val[2]*a+cal33[int(val[2])] +
  691. val[3]*b+cal25[int(val[3])] +
  692. val[4]*c+cal3[int(val[4])] + (zero25B - val[6])*b + (cal25B[int(val[6])] if cal25B is not None else 0) for val in data[0]])*1e-12
  693. return scanx
  694. def prepareScan(self, data, a=330,b=25,c=3, cal33=None, cal25=None, cal3=None, steps = [0,3,6,9,12], defaultB=True, zero25B=4, cal25B=None):
  695. scany = []
  696. tmp = []
  697. #print(data.shape)
  698. for i in range(len(data)):
  699. y = data[i].T[0]
  700. if defaultB:
  701. y = y[np.where(data[0,:,6] == zero25B)]
  702. scany.append(y)
  703. scany = np.array(scany)
  704. scanx = self.prepareX(data,a,b,c, cal33, cal25, cal3, steps, zero25B, cal25B)
  705. if defaultB:
  706. scanx = scanx[np.where(data[0,:,6] == zero25B)]
  707. return scanx, scany
  708. def selectScan(self, data, selector):
  709. #selector = [0,1,3,4,6,7]
  710. erg = [[],[],[],[], [],[],[],[]]
  711. for i in range(len(data[0])):
  712. if data[0][i][2] in selector:
  713. for j in range(self.timeScan.adcNumber):
  714. erg[j].append(data[j][i])
  715. return np.array(erg)
  716. def findMax(self, scanx, popt, fitFun, findMin=False):
  717. x = np.linspace(np.min(scanx), np.max(scanx), 100000)
  718. y = fitFun(x, *popt)
  719. if not findMin:
  720. return x[np.where(y==np.max(y))][0], np.max(y)
  721. else:
  722. return x[np.where(y==np.min(y))][0], np.min(y)
  723. def fit500(self, x, y):
  724. p0 = (800, 500e6, 2048, 4.5)
  725. label = [' A ', ' f ', ' b ', ' phi']
  726. popt, pcov = curve_fit(sinus, x, y, p0=p0)
  727. #popt[0] = np.max(y)-popt[2]
  728. perr = np.sqrt(np.absolute(np.diag(pcov)))
  729. return popt, perr
  730. def findDeltaX(self, x, y, tol, popt, i):
  731. tmpx = np.linspace(x-50e-12, x+50e-12, 500000)
  732. tmpy = sinus(tmpx, *popt)
  733. sel = np.where((tmpy < y+tol) & (tmpy > y-tol))
  734. res = tmpx[sel]
  735. tmpy = tmpy[sel]
  736. tmp = res
  737. while len(tmp) > 4:
  738. res=tmp
  739. tol = tol*0.4
  740. sel = np.where((tmpy < y+tol) & (tmpy > y-tol))
  741. tmp = tmp[sel]
  742. tmpy = tmpy[sel]
  743. #if i%(24) == 0: print('tol ', tol, len(res))
  744. if len(res) > 1:
  745. res = [res[len(res)//2]]
  746. if len(res) == 0:
  747. print('bad',x, y)
  748. res= [x]
  749. return res[0]-x
  750. def doFit(self, x,y, type, p0=None, baseline=0, findMin=False):
  751. #np.seterr(all='warn')
  752. #warnings.filterwarnings('error')
  753. def linear(x,a,b):
  754. return a + b*x
  755. def gauss(x, sigma, mu, A, b):
  756. return A*np.exp(-0.5*((x-mu)/sigma)**2) + b
  757. def expgauss(x, s, m, a ,l, b):
  758. return a*l/2*np.exp(l/2*(2*m + l*s**2 - 2*x)) * erfc((m +l*s**2 -x)/(np.sqrt(2)*s)) + b
  759. def expgauss2(x, s, m, a, t, b):
  760. return a*s/t*np.sqrt(np.pi/2) * np.exp(0.5 * (s/t)**2 - (x-m)/t) * erfc(1/np.sqrt(2)*(s/t - (x-m)/s)) + b
  761. def sinus(x,a,b,c,d):
  762. return a*np.sin(b*x*(2*np.pi)+d)+c
  763. def skewnorm(x, s, m, a, l, b):
  764. def p(x):
  765. return 1/np.sqrt(2*np.pi) * np.exp(- x**2/2)
  766. def g(x):
  767. return 0.5*(1+erf(x/np.sqrt(2)))
  768. return a*2/s*p((x-m)/s)*g(l*(x-m)/s) + b
  769. if findMin:
  770. startx = x[np.where(y==np.min(y))]
  771. else:
  772. startx = x[np.where(y==np.max(y))]
  773. y = y[np.argsort(x)]
  774. x = x[np.argsort(x)]
  775. if type == EGAUSS:
  776. fitFun = expgauss
  777. p0 = (23e-12, startx, 7e-8, 0.02e12, 2040)
  778. if findMin:
  779. p0 = (23e-12, startx, -7e-8, 0.02e12, 2040)
  780. label = [' s ', ' m ', ' a ', ' l ', ' b ']
  781. elif type == EGAUSSB:
  782. fitFun = expgauss2
  783. p0 = [19e-12, startx, 1200, 40e-12, 2040]
  784. if findMin:
  785. p0 = [19e-12, startx, -1200, 40e-12, 2040]
  786. label = [' s ', ' m ', ' a ', ' l ', ' b ']
  787. elif type == SKEW:
  788. fitFun = skewnorm
  789. p0 = [80e-12, startx, 6e-8, 3, 2040] # 220e-12
  790. if findMin:
  791. p0 = [80e-12, startx, -6e-8, 3, 2040] # 220e-12
  792. label = [' s ', ' m ', ' a ', ' l ', ' b ']
  793. else:
  794. print('Fit type unknown ', type)
  795. return 0,0, lambda x: x , 0
  796. if baseline != 0:
  797. print('baseline', baseline)
  798. fitFunOrg = fitFun
  799. fitFun = lambda x, s, m, a, l: fitFunOrg(x,s,m,a,l, baseline)
  800. p0 = p0[:-1]
  801. if p0 is not None:
  802. popt, pcov = curve_fit(fitFun, x, y, p0=p0)
  803. else:
  804. popt, pcov = curve_fit(fitFun, x, y)
  805. #popt = p0
  806. perr = np.sqrt(np.absolute(np.diag(pcov)))
  807. if baseline != 0:
  808. fitFun = fitFunOrg
  809. popt = np.append(popt, baseline)
  810. return popt, perr, fitFun, pcov, label, x
  811. # 8888888b. 888 888 888 d8b 888 888
  812. # 888 Y88b 888 888 o 888 Y8P 888 888
  813. # 888 888 888 888 d8b 888 888 888
  814. # 888 d88P 888d888 .d88b. .d8888b .d88b. .d8888b 88888b. 8888b. 888d888 888 d888b 888 888 .d88888 .d88b. .d88b. 888888
  815. # 8888888P" 888P" d88""88b d88P" d8P Y8b 88K 888 "88b "88b 888P" 888d88888b888 888 d88" 888 d88P"88b d8P Y8b 888
  816. # 888 888 888 888 888 88888888 "Y8888b. 888 888 .d888888 888 88888P Y88888 888 888 888 888 888 88888888 888
  817. # 888 888 Y88..88P Y88b. Y8b. X88 888 d88P 888 888 888 8888P Y8888 888 Y88b 888 Y88b 888 Y8b. Y88b.
  818. # 888 888 "Y88P" "Y8888P "Y8888 88888P' 88888P" "Y888888 888 888P Y888 888 "Y88888 "Y88888 "Y8888 "Y888
  819. # 888
  820. # Y8b d88P
  821. # "Y88P"
  822. class ProcesbarWidget(kcgw.KCGWidgets):
  823. """
  824. The Timescan result plot subwindow.
  825. """
  826. def __init__(self, parent, twobars=False):
  827. super(ProcesbarWidget, self).__init__()
  828. self.setWindowTitle("Running...")
  829. # ------[ Variable declaration ]------------
  830. self.parent = parent
  831. self.twobars = twobars
  832. # -------[ Create structure ]----------
  833. self.outerLayout = QtGui.QVBoxLayout() # Outermost layout of this window
  834. self.setLayout(self.outerLayout)
  835. self.progressbar = QtGui.QProgressBar()
  836. #self.layout.addWidget(self.progressbar, lineindex,0,1,4)
  837. self.progressbar.setRange(0,1000)
  838. self.outerLayout.addWidget(self.createLabel(' ....Running.... '))
  839. self.outerLayout.addWidget(self.progressbar)
  840. if twobars:
  841. self.progressbar2 = QtGui.QProgressBar()
  842. #self.layout.addWidget(self.progressbar, lineindex,0,1,4)
  843. self.progressbar2.setRange(0,1000)
  844. self.outerLayout.addWidget(self.progressbar2)
  845. self.show()
  846. def update(self, value, value2=0):
  847. self.progressbar.setValue(value)
  848. if self.twobars:
  849. self.progressbar2.setValue(value2)
  850. QtGui.qApp.processEvents()
  851. ##################################################################################
  852. def closeEvent(self, event):
  853. """
  854. Event handler for closing this window
  855. """
  856. self.parent.processbarWidget = None
  857. pass
  858. class WaitingWidget(kcgw.KCGWidgets):
  859. """
  860. The Timescan result plot subwindow.
  861. """
  862. def __init__(self, parent):
  863. super(WaitingWidget, self).__init__()
  864. self.setWindowTitle("please wait")
  865. # ------[ Variable declaration ]------------
  866. self.parent = parent
  867. # -------[ Create structure ]----------
  868. self.outerLayout = QtGui.QVBoxLayout() # Outermost layout of this window
  869. self.setLayout(self.outerLayout)
  870. self.outerLayout.addWidget(self.createLabel(' ....Loading.... '))
  871. self.show()
  872. QtGui.qApp.processEvents()
  873. ##################################################################################
  874. def closeEvent(self, event):
  875. """
  876. Event handler for closing this window
  877. """
  878. self.parent.processbarWidget = None
  879. pass