Voxel Calibration Wizard

Source code for wizard.CalibrationTemperaturePage

#
# TI Voxel Viewer component.
#
# Copyright (c) 2014 Texas Instruments Inc.
#

from PySide import QtCore, QtGui
from CalibrationPage import CalibrationPage

import os
import csv

import numpy as np
from wizard.Calibrations import CALIB_SHOW
# from wizard import CalibrationPage

[docs]class CalibratePhaseTableDelegate(QtGui.QItemDelegate): def __init__(self, parent = None): super(CalibratePhaseTableDelegate, self).__init__(parent)
[docs] def createEditor(self, parent, option, index): spinbox = QtGui.QSpinBox(parent) if index.column() == 2 or index.column() == 3: spinbox.setRange(0, 4095) else: spinbox.setRange(0, 200) # 200 degree celcius return spinbox
[docs]class CalibrationTemperaturePage(CalibrationPage): CSV_FILE_NAME = 'temperature-phase-offset.csv' MAX_PHASE_VALUE = 4096 def __init__(self, calibrationWizard): super(CalibrationTemperaturePage, self).__init__() self.calibrationWizard = calibrationWizard if CALIB_SHOW['temperature'] ==True: self.doShow = True self.setTitle('Temperature Calibration') self.setSubTitle('Computation of influence of temperature on phase. Please measure the phase value at cx, cy') self.layout = QtGui.QVBoxLayout(self) hlayout = QtGui.QHBoxLayout() self.centerPointText = QtGui.QLabel() hlayout.addWidget(self.centerPointText) hlayout.addStretch() self.calibrateButton = QtGui.QPushButton('&Calibrate') self.calibrateButton.pressed.connect(self.calibrate) self.calibrateButton.setShortcut('Alt+C') hlayout.addWidget(self.calibrateButton) self.layout.addLayout(hlayout) groupbox = QtGui.QGroupBox() groupbox.setTitle('Temperature Measurements') self.layout.addWidget(groupbox) vglayout = QtGui.QVBoxLayout() groupbox.setLayout(vglayout) self.temperatureMeasurements = QtGui.QTableWidget() self.calibParams = {} # if self.chipset == CalibrationPage.CHIPSET_HADDOCK: # self.temperatureMeasurements.setColumnCount(4) # self.temperatureMeasurements.setHorizontalHeaderLabels(['Tsensor', 'Tillum', 'Phase 1', 'Phase 2']) # else: self.temperatureMeasurements.setColumnCount(3) self.temperatureMeasurements.setHorizontalHeaderLabels(['Tsensor', 'Tillum', 'Phase 1']) self.temperatureMeasurements.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.temperatureMeasurements.setToolTip('Please ensure that entries are in increasing order of temperature values') self.temperatureMeasurements.setItemDelegate(CalibratePhaseTableDelegate()) vglayout.addWidget(self.temperatureMeasurements) insertRowAction = QtGui.QAction('Insert Row', self.temperatureMeasurements) insertRowAction.setShortcut('Insert') insertRowAction.triggered.connect(self.insertRow) self.temperatureMeasurements.addAction(insertRowAction) removeRowAction = QtGui.QAction('Remove Row', self.temperatureMeasurements) removeRowAction.setShortcut('Del') removeRowAction.triggered.connect(self.removeRow) self.temperatureMeasurements.addAction(removeRowAction) removeAllRowsAction = QtGui.QAction('Remove All Rows', self.temperatureMeasurements) removeAllRowsAction.setShortcut('Shift+Del') removeAllRowsAction.triggered.connect(self.removeAllRows) self.temperatureMeasurements.addAction(removeAllRowsAction) self.importCSVButton = QtGui.QPushButton('&Import From CSV') self.importCSVButton.setShortcut('Alt+I') self.importCSVButton.pressed.connect(self.importCSV) vglayout.addWidget(self.importCSVButton) self.paramsGroupbox = QtGui.QGroupBox() self.paramsGroupbox.setTitle('Temperature Parameters') self.layout.addWidget(self.paramsGroupbox) self.paramsText = QtGui.QLabel() vglayout = QtGui.QVBoxLayout() vglayout.addWidget(self.paramsText) self.paramsGroupbox.setLayout(vglayout) self.paramsGroupbox.hide() self.calibrated = False
[docs] def isComplete(self): return self.calibrated
[docs] def insertRow(self): i = self.temperatureMeasurements.currentRow() if i >= 0 and i < self.temperatureMeasurements.rowCount(): self.temperatureMeasurements.insertRow(i + 1) elif self.temperatureMeasurements.rowCount() == 0: self.temperatureMeasurements.insertRow(0)
[docs] def removeRow(self): i = self.temperatureMeasurements.currentRow() if i >= 0 and i < self.temperatureMeasurements.rowCount(): r = QtGui.QMessageBox.question(self, 'Remove Row', 'Are you sure you want to remove the current row?', \ buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if r == QtGui.QMessageBox.Yes: self.temperatureMeasurements.removeRow(i)
[docs] def removeAllRows(self): r = QtGui.QMessageBox.question(self, 'Remove All Rows', 'Are you sure you want to remove all rows?', \ buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if r == QtGui.QMessageBox.Yes: for i in range(0, self.temperatureMeasurements.rowCount()): self.temperatureMeasurements.removeRow(0)
[docs] def writeCSV(self, data, csvFile): with open(csvFile, 'w') as f: for r in data: f.write(','.join(format(c, ".0f") for c in r) + '\n')
[docs] def importCSV(self, csvFile = None): if csvFile is None: name, filter = QtGui.QFileDialog.getOpenFileName(self, 'Select CSV File', filter = 'CSV Files (*.csv)') if name: csvFile = str(name) else: return if not os.path.exists(csvFile): return with open(csvFile, 'rb') as f: reader = csv.reader(f) c = 0 for row in reader: if len(row) != self.temperatureMeasurements.columnCount(): QtGui.QMessageBox.critical(self, 'Invalid row count', ('Expected %d columns per row,' + \ ' but got %d for row %d.')%(self.temperatureMeasurements.columnCount(), len(row), c)) return r = self.temperatureMeasurements.rowCount() self.temperatureMeasurements.insertRow(self.temperatureMeasurements.rowCount()) for i in range(0, len(row)): self.temperatureMeasurements.setItem(r, i, QtGui.QTableWidgetItem(row[i])) c += 1
[docs] def initializePage(self): super(CalibrationTemperaturePage, self).initializePage() # if os.path.exists(self.basePath + os.sep + CalibrationTemperaturePage.CSV_FILE_NAME): # self.importCSV(self.basePath + os.sep + CalibrationTemperaturePage.CSV_FILE_NAME)
[docs] def getData(self): d = [] for r in range(0, self.temperatureMeasurements.rowCount()): x = [] for c in range(0, self.temperatureMeasurements.columnCount()): t = self.temperatureMeasurements.item(r, c).text() if len(t) == 0: QtGui.QMessageBox.critical(self, 'Data Missing', 'Data at row = %d, column = %d is empty'%(r, c)) return [] x.append(float(t)) d.append(x) return d
[docs] def calibrate(self): d1 = self.getData() if len(d1) == 0: QtGui.QMessageBox.critical(self, 'Data Missing', 'Cannot perform calibration with missing data') return d = np.array(d1) d = d[d[:,0].argsort()] A = d[:,0:2] b1 = d[:,2] tSensorCalib = A[0, 0] tIllumCalib = A[0, 1] phaseCorr1 = b1[0] A[:,0] -= tSensorCalib A[:,1] -= tIllumCalib b1 -= phaseCorr1 # if self.chipset == CalibrationPage.CHIPSET_HADDOCK: # b2 = d[:,3] # phaseCorr2 = b2[0] # b2 -= phaseCorr2 At = np.transpose(A) try: APsuedo = np.dot(At, A) if np.linalg.det(APsuedo) < 1E-6: # singular? if APsuedo[0, 0] < 1E-6: raise Exception('Invalid data') else: t1 = np.array([np.dot(1/APsuedo[0, 0]*At[0,:], b1), 0]) # if self.chipset == CalibrationPage.CHIPSET_HADDOCK: # t2 = np.array([np.dot(1/APsuedo[0, 0]*At[0,:], b2), 0]) else: APsuedoInv = np.dot(np.linalg.inv(APsuedo), At) t1 = np.dot(APsuedoInv, b1) # if self.chipset == CalibrationPage.CHIPSET_HADDOCK: # t2 = np.array([np.dot(1/APsuedo[0, 0]*At[0,:], b2), 0]) except Exception, e: QtGui.QMessageBox.critical(self, 'Data Singularity', 'Temperature data provided is singular. Please provide more indepedent measurements.') return # if self.chipset == CalibrationPage.CHIPSET_HADDOCK: # self.calibParams['coeff_illum_1'] = int(round(t1[1], 0)) # self.calibParams['coeff_sensor_1'] = int(round(t1[0], 0)) # self.calibParams['coeff_illum_2'] = int(round(t2[1], 0)) # self.calibParams['coeff_sensor_2'] = int(round(t2[0], 0)) # # self.paramsText.setText(('coeff_illum_1 = %d, coeff_sensor_1 = %d,' +\ # '\ncoeff_illum_2 = %d, coeff_sensor_2 = %d,\n')%\ # (int(round(t1[1], 0)), int(round(t1[0], 0)), int(round(t2[1], 0)), int(round(t2[0], 0)))) # else: t1 *= 16 # for calib_prec = 1 calibPrec = 1 if np.any(t1 >= 2048) or np.any(t1 < -2048): t1 /= 16 calibPrec = 0 self.calibrationWizard.calibParams['coeff_illum'] = int(round(t1[1], 0)) self.calibrationWizard.calibParams['coeff_sensor'] = int(round(t1[0], 0)) self.calibrationWizard.calibParams['calib_prec'] = calibPrec self.paramsText.setText(('coeff_illum_1 = %d, coeff_sensor_1 = %d,\n' + 'calib_prec = %d')%\ (int(round(t1[1], 0)), int(round(t1[0], 0)), calibPrec)) self.paramsGroupbox.show() self.calibrated = True # self.writeCSV(d1, self.basePath + os.sep + CalibrationTemperaturePage.CSV_FILE_NAME) self.completeChanged.emit()
[docs] def wrapPhaseToSignedInteger(self, phase): if phase >= CalibrationTemperaturePage.MAX_PHASE_VALUE/2: return -1*(CalibrationTemperaturePage.MAX_PHASE_VALUE - phase) else: return phase