def main(args=None): if isinstance(args, str): import shlex args = shlex.split(args) import argparse parser = argparse.ArgumentParser('calibrateMotorFrequencies', add_help=True) parser.add_argument( 'moduleName', type=str, help='the name of the module (e.g. "SC03", "Spare1", or "PFI")') parser.add_argument( '--initOntimes', action='store_true', help='set the model ontimes to some sane initial value.') parser.add_argument( '--fpgaHost', type=str, default='localhost', help='connect to the given FPGA host instead of the simulator.') parser.add_argument('--modelVersion', type=str, default='init', help='specify the version of the input model.') parser.add_argument('--saveModelFile', type=pathlib.Path, default=None, help='save the updated model in the given file.') opts = parser.parse_args(args) print(opts) output = butler.RunTree() pfi = pfiModule.PFI(fpgaHost=opts.fpgaHost, logDir=output.logDir, doLoadModel=False) mapPath = butler.mapPathForModule(opts.moduleName, opts.modelVersion) print(mapPath) pfi.loadModel(mapPath) pfi = calibrateMotorFrequencies(pfi=pfi, updateModel=True) if opts.initOntimes: thetaOntimes = np.full(57, 0.065) phiOntimes = np.full(57, 0.045) pfi.calibModel.updateOntimes(thtFwd=thetaOntimes, thtRev=thetaOntimes, phiFwd=phiOntimes, phiRev=phiOntimes) if opts.saveModelFile is not None: if opts.saveModelFile.is_absolute(): outputPath = opts.saveModelFile else: outputPath = output.outputDir / opts.saveModelFile pfi.calibModel.createCalibrationFile(outputPath) print(f"wrote updated map file to {outputPath}")
def makeTablefromXML(XML, filename): XMLfile = XML tablename = filename pfi = pfiControl.PFI(fpgaHost='localhost', doConnect=False) #'fpga' for real device. pfi.loadModel(XMLfile) model = pfi.calibModel pid = np.arange(1, 58, 1) # Formaing XY from complex number to string centers = [] for num in pfi.calibModel.centers: cen = f'({num.real:.2f} {num.imag:.2f})' centers.append(cen) #centerX = pfi.calibModel.centers.real #centerY = pfi.calibModel.centers.imag t = Table([ pid, centers, model.L1, np.rad2deg(model.tht0), np.rad2deg(model.tht1), model.motorOntimeFwd1, model.motorOntimeRev1, model.L2, np.rad2deg(model.phiIn + np.pi), np.rad2deg(model.phiOut + np.pi), model.motorOntimeFwd2, model.motorOntimeRev2 ], names=('Fiber No.', 'Center', 'L1', 'ThetaCCWLimit', 'ThetaCWLimit', 'ThetaOntimeFwd', 'ThetaOntimeRev', 'L2', 'PhiCCWLimit', 'PhiCWLimit', 'PhiOntimeFwd', 'PhiOntimeRev')) t.write(tablename, format='ascii.ecsv', overwrite=True, formats={ 'Fiber No.': '%i', 'Center': '%s', 'L1': '%f', 'ThetaCCWLimit': '%f', 'ThetaCWLimit': '%f', 'ThetaOntimeFwd': '%f', 'ThetaOntimeRev': '%f', 'L2': '%f', 'PhiCCWLimit': '%f', 'PhiCWLimit': '%f', 'PhiOntimeFwd': '%f', 'PhiOntimeRev': '%f' })
def __init__(self): super().__init__() self.pfi = pfiControl.PFI(fpgaHost='localhost', doLoadModel=False) self.setWindowTitle('Cobra controller') self.statusBar().showMessage('Please load XML file') block1 = QHBoxLayout() self.xml = QLineEdit() self.xml.setMinimumWidth(240) block1.addWidget(self.xml) self.btn_xml = QPushButton('Load XML file') self.btn_xml.clicked.connect(self.click_load) block1.addWidget(self.btn_xml) block1.addWidget(QSplitter(Qt.Vertical), QSizePolicy.Expanding) btn = QPushButton('Move Up/Down') btn.clicked.connect(self.move_up_down) block1.addWidget(btn) block2 = QHBoxLayout() self.btn_go = QPushButton('Go') block2.addWidget(self.btn_go, QSizePolicy.Expanding) self.btn_go.clicked.connect(self.click_go) onlyInt = QIntValidator() block2.addWidget(QLabel('theta:')) self.theta = QLineEdit('0') self.theta.setValidator(onlyInt) block2.addWidget(self.theta) block2.addWidget(QLabel('phi:')) self.phi = QLineEdit('0') self.phi.setValidator(onlyInt) block2.addWidget(self.phi) block3 = QHBoxLayout() btn_odd = QPushButton('Odd') btn_odd.setCheckable(True) btn_odd.clicked[bool].connect(self.click_odd) block3.addWidget(btn_odd) block4 = QHBoxLayout() btn_even = QPushButton('Even') btn_even.setCheckable(True) btn_even.clicked[bool].connect(self.click_even) block4.addWidget(btn_even) self.btn_cobras = [] for idx in range(57): btn_c = CobraButton(idx) self.btn_cobras.append(btn_c) if idx % 2 == 0: block3.addWidget(btn_c, QSizePolicy.Minimum) else: block4.addWidget(btn_c, QSizePolicy.Minimum) btn_c = QPushButton() btn_c.setMaximumWidth(20) block4.addWidget(btn_c) block5 = QHBoxLayout() block5.addWidget(QLabel('Right click to mark bad cobras'), QSizePolicy.Expanding) self.cb_use_bad = QCheckBox('Use bad cobras') block5.addWidget(self.cb_use_bad) self.btn_speed = QPushButton('Fast') self.btn_speed.setCheckable(True) self.btn_speed.clicked[bool].connect(self.click_speed) block5.addWidget(self.btn_speed) layout = QVBoxLayout() layout.addLayout(block1) layout.addWidget(QSplitter()) layout.addLayout(block2) layout.addLayout(block5) layout.addLayout(block3) layout.addLayout(block4) cw = QWidget() cw.setLayout(layout) self.setCentralWidget(cw)
def geometryStat(XMLarray, tablename, skipfiber=False): Xarray = [] Yarray = [] L1array = [] L2array = [] tht0array = [] tht1array = [] phiInarray = [] phiOutarray = [] for count, file in enumerate(XMLarray): print(file) pfi = pfiControl.PFI(fpgaHost='localhost', doConnect=False) #'fpga' for real device. pfi.loadModel(file) model = pfi.calibModel if count == 0: L1array = model.L1 L2array = model.L2 tht0array = np.rad2deg(model.tht0) tht1array = np.rad2deg(model.tht1) phiInarray = np.rad2deg(model.phiIn + np.pi) phiOutarray = np.rad2deg(model.phiOut + np.pi) Xarray = pfi.calibModel.centers.real Yarray = pfi.calibModel.centers.imag else: L1array = np.vstack((L1array, model.L1)) L2array = np.vstack((L2array, model.L2)) tht0array = np.vstack((tht0array, np.rad2deg(model.tht0))) tht1array = np.vstack((tht1array, np.rad2deg(model.tht1))) phiInarray = np.vstack( (phiInarray, np.rad2deg(model.phiIn + np.pi))) phiOutarray = np.vstack( (phiOutarray, np.rad2deg(model.phiOut + np.pi))) Xarray = np.vstack((Xarray, pfi.calibModel.centers.real)) Yarray = np.vstack((Yarray, pfi.calibModel.centers.imag)) L1mean = np.mean(L1array, axis=0) L1std = np.std(L1array, axis=0) L2mean = np.mean(L2array, axis=0) L2std = np.std(L2array, axis=0) tht0mean = np.mean(tht0array, axis=0) tht0std = np.std(tht0array, axis=0) tht1mean = np.mean(tht1array, axis=0) tht1std = np.std(tht1array, axis=0) phiInmean = np.mean(phiInarray, axis=0) PhiInstd = np.std(phiInarray, axis=0) phiOutmean = np.mean(phiOutarray, axis=0) PhiOutstd = np.std(phiOutarray, axis=0) Xmean = np.mean(Xarray, axis=0) Xstd = np.std(Xarray, axis=0) Ymean = np.mean(Yarray, axis=0) Ystd = np.std(Yarray, axis=0) print(tht0std) print(tht1std) pid = np.arange(1, 58, 1) t = Table([ pid, Xmean, Xstd, Ymean, Ystd, L1mean, L1std, L2mean, L2std, tht0mean, tht0std, tht1mean, tht1std, phiInmean, PhiInstd, phiOutmean, PhiOutstd ], names=('Fiber No.', 'X', 'Xstd', 'Y', 'Ystd', 'L1mean', 'L1std', 'L2mean', 'L2std', 'ThetaCCWLimitMean', 'ThetaCCWLimitStd', 'ThetaCWLimitMean', 'ThetaCWLimitStd', 'PhiCCWLimitMean', 'PhiCCWLimitStd', 'PhiCWLimitMean', 'PhiCWLimitStd')) if skipfiber is not False: t.remove_rows(skipfiber) t.write(tablename, format='ascii.ecsv', overwrite=True, formats={ 'Fiber No.': '%i', 'X': '%f', 'Xstd': '%f', 'Y': '%f', 'Ystd': '%f', 'L1mean': '%f', 'L1std': '%f', 'L2mean': '%f', 'L2std': '%f', 'ThetaCCWLimitMean': '%f', 'ThetaCCWLimitStd': '%f', 'ThetaCWLimitMean': '%f', 'ThetaCWLimitStd': '%f', 'PhiCCWLimitMean': '%f', 'PhiCCWLimitStd': '%f', 'PhiCWLimitMean': '%f', 'PhiCWLimitStd': '%f' })
def bootstrapModule(moduleName, initialXml=None, outputName=None, fpgaHost='fpga', simulationPath=None, setCenters=True, clearGeometry=True, brokenFibers=(), doCalibrate=True, numberCobrasFromRight=False, setModuleId=True): run = butler.RunTree() if fpgaHost == 'fpga': fpgaHost = '128.149.77.24' # See INSTRM-464 elif fpgaHost == 'None' or fpgaHost == '': fpgaHost = None if initialXml is None: initialXml = butler.mapPathForModule(moduleName, 'init') if outputName is None: outputName = f"{moduleName}_bootstrap.xml" cam = camera.cameraFactory(runManager=run, simulationPath=simulationPath, doClear=True) cam.resetStack(doStack=False) _ = cam.expose() # Just to record in case calibrartion moves far. nCobras = 57 if fpgaHost is None: pfi = None pfiModel = pfiDesign.PFIDesign(initialXml) else: pfi = pfiControl.PFI(fpgaHost=fpgaHost, logDir=run.logDir, doLoadModel=False) pfi.loadModel(initialXml) pfiModel = pfi.calibModel pfi.reset() # Override undependable ontimes. We want fast defaults which will drive full range pfi.calibModel.updateOntimes(phiFwd=[0.07]*nCobras, phiRev=[0.07]*nCobras, fast=True) pfi.calibModel.updateOntimes(phiFwd=[0.05]*nCobras, phiRev=[0.05]*nCobras, fast=False) pfi.calibModel.updateOntimes(thetaFwd=[0.08]*nCobras, thetaRev=[0.08]*nCobras, fast=True) pfi.calibModel.updateOntimes(thetaFwd=[0.06]*nCobras, thetaRev=[0.06]*nCobras, fast=False) # if we need to calibrate motor frequencies , assume the worst # (as seen in the assembly station init files): the values # would leave the motors not safe to run. So calibrate phi now, so # that we can reliably move it to home. if doCalibrate: calibrateMotorFrequencies.calibrateMotorFrequencies(pfi, enabled=(False, True)) pfi.moveAllSteps(None, 0, -4000) else: pfi.setFreq() if setModuleId: moduleId = pfiModel.setModuleId(moduleName) cs, im, _ = cam.expose() imCenters = np.stack((cs['x'], cs['y']), 1) # Needs to come from pfiDesign.nVisibleCobras, etc. nspots = len(cs) if nspots != nCobras - len(brokenFibers): raise RuntimeError(f'expect {nCobras - len(brokenFibers)} spots, got {nspots}') visibleIdx = list(pfiModel.findAllCobras()) for b in brokenFibers: pfiModel.setCobraStatus(b, moduleId, invisible=True) visibleIdx.remove(pfiModel.findCobraByModuleAndPositioner(moduleId, b)) visibleIdx = np.array(visibleIdx, 'i4') oldCenters = pfiModel.centers[visibleIdx] modelCenters = np.stack((np.real(oldCenters), np.imag(oldCenters)), 1) # The _only_ point of this step is to match up the fiber # numbers with the spots. # Forcing the images to have the boards run horizontally is a robust way # to do this. imIdx, _ = coordinates.laydown(imCenters) modelIdx, _ = coordinates.laydown(modelCenters) # These are now sorted descending by x, alternating between top # and bottom cobras. But the cobras centers in the xml files can # have real trash coordinates. For all the existing science # modules at CIT, several cobras have the same coordinates. So do # _not_ use the model coordinates by default. Simply assign the # cobras by increasing/decreasing X. # # We want the cobras to be numbered from the left by default. # if numberCobrasFromRight: imIdx = imIdx[::-1] # The ASRD camera has cobra 1 in the top-right. homes = imCenters[imIdx,0] + imCenters[imIdx,1]*(1j) # Usually only use scale from this. Only use the reset if we neither assign new centers nor # clear the geometry. offset1, scale1, tilt1, convert1 = coordinates.makeTransform(oldCenters[modelIdx], homes) if setCenters: centers = pfiModel.centers[:] * 0 centers[visibleIdx] = homes else: centers = convert1(pfiModel.centers) if clearGeometry: tht0 = pfiModel.tht0[:] * 0.0 tht1 = pfiModel.tht1[:] * 0.0 + 20.0 * np.pi/180 phiIn = pfiModel.phiIn[:] * 0.0 phiOut = pfiModel.phiOut[:] * 0.0 + 180.0 * np.pi/180 else: tht0 = (pfiModel.tht0+tilt1)%(2*np.pi) tht1 = (pfiModel.tht1+tilt1)%(2*np.pi) phiIn = pfiModel.phiIn phiOut = pfiModel.phiOut L1 = pfiModel.L1*scale1 L2 = pfiModel.L2*scale1 pfiModel.updateGeometry(centers, L1, L2) pfiModel.updateThetaHardStops(tht0, tht1) pfiModel.updatePhiHardStops(phiIn, phiOut) if doCalibrate: # Now can calibrate theta motors. calibrateMotorFrequencies.calibrateMotorFrequencies(pfi, enabled=(True, False)) xmlDir = run.outputDir outPath = xmlDir / outputName pfiModel.createCalibrationFile(outPath, name='bootstrap') pfiModel.createCalibrationFile(butler.mapPathForModule(moduleName, version='bootstrap'), name='bootstrap') return outPath