Example #1
0
 def initialize_image_data_pipeline(self):
     self.idp = Image_Data_Pipeline(
         num_buffers=15,
         buffer_shape=(1, 2042, 2060),  ##256 or 2048, 2060
         camera_high_priority=True)
     desired_exposure_time_microseconds = 60000
     """
     Rep rate of camera is dictated by rep rate of the wheel. Exposure
     time of the camera has to be 20 microseconds shorter than the
     rep time of the camera or else the software can't keep up.
     """
     self.idp.camera.commands.send((
         'apply_settings',
         {
             'trigger': 'external trigger/software exposure control',
             'region_of_interest': (-1, 4, 10000, 2044),  ##897, 1152
             'exposure_time_microseconds':
             desired_exposure_time_microseconds
         }))
     camera_response = self.idp.camera.commands.recv()
     print "Camera response:", camera_response
     (
         trigger_mode,
         self.exposure_time_microseconds,
         self.region_of_interest,
     ) = camera_response
     self.idp.camera.commands.send(('set_timeout', {'timeout': 1}))
     print "Camera timeout:", self.idp.camera.commands.recv(), "s"
     self.idp.camera.commands.send(('set_preframes', {'preframes': 0}))
     print "Camera preframes:", self.idp.camera.commands.recv()
     self.idp.set_display_intensity_scaling(scaling='autoscale')
     print self.idp.get_display_intensity_scaling()
     self.saved_files = 0
Example #2
0
 def initialize_image_data_pipeline(self):
     self.idp = Image_Data_Pipeline(
         num_buffers=15,
         buffer_shape=(1, 2042, 2060), ##256 or 2048, 2060
         camera_high_priority=True)
     desired_exposure_time_microseconds = 60000
     """
     Rep rate of camera is dictated by rep rate of the wheel. Exposure
     time of the camera has to be 20 microseconds shorter than the
     rep time of the camera or else the software can't keep up.
     """
     self.idp.camera.commands.send(
         ('apply_settings',
          {'trigger': 'external trigger/software exposure control',
           'region_of_interest': (-1, 4, 10000, 2044),##897, 1152
           'exposure_time_microseconds': desired_exposure_time_microseconds}
          ))
     camera_response = self.idp.camera.commands.recv()
     print "Camera response:", camera_response
     (trigger_mode,
      self.exposure_time_microseconds,
      self.region_of_interest,
      ) = camera_response
     self.idp.camera.commands.send(('set_timeout', {'timeout': 1}))
     print "Camera timeout:", self.idp.camera.commands.recv(), "s"
     self.idp.camera.commands.send(('set_preframes', {'preframes': 0}))
     print "Camera preframes:", self.idp.camera.commands.recv()
     self.idp.set_display_intensity_scaling(scaling='autoscale')
     print self.idp.get_display_intensity_scaling()
     self.saved_files = 0
