def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() if set(self.axisToHandlers.keys()) != {0, 1, 2}: raise ValueError('stage mover requires 3 axis: X, Y, and Z') # FIXME: we should have sensible defaults. self._saved_top = userConfig.getValue('savedTop', default=3010.0) self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0) ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} # Compute the hard motion limits for each axis as the # summation of all limits for handlers on that axis. hard_limits = [None] * 3 for axis in range(3): lower = 0.0 upper = 0.0 # We need set() to avoid duplicated handlers, and we might # have duplicated handlers because of the hack to meet # cockpit requirements that all axis have the same number # of handlers (see comments on issue #413). for handler in set(self.axisToHandlers[axis]): handler_limits = handler.getHardLimits() lower += handler_limits[0] upper += handler_limits[1] hard_limits[axis] = (lower, upper) # Use a tuple to prevent changes to it, and assemble it like # this to enable static code analysis. self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2]) ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe(events.STAGE_MOVER, self.onMotion) events.subscribe(events.STAGE_STOPPED, self.onStop)
def OnSelectROI(self, event: wx.CommandEvent) -> None: del event image_raw = self._device.acquireRaw() if np.max(image_raw) > 10: original_dim = np.shape(image_raw)[0] resize_dim = 512 while original_dim % resize_dim != 0: resize_dim -= 1 if resize_dim < original_dim / resize_dim: resize_dim = int(np.round(original_dim / resize_dim)) scale_factor = original_dim / resize_dim img = _bin_ndarray(image_raw, new_shape=(resize_dim, resize_dim)) img = np.require(img, requirements="C") last_roi = userConfig.getValue("dm_circleParams") last_roi = ( last_roi[1] / scale_factor, last_roi[0] / scale_factor, last_roi[2] / scale_factor, ) frame = _ROISelect(self, img, last_roi, scale_factor) frame.Show() else: logger.log.warning("Detected nothing but background noise")
def checkIfCalibrated(self): try: self.proxy.get_controlMatrix() except Exception as e: try: controlMatrix = np.asarray( userConfig.getValue("dm_controlMatrix")) self.proxy.set_controlMatrix(controlMatrix) except Exception: raise e
def updateROI(self): circle_parameters = userConfig.getValue("dm_circleParams") self.proxy.set_roi(*circle_parameters) # Check we have the interferogram ROI try: self.proxy.get_roi() except Exception as e: try: self.proxy.set_roi(*circle_parameters) except Exception: raise e
def checkFourierFilter(self): circle_parameters = userConfig.getValue("dm_circleParams") try: self.proxy.get_fourierfilter() except Exception as e: try: test_image = self.proxy.acquire() self.proxy.set_fourierfilter( test_image=test_image, window_dim=50, mask_di=int((2 * circle_parameters[2]) * (3.0 / 16.0)), ) except Exception: raise e
def OnSelectROI(self, event: wx.CommandEvent) -> None: del event image_raw = self._device.acquireRaw() if np.max(image_raw) > 10: original_dim = np.shape(image_raw)[0] resize_dim = 512 while original_dim % resize_dim != 0: resize_dim -= 1 if resize_dim < original_dim / resize_dim: resize_dim = int(np.round(original_dim / resize_dim)) scale_factor = original_dim / resize_dim img = _bin_ndarray(image_raw, new_shape=(resize_dim, resize_dim)) img = np.require(img, requirements="C") last_roi = userConfig.getValue("dm_circleParams", ) # We need to check if getValue() returns None, instead of # passing a default value to getValue(). The reason is # that if there is no ROI at the start, by the time we get # here the device initialize has called updateROI which # also called getValue() which has have the side effect of # setting its value to None. And we can't set a sensible # default at that time because we have no method to get # the wavefront camera sensor size. if last_roi is None: last_roi = ( *[d // 2 for d in image_raw.shape], min(image_raw.shape) // 4, ) last_roi = ( last_roi[1] / scale_factor, last_roi[0] / scale_factor, last_roi[2] / scale_factor, ) frame = _ROISelect(self, img, last_roi, scale_factor) frame.Show() else: wx.MessageBox( "Detected nothing but background noise.", caption="No good image acquired", style=wx.ICON_ERROR | wx.OK | wx.CENTRE, )
def initialize(self): self.proxy = Pyro4.Proxy(self.uri) self.proxy.set_trigger(cp_ttype="FALLING_EDGE", cp_tmode="ONCE") self.no_actuators = self.proxy.get_n_actuators() # Need initial values for system flat calculations self.sys_flat_num_it = 10 self.sys_error_thresh = np.inf self.sysFlatNollZernike = np.linspace(start=4, stop=68, num=65, dtype=int) # Need intial values for sensorless AO self.numMes = 9 self.num_it = 2 self.z_max = 1.5 self.z_min = -1.5 self.nollZernike = np.asarray([11, 22, 5, 6, 7, 8, 9, 10]) # Shared state for the new image callbacks during sensorless self.actuator_offset = None self.camera = None self.correction_stack = [] self.sensorless_correct_coef = np.zeros(self.no_actuators) self.z_steps = np.linspace(self.z_min, self.z_max, self.numMes) self.zernike_applied = None # Excercise the DM to remove residual static and then set to 0 position for _ in range(50): self.proxy.send(np.random.rand(self.no_actuators)) time.sleep(0.01) self.reset() # Load values from config try: self.updateROI() except Exception: pass try: controlMatrix = np.asarray(userConfig.getValue("dm_controlMatrix")) self.proxy.set_controlMatrix(controlMatrix) except Exception: pass
def applySysFlat(self): sys_flat_values = np.asarray(userConfig.getValue("dm_sys_flat")) self.proxy.send(sys_flat_values)
def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() if set(self.axisToHandlers.keys()) != {0, 1, 2}: raise ValueError('stage mover requires 3 axis: X, Y, and Z') # FIXME: we should have sensible defaults (see issue #638). self._saved_top = userConfig.getValue('savedTop', default=3010.0) self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0) ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} # Compute the hard motion limits for each axis as the # summation of all limits for handlers on that axis. hard_limits = [None] * 3 for axis in range(3): lower = 0.0 upper = 0.0 # We need set() to avoid duplicated handlers, and we might # have duplicated handlers because of the hack to meet # cockpit requirements that all axis have the same number # of handlers (see comments on issue #413). for handler in set(self.axisToHandlers[axis]): handler_limits = handler.getHardLimits() lower += handler_limits[0] upper += handler_limits[1] hard_limits[axis] = (lower, upper) # Use a tuple to prevent changes to it, and assemble it like # this to enable static code analysis. self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2]) # Compute the initial step sizes. We have different step # sizes for each handler index which maybe doesn't make sense # anymore but comes from the time when it were the handlers # themselves that kept track of step size. self._step_sizes = [ ] # type: typing.List[typing.Tuple[float, float, float]] for stage_index in range(self.n_stages): default_step_sizes = [] for axis in (0, 1, 2): limits = self.axisToHandlers[axis][stage_index].getHardLimits() step_size = SensiblePreviousStepSize( (limits[1] - limits[0]) / 100.0) default_step_sizes.append(step_size) # Default is 1/100 of the axis length but in rectangular # stages that will lead to xy with different step sizes so # use the min of the two. min_xy = min(default_step_sizes[0], default_step_sizes[1]) self._step_sizes.append((min_xy, min_xy, default_step_sizes[2])) ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe(events.STAGE_MOVER, self.onMotion) events.subscribe(events.STAGE_STOPPED, self.onStop)