Exemple #1
0
 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
Exemple #2
0
 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()
Exemple #3
0
    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
Exemple #4
0
 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()
Exemple #5
0
    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
Exemple #6
0
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)
Exemple #7
0
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()
Exemple #8
0
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)
Exemple #9
0
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)
Exemple #10
0
    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
Exemple #11
0
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.'
Exemple #12
0
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
Exemple #13
0
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()
Exemple #14
0
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
Exemple #15
0
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()