def __init__(self): try: self.controller = MirrorControllerPython() print 'Mirror python initialization succeeded.' except Exception as e: print 'Mirror python initialization failed:',e try: self.controller = MirrorControllerPythonOld() print 'Mirror python (old style) initialization succeeded.' except Exception as e: print 'Mirror python (old style) initialization failed:',e try: self.controller = MirrorControllerCtypes() print 'Mirror c initialization succeeded.' except Exception as e: print e print 'No mirror driver found. Using virtual mirror.' self.controller = MirrorController() self.mirror_mask = np.loadtxt(ccfg.mirror_mask_filename) self.n_actuators = ccfg.mirror_n_actuators self.flat = np.loadtxt(ccfg.mirror_flat_filename) self.flat0 = np.loadtxt(ccfg.mirror_flat_filename) self.command_max = ccfg.mirror_command_max self.command_min = ccfg.mirror_command_min self.settling_time = ccfg.mirror_settling_time_s self.update_rate = ccfg.mirror_update_rate self.flatten() self.frame_timer = FrameTimer('Mirror',verbose=False) self.logging = False self.paused = False
def __init__(self, loop): super(UI, self).__init__() self.loop = loop self.loop.finished.connect(self.update) self.init_UI() self.frame_timer = FrameTimer('UI', verbose=False) self.show()
def __init__(self, camera): super(Sensor, self).__init__() self.image_width_px = ccfg.image_width_px self.image_height_px = ccfg.image_height_px self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m self.pixel_size_m = ccfg.pixel_size_m self.beam_diameter_m = ccfg.beam_diameter_m self.wavelength_m = ccfg.wavelength_m self.background_correction = ccfg.background_correction self.centroiding_iterations = ccfg.centroiding_iterations self.iterative_centroiding_step = ccfg.iterative_centroiding_step self.filter_lenslets = ccfg.sensor_filter_lenslets self.estimate_background = ccfg.estimate_background self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt try: xy = np.loadtxt(ccfg.reference_coordinates_filename) except Exception as e: xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename) print 'Bootstrapping with %s' % ccfg.reference_coordinates_bootstrap_filename self.search_boxes = SearchBoxes(xy[:, 0], xy[:, 1], ccfg.search_box_half_width) self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename) self.x0 = np.zeros(self.search_boxes.x.shape) self.y0 = np.zeros(self.search_boxes.y.shape) self.x0[:] = self.search_boxes.x[:] self.y0[:] = self.search_boxes.y[:] self.n_lenslets = self.search_boxes.n n_lenslets = self.n_lenslets self.image = np.zeros((ccfg.image_height_px, ccfg.image_width_px)) self.x_slopes = np.zeros(n_lenslets) self.y_slopes = np.zeros(n_lenslets) self.x_centroids = np.zeros(n_lenslets) self.y_centroids = np.zeros(n_lenslets) self.box_maxes = np.zeros(n_lenslets) self.box_mins = np.zeros(n_lenslets) self.box_means = np.zeros(n_lenslets) self.box_backgrounds = np.zeros(n_lenslets) self.error = 0.0 self.tip = 0.0 self.tilt = 0.0 self.zernikes = None self.wavefront = np.zeros(self.sensor_mask.shape) self.cam = camera self.frame_timer = FrameTimer('Sensor', verbose=False) self.reconstructor = Reconstructor(self.search_boxes.x, self.search_boxes.y, self.sensor_mask) self.logging = False self.paused = False
def __init__(self, loop): super(UI, self).__init__() self.sensor_mutex = QMutex() #loop.sensor_mutex self.mirror_mutex = QMutex() #loop.mirror_mutex self.loop = loop try: self.loop.finished.connect(self.update) except Exception as e: pass self.draw_boxes = ccfg.show_search_boxes self.draw_lines = ccfg.show_slope_lines self.init_UI() self.frame_timer = FrameTimer('UI', verbose=False) self.show()
def __init__(self,camera): self.image_width_px = ccfg.image_width_px self.image_height_px = ccfg.image_height_px self.dark_image = np.zeros((ccfg.image_height_px,ccfg.image_width_px),dtype=np.int16) self.dark_subtract = False self.n_dark = 10 self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m self.pixel_size_m = ccfg.pixel_size_m self.beam_diameter_m = ccfg.beam_diameter_m self.wavelength_m = ccfg.wavelength_m self.background_correction = ccfg.background_correction self.centroiding_iterations = ccfg.centroiding_iterations self.iterative_centroiding_step = ccfg.iterative_centroiding_step self.filter_lenslets = ccfg.sensor_filter_lenslets self.estimate_background = ccfg.estimate_background self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt # calculate diffraction limited spot size on sensor, to determine # the centroiding window size lenslet_dlss = 1.22*self.wavelength_m*self.lenslet_focal_length_m/self.lenslet_pitch_m lenslet_dlss_px = lenslet_dlss/self.pixel_size_m # now we need to account for smearing of spots due to axial displacement of retinal layers extent = 500e-6 # retinal thickness smear = extent*6.75/16.67 # pupil diameter and focal length; use diameter in case beacon is at edge of field try: magnification = ccfg.retina_sensor_magnification except Exception as e: magnification = 1.0 total_size = lenslet_dlss+smear*magnification total_size_px = total_size/self.pixel_size_m self.centroiding_half_width = int(np.floor(total_size_px/2.0))*2 try: xy = np.loadtxt(ccfg.reference_coordinates_filename) except Exception as e: xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename) print 'Bootstrapping with %s'%ccfg.reference_coordinates_bootstrap_filename self.search_boxes = SearchBoxes(xy[:,0],xy[:,1],ccfg.search_box_half_width) self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename) self.x0 = np.zeros(self.search_boxes.x.shape) self.y0 = np.zeros(self.search_boxes.y.shape) self.x0[:] = self.search_boxes.x[:] self.y0[:] = self.search_boxes.y[:] self.n_lenslets = self.search_boxes.n n_lenslets = self.n_lenslets self.image = np.zeros((ccfg.image_height_px,ccfg.image_width_px)) self.x_slopes = np.zeros(n_lenslets) self.y_slopes = np.zeros(n_lenslets) self.x_centroids = np.zeros(n_lenslets) self.y_centroids = np.zeros(n_lenslets) self.box_maxes = np.zeros(n_lenslets) self.box_mins = np.zeros(n_lenslets) self.box_means = np.zeros(n_lenslets) self.valid_centroids = np.zeros(n_lenslets,dtype=np.int16) try: self.fast_centroiding = ccfg.fast_centroiding except Exception as e: self.fast_centroiding = False self.box_backgrounds = np.zeros(n_lenslets) self.error = 0.0 self.tip = 0.0 self.tilt = 0.0 self.zernikes = np.zeros(ccfg.n_zernike_terms) self.wavefront = np.zeros(self.sensor_mask.shape) self.image_max = -1 self.image_min = -1 self.image_mean = -1 self.cam = camera self.frame_timer = FrameTimer('Sensor',verbose=False) self.reconstructor = Reconstructor(self.search_boxes.x, self.search_boxes.y,self.sensor_mask) self.n_zernike_orders_corrected=self.reconstructor.N_orders self.centroiding_time = -1.0 self.beeper = Beeper() self.logging = False self.paused = False self.sense_timer = BlockTimer('Sensor sense method') try: self.profile_update_method = ccfg.profile_sensor_update_method except: self.profile_update_method = False
class Sensor: def __init__(self,camera): self.image_width_px = ccfg.image_width_px self.image_height_px = ccfg.image_height_px self.dark_image = np.zeros((ccfg.image_height_px,ccfg.image_width_px),dtype=np.int16) self.dark_subtract = False self.n_dark = 10 self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m self.pixel_size_m = ccfg.pixel_size_m self.beam_diameter_m = ccfg.beam_diameter_m self.wavelength_m = ccfg.wavelength_m self.background_correction = ccfg.background_correction self.centroiding_iterations = ccfg.centroiding_iterations self.iterative_centroiding_step = ccfg.iterative_centroiding_step self.filter_lenslets = ccfg.sensor_filter_lenslets self.estimate_background = ccfg.estimate_background self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt # calculate diffraction limited spot size on sensor, to determine # the centroiding window size lenslet_dlss = 1.22*self.wavelength_m*self.lenslet_focal_length_m/self.lenslet_pitch_m lenslet_dlss_px = lenslet_dlss/self.pixel_size_m # now we need to account for smearing of spots due to axial displacement of retinal layers extent = 500e-6 # retinal thickness smear = extent*6.75/16.67 # pupil diameter and focal length; use diameter in case beacon is at edge of field try: magnification = ccfg.retina_sensor_magnification except Exception as e: magnification = 1.0 total_size = lenslet_dlss+smear*magnification total_size_px = total_size/self.pixel_size_m self.centroiding_half_width = int(np.floor(total_size_px/2.0))*2 try: xy = np.loadtxt(ccfg.reference_coordinates_filename) except Exception as e: xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename) print 'Bootstrapping with %s'%ccfg.reference_coordinates_bootstrap_filename self.search_boxes = SearchBoxes(xy[:,0],xy[:,1],ccfg.search_box_half_width) self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename) self.x0 = np.zeros(self.search_boxes.x.shape) self.y0 = np.zeros(self.search_boxes.y.shape) self.x0[:] = self.search_boxes.x[:] self.y0[:] = self.search_boxes.y[:] self.n_lenslets = self.search_boxes.n n_lenslets = self.n_lenslets self.image = np.zeros((ccfg.image_height_px,ccfg.image_width_px)) self.x_slopes = np.zeros(n_lenslets) self.y_slopes = np.zeros(n_lenslets) self.x_centroids = np.zeros(n_lenslets) self.y_centroids = np.zeros(n_lenslets) self.box_maxes = np.zeros(n_lenslets) self.box_mins = np.zeros(n_lenslets) self.box_means = np.zeros(n_lenslets) self.valid_centroids = np.zeros(n_lenslets,dtype=np.int16) try: self.fast_centroiding = ccfg.fast_centroiding except Exception as e: self.fast_centroiding = False self.box_backgrounds = np.zeros(n_lenslets) self.error = 0.0 self.tip = 0.0 self.tilt = 0.0 self.zernikes = np.zeros(ccfg.n_zernike_terms) self.wavefront = np.zeros(self.sensor_mask.shape) self.image_max = -1 self.image_min = -1 self.image_mean = -1 self.cam = camera self.frame_timer = FrameTimer('Sensor',verbose=False) self.reconstructor = Reconstructor(self.search_boxes.x, self.search_boxes.y,self.sensor_mask) self.n_zernike_orders_corrected=self.reconstructor.N_orders self.centroiding_time = -1.0 self.beeper = Beeper() self.logging = False self.paused = False self.sense_timer = BlockTimer('Sensor sense method') try: self.profile_update_method = ccfg.profile_sensor_update_method except: self.profile_update_method = False def update(self): if not self.paused: try: self.sense() except Exception as e: print 'Sensor update exception:',e if self.logging: self.log() self.frame_timer.tick() def pause(self): print 'sensor paused' self.paused = True def unpause(self): print 'sensor unpaused' self.paused = False def get_average_background(self): return np.mean(self.box_backgrounds) def get_n_zernike_orders_corrected(self): return self.n_zernike_orders_corrected def set_n_zernike_orders_corrected(self,n): self.n_zernike_orders_corrected = n def set_dark_subtraction(self,val): self.dark_subtract = val def set_n_dark(self,val): self.n_dark = val def set_dark(self): self.pause() temp = np.zeros(self.dark_image.shape) for k in range(self.n_dark): temp = temp + self.cam.get_image() temp = np.round(temp/float(self.n_dark)).astype(np.int16) self.dark_image[...] = temp[...] self.unpause() def log0(self): t_string = now_string(True) #seconds = float(datetime.datetime.strptime(t_string,'%Y%m%d%H%M%S.%f').strftime('%s.%f')) outfn = os.path.join(ccfg.logging_directory,'sensor_%s.mat'%(t_string)) d = {} #d['time_seconds'] = seconds d['x_slopes'] = self.x_slopes d['y_slopes'] = self.y_slopes d['x_centroids'] = self.x_centroids d['y_centroids'] = self.y_centroids d['search_box_x1'] = self.search_boxes.x1 d['search_box_x2'] = self.search_boxes.x2 d['search_box_y1'] = self.search_boxes.y1 d['search_box_y2'] = self.search_boxes.y2 d['ref_x'] = self.search_boxes.x d['ref_y'] = self.search_boxes.y d['error'] = np.squeeze(self.error) d['tip'] = self.tip d['tilt'] = self.tilt d['wavefront'] = self.wavefront d['zernikes'] = np.squeeze(self.zernikes) #d['spots_image'] = self.image sio.savemat(outfn,d) def log(self): t_string = now_string(True) #seconds = float(datetime.datetime.strptime(t_string,'%Y%m%d%H%M%S.%f').strftime('%s.%f')) d = {} #d['time_seconds'] = np.array([seconds]) d['x_slopes'] = self.x_slopes d['y_slopes'] = self.y_slopes d['x_centroids'] = self.x_centroids d['y_centroids'] = self.y_centroids d['search_box_x1'] = self.search_boxes.x1 d['search_box_x2'] = self.search_boxes.x2 d['search_box_y1'] = self.search_boxes.y1 d['search_box_y2'] = self.search_boxes.y2 d['ref_x'] = self.search_boxes.x d['ref_y'] = self.search_boxes.y d['error'] = np.array([np.squeeze(self.error)]) #d['tip'] = self.tip #d['tilt'] = self.tilt d['wavefront'] = self.wavefront d['zernikes'] = np.squeeze(self.zernikes) d['spots_image'] = self.image.astype(np.uint16) for k in d.keys(): outfn = os.path.join(ccfg.logging_directory,'sensor_%s_%s.txt'%(k,t_string)) if k=='spots_image': np.savetxt(outfn,d[k],fmt='%d') else: np.savetxt(outfn,d[k]) #sio.savemat(outfn,d) def set_background_correction(self,val): #sensor_mutex.lock() self.background_correction = val #sensor_mutex.unlock() def set_fast_centroiding(self,val): self.fast_centroiding = val def set_logging(self,val): self.logging = val def set_defocus(self,val): self.pause() newx = self.search_boxes.x0 + self.reconstructor.defocus_dx*val*ccfg.zernike_dioptric_equivalent newy = self.search_boxes.y0 + self.reconstructor.defocus_dy*val*ccfg.zernike_dioptric_equivalent self.search_boxes.move(newx,newy) self.unpause() def set_astig0(self,val): self.pause() newx = self.search_boxes.x + self.reconstructor.astig0_dx*val*ccfg.zernike_dioptric_equivalent newy = self.search_boxes.y + self.reconstructor.astig0_dy*val*ccfg.zernike_dioptric_equivalent self.search_boxes.move(newx,newy) self.unpause() def set_astig1(self,val): self.pause() newx = self.search_boxes.x + self.reconstructor.astig1_dx*val*ccfg.zernike_dioptric_equivalent newy = self.search_boxes.y + self.reconstructor.astig1_dy*val*ccfg.zernike_dioptric_equivalent self.search_boxes.move(newx,newy) self.unpause() def aberration_reset(self): self.pause() self.search_boxes.move(self.x0,self.y0) self.unpause() def set_centroiding_half_width(self,val): self.centroiding_half_width = val def sense(self,debug=False): if self.profile_update_method: self.sense_timer.tick('start') self.image = self.cam.get_image() if self.profile_update_method: self.sense_timer.tick('cam.get_image') if self.dark_subtract: self.image = self.image - self.dark_image self.image_min = self.image.min() self.image_mean = self.image.mean() self.image_max = self.image.max() if self.profile_update_method: self.sense_timer.tick('image stats') t0 = time.time() if not self.fast_centroiding: if self.estimate_background: centroid.estimate_backgrounds(spots_image=self.image, sb_x_vec = self.search_boxes.x, sb_y_vec = self.search_boxes.y, sb_bg_vec = self.box_backgrounds, sb_half_width_p = self.search_boxes.half_width) self.box_backgrounds = self.box_backgrounds + self.background_correction if self.profile_update_method: self.sense_timer.tick('estimate background') centroid.compute_centroids(spots_image=self.image, sb_x_vec = self.search_boxes.x, sb_y_vec = self.search_boxes.y, sb_bg_vec = self.box_backgrounds, sb_half_width_p = self.search_boxes.half_width, iterations_p = self.centroiding_iterations, iteration_step_px_p = self.iterative_centroiding_step, x_out = self.x_centroids, y_out = self.y_centroids, mean_intensity = self.box_means, maximum_intensity = self.box_maxes, minimum_intensity = self.box_mins, num_threads_p = 1) if self.profile_update_method: self.sense_timer.tick('centroid') else: centroid.fast_centroids(spots_image=self.image, sb_x_vec = self.search_boxes.x, sb_y_vec = self.search_boxes.y, sb_half_width_p = self.search_boxes.half_width, centroiding_half_width_p = self.centroiding_half_width, x_out = self.x_centroids, y_out = self.y_centroids, sb_max_vec = self.box_maxes, valid_vec = self.valid_centroids, verbose_p = 0, num_threads_p = 1) self.centroiding_time = time.time()-t0 self.x_slopes = (self.x_centroids-self.search_boxes.x)*self.pixel_size_m/self.lenslet_focal_length_m self.y_slopes = (self.y_centroids-self.search_boxes.y)*self.pixel_size_m/self.lenslet_focal_length_m self.tilt = np.mean(self.x_slopes) self.tip = np.mean(self.y_slopes) if self.remove_tip_tilt: self.x_slopes-=self.tilt self.y_slopes-=self.tip if self.reconstruct_wavefront: self.zernikes,self.wavefront,self.error = self.reconstructor.get_wavefront(self.x_slopes,self.y_slopes) if self.profile_update_method: self.sense_timer.tick('reconstruct wavefront') self.filter_slopes = self.n_zernike_orders_corrected<self.reconstructor.N_orders if self.filter_slopes: # Outline of approach: the basic idea is to filter the residual error # slopes by Zernike mode before multiplying by the mirror command # matrix. # 1. multiply the slopes by a wavefront reconstructor matrix # to get Zernike coefficients; these are already output by # the call to self.reconstructor.get_wavefront above # 2. zero the desired modes # 3. multiply the modes by the inverse of that matrix, which is stored # in the Reconstructor object as reconstructor.slope_matrix # convert the order into a number of terms: n_terms = self.reconstructor.Z.nm2j(self.n_zernike_orders_corrected,self.n_zernike_orders_corrected) # get the slope matrix (inverse of zernike matrix, which maps slopes onto zernikes) slope_matrix = self.reconstructor.slope_matrix # create a filtered set of zernike terms # not sure if we should zero piston here z_filt = np.zeros(len(self.zernikes)) z_filt[:n_terms+1] = self.zernikes[:n_terms+1] zero_piston = True if zero_piston: z_filt[0] = 0.0 # filter the slopes, and assign them to this sensor object: filtered_slopes = np.dot(slope_matrix,z_filt) self.x_slopes = filtered_slopes[:self.n_lenslets] self.y_slopes = filtered_slopes[self.n_lenslets:] if self.profile_update_method: self.sense_timer.tick('end sense') self.sense_timer.tock() try: self.beeper.beep(self.error) except Exception as e: print e print self.error sys.exit() def record_reference(self): print 'recording reference' self.pause() xcent = [] ycent = [] for k in range(ccfg.reference_n_measurements): print 'measurement %d of %d'%(k+1,ccfg.reference_n_measurements), self.sense() print '...done' xcent.append(self.x_centroids) ycent.append(self.y_centroids) xcent = np.array(xcent) ycent = np.array(ycent) x_ref = xcent.mean(0) y_ref = ycent.mean(0) x_var = xcent.var(0) y_var = ycent.var(0) err = np.sqrt(np.mean([x_var,y_var])) print 'reference coordinate error %0.3e px RMS'%err self.search_boxes = SearchBoxes(x_ref,y_ref,self.search_boxes.half_width) refxy = np.array((x_ref,y_ref)).T # Record the new reference set to two locations, the # filename specified by reference_coordinates_filename # in ciao config, and also an archival filename to keep # track of the history. archive_fn = os.path.join(ccfg.reference_directory,prepend('reference.txt',now_string())) np.savetxt(archive_fn,refxy,fmt='%0.3f') np.savetxt(ccfg.reference_coordinates_filename,refxy,fmt='%0.3f') self.unpause() time.sleep(1)
class UI(QWidget): def __init__(self, loop): super(UI, self).__init__() self.loop = loop self.loop.finished.connect(self.update) self.init_UI() self.frame_timer = FrameTimer('UI', verbose=False) self.show() def init_UI(self): self.setWindowIcon(QIcon('./icons/kungpao.png')) self.setWindowTitle('kungpao') layout = QHBoxLayout() imax = 2**ccfg.bit_depth - 1 imin = 0 self.id_spots = ImageDisplay('spots', downsample=2, clim=None, colormap=ccfg.spots_colormap, image_min=imin, image_max=imax, draw_boxes=ccfg.show_search_boxes, draw_lines=ccfg.show_slope_lines, zoomable=True) #self.id_spots = ImageDisplay('spots',downsample=2,clim=(50,1000),colormap=ccfg.spots_colormap,image_min=imin,image_max=imax,draw_boxes=ccfg.show_search_boxes,draw_lines=ccfg.show_slope_lines,zoomable=True) layout.addWidget(self.id_spots) self.id_mirror = ImageDisplay('mirror', downsample=1, clim=(-0.5, 0.5), colormap=ccfg.mirror_colormap, image_min=ccfg.mirror_command_min, image_max=ccfg.mirror_command_max, width=256, height=256) beam_d = ccfg.beam_diameter_m errmax = beam_d * 1e-4 self.id_wavefront = ImageDisplay('wavefront', downsample=1, clim=(-1.0e-8, 1.0e-8), colormap=ccfg.wavefront_colormap, image_min=-errmax, image_max=errmax, width=256, height=256) column_1 = QVBoxLayout() column_1.setAlignment(Qt.AlignTop) column_1.addWidget(self.id_mirror) column_1.addWidget(self.id_wavefront) layout.addLayout(column_1) column_2 = QVBoxLayout() column_2.setAlignment(Qt.AlignTop) self.cb_closed = QCheckBox('Loop &closed') self.cb_closed.setChecked(self.loop.closed) self.cb_closed.stateChanged.connect(self.loop.set_closed) self.cb_draw_boxes = QCheckBox('Draw boxes') self.cb_draw_boxes.setChecked(self.id_spots.draw_boxes) self.cb_draw_boxes.stateChanged.connect(self.id_spots.set_draw_boxes) self.cb_draw_lines = QCheckBox('Draw lines') self.cb_draw_lines.setChecked(self.id_spots.draw_lines) self.cb_draw_lines.stateChanged.connect(self.id_spots.set_draw_lines) self.cb_logging = QCheckBox('Logging') self.cb_logging.setChecked(False) self.cb_logging.stateChanged.connect(self.loop.sensor.set_logging) self.cb_logging.stateChanged.connect(self.loop.mirror.set_logging) self.pb_poke = QPushButton('Poke') self.pb_poke.clicked.connect(self.loop.run_poke) self.pb_record_reference = QPushButton('Record reference') self.pb_record_reference.clicked.connect( self.loop.sensor.record_reference) self.pb_flatten = QPushButton('&Flatten') self.pb_flatten.clicked.connect(self.loop.mirror.flatten) self.pb_quit = QPushButton('&Quit') self.pb_quit.clicked.connect(sys.exit) poke_layout = QHBoxLayout() poke_layout.addWidget(QLabel('Modes:')) self.modes_spinbox = QSpinBox() self.modes_spinbox.setMaximum(ccfg.mirror_n_actuators) self.modes_spinbox.setMinimum(0) self.modes_spinbox.valueChanged.connect(self.loop.set_n_modes) self.modes_spinbox.setValue(self.loop.get_n_modes()) poke_layout.addWidget(self.modes_spinbox) self.pb_invert = QPushButton('Invert') self.pb_invert.clicked.connect(self.loop.invert) poke_layout.addWidget(self.pb_invert) bg_layout = QHBoxLayout() bg_layout.addWidget(QLabel('Background correction:')) self.bg_spinbox = QSpinBox() self.bg_spinbox.setValue(self.loop.sensor.background_correction) self.bg_spinbox.setMaximum(500) self.bg_spinbox.setMinimum(-500) self.bg_spinbox.valueChanged.connect( self.loop.sensor.set_background_correction) bg_layout.addWidget(self.bg_spinbox) f_layout = QHBoxLayout() f_layout.addWidget(QLabel('Defocus:')) self.f_spinbox = QDoubleSpinBox() self.f_spinbox.setValue(0.0) self.f_spinbox.setSingleStep(0.01) self.f_spinbox.setMaximum(1.0) self.f_spinbox.setMinimum(-1.0) self.f_spinbox.valueChanged.connect(self.loop.sensor.set_defocus) f_layout.addWidget(self.f_spinbox) self.lbl_error = QLabel() self.lbl_error.setAlignment(Qt.AlignRight) self.lbl_tip = QLabel() self.lbl_tip.setAlignment(Qt.AlignRight) self.lbl_tilt = QLabel() self.lbl_tilt.setAlignment(Qt.AlignRight) self.lbl_cond = QLabel() self.lbl_cond.setAlignment(Qt.AlignRight) self.lbl_sensor_fps = QLabel() self.lbl_sensor_fps.setAlignment(Qt.AlignRight) self.lbl_mirror_fps = QLabel() self.lbl_mirror_fps.setAlignment(Qt.AlignRight) self.lbl_ui_fps = QLabel() self.lbl_ui_fps.setAlignment(Qt.AlignRight) column_2.addWidget(self.pb_flatten) column_2.addWidget(self.cb_closed) column_2.addLayout(f_layout) column_2.addLayout(bg_layout) column_2.addLayout(poke_layout) column_2.addWidget(self.cb_draw_boxes) column_2.addWidget(self.cb_draw_lines) column_2.addWidget(self.pb_quit) column_2.addWidget(self.lbl_error) column_2.addWidget(self.lbl_tip) column_2.addWidget(self.lbl_tilt) column_2.addWidget(self.lbl_cond) column_2.addWidget(self.lbl_sensor_fps) column_2.addWidget(self.lbl_mirror_fps) column_2.addWidget(self.lbl_ui_fps) column_2.addWidget(self.pb_poke) column_2.addWidget(self.pb_record_reference) column_2.addWidget(self.cb_logging) layout.addLayout(column_2) self.setLayout(layout) @pyqtSlot() def update(self): try: sensor = self.loop.sensor mirror = self.loop.mirror sb = sensor.search_boxes if self.id_spots.draw_boxes: boxes = [sb.x1, sb.x2, sb.y1, sb.y2] else: boxes = None if self.id_spots.draw_lines: lines = [ sb.x, sb.x + sensor.x_slopes * ccfg.slope_line_magnification, sb.y, sb.y + sensor.y_slopes * ccfg.slope_line_magnification ] else: lines = None self.id_spots.show(sensor.image, boxes=boxes, lines=lines, mask=self.loop.active_lenslets) mirror_map = np.zeros(mirror.mask.shape) mirror_map[np.where(mirror.mask)] = mirror.get_command()[:] self.id_mirror.show(mirror_map) self.id_wavefront.show(sensor.wavefront) self.lbl_error.setText(ccfg.wavefront_error_fmt % (sensor.error * 1e9)) self.lbl_tip.setText(ccfg.tip_fmt % (sensor.tip * 1000000)) self.lbl_tilt.setText(ccfg.tilt_fmt % (sensor.tilt * 1000000)) self.lbl_cond.setText(ccfg.cond_fmt % (self.loop.get_condition_number())) self.lbl_sensor_fps.setText(ccfg.sensor_fps_fmt % sensor.frame_timer.fps) self.lbl_mirror_fps.setText(ccfg.mirror_fps_fmt % mirror.frame_timer.fps) self.lbl_ui_fps.setText(ccfg.ui_fps_fmt % self.frame_timer.fps) except Exception as e: print e def select_single_spot(self, click): print 'foo' x = click.x() * self.downsample y = click.y() * self.downsample self.single_spot_index = self.loop.sensor.search_boxes.get_lenslet_index( x, y) def paintEvent(self, event): self.frame_timer.tick()
class Sensor(QObject): finished = pyqtSignal() def __init__(self, camera): super(Sensor, self).__init__() self.image_width_px = ccfg.image_width_px self.image_height_px = ccfg.image_height_px self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m self.pixel_size_m = ccfg.pixel_size_m self.beam_diameter_m = ccfg.beam_diameter_m self.wavelength_m = ccfg.wavelength_m self.background_correction = ccfg.background_correction self.centroiding_iterations = ccfg.centroiding_iterations self.iterative_centroiding_step = ccfg.iterative_centroiding_step self.filter_lenslets = ccfg.sensor_filter_lenslets self.estimate_background = ccfg.estimate_background self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt try: xy = np.loadtxt(ccfg.reference_coordinates_filename) except Exception as e: xy = np.loadtxt(ccfg.reference_coordinates_bootstrap_filename) print 'Bootstrapping with %s' % ccfg.reference_coordinates_bootstrap_filename self.search_boxes = SearchBoxes(xy[:, 0], xy[:, 1], ccfg.search_box_half_width) self.sensor_mask = np.loadtxt(ccfg.reference_mask_filename) self.x0 = np.zeros(self.search_boxes.x.shape) self.y0 = np.zeros(self.search_boxes.y.shape) self.x0[:] = self.search_boxes.x[:] self.y0[:] = self.search_boxes.y[:] self.n_lenslets = self.search_boxes.n n_lenslets = self.n_lenslets self.image = np.zeros((ccfg.image_height_px, ccfg.image_width_px)) self.x_slopes = np.zeros(n_lenslets) self.y_slopes = np.zeros(n_lenslets) self.x_centroids = np.zeros(n_lenslets) self.y_centroids = np.zeros(n_lenslets) self.box_maxes = np.zeros(n_lenslets) self.box_mins = np.zeros(n_lenslets) self.box_means = np.zeros(n_lenslets) self.box_backgrounds = np.zeros(n_lenslets) self.error = 0.0 self.tip = 0.0 self.tilt = 0.0 self.zernikes = None self.wavefront = np.zeros(self.sensor_mask.shape) self.cam = camera self.frame_timer = FrameTimer('Sensor', verbose=False) self.reconstructor = Reconstructor(self.search_boxes.x, self.search_boxes.y, self.sensor_mask) self.logging = False self.paused = False @pyqtSlot() def update(self): if not self.paused: try: self.sense() except Exception as e: print 'Sensor update exception:', e if self.logging: self.log() self.finished.emit() self.frame_timer.tick() @pyqtSlot() def pause(self): print 'sensor paused' self.paused = True @pyqtSlot() def unpause(self): print 'sensor unpaused' self.paused = False #self.sense() def log(self): outfn = os.path.join(ccfg.logging_directory, 'sensor_%s.mat' % (now_string(True))) d = {} d['x_slopes'] = self.x_slopes d['y_slopes'] = self.y_slopes d['x_centroids'] = self.x_centroids d['y_centroids'] = self.y_centroids d['search_box_x1'] = self.search_boxes.x1 d['search_box_x2'] = self.search_boxes.x2 d['search_box_y1'] = self.search_boxes.y1 d['search_box_y2'] = self.search_boxes.y2 d['ref_x'] = self.search_boxes.x d['ref_y'] = self.search_boxes.y d['error'] = self.error d['tip'] = self.tip d['tilt'] = self.tilt d['wavefront'] = self.wavefront d['zernikes'] = self.zernikes sio.savemat(outfn, d) def set_background_correction(self, val): #sensor_mutex.lock() self.background_correction = val #sensor_mutex.unlock() def set_logging(self, val): self.logging = val def set_defocus(self, val): self.pause() newx = self.x0 + self.reconstructor.defocus_dx * val * ccfg.zernike_dioptric_equivalent newy = self.y0 + self.reconstructor.defocus_dy * val * ccfg.zernike_dioptric_equivalent self.search_boxes.move(newx, newy) self.unpause() def sense(self, debug=False): self.image = self.cam.get_image() centroid.estimate_backgrounds( spots_image=self.image, sb_x_vec=self.search_boxes.x, sb_y_vec=self.search_boxes.y, sb_bg_vec=self.box_backgrounds, sb_half_width_p=self.search_boxes.half_width) centroid.compute_centroids( spots_image=self.image, sb_x_vec=self.search_boxes.x, sb_y_vec=self.search_boxes.y, sb_bg_vec=self.box_backgrounds, sb_half_width_p=self.search_boxes.half_width, iterations_p=self.centroiding_iterations, iteration_step_px_p=self.iterative_centroiding_step, x_out=self.x_centroids, y_out=self.y_centroids, mean_intensity=self.box_means, maximum_intensity=self.box_maxes, minimum_intensity=self.box_mins, num_threads_p=1) self.x_slopes = (self.x_centroids - self.search_boxes.x ) * self.pixel_size_m / self.lenslet_focal_length_m self.y_slopes = (self.y_centroids - self.search_boxes.y ) * self.pixel_size_m / self.lenslet_focal_length_m self.tilt = np.mean(self.x_slopes) self.tip = np.mean(self.y_slopes) if self.remove_tip_tilt: self.x_slopes -= self.tilt self.y_slopes -= self.tip if self.reconstruct_wavefront: self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront( self.x_slopes, self.y_slopes) def sense0(self, debug=False): image = self.cam.get_image() sb = self.search_boxes xr = np.zeros(self.search_boxes.x.shape) xr[:] = self.search_boxes.x[:] yr = np.zeros(self.search_boxes.y.shape) yr[:] = self.search_boxes.y[:] half_width = sb.half_width for iteration in range(self.centroiding_iterations): #QApplication.processEvents() msi = iteration == self.centroiding_iterations - 1 if debug: plt.figure() plt.imshow(image) plt.title('iteration %d' % iteration) centroid.compute_centroids( spots_image=image, sb_x1_vec=sb.x1, sb_x2_vec=sb.x2, sb_y1_vec=sb.y1, sb_y2_vec=sb.y2, x_out=xr, y_out=yr, mean_intensity=self.box_means, maximum_intensity=self.box_maxes, minimum_intensity=self.box_mins, background_intensity=self.box_backgrounds, estimate_background=self.estimate_background, background_correction=self.background_correction, num_threads=1, modify_spots_image=msi) half_width -= self.iterative_centroiding_step sb = SearchBoxes(xr, yr, half_width) if debug: plt.figure() plt.imshow(image) plt.show() sys.exit() self.x_centroids[:] = xr[:] self.y_centroids[:] = yr[:] self.x_slopes = (self.x_centroids - self.search_boxes.x ) * self.pixel_size_m / self.lenslet_focal_length_m self.y_slopes = (self.y_centroids - self.search_boxes.y ) * self.pixel_size_m / self.lenslet_focal_length_m self.tilt = np.mean(self.x_slopes) self.tip = np.mean(self.y_slopes) if self.remove_tip_tilt: self.x_slopes -= self.tilt self.y_slopes -= self.tip self.image = image if self.reconstruct_wavefront: self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront( self.x_slopes, self.y_slopes) def record_reference(self): print 'recording reference' self.pause() xcent = [] ycent = [] for k in range(ccfg.reference_n_measurements): print 'measurement %d of %d' % (k + 1, ccfg.reference_n_measurements), self.sense() print '...done' xcent.append(self.x_centroids) ycent.append(self.y_centroids) xcent = np.array(xcent) ycent = np.array(ycent) x_ref = xcent.mean(0) y_ref = ycent.mean(0) x_var = xcent.var(0) y_var = ycent.var(0) err = np.sqrt(np.mean([x_var, y_var])) print 'reference coordinate error %0.3e px RMS' % err self.search_boxes = SearchBoxes(x_ref, y_ref, self.search_boxes.half_width) refxy = np.array((x_ref, y_ref)).T # Record the new reference set to two locations, the # filename specified by reference_coordinates_filename # in ciao config, and also an archival filename to keep # track of the history. archive_fn = os.path.join(ccfg.reference_directory, prepend('reference.txt', now_string())) np.savetxt(archive_fn, refxy, fmt='%0.3f') np.savetxt(ccfg.reference_coordinates_filename, refxy, fmt='%0.3f') self.unpause() time.sleep(1)
class Sensor(QObject): finished = pyqtSignal() def __init__(self, camera): super(Sensor, self).__init__() self.image_width_px = ccfg.image_width_px self.image_height_px = ccfg.image_height_px self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.lenslet_focal_length_m = ccfg.lenslet_focal_length_m self.pixel_size_m = ccfg.pixel_size_m self.beam_diameter_m = ccfg.beam_diameter_m self.wavelength_m = ccfg.wavelength_m self.background_correction = ccfg.background_correction self.centroiding_iterations = ccfg.centroiding_iterations self.iterative_centroiding_step = ccfg.iterative_centroiding_step self.filter_lenslets = ccfg.sensor_filter_lenslets self.estimate_background = ccfg.estimate_background self.reconstruct_wavefront = ccfg.sensor_reconstruct_wavefront self.remove_tip_tilt = ccfg.sensor_remove_tip_tilt try: # check to see if the camera object produced its own # search boxes, and if not, use reference coordinates self.search_boxes = camera.search_boxes self.mask = camera.lenslet_mask except Exception as e: xy = np.loadtxt(ccfg.reference_coordinates_filename) self.search_boxes = SearchBoxes(xy[:, 0], xy[:, 1], ccfg.search_box_half_width) self.mask = np.loadtxt(ccfg.reference_mask_filename) self.x0 = np.zeros(self.search_boxes.x.shape) self.y0 = np.zeros(self.search_boxes.y.shape) self.x0[:] = self.search_boxes.x[:] self.y0[:] = self.search_boxes.y[:] self.n_lenslets = self.search_boxes.n n_lenslets = self.n_lenslets self.image = np.zeros((ccfg.image_height_px, ccfg.image_width_px)) self.x_slopes = np.zeros(n_lenslets) self.y_slopes = np.zeros(n_lenslets) self.x_centroids = np.zeros(n_lenslets) self.y_centroids = np.zeros(n_lenslets) self.box_maxes = np.zeros(n_lenslets) self.box_mins = np.zeros(n_lenslets) self.box_means = np.zeros(n_lenslets) self.box_backgrounds = np.zeros(n_lenslets) self.error = 0.0 self.tip = 0.0 self.tilt = 0.0 self.zernikes = None self.wavefront = None self.cam = camera self.frame_timer = FrameTimer('Sensor', verbose=False) self.reconstructor = Reconstructor(self.search_boxes.x, self.search_boxes.y, self.mask) self.logging = False self.paused = False @pyqtSlot() def update(self): if not self.paused: try: self.sense() except Exception as e: print e if self.logging: self.log() self.finished.emit() self.frame_timer.tick() @pyqtSlot() def pause(self): print 'sensor paused' self.paused = True @pyqtSlot() def unpause(self): print 'sensor unpaused' self.paused = False #self.sense() def log(self): outfn = os.path.join(ccfg.logging_directory, 'sensor_%s.mat' % (now_string(True))) d = {} d['x_slopes'] = self.x_slopes d['y_slopes'] = self.y_slopes d['x_centroids'] = self.x_centroids d['y_centroids'] = self.y_centroids d['search_box_x1'] = self.search_boxes.x1 d['search_box_x2'] = self.search_boxes.x2 d['search_box_y1'] = self.search_boxes.y1 d['search_box_y2'] = self.search_boxes.y2 d['ref_x'] = self.search_boxes.x d['ref_y'] = self.search_boxes.y d['error'] = self.error d['tip'] = self.tip d['tilt'] = self.tilt d['wavefront'] = self.wavefront d['zernikes'] = self.zernikes sio.savemat(outfn, d) def set_background_correction(self, val): #sensor_mutex.lock() self.background_correction = val #sensor_mutex.unlock() def set_logging(self, val): self.logging = val def set_defocus(self, val): self.pause() newx = self.x0 + self.reconstructor.defocus_dx * val * ccfg.zernike_dioptric_equivalent newy = self.y0 + self.reconstructor.defocus_dy * val * ccfg.zernike_dioptric_equivalent self.search_boxes.move(newx, newy) self.unpause() def sense(self): image = self.cam.get_image() sb = self.search_boxes xr = np.zeros(self.search_boxes.x.shape) xr[:] = self.search_boxes.x[:] yr = np.zeros(self.search_boxes.y.shape) yr[:] = self.search_boxes.y[:] half_width = sb.half_width for iteration in range(self.centroiding_iterations): #QApplication.processEvents() msi = iteration == self.centroiding_iterations - 1 centroid.compute_centroids( spots_image=image, sb_x1_vec=sb.x1, sb_x2_vec=sb.x2, sb_y1_vec=sb.y1, sb_y2_vec=sb.y2, x_out=xr, y_out=yr, mean_intensity=self.box_means, maximum_intensity=self.box_maxes, minimum_intensity=self.box_mins, background_intensity=self.box_backgrounds, estimate_background=self.estimate_background, background_correction=self.background_correction, num_threads=1, modify_spots_image=msi) half_width -= self.iterative_centroiding_step sb = SearchBoxes(xr, yr, half_width) self.x_centroids[:] = xr[:] self.y_centroids[:] = yr[:] self.x_slopes = (self.x_centroids - self.search_boxes.x ) * self.pixel_size_m / self.lenslet_focal_length_m self.y_slopes = (self.y_centroids - self.search_boxes.y ) * self.pixel_size_m / self.lenslet_focal_length_m self.tilt = np.mean(self.x_slopes) self.tip = np.mean(self.y_slopes) if self.remove_tip_tilt: self.x_slopes -= self.tilt self.y_slopes -= self.tip self.image = image if self.reconstruct_wavefront: self.zernikes, self.wavefront, self.error = self.reconstructor.get_wavefront( self.x_slopes, self.y_slopes) def record_reference(self): print 'recording reference' self.pause() xcent = [] ycent = [] for k in range(ccfg.reference_n_measurements): print 'measurement %d of %d' % (k + 1, ccfg.reference_n_measurements), self.sense() print '...done' xcent.append(self.x_centroids) ycent.append(self.y_centroids) x_ref = np.array(xcent).mean(0) y_ref = np.array(ycent).mean(0) self.search_boxes = SearchBoxes(x_ref, y_ref, self.search_boxes.half_width) outfn = os.path.join(ccfg.reference_directory, prepend('coords.txt', now_string())) refxy = np.array((x_ref, y_ref)).T np.savetxt(outfn, refxy, fmt='%0.2f') self.unpause() time.sleep(1)
def __init__(self): """The Simulator object simulates the camera, mirror, and dynamic aberrations of the system. CIAO can be run in simulation mode by instantiating a simulator object, then a sensor object using the simulator as its camera, and then a loop object using that sensor and the simulator in place of the mirror.""" self.frame_timer = FrameTimer('simulator') # We need to define a meshes on which to build the simulated spots images # and the simulated wavefront: self.sy = ccfg.image_height_px self.sx = ccfg.image_width_px self.wavefront = np.zeros((self.sy, self.sx)) # Some parameters for the spots image: self.dc = 100 self.spots_range = 2000 self.spots = np.ones((self.sy, self.sx)) * self.dc self.spots = self.noise(self.spots) self.pixel_size_m = ccfg.pixel_size_m # compute single spot self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.f = ccfg.lenslet_focal_length_m self.L = ccfg.wavelength_m fwhm_px = (1.22 * self.L * self.f / self.lenslet_pitch_m) / self.pixel_size_m xvec = np.arange(self.sx) yvec = np.arange(self.sy) xvec = xvec - xvec.mean() yvec = yvec - yvec.mean() XX, YY = np.meshgrid(xvec, yvec) d = np.sqrt(XX**2 + YY**2) self.beam_diameter_m = ccfg.beam_diameter_m self.beam_radius_m = self.beam_diameter_m / 2.0 self.disc_diameter = 170 #self.disc_diameter = ccfg.beam_diameter_m/self.pixel_size_m # was just set to 110 self.disc = np.zeros((self.sy, self.sx)) self.disc[np.where(d <= self.disc_diameter)] = 1.0 self.X = np.arange(self.sx, dtype=np.float) * self.pixel_size_m self.Y = np.arange(self.sy, dtype=np.float) * self.pixel_size_m self.X = self.X - self.X.mean() self.Y = self.Y - self.Y.mean() self.XX, self.YY = np.meshgrid(self.X, self.Y) self.RR = np.sqrt(self.XX**2 + self.YY**2) self.mask = np.zeros(self.RR.shape) self.mask[np.where(self.RR <= self.beam_radius_m)] = 1.0 use_partially_illuminated_lenslets = True if use_partially_illuminated_lenslets: d_lenslets = int( np.ceil(self.beam_diameter_m / self.lenslet_pitch_m)) else: d_lenslets = int( np.floor(self.beam_diameter_m / self.lenslet_pitch_m)) rad = float(d_lenslets) / 2.0 xx, yy = np.meshgrid(np.arange(d_lenslets), np.arange(d_lenslets)) xx = xx - float(d_lenslets - 1) / 2.0 yy = yy - float(d_lenslets - 1) / 2.0 d = np.sqrt(xx**2 + yy**2) self.lenslet_mask = np.zeros(xx.shape, dtype=np.uint8) self.lenslet_mask[np.where(d <= rad)] = 1 self.n_lenslets = int(np.sum(self.lenslet_mask)) self.x_lenslet_coords = xx * self.lenslet_pitch_m / self.pixel_size_m + self.sx / 2.0 self.y_lenslet_coords = yy * self.lenslet_pitch_m / self.pixel_size_m + self.sy / 2.0 in_pupil = np.where(self.lenslet_mask) self.x_lenslet_coords = self.x_lenslet_coords[in_pupil] self.y_lenslet_coords = self.y_lenslet_coords[in_pupil] self.lenslet_boxes = SearchBoxes(self.x_lenslet_coords, self.y_lenslet_coords, ccfg.search_box_half_width) #plt.plot(self.x_lenslet_coords,self.y_lenslet_coords,'ks') #plt.show() self.mirror_mask = np.loadtxt(ccfg.mirror_mask_filename) self.n_actuators = int(np.sum(self.mirror_mask)) self.command = np.zeros(self.n_actuators) # virtual actuator spacing in magnified or demagnified # plane of camera actuator_spacing = ccfg.beam_diameter_m / float( self.mirror_mask.shape[0]) ay, ax = np.where(self.mirror_mask) ay = ay * actuator_spacing ax = ax * actuator_spacing ay = ay - ay.mean() ax = ax - ax.mean() self.flat = np.loadtxt(ccfg.mirror_flat_filename) self.flat0 = np.loadtxt(ccfg.mirror_flat_filename) self.n_zernike_terms = ccfg.n_zernike_terms #actuator_sigma = actuator_spacing*0.75 actuator_sigma = actuator_spacing * 1.5 self.exposure = 10000 # microseconds key = '%d' % hash((tuple(ax), tuple(ay), actuator_sigma, tuple( self.X), tuple(self.Y), self.n_zernike_terms)) key = key.replace('-', 'm') try: os.mkdir(ccfg.simulator_cache_directory) except OSError as e: pass cfn = os.path.join(ccfg.simulator_cache_directory, '%s_actuator_basis.npy' % key) try: self.actuator_basis = np.load(cfn) print 'Loading cached actuator basis set...' except Exception as e: actuator_basis = [] print 'Building actuator basis set...' for x, y in zip(ax, ay): xx = self.XX - x yy = self.YY - y surf = np.exp((-(xx**2 + yy**2) / (2 * actuator_sigma**2))) surf = (surf - surf.min()) / (surf.max() - surf.min()) actuator_basis.append(surf.ravel()) plt.clf() plt.imshow(surf) plt.title('generating actuator basis\n%0.2e,%0.2e' % (x, y)) plt.pause(.1) self.actuator_basis = np.array(actuator_basis) np.save(cfn, self.actuator_basis) zfn = os.path.join(ccfg.simulator_cache_directory, '%s_zernike_basis.npy' % key) self.zernike = Zernike() try: self.zernike_basis = np.load(zfn) print 'Loading cached zernike basis set...' except Exception as e: zernike_basis = [] print 'Building zernike basis set...' #zernike = Zernike() for z in range(self.n_zernike_terms): surf = self.zernike.get_j_surface(z, self.XX, self.YY) zernike_basis.append(surf.ravel()) self.zernike_basis = np.array(zernike_basis) np.save(zfn, self.zernike_basis) #self.new_error_sigma = np.ones(self.n_zernike_terms)*100.0 self.zernike_orders = np.zeros(self.n_zernike_terms) for j in range(self.n_zernike_terms): self.zernike_orders[j] = self.zernike.j2nm(j)[0] self.baseline_error_sigma = 1.0 / (1.0 + self.zernike_orders) * 10.0 self.baseline_error_sigma[3:6] = 150.0 self.new_error_sigma = self.zernike_orders / 10.0 / 100.0 # don't generate any piston, tip, or tilt: self.baseline_error_sigma[:3] = 0.0 self.new_error_sigma[:3] = 0.0 self.error = self.get_error(self.baseline_error_sigma) self.paused = False
class Simulator: def __init__(self): """The Simulator object simulates the camera, mirror, and dynamic aberrations of the system. CIAO can be run in simulation mode by instantiating a simulator object, then a sensor object using the simulator as its camera, and then a loop object using that sensor and the simulator in place of the mirror.""" self.frame_timer = FrameTimer('simulator') # We need to define a meshes on which to build the simulated spots images # and the simulated wavefront: self.sy = ccfg.image_height_px self.sx = ccfg.image_width_px self.wavefront = np.zeros((self.sy, self.sx)) # Some parameters for the spots image: self.dc = 100 self.spots_range = 2000 self.spots = np.ones((self.sy, self.sx)) * self.dc self.spots = self.noise(self.spots) self.pixel_size_m = ccfg.pixel_size_m # compute single spot self.lenslet_pitch_m = ccfg.lenslet_pitch_m self.f = ccfg.lenslet_focal_length_m self.L = ccfg.wavelength_m fwhm_px = (1.22 * self.L * self.f / self.lenslet_pitch_m) / self.pixel_size_m xvec = np.arange(self.sx) yvec = np.arange(self.sy) xvec = xvec - xvec.mean() yvec = yvec - yvec.mean() XX, YY = np.meshgrid(xvec, yvec) d = np.sqrt(XX**2 + YY**2) self.beam_diameter_m = ccfg.beam_diameter_m self.beam_radius_m = self.beam_diameter_m / 2.0 self.disc_diameter = 170 #self.disc_diameter = ccfg.beam_diameter_m/self.pixel_size_m # was just set to 110 self.disc = np.zeros((self.sy, self.sx)) self.disc[np.where(d <= self.disc_diameter)] = 1.0 self.X = np.arange(self.sx, dtype=np.float) * self.pixel_size_m self.Y = np.arange(self.sy, dtype=np.float) * self.pixel_size_m self.X = self.X - self.X.mean() self.Y = self.Y - self.Y.mean() self.XX, self.YY = np.meshgrid(self.X, self.Y) self.RR = np.sqrt(self.XX**2 + self.YY**2) self.mask = np.zeros(self.RR.shape) self.mask[np.where(self.RR <= self.beam_radius_m)] = 1.0 use_partially_illuminated_lenslets = True if use_partially_illuminated_lenslets: d_lenslets = int( np.ceil(self.beam_diameter_m / self.lenslet_pitch_m)) else: d_lenslets = int( np.floor(self.beam_diameter_m / self.lenslet_pitch_m)) rad = float(d_lenslets) / 2.0 xx, yy = np.meshgrid(np.arange(d_lenslets), np.arange(d_lenslets)) xx = xx - float(d_lenslets - 1) / 2.0 yy = yy - float(d_lenslets - 1) / 2.0 d = np.sqrt(xx**2 + yy**2) self.lenslet_mask = np.zeros(xx.shape, dtype=np.uint8) self.lenslet_mask[np.where(d <= rad)] = 1 self.n_lenslets = int(np.sum(self.lenslet_mask)) self.x_lenslet_coords = xx * self.lenslet_pitch_m / self.pixel_size_m + self.sx / 2.0 self.y_lenslet_coords = yy * self.lenslet_pitch_m / self.pixel_size_m + self.sy / 2.0 in_pupil = np.where(self.lenslet_mask) self.x_lenslet_coords = self.x_lenslet_coords[in_pupil] self.y_lenslet_coords = self.y_lenslet_coords[in_pupil] self.lenslet_boxes = SearchBoxes(self.x_lenslet_coords, self.y_lenslet_coords, ccfg.search_box_half_width) #plt.plot(self.x_lenslet_coords,self.y_lenslet_coords,'ks') #plt.show() self.mirror_mask = np.loadtxt(ccfg.mirror_mask_filename) self.n_actuators = int(np.sum(self.mirror_mask)) self.command = np.zeros(self.n_actuators) # virtual actuator spacing in magnified or demagnified # plane of camera actuator_spacing = ccfg.beam_diameter_m / float( self.mirror_mask.shape[0]) ay, ax = np.where(self.mirror_mask) ay = ay * actuator_spacing ax = ax * actuator_spacing ay = ay - ay.mean() ax = ax - ax.mean() self.flat = np.loadtxt(ccfg.mirror_flat_filename) self.flat0 = np.loadtxt(ccfg.mirror_flat_filename) self.n_zernike_terms = ccfg.n_zernike_terms #actuator_sigma = actuator_spacing*0.75 actuator_sigma = actuator_spacing * 1.5 self.exposure = 10000 # microseconds key = '%d' % hash((tuple(ax), tuple(ay), actuator_sigma, tuple( self.X), tuple(self.Y), self.n_zernike_terms)) key = key.replace('-', 'm') try: os.mkdir(ccfg.simulator_cache_directory) except OSError as e: pass cfn = os.path.join(ccfg.simulator_cache_directory, '%s_actuator_basis.npy' % key) try: self.actuator_basis = np.load(cfn) print 'Loading cached actuator basis set...' except Exception as e: actuator_basis = [] print 'Building actuator basis set...' for x, y in zip(ax, ay): xx = self.XX - x yy = self.YY - y surf = np.exp((-(xx**2 + yy**2) / (2 * actuator_sigma**2))) surf = (surf - surf.min()) / (surf.max() - surf.min()) actuator_basis.append(surf.ravel()) plt.clf() plt.imshow(surf) plt.title('generating actuator basis\n%0.2e,%0.2e' % (x, y)) plt.pause(.1) self.actuator_basis = np.array(actuator_basis) np.save(cfn, self.actuator_basis) zfn = os.path.join(ccfg.simulator_cache_directory, '%s_zernike_basis.npy' % key) self.zernike = Zernike() try: self.zernike_basis = np.load(zfn) print 'Loading cached zernike basis set...' except Exception as e: zernike_basis = [] print 'Building zernike basis set...' #zernike = Zernike() for z in range(self.n_zernike_terms): surf = self.zernike.get_j_surface(z, self.XX, self.YY) zernike_basis.append(surf.ravel()) self.zernike_basis = np.array(zernike_basis) np.save(zfn, self.zernike_basis) #self.new_error_sigma = np.ones(self.n_zernike_terms)*100.0 self.zernike_orders = np.zeros(self.n_zernike_terms) for j in range(self.n_zernike_terms): self.zernike_orders[j] = self.zernike.j2nm(j)[0] self.baseline_error_sigma = 1.0 / (1.0 + self.zernike_orders) * 10.0 self.baseline_error_sigma[3:6] = 150.0 self.new_error_sigma = self.zernike_orders / 10.0 / 100.0 # don't generate any piston, tip, or tilt: self.baseline_error_sigma[:3] = 0.0 self.new_error_sigma[:3] = 0.0 self.error = self.get_error(self.baseline_error_sigma) self.paused = False def pause(self): self.paused = True def unpause(self): self.paused = False def set_logging(self, val): self.logging = val def flatten(self): self.command[:] = self.flat[:] #self.update() def set_exposure(self, val): self.exposure = val def get_exposure(self): return self.exposure def restore_flat(self): self.flat[:] = self.flat0[:] def set_flat(self): self.flat[:] = self.get_command()[:] def get_command(self): return self.command def set_command(self, vec): self.command[:] = vec[:] #self.update() def set_actuator(self, index, value): self.command[index] = value self.update() def noise(self, im): noiserms = np.random.randn(im.shape[0], im.shape[1]) * np.sqrt(im) return im + noiserms def get_error(self, sigma): coefs = np.random.randn(self.n_zernike_terms) * sigma return np.reshape(np.dot(coefs, self.zernike_basis), (self.sy, self.sx)) def defocus_animation(self): err = np.zeros(self.n_zernike_terms) for k in np.arange(0.0, 100.0): err[4] = np.random.randn() im = np.reshape(np.dot(err, self.zernike_basis), (self.sy, self.sx)) plt.clf() plt.imshow(im - im.min()) plt.colorbar() plt.pause(.1) def plot_actuators(self): edge = self.XX.min() wid = self.XX.max() - edge plt.imshow(self.mask, extent=[edge, edge + wid, edge, edge + wid]) plt.autoscale(False) plt.plot(ax, ay, 'ks') plt.show() def update(self): mirror = np.reshape(np.dot(self.command, self.actuator_basis), (self.sy, self.sx)) err = self.error + self.get_error(self.new_error_sigma) dx = np.diff(err, axis=1) dy = np.diff(err, axis=0) sy, sx = err.shape col = np.zeros((sy, 1)) row = np.zeros((1, sx)) dx = np.hstack((col, dx)) dy = np.vstack((row, dy)) #err = err - dx - dy self.wavefront = mirror + err y_slope_vec = [] x_slope_vec = [] self.spots[:] = 0.0 for idx, (x, y, x1, x2, y1, y2) in enumerate( zip(self.lenslet_boxes.x, self.lenslet_boxes.y, self.lenslet_boxes.x1, self.lenslet_boxes.x2, self.lenslet_boxes.y1, self.lenslet_boxes.y2)): subwf = self.wavefront[y1:y2 + 1, x1:x2 + 1] yslope = np.mean(np.diff(subwf.mean(1))) dy = yslope * self.f / self.pixel_size_m ycentroid = y + dy ypx = int(round(y + dy)) xslope = np.mean(np.diff(subwf.mean(0))) dx = xslope * self.f / self.pixel_size_m xcentroid = x + dx #if idx==20: # continue self.spots = self.interpolate_dirac(xcentroid, ycentroid, self.spots) x_slope_vec.append(xslope) y_slope_vec.append(yslope) #QApplication.processEvents() self.spots = np.abs( np.fft.ifft2(np.fft.fftshift(np.fft.fft2(self.spots)) * self.disc)) self.x_slopes = np.array(x_slope_vec) self.y_slopes = np.array(y_slope_vec) def get_image(self): self.update() self.frame_timer.tick() spots = (self.spots - self.spots.min()) / ( self.spots.max() - self.spots.min()) * self.spots_range + self.dc nspots = self.noise(spots) * (self.exposure / 10000) nspots = np.clip(nspots, 0, 4095) nspots = np.round(nspots).astype(np.int16) return nspots def interpolate_dirac(self, x, y, frame): # take subpixel precision locations x and y and insert an interpolated # delta w/ amplitude 1 there #no interpolation case: #frame[int(round(y)),int(round(x))] = 1.0 #return frame x1 = int(np.floor(x)) x2 = x1 + 1 y1 = int(np.floor(y)) y2 = y1 + 1 for yi in [y1, y2]: for xi in [x1, x2]: yweight = 1.0 - (abs(yi - y)) xweight = 1.0 - (abs(xi - x)) try: frame[yi, xi] = yweight * xweight except Exception as e: pass return frame def wavefront_to_spots(self): pass def show_zernikes(self): for k in range(self.n_zernike_terms): b = np.reshape(self.zernike_basis[k, :], (self.sy, self.sx)) plt.clf() plt.imshow(b) plt.colorbar() plt.pause(.5) def close(self): print 'Closing simulator.'
class Mirror: def __init__(self): try: self.controller = MirrorControllerPython() print 'Mirror python initialization succeeded.' except Exception as e: print 'Mirror python initialization failed:',e try: self.controller = MirrorControllerPythonOld() print 'Mirror python (old style) initialization succeeded.' except Exception as e: print 'Mirror python (old style) initialization failed:',e try: self.controller = MirrorControllerCtypes() print 'Mirror c initialization succeeded.' except Exception as e: print e print 'No mirror driver found. Using virtual mirror.' self.controller = MirrorController() self.mirror_mask = np.loadtxt(ccfg.mirror_mask_filename) self.n_actuators = ccfg.mirror_n_actuators self.flat = np.loadtxt(ccfg.mirror_flat_filename) self.flat0 = np.loadtxt(ccfg.mirror_flat_filename) self.command_max = ccfg.mirror_command_max self.command_min = ccfg.mirror_command_min self.settling_time = ccfg.mirror_settling_time_s self.update_rate = ccfg.mirror_update_rate self.flatten() self.frame_timer = FrameTimer('Mirror',verbose=False) self.logging = False self.paused = False def update(self): if not self.paused: self.send() if self.logging: self.log() self.frame_timer.tick() def pause(self): print 'mirror paused' self.paused = True def unpause(self): print 'mirror unpaused' self.paused = False def send(self): self.controller.send() def flatten(self): self.controller.set(self.flat) self.send() def set_actuator(self,index,value): self.controller.command[index] = value self.send() def set_command(self,vec): self.controller.set(vec) def get_command(self): return self.controller.command def restore_flat(self): self.flat[:] = self.flat0[:] def set_flat(self): self.flat[:] = self.get_command()[:] def log(self): #outfn = os.path.join(ccfg.logging_directory,'mirror_%s.mat'%(now_string(True))) #d = {} #d['command'] = self.controller.command #sio.savemat(outfn,d) outfn = os.path.join(ccfg.logging_directory,'mirror_%s.txt'%(now_string(True))) np.savetxt(outfn,self.controller.command) def set_logging(self,val): self.logging = val
class UI(QWidget): def __init__(self, loop): super(UI, self).__init__() self.sensor_mutex = QMutex() #loop.sensor_mutex self.mirror_mutex = QMutex() #loop.mirror_mutex self.loop = loop try: pass self.loop.finished.connect(self.update) except Exception as e: pass self.draw_boxes = ccfg.show_search_boxes self.draw_lines = ccfg.show_slope_lines self.init_UI() self.frame_timer = FrameTimer('UI', verbose=False) self.update_timer = BlockTimer('UI update method') try: self.profile_update_method = ccfg.profile_ui_update_method except: self.profile_update_method = False self.show() #def get_draw_boxes(self): # return self.draw_boxes def __del__(self): print "hello?" self.update_timer.tock() def keyPressEvent(self, event): if event.key() == Qt.Key_W: self.loop.sensor.search_boxes.up() if event.key() == Qt.Key_Z: self.loop.sensor.search_boxes.down() if event.key() == Qt.Key_A: self.loop.sensor.search_boxes.left() if event.key() == Qt.Key_S: self.loop.sensor.search_boxes.right() self.update_box_coords() def update_box_coords(self): self.boxes_coords = [] for x1, x2, y1, y2 in zip(self.loop.sensor.search_boxes.x1, self.loop.sensor.search_boxes.x2, self.loop.sensor.search_boxes.y1, self.loop.sensor.search_boxes.y2): self.boxes_coords.append((x1, x2, y1, y2)) self.overlay_boxes.coords = self.boxes_coords def update_focus(self, val): self.loop.sensor.set_defocus(val) self.update_box_coords() def set_draw_boxes(self, val): self.draw_boxes = val self.overlay_boxes.visible = val #def get_draw_lines(self): # return self.draw_lines def set_draw_lines(self, val): self.draw_lines = val self.overlay_slopes.visible = val def init_UI(self): self.setWindowIcon(QIcon('./icons/ciao.png')) self.setWindowTitle('CIAO') self.setMinimumWidth(ccfg.ui_width_px) self.setMinimumHeight(ccfg.ui_height_px) layout = QGridLayout() imax = 2**ccfg.bit_depth - 1 imin = 0 self.boxes_coords = [] for x1, x2, y1, y2 in zip(self.loop.sensor.search_boxes.x1, self.loop.sensor.search_boxes.x2, self.loop.sensor.search_boxes.y1, self.loop.sensor.search_boxes.y2): self.boxes_coords.append((x1, x2, y1, y2)) self.overlay_boxes = Overlay(coords=self.boxes_coords, mode='rects', color=ccfg.search_box_color, thickness=ccfg.search_box_thickness) self.overlay_slopes = Overlay(coords=[], mode='lines', color=ccfg.slope_line_color, thickness=ccfg.slope_line_thickness) self.id_spots = ZoomDisplay( 'Spots', clim=ccfg.spots_contrast_limits, colormap=ccfg.spots_colormap, zoom=0.25, overlays=[self.overlay_boxes, self.overlay_slopes], downsample=ccfg.spots_image_downsampling) layout.addWidget(self.id_spots, 0, 0, 3, 3) self.id_mirror = ZoomDisplay('Mirror', clim=ccfg.mirror_contrast_limits, colormap=ccfg.mirror_colormap, zoom=1.0) self.id_wavefront = ZoomDisplay('Wavefront', clim=ccfg.wavefront_contrast_limits, colormap=ccfg.wavefront_colormap, zoom=1.0) self.id_zoomed_spots = ZoomDisplay('Zoomed spots', clim=ccfg.spots_contrast_limits, colormap=ccfg.spots_colormap, zoom=5.0) layout.addWidget(self.id_mirror, 0, 3, 1, 1) layout.addWidget(self.id_wavefront, 1, 3, 1, 1) layout.addWidget(self.id_zoomed_spots, 2, 3, 1, 1) column_2 = QVBoxLayout() column_2.setAlignment(Qt.AlignTop) self.cb_closed = QCheckBox('Loop &closed') self.cb_closed.setChecked(self.loop.closed) self.cb_closed.stateChanged.connect(self.loop.set_closed) self.cb_paused = QCheckBox('Loop &paused') self.cb_paused.setChecked(self.loop.paused) self.cb_paused.stateChanged.connect(self.loop.set_paused) self.cb_safe = QCheckBox('Loop safe') self.cb_safe.setChecked(self.loop.safe) self.cb_safe.stateChanged.connect(self.loop.set_safe) loop_control_layout = QHBoxLayout() loop_control_layout.addWidget(self.cb_closed) loop_control_layout.addWidget(self.cb_paused) loop_control_layout.addWidget(self.cb_safe) self.cb_draw_boxes = QCheckBox('Draw boxes') self.cb_draw_boxes.setChecked(self.draw_boxes) self.cb_draw_boxes.stateChanged.connect(self.set_draw_boxes) self.cb_draw_lines = QCheckBox('Draw lines') self.cb_draw_lines.setChecked(self.draw_lines) self.cb_draw_lines.stateChanged.connect(self.set_draw_lines) self.cb_logging = QCheckBox('Logging') self.cb_logging.setChecked(False) self.cb_logging.stateChanged.connect(self.loop.sensor.set_logging) self.cb_logging.stateChanged.connect(self.loop.mirror.set_logging) self.pb_poke = QPushButton('Measure poke matrix') self.pb_poke.clicked.connect(self.loop.run_poke) self.pb_record_reference = QPushButton('Record reference') self.pb_record_reference.clicked.connect( self.loop.sensor.record_reference) self.pb_flatten = QPushButton('&Flatten') self.pb_flatten.clicked.connect(self.loop.mirror.flatten) self.pb_restore_flat = QPushButton('Restore flat') self.pb_restore_flat.clicked.connect(self.restore_flat) self.pb_restore_flat.setEnabled(False) self.pb_set_flat = QPushButton('Set flat') self.pb_set_flat.clicked.connect(self.set_flat) self.pb_set_flat.setCheckable(True) #print dir(self.pb_set_flat) #sys.exit() self.pb_quit = QPushButton('&Quit') self.pb_quit.clicked.connect(self.quit) poke_layout = QHBoxLayout() poke_layout.addWidget(QLabel('Modes:')) self.modes_spinbox = QSpinBox() n_actuators = int(np.sum(self.loop.mirror.mirror_mask)) self.modes_spinbox.setMaximum(n_actuators) self.modes_spinbox.setMinimum(0) self.modes_spinbox.valueChanged.connect(self.loop.set_n_modes) self.modes_spinbox.setValue(self.loop.get_n_modes()) poke_layout.addWidget(self.modes_spinbox) self.pb_invert = QPushButton('Invert') self.pb_invert.clicked.connect(self.loop.invert) poke_layout.addWidget(self.pb_invert) modal_layout = QHBoxLayout() modal_layout.addWidget(QLabel('Corrected Zernike orders:')) self.corrected_order_spinbox = QSpinBox() max_order = self.loop.sensor.reconstructor.N_orders self.corrected_order_spinbox.setMaximum(max_order) self.corrected_order_spinbox.setMinimum(0) self.corrected_order_spinbox.valueChanged.connect( self.loop.sensor.set_n_zernike_orders_corrected) self.corrected_order_spinbox.setValue( self.loop.sensor.get_n_zernike_orders_corrected()) modal_layout.addWidget(self.corrected_order_spinbox) modal_layout.addWidget(QLabel('(%d -> no filtering)' % max_order)) dark_layout = QHBoxLayout() self.cb_dark_subtraction = QCheckBox('Subtract dark') self.cb_dark_subtraction.setChecked(self.loop.sensor.dark_subtract) self.cb_dark_subtraction.stateChanged.connect( self.loop.sensor.set_dark_subtraction) dark_layout.addWidget(self.cb_dark_subtraction) dark_layout.addWidget(QLabel('Dark subtract N:')) self.n_dark_spinbox = QSpinBox() self.n_dark_spinbox.setMinimum(1) self.n_dark_spinbox.setMaximum(9999) self.n_dark_spinbox.valueChanged.connect(self.loop.sensor.set_n_dark) self.n_dark_spinbox.setValue(self.loop.sensor.n_dark) dark_layout.addWidget(self.n_dark_spinbox) self.pb_set_dark = QPushButton('Set dark') self.pb_set_dark.clicked.connect(self.loop.sensor.set_dark) dark_layout.addWidget(self.pb_set_dark) centroiding_layout = QHBoxLayout() centroiding_layout.addWidget(QLabel('Centroiding:')) self.cb_fast_centroiding = QCheckBox('Fast centroiding') self.cb_fast_centroiding.setChecked(self.loop.sensor.fast_centroiding) self.cb_fast_centroiding.stateChanged.connect( self.loop.sensor.set_fast_centroiding) centroiding_layout.addWidget(self.cb_fast_centroiding) self.centroiding_width_spinbox = QSpinBox() self.centroiding_width_spinbox.setMaximum( self.loop.sensor.search_boxes.half_width) self.centroiding_width_spinbox.setMinimum(0) self.centroiding_width_spinbox.valueChanged.connect( self.loop.sensor.set_centroiding_half_width) self.centroiding_width_spinbox.setValue( self.loop.sensor.centroiding_half_width) centroiding_layout.addWidget(self.centroiding_width_spinbox) bg_layout = QHBoxLayout() bg_layout.addWidget(QLabel('Background adjustment:')) self.bg_spinbox = QSpinBox() self.bg_spinbox.setValue(self.loop.sensor.background_correction) self.bg_spinbox.setMaximum(500) self.bg_spinbox.setMinimum(-500) self.bg_spinbox.valueChanged.connect( self.loop.sensor.set_background_correction) bg_layout.addWidget(self.bg_spinbox) aberration_layout = QHBoxLayout() aberration_layout.addWidget(QLabel('Defocus:')) self.f_spinbox = QDoubleSpinBox() self.f_spinbox.setValue(0.0) self.f_spinbox.setSingleStep(0.01) self.f_spinbox.setMaximum(10.0) self.f_spinbox.setMinimum(-10.0) #self.f_spinbox.valueChanged.connect(self.loop.sensor.set_defocus) self.f_spinbox.valueChanged.connect(self.update_focus) aberration_layout.addWidget(self.f_spinbox) aberration_layout.addWidget(QLabel('Astig 0:')) self.a0_spinbox = QDoubleSpinBox() self.a0_spinbox.setValue(0.0) self.a0_spinbox.setSingleStep(0.01) self.a0_spinbox.setMaximum(10.0) self.a0_spinbox.setMinimum(-10.0) self.a0_spinbox.valueChanged.connect(self.loop.sensor.set_astig0) aberration_layout.addWidget(self.a0_spinbox) aberration_layout.addWidget(QLabel('Astig 45:')) self.a1_spinbox = QDoubleSpinBox() self.a1_spinbox.setValue(0.0) self.a1_spinbox.setSingleStep(0.01) self.a1_spinbox.setMaximum(10.0) self.a1_spinbox.setMinimum(-10.0) self.a1_spinbox.valueChanged.connect(self.loop.sensor.set_astig1) aberration_layout.addWidget(self.a1_spinbox) self.pb_aberration_reset = QPushButton('Reset') def reset(): self.f_spinbox.setValue(0.0) self.a0_spinbox.setValue(0.0) self.a1_spinbox.setValue(0.0) self.loop.sensor.aberration_reset() self.pb_aberration_reset.clicked.connect(reset) aberration_layout.addWidget(self.pb_aberration_reset) exp_layout = QHBoxLayout() exp_layout.addWidget(QLabel('Exposure (us):')) self.exp_spinbox = QSpinBox() self.exp_spinbox.setValue(self.loop.sensor.cam.get_exposure()) self.exp_spinbox.setSingleStep(100) self.exp_spinbox.setMaximum(1000000) self.exp_spinbox.setMinimum(100) self.exp_spinbox.valueChanged.connect( self.loop.sensor.cam.set_exposure) exp_layout.addWidget(self.exp_spinbox) self.stripchart_error = StripChart( ylim=ccfg.error_plot_ylim, ytick_interval=ccfg.error_plot_ytick_interval, print_function=ccfg.error_plot_print_func, hlines=[0.0, ccfg.wavelength_m / 14.0], buffer_length=ccfg.error_plot_buffer_length) self.stripchart_error.setAlignment(Qt.AlignRight) #self.stripchart_defocus = StripChart(ylim=ccfg.zernike_plot_ylim,ytick_interval=ccfg.zernike_plot_ytick_interval,print_function=ccfg.zernike_plot_print_func,buffer_length=ccfg.zernike_plot_buffer_length) #self.stripchart_defocus.setAlignment(Qt.AlignRight) self.lbl_tip = QLabel() self.lbl_tip.setAlignment(Qt.AlignRight) self.lbl_tilt = QLabel() self.lbl_tilt.setAlignment(Qt.AlignRight) self.lbl_cond = QLabel() self.lbl_cond.setAlignment(Qt.AlignRight) self.lbl_sensor_fps = QLabel() self.lbl_sensor_fps.setAlignment(Qt.AlignRight) self.ind_centroiding_time = Indicator( buffer_length=50, print_function=lambda x: '%0.0f us (centroiding)' % (x * 1e6)) self.ind_centroiding_time.setAlignment(Qt.AlignRight) self.ind_image_max = Indicator( buffer_length=10, print_function=lambda x: '%d ADU (max)' % x) self.ind_image_mean = Indicator( buffer_length=10, print_function=lambda x: '%d ADU (mean)' % x) self.ind_image_min = Indicator( buffer_length=10, print_function=lambda x: '%d ADU (min)' % x) self.ind_mean_box_background = Indicator( buffer_length=10, print_function=lambda x: '%d ADU (background)' % x) self.ind_image_max.setAlignment(Qt.AlignRight) self.ind_image_mean.setAlignment(Qt.AlignRight) self.ind_image_min.setAlignment(Qt.AlignRight) self.ind_mean_box_background.setAlignment(Qt.AlignRight) self.lbl_mirror_fps = QLabel() self.lbl_mirror_fps.setAlignment(Qt.AlignRight) self.lbl_ui_fps = QLabel() self.lbl_ui_fps.setAlignment(Qt.AlignRight) flatten_layout = QHBoxLayout() flatten_layout.addWidget(self.pb_flatten) flatten_layout.addWidget(self.pb_restore_flat) flatten_layout.addWidget(self.pb_set_flat) column_2.addLayout(flatten_layout) column_2.addLayout(loop_control_layout) #column_2.addWidget(self.cb_fast_centroiding) column_2.addLayout(aberration_layout) #column_2.addLayout(exp_layout) #column_2.addLayout(centroiding_layout) if ccfg.estimate_background: column_2.addLayout(bg_layout) #column_2.addLayout(poke_layout) #column_2.addLayout(modal_layout) if ccfg.use_dark_subtraction: column_2.addLayout(dark_layout) column_2.addWidget(self.cb_draw_boxes) column_2.addWidget(self.cb_draw_lines) column_2.addWidget(self.pb_quit) column_2.addWidget(self.stripchart_error) #column_2.addWidget(self.stripchart_defocus) column_2.addWidget(self.lbl_tip) column_2.addWidget(self.lbl_tilt) column_2.addWidget(self.lbl_cond) column_2.addWidget(self.ind_image_max) column_2.addWidget(self.ind_image_mean) column_2.addWidget(self.ind_image_min) column_2.addWidget(self.ind_mean_box_background) column_2.addWidget(self.ind_centroiding_time) column_2.addWidget(self.lbl_sensor_fps) column_2.addWidget(self.lbl_mirror_fps) column_2.addWidget(self.lbl_ui_fps) column_2.addWidget(self.pb_poke) column_2.addWidget(self.pb_record_reference) column_2.addWidget(self.cb_logging) layout.addLayout(column_2, 0, 6, 3, 1) self.setLayout(layout) def quit(self): self.loop.sensor.cam.close() sys.exit() def flatten(self): self.mirror_mutex.lock() self.loop.mirror.flatten() self.mirror_mutex.unlock() def restore_flat(self): self.loop.mirror.restore_flat() self.pb_set_flat.setChecked(False) self.pb_set_flat.setFocus(False) self.pb_restore_flat.setEnabled(False) def set_flat(self): self.loop.mirror.set_flat() self.pb_set_flat.setChecked(True) self.pb_restore_flat.setEnabled(True) @pyqtSlot() def update(self): if self.profile_update_method: self.update_timer.tick('start') #self.mirror_mutex.lock() #self.sensor_mutex.lock() sensor = self.loop.sensor mirror = self.loop.mirror temp = [(x, xerr, y, yerr) for x, xerr, y, yerr in zip( sensor.search_boxes.x, sensor.x_centroids, sensor.search_boxes.y, sensor.y_centroids)] self.overlay_slopes.coords = [] for x, xerr, y, yerr in temp: dx = (xerr - x) * ccfg.slope_line_magnification dy = (yerr - y) * ccfg.slope_line_magnification x2 = x + dx y2 = y + dy self.overlay_slopes.coords.append((x, x2, y, y2)) if self.profile_update_method: self.update_timer.tick('create slope lines overlay') self.id_spots.show(sensor.image, self.loop.active_lenslets) if self.profile_update_method: self.update_timer.tick('show spots') mirror_map = np.zeros(mirror.mirror_mask.shape) mirror_map[np.where(mirror.mirror_mask)] = mirror.get_command()[:] self.id_mirror.show(mirror_map) self.id_wavefront.show(sensor.wavefront) self.id_zoomed_spots.show(self.id_spots.zoomed()) #self.lbl_error.setText(ccfg.wavefront_error_fmt%(sensor.error*1e9)) self.stripchart_error.setValue(sensor.error) #self.stripchart_defocus.setValue(sensor.zernikes[4]*ccfg.beam_diameter_m) self.lbl_tip.setText(ccfg.tip_fmt % (sensor.tip * 1000000)) self.lbl_tilt.setText(ccfg.tilt_fmt % (sensor.tilt * 1000000)) self.lbl_cond.setText(ccfg.cond_fmt % (self.loop.get_condition_number())) self.ind_image_max.setValue(sensor.image_max) self.ind_image_mean.setValue(sensor.image_mean) self.ind_image_min.setValue(sensor.image_min) self.ind_mean_box_background.setValue(sensor.get_average_background()) self.ind_centroiding_time.setValue(sensor.centroiding_time) self.lbl_sensor_fps.setText(ccfg.sensor_fps_fmt % sensor.frame_timer.fps) self.lbl_mirror_fps.setText(ccfg.mirror_fps_fmt % mirror.frame_timer.fps) self.lbl_ui_fps.setText(ccfg.ui_fps_fmt % self.frame_timer.fps) if self.loop.close_ok: self.cb_closed.setEnabled(True) else: self.cb_closed.setEnabled(False) self.cb_closed.setChecked(False) self.loop.closed = False if self.profile_update_method: self.update_timer.tick('end update') self.update_timer.tock() #self.mirror_mutex.unlock() #self.sensor_mutex.unlock() def select_single_spot(self, click): x = click.x() * self.downsample y = click.y() * self.downsample self.single_spot_index = self.loop.sensor.search_boxes.get_lenslet_index( x, y) def paintEvent(self, event): self.frame_timer.tick()
class Mirror(QObject): finished = pyqtSignal(QObject) def __init__(self): super(Mirror, self).__init__() try: self.controller = MirrorControllerPython() print 'Mirror python initialization succeeded.' except Exception as e: print 'Mirror python initialization failed:', e try: self.controller = MirrorControllerPythonOld() print 'Mirror python (old style) initialization succeeded.' except Exception as e: print 'Mirror python (old style) initialization failed:', e try: self.controller = MirrorControllerCtypes() print 'Mirror c initialization succeeded.' except Exception as e: print e print 'No mirror driver found. Using virtual mirror.' self.controller = MirrorController() self.mirror_mask = np.loadtxt(ccfg.mirror_mask_filename) self.n_actuators = ccfg.mirror_n_actuators self.flat = np.loadtxt(ccfg.mirror_flat_filename) self.command_max = ccfg.mirror_command_max self.command_min = ccfg.mirror_command_min self.settling_time = ccfg.mirror_settling_time_s self.update_rate = ccfg.mirror_update_rate self.flatten() self.timer = QTimer() #self.timer.timeout.connect(self.update) #self.timer.start(1.0/self.update_rate*1000.0) self.frame_timer = FrameTimer('Mirror', verbose=False) self.logging = False self.paused = False @pyqtSlot() def update(self): if not self.paused: self.send() if self.logging: self.log() self.frame_timer.tick() @pyqtSlot() def pause(self): print 'mirror paused' self.paused = True @pyqtSlot() def unpause(self): print 'mirror unpaused' self.paused = False def send(self): self.controller.send() def flatten(self): self.controller.set(self.flat) self.send() def set_actuator(self, index, value): self.controller.command[index] = value self.send() def set_command(self, vec): self.controller.set(vec) def get_command(self): return self.controller.command def log(self): outfn = os.path.join(ccfg.logging_directory, 'mirror_%s.mat' % (now_string(True))) d = {} d['command'] = self.controller.command sio.savemat(outfn, d) def set_logging(self, val): self.logging = val
class UI(QWidget): def __init__(self, loop): super(UI, self).__init__() self.sensor_mutex = QMutex() #loop.sensor_mutex self.mirror_mutex = QMutex() #loop.mirror_mutex self.loop = loop try: self.loop.finished.connect(self.update) except Exception as e: pass self.draw_boxes = ccfg.show_search_boxes self.draw_lines = ccfg.show_slope_lines self.init_UI() self.frame_timer = FrameTimer('UI', verbose=False) self.show() #def get_draw_boxes(self): # return self.draw_boxes def keyPressEvent(self, event): if event.key() == Qt.Key_W: self.loop.sensor.search_boxes.up() if event.key() == Qt.Key_Z: self.loop.sensor.search_boxes.down() if event.key() == Qt.Key_A: self.loop.sensor.search_boxes.left() if event.key() == Qt.Key_S: self.loop.sensor.search_boxes.right() self.update_box_coords() def update_box_coords(self): self.boxes_coords = [] for x1, x2, y1, y2 in zip(self.loop.sensor.search_boxes.x1, self.loop.sensor.search_boxes.x2, self.loop.sensor.search_boxes.y1, self.loop.sensor.search_boxes.y2): self.boxes_coords.append((x1, x2, y1, y2)) self.overlay_boxes.coords = self.boxes_coords def set_draw_boxes(self, val): self.draw_boxes = val self.overlay_boxes.visible = val #def get_draw_lines(self): # return self.draw_lines def set_draw_lines(self, val): self.draw_lines = val self.overlay_slopes.visible = val def init_UI(self): self.setWindowIcon(QIcon('./icons/ciao.png')) self.setWindowTitle('CIAO') layout = QGridLayout() imax = 2**ccfg.bit_depth - 1 imin = 0 self.boxes_coords = [] for x1, x2, y1, y2 in zip(self.loop.sensor.search_boxes.x1, self.loop.sensor.search_boxes.x2, self.loop.sensor.search_boxes.y1, self.loop.sensor.search_boxes.y2): self.boxes_coords.append((x1, x2, y1, y2)) self.overlay_boxes = Overlay(coords=self.boxes_coords, mode='rects', color=ccfg.search_box_color, thickness=ccfg.search_box_thickness) self.overlay_slopes = Overlay(coords=[], mode='lines', color=ccfg.slope_line_color, thickness=ccfg.slope_line_thickness) self.id_spots = ZoomDisplay( 'spots', clim=(0, 4095), colormap=ccfg.spots_colormap, zoom=0.25, overlays=[self.overlay_boxes, self.overlay_slopes], downsample=ccfg.spots_image_downsampling) layout.addWidget(self.id_spots, 0, 0, 3, 3) self.id_mirror = ZoomDisplay('mirror', clim=ccfg.mirror_clim, colormap=ccfg.mirror_colormap, zoom=1.0) self.id_wavefront = ZoomDisplay('wavefront', clim=ccfg.wavefront_clim, colormap=ccfg.wavefront_colormap, zoom=1.0) self.id_zoomed_spots = ZoomDisplay('zoomed_spots', clim=(0, 4095), colormap=ccfg.spots_colormap, zoom=5.0) layout.addWidget(self.id_mirror, 0, 3, 1, 1) layout.addWidget(self.id_wavefront, 1, 3, 1, 1) layout.addWidget(self.id_zoomed_spots, 2, 3, 1, 1) column_2 = QVBoxLayout() column_2.setAlignment(Qt.AlignTop) self.cb_closed = QCheckBox('Loop &closed') self.cb_closed.setChecked(self.loop.closed) self.cb_closed.stateChanged.connect(self.loop.set_closed) self.cb_draw_boxes = QCheckBox('Draw boxes') self.cb_draw_boxes.setChecked(self.draw_boxes) self.cb_draw_boxes.stateChanged.connect(self.set_draw_boxes) self.cb_draw_lines = QCheckBox('Draw lines') self.cb_draw_lines.setChecked(self.draw_lines) self.cb_draw_lines.stateChanged.connect(self.set_draw_lines) self.cb_logging = QCheckBox('Logging') self.cb_logging.setChecked(False) self.cb_logging.stateChanged.connect(self.loop.sensor.set_logging) self.cb_logging.stateChanged.connect(self.loop.mirror.set_logging) self.pb_poke = QPushButton('Poke') self.pb_poke.clicked.connect(self.loop.run_poke) self.pb_record_reference = QPushButton('Record reference') self.pb_record_reference.clicked.connect( self.loop.sensor.record_reference) self.pb_flatten = QPushButton('&Flatten') self.pb_flatten.clicked.connect(self.flatten) self.pb_quit = QPushButton('&Quit') self.pb_quit.clicked.connect(self.quit) poke_layout = QHBoxLayout() poke_layout.addWidget(QLabel('Modes:')) self.modes_spinbox = QSpinBox() n_actuators = int(np.sum(self.loop.mirror.mirror_mask)) self.modes_spinbox.setMaximum(n_actuators) self.modes_spinbox.setMinimum(0) self.modes_spinbox.valueChanged.connect(self.loop.set_n_modes) self.modes_spinbox.setValue(self.loop.get_n_modes()) poke_layout.addWidget(self.modes_spinbox) self.pb_invert = QPushButton('Invert') self.pb_invert.clicked.connect(self.loop.invert) poke_layout.addWidget(self.pb_invert) bg_layout = QHBoxLayout() bg_layout.addWidget(QLabel('Background correction:')) self.bg_spinbox = QSpinBox() self.bg_spinbox.setValue(self.loop.sensor.background_correction) self.bg_spinbox.setMaximum(500) self.bg_spinbox.setMinimum(-500) self.bg_spinbox.valueChanged.connect( self.loop.sensor.set_background_correction) bg_layout.addWidget(self.bg_spinbox) f_layout = QHBoxLayout() f_layout.addWidget(QLabel('Defocus:')) self.f_spinbox = QDoubleSpinBox() self.f_spinbox.setValue(0.0) self.f_spinbox.setSingleStep(0.01) self.f_spinbox.setMaximum(1.0) self.f_spinbox.setMinimum(-1.0) self.f_spinbox.valueChanged.connect(self.loop.sensor.set_defocus) f_layout.addWidget(self.f_spinbox) self.lbl_error = QLabel() self.lbl_error.setAlignment(Qt.AlignRight) self.lbl_tip = QLabel() self.lbl_tip.setAlignment(Qt.AlignRight) self.lbl_tilt = QLabel() self.lbl_tilt.setAlignment(Qt.AlignRight) self.lbl_cond = QLabel() self.lbl_cond.setAlignment(Qt.AlignRight) self.lbl_sensor_fps = QLabel() self.lbl_sensor_fps.setAlignment(Qt.AlignRight) self.lbl_mirror_fps = QLabel() self.lbl_mirror_fps.setAlignment(Qt.AlignRight) self.lbl_ui_fps = QLabel() self.lbl_ui_fps.setAlignment(Qt.AlignRight) column_2.addWidget(self.pb_flatten) column_2.addWidget(self.cb_closed) column_2.addLayout(f_layout) column_2.addLayout(bg_layout) column_2.addLayout(poke_layout) column_2.addWidget(self.cb_draw_boxes) column_2.addWidget(self.cb_draw_lines) column_2.addWidget(self.pb_quit) column_2.addWidget(self.lbl_error) column_2.addWidget(self.lbl_tip) column_2.addWidget(self.lbl_tilt) column_2.addWidget(self.lbl_cond) column_2.addWidget(self.lbl_sensor_fps) column_2.addWidget(self.lbl_mirror_fps) column_2.addWidget(self.lbl_ui_fps) column_2.addWidget(self.pb_poke) column_2.addWidget(self.pb_record_reference) column_2.addWidget(self.cb_logging) layout.addLayout(column_2, 0, 6, 3, 1) self.setLayout(layout) def quit(self): self.loop.sensor.cam.close() sys.exit() def flatten(self): self.mirror_mutex.lock() self.loop.mirror.flatten() self.mirror_mutex.unlock() @pyqtSlot() def update(self): self.mirror_mutex.lock() self.sensor_mutex.lock() sensor = self.loop.sensor mirror = self.loop.mirror temp = [(x, xerr, y, yerr) for x, xerr, y, yerr in zip( sensor.search_boxes.x, sensor.x_centroids, sensor.search_boxes.y, sensor.y_centroids)] self.overlay_slopes.coords = [] for x, xerr, y, yerr in temp: dx = (xerr - x) * ccfg.slope_line_magnification dy = (yerr - y) * ccfg.slope_line_magnification x2 = x + dx y2 = y + dy self.overlay_slopes.coords.append((x, x2, y, y2)) self.id_spots.show(sensor.image) mirror_map = np.zeros(mirror.mirror_mask.shape) mirror_map[np.where(mirror.mirror_mask)] = mirror.get_command()[:] self.id_mirror.show(mirror_map) self.id_wavefront.show(sensor.wavefront) self.id_zoomed_spots.show(self.id_spots.zoomed()) self.lbl_error.setText(ccfg.wavefront_error_fmt % (sensor.error * 1e9)) self.lbl_tip.setText(ccfg.tip_fmt % (sensor.tip * 1000000)) self.lbl_tilt.setText(ccfg.tilt_fmt % (sensor.tilt * 1000000)) self.lbl_cond.setText(ccfg.cond_fmt % (self.loop.get_condition_number())) self.lbl_sensor_fps.setText(ccfg.sensor_fps_fmt % sensor.frame_timer.fps) self.lbl_mirror_fps.setText(ccfg.mirror_fps_fmt % mirror.frame_timer.fps) self.lbl_ui_fps.setText(ccfg.ui_fps_fmt % self.frame_timer.fps) self.mirror_mutex.unlock() self.sensor_mutex.unlock() def select_single_spot(self, click): x = click.x() * self.downsample y = click.y() * self.downsample self.single_spot_index = self.loop.sensor.search_boxes.get_lenslet_index( x, y) def paintEvent(self, event): self.frame_timer.tick()