Example #3
0
class ParentFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(
            self, parent, id, title, wx.DefaultPosition, (500, 300))
        self.panel = wx.Panel(self, -1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_objective = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_excitation_galvo = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_illumination = wx.BoxSizer(wx.HORIZONTAL)

        self.floatspin_objective = FS.FloatSpin(
            self.panel, -1, pos=(0, 0), min_val=0, max_val=10,
            increment=0.1, value=5, agwStyle=FS.FS_CENTRE)
        self.floatspin_objective.SetFormat("%f")
        self.floatspin_objective.SetDigits(2)

        self.floatspin_excitation_galvo = FS.FloatSpin(
            self.panel, -1, pos=(0, 0), min_val=-9.99, max_val=9.99,
            increment=0.1, value=0, agwStyle=FS.FS_CENTRE)
        self.floatspin_excitation_galvo.SetFormat("%f")
        self.floatspin_excitation_galvo.SetDigits(2)

        self.floatspin_length = FS.FloatSpin(
            self.panel, -1, pos=(0, 0), min_val=0, max_val=250,
            increment=1, value=1, agwStyle=FS.FS_CENTRE)
        self.floatspin_length.SetFormat("%f")
        self.floatspin_length.SetDigits(1)

        self.floatspin_offset = FS.FloatSpin(
            self.panel, -1, pos=(0, 0), min_val=-250, max_val=250,
            increment=1, value=0, agwStyle=FS.FS_CENTRE)
        self.floatspin_offset.SetFormat("%f")
        self.floatspin_offset.SetDigits(1)

        btnAdjust_Objective = wx.Button(self.panel, 7, 'Adjust Objective')
        btnAdjust_Excitation_Galvo = wx.Button(
            self.panel, 6, 'Adjust Excitation Galvo')
        st1 = wx.StaticText(self.panel, label="Length:")
        st2 = wx.StaticText(self.panel, label="Offset:")
        btnAdjust_Illumination = wx.Button(
            self.panel, 5, 'Adjust Illumination')
        self.illumination_length = 1
        self.illumination_offset = 0
        btnSnap = wx.Button(self.panel, 8, 'Snap')
        btnClose = wx.Button(self.panel, 9, 'Close')
        btnCharacterize = wx.Button(self.panel, 10, 'Characterize')
        btnVolume = wx.Button(self.panel, 11, 'Volume')

        self.Bind(wx.EVT_CLOSE, self.OnClose)
        btnAdjust_Objective.Bind(wx.EVT_BUTTON, self.on_adjust_objective)
        btnAdjust_Illumination.Bind(wx.EVT_BUTTON, self.on_adjust_illumination)
        btnAdjust_Excitation_Galvo.Bind(wx.EVT_BUTTON, self.on_adjust_excitation_galvo)
        btnSnap.Bind(wx.EVT_BUTTON, self.on_snap)
        btnCharacterize.Bind(wx.EVT_BUTTON, self.on_characterize)
        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)


        vbox.AddSpacer(25)
        hbox_adjust_illumination.Add(st1, 1, 25)
        hbox_adjust_illumination.Add(self.floatspin_length, 1, 25)
        hbox_adjust_illumination.Add(st2, 1, 25)
        hbox_adjust_illumination.Add(self.floatspin_offset, 1, 25)
        hbox_adjust_illumination.AddSpacer(15)
        hbox_adjust_illumination.Add(btnAdjust_Illumination, 1, 25)
        vbox.Add(hbox_adjust_illumination, 0, wx.ALIGN_CENTRE, 10)

        vbox.AddSpacer(15)
        hbox_adjust_objective.Add(self.floatspin_objective, 1, 25)
        hbox_adjust_objective.AddSpacer(15)
        hbox_adjust_objective.Add(btnAdjust_Objective, 1, 25)
        vbox.Add(hbox_adjust_objective, 0, wx.ALIGN_CENTRE, 10)
        vbox.AddSpacer(15)
        hbox_adjust_excitation_galvo.Add(self.floatspin_excitation_galvo, 1, 25)
        hbox_adjust_excitation_galvo.AddSpacer(15)
        hbox_adjust_excitation_galvo.Add(btnAdjust_Excitation_Galvo, 1, 25)
        vbox.Add(hbox_adjust_excitation_galvo, 0, wx.ALIGN_CENTRE, 10)
        vbox.AddSpacer(15)
        hbox.Add(btnVolume, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnSnap, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnCharacterize, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnClose, 1, 10)
        vbox.Add(hbox, 0, wx.ALIGN_CENTRE | wx.ALL, 10)
        self.panel.SetSizer(vbox)

        self.CreateStatusBar() 

        filemenu= wx.Menu()
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About",
                                    " Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
        imagemenu= wx.Menu()
        menuScale = imagemenu.Append(
            wx.ID_ANY, "&Scale", " Adjust the scaling of the image")

        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File")
        menuBar.Append(imagemenu, "&Image")
        self.SetMenuBar(menuBar)
        
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnClose, menuExit)
        self.Bind(wx.EVT_MENU, self.OnScale, menuScale)
        
        logger = mp.log_to_stderr()
        logger.setLevel(logging.INFO)

        self.initialize_image_data_pipeline()
        self.initialize_daq()
        self.initialize_snap()
        self.initialize_characterize()

    def OnAbout(self, e):
        dlg = wx.MessageDialog( self, "The fastest motherfuckers in the West",
                                "About Microscope Control", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def OnScale(self, e):
        try:
            """
            Does the scale frame already exist?
            """
            getattr(self.scale_frame, 'thisown')
        except (NameError, AttributeError):
            """
            The scale frame doesn't exist yet. Make it!
            """
            self.scale_frame = IntensityScaleFrame(self)
        self.scale_frame.Show(True)
        self.scale_frame.Iconize(False)
        self.scale_frame.Raise()

    def on_adjust_illumination(self, event):
        change_length_value = self.floatspin_length.GetValue()
        change_offset_value = self.floatspin_offset.GetValue()
        if change_length_value >= 0 and change_length_value <250:
            self.illumination_length = change_length_value
            self.illumination_offset = change_offset_value
            print "offset", change_offset_value
            self.initialize_snap()

    def on_adjust_objective(self, event):
        change_voltage_value = self.floatspin_objective.GetValue()
        change_voltage = np.zeros((self.daq.write_length), dtype=np.float64)
        change_voltage[:] = change_voltage_value
        if change_voltage[0] > 0 and change_voltage[0] <10:
            self.daq.set_default_voltage(change_voltage, 3)
            self.initialize_snap()
            self.initialize_characterize()

    def on_adjust_excitation_galvo(self, event):
        change_voltage_value = self.floatspin_excitation_galvo.GetValue()
        change_voltage = np.zeros((self.daq.write_length), dtype=np.float64)
        change_voltage[:] = change_voltage_value
        if change_voltage[0] > -10 and change_voltage[0] <10:
            self.daq.set_default_voltage(change_voltage, 4)
            self.initialize_snap()
            self.initialize_characterize()

    def on_snap(self, event):
        print self.idp.check_children() #Eventually add this to a timer
        self.idp.collect_data_buffers()
        if len(self.idp.idle_data_buffers) > 0:
            self.idp.load_data_buffers(
                1, ) ##[{'outfile':'image_%06i.tif'%self.saved_files}])
            self.daq.play_voltage('snap')
            print "OH SNAP!"
            self.saved_files += 1
        else:
            print "Not enough buffers available"
##        if self.scale_frame_open: #Eventually shift responsiblilty to a timer
##            display_scaling = self.idp.get_display_intensity_scaling()
##            self.child.min.SetValue(
##                str(display_scaling[1]))
##            self.child.max.SetValue(
##                str(display_scaling[2]))
        
    def on_characterize(self, event):
        """
        Send a buffer (save to file)
        Play the 'characterize' waveform
        Roll one channel of the 'characterize' signal
        Repeat until the whooooole bottle
        """
        data_dir = os.path.join(os.getcwd(), 'characterization')
        if not os.path.exists(data_dir):
            os.mkdir(data_dir)
        saved_files = 0
        roll_pixels = 2
        characterize_pixels = 6000
        steps_per_rep = characterize_pixels // roll_pixels
        num_reps = 1
        for r in range(num_reps):
            for step in range(steps_per_rep):
                status = self.idp.check_children()
                for k in sorted(status.keys()):
                    if not status[k]:
                        print '*\n'*20
                        print k, status[k]
                        print '*\n'*20
                while len(self.idp.idle_data_buffers) < 1:
                    self.idp.collect_data_buffers()
                self.idp.load_data_buffers(
                    1, [{'outfile': os.path.join(
                        data_dir, 'image_%06i.tif'%saved_files)}])
                self.daq.play_voltage('characterize')
                print "OH CHARACTERIZE!"
                saved_files += 1
                self.daq.roll_voltage(voltage_name='characterize',
                                      channel=n2c['emission_scan'],
                                      roll_pixels=-roll_pixels)
            """
            Clean up after ourselves
            """
            self.daq.roll_voltage(voltage_name='characterize',
                              channel=n2c['emission_scan'],
                              roll_pixels=steps_per_rep * roll_pixels)
        return None
   
    def OnClose(self, event):
        self.daq.close()
        self.idp.close()
        print "DAQ Closing"
        self.Destroy()

    def initialize_characterize(self):
        """
        Create the murrrcle signal up here. All we care about is how
        many DAQ points long it is.
        """
##        impulse_strength = 1
##        num_periods = 4
##        daq_timepoints_per_period = 1500
##        amplitude_volts = 0.1
##        murrcle_signal = np.sin(np.linspace(
##            0, 2*np.pi*num_periods, num_periods * daq_timepoints_per_period))
##        murrcle_signal[:daq_timepoints_per_period] = 0
##        murrcle_signal[-daq_timepoints_per_period:] = 0
        murrcle_signal = np.zeros(20000, dtype=np.float64)
        default_murrcle = self.daq.default_voltages[-1, n2c['emission_scan']]
        murrcle_signal[:] = default_murrcle
##        murrcle_signal[1000:1152] = 0.05
##        murrcle_signal[1152:-1000] = 0.1
##        murrcle_signal[200:204] = default_murrcle + impulse_strength


        """
        Read in an arbitrary signal from a tif file
        """
        loaded_signal = tif_to_array(
            filename='input_voltage_to_mirror_05.tif').astype(np.float64)
##        loaded_signal += default_murrcle
##        loaded_signal *= 1.75

##
##        loaded_signal[loaded_signal < 0] *= 0.45
##
##        print "Pre Loaded signal min, max:",
##        print loaded_signal.min(), loaded_signal.max()    
##     
        print "Loaded signal min, max:",
        print loaded_signal.min(), loaded_signal.max()
        print
        """
        Put this optimzed waveform into the larger array
        """
        murrcle_signal[:loaded_signal.size] = loaded_signal[:, 0, 0]
        print "Loaded signal size", loaded_signal.size
##        """
##        Smoothly drop the voltage to default; hopefully this reduces ringing.
##        """
##        murrcle_signal[loaded_signal.size:2*(loaded_signal.size)
##                       ] = np.linspace(
##                           loaded_signal[-1, 0, 0],
##                           default_murrcle,
##                           loaded_signal.size)
##        print "last value for signal" , loaded_signal[-1, 0 , 0]
##        print murrcle_signal[loaded_signal.size * 1.5] #Remove this soon
##        
        self.characterization_points = murrcle_signal.size

        delay_points = max(#Figure out the limiting factor
            murrcle_signal.size,
            1e-6 * self.get_camera_rolling_time_microseconds() * self.daq.rate)
        start_point_laser = (#Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[0] +
            self.daq.write_length * int(np.ceil(delay_points * 1.0 /
                                                self.daq.write_length)))
        assert (self.exposure_time_microseconds * 1e6 >=
                start_point_laser * 1.0 / self.daq.rate)
        voltage = np.zeros(((start_point_laser +  murrcle_signal.shape[0]),
                            self.daq.num_mutable_channels),
                           dtype=np.float64)
        
        """
        Trigger the camera
        """
        voltage[:self.daq.write_length//4, n2c['camera']] = 3
        """
        Trigger the laser
        """
        voltage[start_point_laser, n2c['488']] = 10
        voltage[start_point_laser, n2c['blanking']] = 10
        """
        Wiggle the murrrrcle
        """
        print "murrcle_Signal[0]", murrcle_signal[0]
        print "murrcle_Signal[-1]", murrcle_signal[-1]
        print "default murrcle", default_murrcle
##        assert murrcle_signal[0] == default_murrcle
        assert murrcle_signal[-1] == default_murrcle
        voltage[:, n2c['emission_scan']] = default_murrcle
        voltage[-murrcle_signal.size:, n2c['emission_scan']] = murrcle_signal
        print "Impulse starts at DAQ pixel:",
        print voltage.size - murrcle_signal.size + 250
        
        """
        Objective stays at what it was
        """
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        voltage[:, n2c['objective']] = objective_voltage
        """
        Excitation Galvo stays at what it was
        """
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        voltage[:, n2c['excitation_scan']] = galvo_voltage

        self.daq.send_voltage(voltage, 'characterize')
        
        return None
    
    def initialize_snap(self):
        
        ##Assume full-frame camera operation, 10 ms roll time
        roll_time = int(np.ceil(self.daq.rate * 0.01))
####        oh_snap_voltages = np.zeros(
####            (self.daq.write_length  + roll_time, self.daq.num_mutable_channels),
####            dtype=np.float64)

        oh_snap_voltages = np.zeros(
            (30000, self.daq.num_mutable_channels),
            dtype=np.float64)

        ##objective stays at what it was
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        oh_snap_voltages[:, n2c['objective']] = objective_voltage

        ##excitation galvo stays at what it was
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        oh_snap_voltages[:, n2c['excitation_scan']] = galvo_voltage

        ##murrcle stays at what it was
        murrcle_voltage = self.daq.default_voltages[-1, n2c['emission_scan']]
        oh_snap_voltages[:, n2c['emission_scan']] = murrcle_voltage
        
        #Camera triggers at the start of a write
        oh_snap_voltages[:self.daq.write_length//4, n2c['camera']] = 3
        
        #AOTF fires on one perpendicular facet
        
        start_point_laser = (#Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[6] + self.illumination_offset+
            self.daq.write_length * int(roll_time * 1.0 /
                                        self.daq.write_length))
        oh_snap_voltages[start_point_laser:start_point_laser+self.illumination_length, n2c['488']] = 10
        oh_snap_voltages[start_point_laser:start_point_laser+self.illumination_length, n2c['blanking']] = 10

##        oh_snap_voltages[start_point_laser, n2c['blanking']] = 10
        time.sleep(1)

        """
        let's test the objective impulse response
        """
##        marker = start_point_laser
##        scan = np.linspace(5, 6, 5000)        
##        oh_snap_voltages[marker:(marker+5000), n2c['objective']] = scan
##        marker += 5000
##        oh_snap_voltages[marker:(
##            marker+2500), n2c['objective']] = 6
##        marker += 2500
##        oh_snap_voltages[marker:(
##            marker+5000), n2c['objective']] = np.linspace(6,5,5000)
##        marker += 5000        
        
##        loaded_signal = tif_to_array(
##            filename='input_voltage_objective_00.tif').astype(
##                np.float64).ravel()
##        loaded_signal += objective_voltage
##        oh_snap_voltages[:22500, n2c['objective']] = loaded_signal[:]
##        print "min", oh_snap_voltages[:, n2c['objective']].min()
##        print "max", oh_snap_voltages[:, n2c['objective']].max()
##
##        loaded_desired_signal = tif_to_array(
##            filename='desired_result_objective.tif').astype(
##                np.float64).ravel()
##        loaded_desired_signal += objective_voltage
##        loaded_desired_signal[0] += 1
##        oh_snap_voltages[:, n2c['561']] = objective_voltage
##        oh_snap_voltages[:22500, n2c['561']] = loaded_desired_signal[:]
        
        print oh_snap_voltages.shape
        self.daq.send_voltage(oh_snap_voltages, 'snap')
        return None

    def initialize_volume(self):
        
        volume_voltages = np.zeros((30000, self.daq.num_mutable_channels),
            dtype=np.float64)

        ##objective starts where it was
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        volume_voltages[:, n2c['objective']] = objective_voltage

        ##objective does loaded scan
        loaded_signal = tif_to_array(
            filename='input_voltage_objective_01.tif').astype(
                np.float64).ravel()
        loaded_signal += objective_voltage
        volume_voltages[:22500, n2c['objective']] = loaded_signal[:]
        print "min", oh_snap_voltages[:, n2c['objective']].min()
        print "max", oh_snap_voltages[:, n2c['objective']].max()

        ##excitation galvo starts where it was
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        volume_voltages[:, n2c['excitation_scan']] = galvo_voltage

        ##excitation galvo scans illumination
        galvo_voltage[5000:10000] = np.linspace(
            galvo_voltage, galvo_voltage + 0.2, 5000)
        galvo_voltage[10000:12500] = galvo_voltage + 0.2
        galvo_voltage[12500:17500] = np.linspace(
            galvo_voltage + 0.2, galvo_voltage, 5000)

        ##murrcle stays at what it was
        murrcle_voltage = self.daq.default_voltages[-1, n2c['emission_scan']]
        oh_snap_voltages[:, n2c['emission_scan']] = murrcle_voltage
        
        #Camera triggers at the start of a write
        oh_snap_voltages[:self.daq.write_length//4, n2c['camera']] = 3
        
        #AOTF fires on one perpendicular facet
        
        start_point_laser = (#Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[6] + self.illumination_offset+
            self.daq.write_length * int(roll_time * 1.0 /
                                        self.daq.write_length))
        oh_snap_voltages[start_point_laser:start_point_laser+self.illumination_length, n2c['488']] = 10
        oh_snap_voltages[start_point_laser:start_point_laser+self.illumination_length, n2c['blanking']] = 10

##        oh_snap_voltages[start_point_laser, n2c['blanking']] = 10
        time.sleep(1)

        """
        let's test the objective impulse response
        """
##        marker = start_point_laser
##        scan = np.linspace(5, 6, 5000)        
##        oh_snap_voltages[marker:(marker+5000), n2c['objective']] = scan
##        marker += 5000
##        oh_snap_voltages[marker:(
##            marker+2500), n2c['objective']] = 6
##        marker += 2500
##        oh_snap_voltages[marker:(
##            marker+5000), n2c['objective']] = np.linspace(6,5,5000)
##        marker += 5000        
        
##        loaded_signal = tif_to_array(
##            filename='input_voltage_objective_00.tif').astype(
##                np.float64).ravel()
##        loaded_signal += objective_voltage
##        oh_snap_voltages[:22500, n2c['objective']] = loaded_signal[:]
##        print "min", oh_snap_voltages[:, n2c['objective']].min()
##        print "max", oh_snap_voltages[:, n2c['objective']].max()
##
##        loaded_desired_signal = tif_to_array(
##            filename='desired_result_objective.tif').astype(
##                np.float64).ravel()
##        loaded_desired_signal += objective_voltage
##        loaded_desired_signal[0] += 1
##        oh_snap_voltages[:, n2c['561']] = objective_voltage
##        oh_snap_voltages[:22500, n2c['561']] = loaded_desired_signal[:]
        
        print oh_snap_voltages.shape
        self.daq.send_voltage(oh_snap_voltages, 'snap')
        return None

    def initialize_image_data_pipeline(self):
        self.idp = Image_Data_Pipeline(
            num_buffers=15,
            buffer_shape=(1, 2042, 2060), ##256 or 2048, 2060
            camera_high_priority=True)
        desired_exposure_time_microseconds = 60000
        """
        Rep rate of camera is dictated by rep rate of the wheel. Exposure
        time of the camera has to be 20 microseconds shorter than the
        rep time of the camera or else the software can't keep up.
        """
        self.idp.camera.commands.send(
            ('apply_settings',
             {'trigger': 'external trigger/software exposure control',
              'region_of_interest': (-1, 4, 10000, 2044),##897, 1152
              'exposure_time_microseconds': desired_exposure_time_microseconds}
             ))
        camera_response = self.idp.camera.commands.recv()
        print "Camera response:", camera_response
        (trigger_mode,
         self.exposure_time_microseconds,
         self.region_of_interest,
         ) = camera_response
        self.idp.camera.commands.send(('set_timeout', {'timeout': 1}))
        print "Camera timeout:", self.idp.camera.commands.recv(), "s"
        self.idp.camera.commands.send(('set_preframes', {'preframes': 0}))
        print "Camera preframes:", self.idp.camera.commands.recv()
        self.idp.set_display_intensity_scaling(scaling='autoscale')
        print self.idp.get_display_intensity_scaling()
        self.saved_files = 0

    def get_camera_rolling_time_microseconds(self):
        """
        The pco edge 4.2 allows an asymmetric region-of-interest, but
        does this simply by acquiring a symmetric region-of-interest
        and cropping the data, so the rolling time is still the same
        as if you'd used a symmetric region of interest.
        """
        num_lines = max(2*self.region_of_interest[3] - 2048,
                        2048 - 2*(self.region_of_interest[1] - 1))
        seconds_per_line = 0.01007 * 1.0 / 2048. #10 ms for the full field
        return int(num_lines * seconds_per_line * 1e6)

    def initialize_daq(self):
        rotations_per_second = 200
        facets_per_rotation = 10
        points_per_second = 500000
        num_channels = 8

        triggers_per_rotation = 2
        triggers_per_second = triggers_per_rotation * rotations_per_second
        points_per_trigger = points_per_second * (1.0 / triggers_per_second)
        facets_per_second = rotations_per_second * facets_per_rotation
        points_per_facet = points_per_second * (1.0 / facets_per_second)
        print
        print "Desired points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Desired points per facet:", points_per_facet
        points_per_facet = int(round(points_per_facet))
        points_per_trigger = int(points_per_facet * #Careful! (Odd-facet case)
                                 facets_per_rotation * 1.0 /
                                 triggers_per_rotation)
        print "Actual points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Actual points per facet:", points_per_facet
        print
        print "Desired rotations per second:", rotations_per_second
        rotations_per_second = (
            points_per_second *
            (1.0 / (points_per_trigger * triggers_per_rotation)))
        print "Actual rotations per second:", rotations_per_second
        points_per_rotation = points_per_trigger * triggers_per_rotation
        print "Write length:", points_per_rotation
        print
        
        wheel_signal = np.zeros(points_per_rotation, dtype=np.float64)
        for i in range(triggers_per_rotation):
            start = i * points_per_trigger
            stop = start + points_per_trigger // 2
            wheel_signal[start:stop] = 6
        
        default_voltage = np.zeros(
            (points_per_rotation, num_channels), dtype=np.float64)

        default_voltage[:, n2c['488']] = 0
        default_voltage[:, n2c['561']] = 0 ##5 ####CHANGE ME BACK
        default_voltage[:, n2c['blanking']] = 0
        default_voltage[:, n2c['objective']] = 5
        default_voltage[:, n2c['excitation_scan']] = 0
        default_voltage[:, n2c['emission_scan']] = 0 #-4.45
        default_voltage[:, n2c['camera']] = 0
        default_voltage[:, n2c['wheel']] = wheel_signal

        self.daq = DAQ_with_queue(num_immutable_channels=1,
                                  default_voltage=default_voltage,
                                  rate=points_per_second,
                                  write_length=points_per_rotation,
                                  high_priority=True)
        """
        Positive lag raises first wheel reflection, lag=65 for 150 rps
        Empirically determined!
        """
        perpendicular_lag = int(np.ceil((10404.0/rotations_per_second) - 10.0))
        self.daq.perpendicular_facet_times = []
        for facet in range(facets_per_rotation):
            self.daq.perpendicular_facet_times.append(
                facet * points_per_facet + perpendicular_lag)

        ##FIXME: Put this shit into an "alignment" panel
        """
##        want continuous laser firing? try these lines.
##        """
####        laser_signal = np.zeros((points_per_rotation), dtype=np.float64)
######        camera_signal = np.zeros((points_per_rotation), dtype=np.float64)
####        laser_duration = 5
####        delay = 0
######        for i in range(len(self.daq.perpendicular_facet_times)):
######            print "flash"
####        place = self.daq.perpendicular_facet_times[0] + delay ##i
####        laser_signal[place:place+laser_duration] = 10##7.5
######            camera_signal[place:place+50] = 3##7.5
####        print "i =", i
####        print laser_signal[self.daq.perpendicular_facet_times[1]]
####        print "changing defaults"
####        self.daq.set_default_voltage(laser_signal, n2c['488'])
####        self.daq.set_default_voltage(laser_signal, n2c['blanking'])
######        self.daq.set_default_voltage(camera_signal, n2c['camera'])
####
        self.seconds_per_write = self.daq.write_length * 1.0 / self.daq.rate
        print "Seconds per write:", self.seconds_per_write
Example #4
0
class ParentFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
                          (500, 300))
        self.panel = wx.Panel(self, -1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_objective = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_excitation_galvo = wx.BoxSizer(wx.HORIZONTAL)
        hbox_adjust_illumination = wx.BoxSizer(wx.HORIZONTAL)

        self.floatspin_objective = FS.FloatSpin(self.panel,
                                                -1,
                                                pos=(0, 0),
                                                min_val=0,
                                                max_val=10,
                                                increment=0.1,
                                                value=5,
                                                agwStyle=FS.FS_CENTRE)
        self.floatspin_objective.SetFormat("%f")
        self.floatspin_objective.SetDigits(2)

        self.floatspin_excitation_galvo = FS.FloatSpin(self.panel,
                                                       -1,
                                                       pos=(0, 0),
                                                       min_val=-9.99,
                                                       max_val=9.99,
                                                       increment=0.1,
                                                       value=0,
                                                       agwStyle=FS.FS_CENTRE)
        self.floatspin_excitation_galvo.SetFormat("%f")
        self.floatspin_excitation_galvo.SetDigits(2)

        self.floatspin_length = FS.FloatSpin(self.panel,
                                             -1,
                                             pos=(0, 0),
                                             min_val=0,
                                             max_val=250,
                                             increment=1,
                                             value=1,
                                             agwStyle=FS.FS_CENTRE)
        self.floatspin_length.SetFormat("%f")
        self.floatspin_length.SetDigits(1)

        self.floatspin_offset = FS.FloatSpin(self.panel,
                                             -1,
                                             pos=(0, 0),
                                             min_val=-250,
                                             max_val=250,
                                             increment=1,
                                             value=0,
                                             agwStyle=FS.FS_CENTRE)
        self.floatspin_offset.SetFormat("%f")
        self.floatspin_offset.SetDigits(1)

        btnAdjust_Objective = wx.Button(self.panel, 7, 'Adjust Objective')
        btnAdjust_Excitation_Galvo = wx.Button(self.panel, 6,
                                               'Adjust Excitation Galvo')
        st1 = wx.StaticText(self.panel, label="Length:")
        st2 = wx.StaticText(self.panel, label="Offset:")
        btnAdjust_Illumination = wx.Button(self.panel, 5,
                                           'Adjust Illumination')
        self.illumination_length = 1
        self.illumination_offset = 0
        btnSnap = wx.Button(self.panel, 8, 'Snap')
        btnClose = wx.Button(self.panel, 9, 'Close')
        btnCharacterize = wx.Button(self.panel, 10, 'Characterize')
        btnVolume = wx.Button(self.panel, 11, 'Volume')

        self.Bind(wx.EVT_CLOSE, self.OnClose)
        btnAdjust_Objective.Bind(wx.EVT_BUTTON, self.on_adjust_objective)
        btnAdjust_Illumination.Bind(wx.EVT_BUTTON, self.on_adjust_illumination)
        btnAdjust_Excitation_Galvo.Bind(wx.EVT_BUTTON,
                                        self.on_adjust_excitation_galvo)
        btnSnap.Bind(wx.EVT_BUTTON, self.on_snap)
        btnCharacterize.Bind(wx.EVT_BUTTON, self.on_characterize)
        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)

        vbox.AddSpacer(25)
        hbox_adjust_illumination.Add(st1, 1, 25)
        hbox_adjust_illumination.Add(self.floatspin_length, 1, 25)
        hbox_adjust_illumination.Add(st2, 1, 25)
        hbox_adjust_illumination.Add(self.floatspin_offset, 1, 25)
        hbox_adjust_illumination.AddSpacer(15)
        hbox_adjust_illumination.Add(btnAdjust_Illumination, 1, 25)
        vbox.Add(hbox_adjust_illumination, 0, wx.ALIGN_CENTRE, 10)

        vbox.AddSpacer(15)
        hbox_adjust_objective.Add(self.floatspin_objective, 1, 25)
        hbox_adjust_objective.AddSpacer(15)
        hbox_adjust_objective.Add(btnAdjust_Objective, 1, 25)
        vbox.Add(hbox_adjust_objective, 0, wx.ALIGN_CENTRE, 10)
        vbox.AddSpacer(15)
        hbox_adjust_excitation_galvo.Add(self.floatspin_excitation_galvo, 1,
                                         25)
        hbox_adjust_excitation_galvo.AddSpacer(15)
        hbox_adjust_excitation_galvo.Add(btnAdjust_Excitation_Galvo, 1, 25)
        vbox.Add(hbox_adjust_excitation_galvo, 0, wx.ALIGN_CENTRE, 10)
        vbox.AddSpacer(15)
        hbox.Add(btnVolume, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnSnap, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnCharacterize, 1, 10)
        hbox.AddSpacer(10)
        hbox.Add(btnClose, 1, 10)
        vbox.Add(hbox, 0, wx.ALIGN_CENTRE | wx.ALL, 10)
        self.panel.SetSizer(vbox)

        self.CreateStatusBar()

        filemenu = wx.Menu()
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About",
                                    " Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT, "E&xit",
                                   " Terminate the program")
        imagemenu = wx.Menu()
        menuScale = imagemenu.Append(wx.ID_ANY, "&Scale",
                                     " Adjust the scaling of the image")

        menuBar = wx.MenuBar()
        menuBar.Append(filemenu, "&File")
        menuBar.Append(imagemenu, "&Image")
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnClose, menuExit)
        self.Bind(wx.EVT_MENU, self.OnScale, menuScale)

        logger = mp.log_to_stderr()
        logger.setLevel(logging.INFO)

        self.initialize_image_data_pipeline()
        self.initialize_daq()
        self.initialize_snap()
        self.initialize_characterize()

    def OnAbout(self, e):
        dlg = wx.MessageDialog(self, "The fastest motherfuckers in the West",
                               "About Microscope Control", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def OnScale(self, e):
        try:
            """
            Does the scale frame already exist?
            """
            getattr(self.scale_frame, 'thisown')
        except (NameError, AttributeError):
            """
            The scale frame doesn't exist yet. Make it!
            """
            self.scale_frame = IntensityScaleFrame(self)
        self.scale_frame.Show(True)
        self.scale_frame.Iconize(False)
        self.scale_frame.Raise()

    def on_adjust_illumination(self, event):
        change_length_value = self.floatspin_length.GetValue()
        change_offset_value = self.floatspin_offset.GetValue()
        if change_length_value >= 0 and change_length_value < 250:
            self.illumination_length = change_length_value
            self.illumination_offset = change_offset_value
            print "offset", change_offset_value
            self.initialize_snap()

    def on_adjust_objective(self, event):
        change_voltage_value = self.floatspin_objective.GetValue()
        change_voltage = np.zeros((self.daq.write_length), dtype=np.float64)
        change_voltage[:] = change_voltage_value
        if change_voltage[0] > 0 and change_voltage[0] < 10:
            self.daq.set_default_voltage(change_voltage, 3)
            self.initialize_snap()
            self.initialize_characterize()

    def on_adjust_excitation_galvo(self, event):
        change_voltage_value = self.floatspin_excitation_galvo.GetValue()
        change_voltage = np.zeros((self.daq.write_length), dtype=np.float64)
        change_voltage[:] = change_voltage_value
        if change_voltage[0] > -10 and change_voltage[0] < 10:
            self.daq.set_default_voltage(change_voltage, 4)
            self.initialize_snap()
            self.initialize_characterize()

    def on_snap(self, event):
        print self.idp.check_children()  #Eventually add this to a timer
        self.idp.collect_data_buffers()
        if len(self.idp.idle_data_buffers) > 0:
            self.idp.load_data_buffers(
                1, )  ##[{'outfile':'image_%06i.tif'%self.saved_files}])
            self.daq.play_voltage('snap')
            print "OH SNAP!"
            self.saved_files += 1
        else:
            print "Not enough buffers available"


##        if self.scale_frame_open: #Eventually shift responsiblilty to a timer
##            display_scaling = self.idp.get_display_intensity_scaling()
##            self.child.min.SetValue(
##                str(display_scaling[1]))
##            self.child.max.SetValue(
##                str(display_scaling[2]))

    def on_characterize(self, event):
        """
        Send a buffer (save to file)
        Play the 'characterize' waveform
        Roll one channel of the 'characterize' signal
        Repeat until the whooooole bottle
        """
        data_dir = os.path.join(os.getcwd(), 'characterization')
        if not os.path.exists(data_dir):
            os.mkdir(data_dir)
        saved_files = 0
        roll_pixels = 2
        characterize_pixels = 6000
        steps_per_rep = characterize_pixels // roll_pixels
        num_reps = 1
        for r in range(num_reps):
            for step in range(steps_per_rep):
                status = self.idp.check_children()
                for k in sorted(status.keys()):
                    if not status[k]:
                        print '*\n' * 20
                        print k, status[k]
                        print '*\n' * 20
                while len(self.idp.idle_data_buffers) < 1:
                    self.idp.collect_data_buffers()
                self.idp.load_data_buffers(1, [{
                    'outfile':
                    os.path.join(data_dir, 'image_%06i.tif' % saved_files)
                }])
                self.daq.play_voltage('characterize')
                print "OH CHARACTERIZE!"
                saved_files += 1
                self.daq.roll_voltage(voltage_name='characterize',
                                      channel=n2c['emission_scan'],
                                      roll_pixels=-roll_pixels)
            """
            Clean up after ourselves
            """
            self.daq.roll_voltage(voltage_name='characterize',
                                  channel=n2c['emission_scan'],
                                  roll_pixels=steps_per_rep * roll_pixels)
        return None

    def OnClose(self, event):
        self.daq.close()
        self.idp.close()
        print "DAQ Closing"
        self.Destroy()

    def initialize_characterize(self):
        """
        Create the murrrcle signal up here. All we care about is how
        many DAQ points long it is.
        """
        ##        impulse_strength = 1
        ##        num_periods = 4
        ##        daq_timepoints_per_period = 1500
        ##        amplitude_volts = 0.1
        ##        murrcle_signal = np.sin(np.linspace(
        ##            0, 2*np.pi*num_periods, num_periods * daq_timepoints_per_period))
        ##        murrcle_signal[:daq_timepoints_per_period] = 0
        ##        murrcle_signal[-daq_timepoints_per_period:] = 0
        murrcle_signal = np.zeros(20000, dtype=np.float64)
        default_murrcle = self.daq.default_voltages[-1, n2c['emission_scan']]
        murrcle_signal[:] = default_murrcle
        ##        murrcle_signal[1000:1152] = 0.05
        ##        murrcle_signal[1152:-1000] = 0.1
        ##        murrcle_signal[200:204] = default_murrcle + impulse_strength
        """
        Read in an arbitrary signal from a tif file
        """
        loaded_signal = tif_to_array(
            filename='input_voltage_to_mirror_05.tif').astype(np.float64)
        ##        loaded_signal += default_murrcle
        ##        loaded_signal *= 1.75

        ##
        ##        loaded_signal[loaded_signal < 0] *= 0.45
        ##
        ##        print "Pre Loaded signal min, max:",
        ##        print loaded_signal.min(), loaded_signal.max()
        ##
        print "Loaded signal min, max:",
        print loaded_signal.min(), loaded_signal.max()
        print
        """
        Put this optimzed waveform into the larger array
        """
        murrcle_signal[:loaded_signal.size] = loaded_signal[:, 0, 0]
        print "Loaded signal size", loaded_signal.size
        ##        """
        ##        Smoothly drop the voltage to default; hopefully this reduces ringing.
        ##        """
        ##        murrcle_signal[loaded_signal.size:2*(loaded_signal.size)
        ##                       ] = np.linspace(
        ##                           loaded_signal[-1, 0, 0],
        ##                           default_murrcle,
        ##                           loaded_signal.size)
        ##        print "last value for signal" , loaded_signal[-1, 0 , 0]
        ##        print murrcle_signal[loaded_signal.size * 1.5] #Remove this soon
        ##
        self.characterization_points = murrcle_signal.size

        delay_points = max(  #Figure out the limiting factor
            murrcle_signal.size,
            1e-6 * self.get_camera_rolling_time_microseconds() * self.daq.rate)
        start_point_laser = (  #Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[0] + self.daq.write_length *
            int(np.ceil(delay_points * 1.0 / self.daq.write_length)))
        assert (self.exposure_time_microseconds * 1e6 >=
                start_point_laser * 1.0 / self.daq.rate)
        voltage = np.zeros(((start_point_laser + murrcle_signal.shape[0]),
                            self.daq.num_mutable_channels),
                           dtype=np.float64)
        """
        Trigger the camera
        """
        voltage[:self.daq.write_length // 4, n2c['camera']] = 3
        """
        Trigger the laser
        """
        voltage[start_point_laser, n2c['488']] = 10
        voltage[start_point_laser, n2c['blanking']] = 10
        """
        Wiggle the murrrrcle
        """
        print "murrcle_Signal[0]", murrcle_signal[0]
        print "murrcle_Signal[-1]", murrcle_signal[-1]
        print "default murrcle", default_murrcle
        ##        assert murrcle_signal[0] == default_murrcle
        assert murrcle_signal[-1] == default_murrcle
        voltage[:, n2c['emission_scan']] = default_murrcle
        voltage[-murrcle_signal.size:, n2c['emission_scan']] = murrcle_signal
        print "Impulse starts at DAQ pixel:",
        print voltage.size - murrcle_signal.size + 250
        """
        Objective stays at what it was
        """
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        voltage[:, n2c['objective']] = objective_voltage
        """
        Excitation Galvo stays at what it was
        """
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        voltage[:, n2c['excitation_scan']] = galvo_voltage

        self.daq.send_voltage(voltage, 'characterize')

        return None

    def initialize_snap(self):

        ##Assume full-frame camera operation, 10 ms roll time
        roll_time = int(np.ceil(self.daq.rate * 0.01))
        ####        oh_snap_voltages = np.zeros(
        ####            (self.daq.write_length  + roll_time, self.daq.num_mutable_channels),
        ####            dtype=np.float64)

        oh_snap_voltages = np.zeros((30000, self.daq.num_mutable_channels),
                                    dtype=np.float64)

        ##objective stays at what it was
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        oh_snap_voltages[:, n2c['objective']] = objective_voltage

        ##excitation galvo stays at what it was
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        oh_snap_voltages[:, n2c['excitation_scan']] = galvo_voltage

        ##murrcle stays at what it was
        murrcle_voltage = self.daq.default_voltages[-1, n2c['emission_scan']]
        oh_snap_voltages[:, n2c['emission_scan']] = murrcle_voltage

        #Camera triggers at the start of a write
        oh_snap_voltages[:self.daq.write_length // 4, n2c['camera']] = 3

        #AOTF fires on one perpendicular facet

        start_point_laser = (  #Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[6] + self.illumination_offset +
            self.daq.write_length *
            int(roll_time * 1.0 / self.daq.write_length))
        oh_snap_voltages[start_point_laser:start_point_laser +
                         self.illumination_length, n2c['488']] = 10
        oh_snap_voltages[start_point_laser:start_point_laser +
                         self.illumination_length, n2c['blanking']] = 10

        ##        oh_snap_voltages[start_point_laser, n2c['blanking']] = 10
        time.sleep(1)
        """
        let's test the objective impulse response
        """
        ##        marker = start_point_laser
        ##        scan = np.linspace(5, 6, 5000)
        ##        oh_snap_voltages[marker:(marker+5000), n2c['objective']] = scan
        ##        marker += 5000
        ##        oh_snap_voltages[marker:(
        ##            marker+2500), n2c['objective']] = 6
        ##        marker += 2500
        ##        oh_snap_voltages[marker:(
        ##            marker+5000), n2c['objective']] = np.linspace(6,5,5000)
        ##        marker += 5000

        ##        loaded_signal = tif_to_array(
        ##            filename='input_voltage_objective_00.tif').astype(
        ##                np.float64).ravel()
        ##        loaded_signal += objective_voltage
        ##        oh_snap_voltages[:22500, n2c['objective']] = loaded_signal[:]
        ##        print "min", oh_snap_voltages[:, n2c['objective']].min()
        ##        print "max", oh_snap_voltages[:, n2c['objective']].max()
        ##
        ##        loaded_desired_signal = tif_to_array(
        ##            filename='desired_result_objective.tif').astype(
        ##                np.float64).ravel()
        ##        loaded_desired_signal += objective_voltage
        ##        loaded_desired_signal[0] += 1
        ##        oh_snap_voltages[:, n2c['561']] = objective_voltage
        ##        oh_snap_voltages[:22500, n2c['561']] = loaded_desired_signal[:]

        print oh_snap_voltages.shape
        self.daq.send_voltage(oh_snap_voltages, 'snap')
        return None

    def initialize_volume(self):

        volume_voltages = np.zeros((30000, self.daq.num_mutable_channels),
                                   dtype=np.float64)

        ##objective starts where it was
        objective_voltage = self.daq.default_voltages[-1, n2c['objective']]
        volume_voltages[:, n2c['objective']] = objective_voltage

        ##objective does loaded scan
        loaded_signal = tif_to_array(
            filename='input_voltage_objective_01.tif').astype(
                np.float64).ravel()
        loaded_signal += objective_voltage
        volume_voltages[:22500, n2c['objective']] = loaded_signal[:]
        print "min", oh_snap_voltages[:, n2c['objective']].min()
        print "max", oh_snap_voltages[:, n2c['objective']].max()

        ##excitation galvo starts where it was
        galvo_voltage = self.daq.default_voltages[-1, n2c['excitation_scan']]
        volume_voltages[:, n2c['excitation_scan']] = galvo_voltage

        ##excitation galvo scans illumination
        galvo_voltage[5000:10000] = np.linspace(galvo_voltage,
                                                galvo_voltage + 0.2, 5000)
        galvo_voltage[10000:12500] = galvo_voltage + 0.2
        galvo_voltage[12500:17500] = np.linspace(galvo_voltage + 0.2,
                                                 galvo_voltage, 5000)

        ##murrcle stays at what it was
        murrcle_voltage = self.daq.default_voltages[-1, n2c['emission_scan']]
        oh_snap_voltages[:, n2c['emission_scan']] = murrcle_voltage

        #Camera triggers at the start of a write
        oh_snap_voltages[:self.daq.write_length // 4, n2c['camera']] = 3

        #AOTF fires on one perpendicular facet

        start_point_laser = (  #Integer num of writes plus a perp facet time
            self.daq.perpendicular_facet_times[6] + self.illumination_offset +
            self.daq.write_length *
            int(roll_time * 1.0 / self.daq.write_length))
        oh_snap_voltages[start_point_laser:start_point_laser +
                         self.illumination_length, n2c['488']] = 10
        oh_snap_voltages[start_point_laser:start_point_laser +
                         self.illumination_length, n2c['blanking']] = 10

        ##        oh_snap_voltages[start_point_laser, n2c['blanking']] = 10
        time.sleep(1)
        """
        let's test the objective impulse response
        """
        ##        marker = start_point_laser
        ##        scan = np.linspace(5, 6, 5000)
        ##        oh_snap_voltages[marker:(marker+5000), n2c['objective']] = scan
        ##        marker += 5000
        ##        oh_snap_voltages[marker:(
        ##            marker+2500), n2c['objective']] = 6
        ##        marker += 2500
        ##        oh_snap_voltages[marker:(
        ##            marker+5000), n2c['objective']] = np.linspace(6,5,5000)
        ##        marker += 5000

        ##        loaded_signal = tif_to_array(
        ##            filename='input_voltage_objective_00.tif').astype(
        ##                np.float64).ravel()
        ##        loaded_signal += objective_voltage
        ##        oh_snap_voltages[:22500, n2c['objective']] = loaded_signal[:]
        ##        print "min", oh_snap_voltages[:, n2c['objective']].min()
        ##        print "max", oh_snap_voltages[:, n2c['objective']].max()
        ##
        ##        loaded_desired_signal = tif_to_array(
        ##            filename='desired_result_objective.tif').astype(
        ##                np.float64).ravel()
        ##        loaded_desired_signal += objective_voltage
        ##        loaded_desired_signal[0] += 1
        ##        oh_snap_voltages[:, n2c['561']] = objective_voltage
        ##        oh_snap_voltages[:22500, n2c['561']] = loaded_desired_signal[:]

        print oh_snap_voltages.shape
        self.daq.send_voltage(oh_snap_voltages, 'snap')
        return None

    def initialize_image_data_pipeline(self):
        self.idp = Image_Data_Pipeline(
            num_buffers=15,
            buffer_shape=(1, 2042, 2060),  ##256 or 2048, 2060
            camera_high_priority=True)
        desired_exposure_time_microseconds = 60000
        """
        Rep rate of camera is dictated by rep rate of the wheel. Exposure
        time of the camera has to be 20 microseconds shorter than the
        rep time of the camera or else the software can't keep up.
        """
        self.idp.camera.commands.send((
            'apply_settings',
            {
                'trigger': 'external trigger/software exposure control',
                'region_of_interest': (-1, 4, 10000, 2044),  ##897, 1152
                'exposure_time_microseconds':
                desired_exposure_time_microseconds
            }))
        camera_response = self.idp.camera.commands.recv()
        print "Camera response:", camera_response
        (
            trigger_mode,
            self.exposure_time_microseconds,
            self.region_of_interest,
        ) = camera_response
        self.idp.camera.commands.send(('set_timeout', {'timeout': 1}))
        print "Camera timeout:", self.idp.camera.commands.recv(), "s"
        self.idp.camera.commands.send(('set_preframes', {'preframes': 0}))
        print "Camera preframes:", self.idp.camera.commands.recv()
        self.idp.set_display_intensity_scaling(scaling='autoscale')
        print self.idp.get_display_intensity_scaling()
        self.saved_files = 0

    def get_camera_rolling_time_microseconds(self):
        """
        The pco edge 4.2 allows an asymmetric region-of-interest, but
        does this simply by acquiring a symmetric region-of-interest
        and cropping the data, so the rolling time is still the same
        as if you'd used a symmetric region of interest.
        """
        num_lines = max(2 * self.region_of_interest[3] - 2048,
                        2048 - 2 * (self.region_of_interest[1] - 1))
        seconds_per_line = 0.01007 * 1.0 / 2048.  #10 ms for the full field
        return int(num_lines * seconds_per_line * 1e6)

    def initialize_daq(self):
        rotations_per_second = 200
        facets_per_rotation = 10
        points_per_second = 500000
        num_channels = 8

        triggers_per_rotation = 2
        triggers_per_second = triggers_per_rotation * rotations_per_second
        points_per_trigger = points_per_second * (1.0 / triggers_per_second)
        facets_per_second = rotations_per_second * facets_per_rotation
        points_per_facet = points_per_second * (1.0 / facets_per_second)
        print
        print "Desired points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Desired points per facet:", points_per_facet
        points_per_facet = int(round(points_per_facet))
        points_per_trigger = int(points_per_facet *  #Careful! (Odd-facet case)
                                 facets_per_rotation * 1.0 /
                                 triggers_per_rotation)
        print "Actual points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Actual points per facet:", points_per_facet
        print
        print "Desired rotations per second:", rotations_per_second
        rotations_per_second = (points_per_second *
                                (1.0 /
                                 (points_per_trigger * triggers_per_rotation)))
        print "Actual rotations per second:", rotations_per_second
        points_per_rotation = points_per_trigger * triggers_per_rotation
        print "Write length:", points_per_rotation
        print

        wheel_signal = np.zeros(points_per_rotation, dtype=np.float64)
        for i in range(triggers_per_rotation):
            start = i * points_per_trigger
            stop = start + points_per_trigger // 2
            wheel_signal[start:stop] = 6

        default_voltage = np.zeros((points_per_rotation, num_channels),
                                   dtype=np.float64)

        default_voltage[:, n2c['488']] = 0
        default_voltage[:, n2c['561']] = 0  ##5 ####CHANGE ME BACK
        default_voltage[:, n2c['blanking']] = 0
        default_voltage[:, n2c['objective']] = 5
        default_voltage[:, n2c['excitation_scan']] = 0
        default_voltage[:, n2c['emission_scan']] = 0  #-4.45
        default_voltage[:, n2c['camera']] = 0
        default_voltage[:, n2c['wheel']] = wheel_signal

        self.daq = DAQ_with_queue(num_immutable_channels=1,
                                  default_voltage=default_voltage,
                                  rate=points_per_second,
                                  write_length=points_per_rotation,
                                  high_priority=True)
        """
        Positive lag raises first wheel reflection, lag=65 for 150 rps
        Empirically determined!
        """
        perpendicular_lag = int(
            np.ceil((10404.0 / rotations_per_second) - 10.0))
        self.daq.perpendicular_facet_times = []
        for facet in range(facets_per_rotation):
            self.daq.perpendicular_facet_times.append(facet *
                                                      points_per_facet +
                                                      perpendicular_lag)

        ##FIXME: Put this shit into an "alignment" panel
        """
##        want continuous laser firing? try these lines.
##        """
        ####        laser_signal = np.zeros((points_per_rotation), dtype=np.float64)
        ######        camera_signal = np.zeros((points_per_rotation), dtype=np.float64)
        ####        laser_duration = 5
        ####        delay = 0
        ######        for i in range(len(self.daq.perpendicular_facet_times)):
        ######            print "flash"
        ####        place = self.daq.perpendicular_facet_times[0] + delay ##i
        ####        laser_signal[place:place+laser_duration] = 10##7.5
        ######            camera_signal[place:place+50] = 3##7.5
        ####        print "i =", i
        ####        print laser_signal[self.daq.perpendicular_facet_times[1]]
        ####        print "changing defaults"
        ####        self.daq.set_default_voltage(laser_signal, n2c['488'])
        ####        self.daq.set_default_voltage(laser_signal, n2c['blanking'])
        ######        self.daq.set_default_voltage(camera_signal, n2c['camera'])
        ####
        self.seconds_per_write = self.daq.write_length * 1.0 / self.daq.rate
        print "Seconds per write:", self.seconds_per_write