コード例 #1
0
def MEC_ISIO():
    """
    interfaces with the shared memory buffer of remote DM

    Here we create the interface between the shm and this code to apply new offsets for the remote DM. The interfacing
    is handled by pyMILK found https://github.com/milk-org/pyMilk. We also create the probe by calling beambar, and
    send that offset map to the shm. We read in the time the probe pattern was applied. Functinality exists to save
    the probe pattern and timestamp together, but it is unused for beammapping on MEC as of 6/4/20 so it is currently
    unused.

    :return: nothing explicitly returned but probe is applied (will persist on DM until it is externally cleared,
            eg by the RTC computer on SCExAO). Saving capability not currently implemented.
    """
    # Create shared memory (shm) interface
    sp = ShmParams()
    MECshm = SHM(
        sp.shm_name)  # create c-type interface using pyMilk's ISIO wrapper
    data = MECshm.get_data(
    )  # used to determine size of struct (removes chance of creating wrong probe size)

    # Create Probe
    bp = BarParams(data.shape)  # import settings
    probe = beambar(bp,
                    line_dir=bp.dir,
                    center=bp.probe_center,
                    debug=bp.debug)  # create probe pattern
    MECshm.set_data(probe)  # Apply Probe
    t_sent = MECshm.IMAGE.md.lastaccesstime  # Read Time

    # Saving Probe and timestamp together
    ap = AppliedProbe(bp, probe, t_sent)

    return MECshm
コード例 #2
0
def example_shm(shm_name="MECshm"):
    """
    example from the isio.shm README found on github

    :param shm_name: name of the shared memory buffer (default is MECshm)
    :return: the struct that contains the shared memory buffer
    """
    MECshm = SHM(shm_name)
    data = MECshm.get_data(check=True)  # Wait for semaphore udate, then read

    # Writing to existing shm stream
    MECshm.set_data(np.random.rand(*MECshm.shape).astype(MECshm.nptype))

    # Reading a RT stream
    ocam = SHM('ocam2d')
    output = ocam.multi_recv_data(
        10000,
        outputFormat=1,  # Puts everything in a 3D np.array
        monitorCount=
        True  # Prints a synthesis of counters, ie likely missed frames
    )
    print(output.shape)  # 10000 x 120 x 120
    print(output.dtype)  # np.uint16

    # Creating a brand new stream (e.g. 30x30 int16 images)
    shm_wr = SHM(
        'shm_name',
        data,  # 30x30 int16 np.array
        location=-1,  # CPU
        shared=True,  # Shared
    )
    # Or with shape and type
    shm_wr = SHM('shm_name', ((30, 30), np.int16), ...)

    return MECshm
コード例 #3
0
    def __init__(self, publisher):
        super().__init__()

        # Define the attributes
        self._INITIALDIR = os.getcwd()
        self._connected = False
        self._pos = 0 * np.ones((core.NSEGMENTS, 3))
        self._off = np.c_[np.ones((core.NSEGMENTS, 2)) * core.TIPTILTMIN,
                          0 * np.ones((core.NSEGMENTS, 1))]
        self._on = 0 * np.ones((core.NSEGMENTS, 3))

        self.pub = publisher
        self.running = True
        self.milk_solution = True

        if self.milk_solution:
            # Prepare the maps to be ploted
            self._init_maps()
            self.flag_test = True

            # Prepare the shared memory
            self.data_plot = SHM(
                'irisaoim', ((self.map_width, self.map_height), np.float32),
                location=-1,
                shared=True)

            # Start the mems
            self.start()
        else:
            self.connect()
            self.flat()
コード例 #4
0
def send_flat(channel):
    """
    sends a DM flat (array of 0's) to the DM channel specified

    SCExAO DM channel names have the format "dm00dispXX" where XX is the channel number. Generally CDI probes or any
    active nulling takes place on channel 06 or 07. I think 00 is the 'observed' DM flat (may not be an array of 0s
    due to voltage anomolies on the DM itself).

    :return: nothing explicitly returned but probe is applied (will persist on DM until it is externally cleared,
            eg by the RTC computer on SCExAO).
    """
    # Create shared memory (shm) interface
    sp = ShmParams()
    # channel = sp.shm_name
    MECshm = SHM(
        channel)  # create c-type interface using pyMilk's ISIO wrapper
    data = MECshm.get_data(
    )  # used to determine size of struct (removes chance of creating wrong probe size)

    # Create Flat
    flat = np.zeros((data.shape[0], data.shape[1]), dtype=np.float32)
    MECshm.set_data(flat)  # Apply flat probe to get start time
コード例 #5
0
    def __init__(self, camera, publisher):
        Thread.__init__(self)

        self.pub = publisher
        self.cam = camera

        self.running = True
        self.data_ready = False
        self.live_pause = False

        self.camera_link = CAMERA_LINK

        self.width = WIDTH_IMAGE
        self.height = HEIGHT_IMAGE

        self.vbin = VERTICAL_BINNING
        self.hbin = HORIZONTAL_BINNING

        self.ReadMode = READ_MODE
        self.AcqMode = ACQUISITION_MODE
        self.ft_mode = FRAME_TRANSFER_MODE

        self.Lower_left_X = LOWER_LEFT_X
        self.Lower_left_Y = LOWER_LEFT_Y

        self.data = np.zeros(
            [np.int(self.width / self.hbin),
             np.int(self.height / self.vbin)])
        self.dark = np.zeros(
            [np.int(self.width / self.hbin),
             np.int(self.height / self.vbin)])
        self.rawdark = []

        self.c_min = None
        self.c_max = None

        self.graphpoints = 200

        self.PLTxdata = np.array([])
        self.PLTydata = np.array([])

        self.CROPsize = 3
        self.CROPpos = [0, self.CROPsize * 2, 0, self.CROPsize * 2]
        self.CROPdata = np.zeros([self.CROPsize * 2, self.CROPsize * 2])

        self.lastPhotArrayTRY = []
        self.lastPhotArraySent = []

        self.FLUX_V2PM = None
        self.FLUX_P2VM = None

        self.exposure_time = DEFAULT_EXP_TIME
        self.gain = DEFAULT_GAIN

        self.rawdata = np.zeros(
            [np.int((self.width / self.hbin) * (self.height / self.vbin))],
            dtype=np.float64)

        self.ixionim = SHM('ixionim',
                           ((np.int(self.width / self.hbin),
                             np.int(self.height / self.vbin)), np.float64),
                           location=-1,
                           shared=1)
        self.ixiondark = SHM('ixiondark',
                             ((np.int(self.width / self.hbin),
                               np.int(self.height / self.vbin)), np.float64),
                             location=-1,
                             shared=1)
コード例 #6
0
class AndorCtrl(Thread):
    def __init__(self, camera, publisher):
        Thread.__init__(self)

        self.pub = publisher
        self.cam = camera

        self.running = True
        self.data_ready = False
        self.live_pause = False

        self.camera_link = CAMERA_LINK

        self.width = WIDTH_IMAGE
        self.height = HEIGHT_IMAGE

        self.vbin = VERTICAL_BINNING
        self.hbin = HORIZONTAL_BINNING

        self.ReadMode = READ_MODE
        self.AcqMode = ACQUISITION_MODE
        self.ft_mode = FRAME_TRANSFER_MODE

        self.Lower_left_X = LOWER_LEFT_X
        self.Lower_left_Y = LOWER_LEFT_Y

        self.data = np.zeros(
            [np.int(self.width / self.hbin),
             np.int(self.height / self.vbin)])
        self.dark = np.zeros(
            [np.int(self.width / self.hbin),
             np.int(self.height / self.vbin)])
        self.rawdark = []

        self.c_min = None
        self.c_max = None

        self.graphpoints = 200

        self.PLTxdata = np.array([])
        self.PLTydata = np.array([])

        self.CROPsize = 3
        self.CROPpos = [0, self.CROPsize * 2, 0, self.CROPsize * 2]
        self.CROPdata = np.zeros([self.CROPsize * 2, self.CROPsize * 2])

        self.lastPhotArrayTRY = []
        self.lastPhotArraySent = []

        self.FLUX_V2PM = None
        self.FLUX_P2VM = None

        self.exposure_time = DEFAULT_EXP_TIME
        self.gain = DEFAULT_GAIN

        self.rawdata = np.zeros(
            [np.int((self.width / self.hbin) * (self.height / self.vbin))],
            dtype=np.float64)

        self.ixionim = SHM('ixionim',
                           ((np.int(self.width / self.hbin),
                             np.int(self.height / self.vbin)), np.float64),
                           location=-1,
                           shared=1)
        self.ixiondark = SHM('ixiondark',
                             ((np.int(self.width / self.hbin),
                               np.int(self.height / self.vbin)), np.float64),
                             location=-1,
                             shared=1)

    def run(self):
        while self.running:
            if not self.live_pause:
                while True:
                    self.cam.GetMostRecentImage(self.rawdata)
                    getimerr = self.cam.GetMostRecentImage_error
                    if getimerr == 20002 or self.live_pause:
                        break
                time.sleep(self.cam.accu_cycle_time + self.exposure_time)
                # Write the image in the shared memory
                self.ixionim.set_data(
                    np.reshape(self.cam.imageArray,
                               (np.int(self.height / self.vbin),
                                np.int(self.width / self.hbin)
                                )))  ## Somehow width and height are inverted

            self.data_ready = True

    def update(self):
        if self.data_ready:
            #self.data_ready = False
            return self.data

    def set_shutter_CLOSED(self):
        '''
        Sets the internal camera shutter to CLOSED position
        '''
        self.cam.AbortAcquisition()
        time.sleep(0.5)
        self.cam.SetShutter(0, 2, 300, 100)
        time.sleep(0.5)
        self.cam.StartAcquisition()

    def set_shutter_OPEN(self):
        '''
        Sets the internal camera shutter to OPEN position
        '''
        self.cam.AbortAcquisition()
        time.sleep(0.5)
        self.cam.SetShutter(0, 1, 300, 100)
        time.sleep(0.5)
        self.cam.StartAcquisition()

    def wait_for_idle(self, maxwaittime=10):
        t0 = time.time()
        while ((time.time() - t0) <= maxwaittime):
            time.sleep(0.1)
            self.cam.GetStatus()
            if self.cam.status == "DRV_IDLE":  # 20073: not acquiring
                return self.cam.status
        return self.cam.status

    def set_camera(self, camera):
        '''
        This command lets the live viewer know which camera to talk to.
        This function probably shouldn't be changed, but can be modified 
        if we whish to use the same code for different camera.
        It also passess all the dll camera commands into the viewer so the
        camera can be controlled from this thread.
        '''
        self.cam = camera

    def get_hardware_info(self):
        get_hardware_info = self.cam.GetHardwareVersion()
        self.pub.pprint(get_hardware_info)
        self.pub.pprint('Firmware Version :' +
                        str(self.cam.CameraFirmwareVersion))
        self.pub.pprint('Firmware Built :' + str(self.cam.CameraFirmwareBuild))

    def get_software_info(self):
        get_software_info = self.cam.GetSoftwareVersion()
        self.pub.pprint(get_software_info)
        self.pub.pprint('Driver Version :' + str(self.cam.vxdVer))
        self.pub.pprint('DLL Version :' + str(self.cam.dllVer))

    #-------------------------------------------------------------------------
    #  Start / Stop live camera
    #-------------------------------------------------------------------------

    def play(self):
        #
        self.live_pause = False

    def pause(self):
        #
        self.live_pause = True

    def start(self):
        '''
        Starts the video display.
        '''
        if self.cam is None:
            raise Exception("Camera not connected!")

        self.get_hardware_info()
        self.get_software_info()

        self.cam.SetReadMode(self.ReadMode)
        self.cam.SetAcquisitionMode(self.AcqMode)
        self.cam.SetFrameTransferMode(self.ft_mode)

        self.cam.SetKineticCycleTime(0)
        # Does nothing: returns DRV_NOT_AVAILABLE - feature is not supported - firmware/driver update maybe ?
        # self.cam.SetIsolatedCropMode(1, self.height, self.width, self.vbin, self.hbin)
        # self.set_camera_link_mode(0)

        self.cam.SetImage(self.hbin, self.vbin, self.Lower_left_X,
                          self.Lower_left_X + np.int(self.width) - 1,
                          self.Lower_left_Y,
                          self.Lower_left_Y + np.int(self.height) - 1)
        #self.cam.SetImage( ??bin , SPECTRAL_bin, ??start, OPD_DIM, ??, SPECTRAL_DIM)

        self.cam.SetShutter(0, 1, 50, 50)
        self.cam.SetExposureTime(self.exposure_time)

        self.cam.GetEMGainRange()
        #self.cam.GetEMCCDGain()
        if self.gain > self.cam.gainRange[1]:
            self.pub.pprint(
                "WARNING : Gain of " + str(self.gain) +
                " is too high. You need to lower your ambition ;-) ")
            self.pub.pprint("Highest available gain: " +
                            str(self.cam.gainRange[1]))
            self.pub.pprint("Gain value changed to 0,")
            self.gain = 0
        self.cam.SetEMCCDGain(self.gain)

        self.set_camera_link_mode(self.camera_link)

        self.cam.GetAcquisitionTimings()
        self.cam.GetEMCCDGain()
        self.pub.pprint("Actual exposure time: " + str(self.cam.exp_time))
        #self.pub.pprint("Actual accu cycle time: "+str(self.cam.accu_cycle_time))
        self.pub.pprint("Actual kine cycle time: " +
                        str(self.cam.kinetic_cycle_time))
        self.pub.pprint("Camera gain: " + str(self.cam.gain))

        self.pub.pprint("\n")
        #self.pub.pprint("Camera Gain: ")
        #self.pub.pprint(str(self.gain))
        self.cam.GetNumberPreAmpGains()
        self.cam.GetPreAmpGain()
        self.cam.GetStatus()
        self.cam.StartAcquisition()
        super().start()
        os.system('shmImshow.py ixionim &')
        self.pub.pprint("Andor iXon Initialised\n")

    def stop(self):
        self.running = False
        self.cam.AbortAcquisition()
        self.cam.SetShutter(0, 2, 300, 100)
        self.cam.ShutDown()
        os.system("pkill -f 'shmImshow.py ixionim'")
        self.join()

    #-------------------------------------------------------------------------
    #  Temperature control
    #-------------------------------------------------------------------------

    def GetCurrentTemperature(self):
        self.cam.GetTemperature()
        self.pub.pprint("Current temperature is: " +
                        str(self.cam.temperature) + "°C\n")
        return 0

    def SetDetTemperature(self, temperature):
        self.cam.GetTemperatureRange()
        if temperature < self.cam.min_temp or temperature > self.cam.max_temp:
            self.pub.pprint("!!!Wrong temperature set!!!")
            self.pub.pprint("Set it again.")
            self.pub.pprint("Valid temperature is in the range [%d, %d].\n" %
                            (self.cam.min_temp, self.cam.max_temp))
            return 0

        self.cam.SetTemperature(temperature)

    #-------------------------------------------------------------------------
    #  Acquisition Mode
    #-------------------------------------------------------------------------

    def set_single_scan(self):
        '''
        Set the acquisition mode to "Fixed" (takes one image).
        '''
        #self.cam.SetSingleScan()
        self.cam.SetReadMode(4)
        self.cam.SetAcquisitionMode(1)

        self.cam.SetImage(1, 1, 1, self.width, 1, self.height)

    def set_video_scan(self):
        '''
        Set the acquisition mode to "Continuous" (takes one image).
        '''
        self.cam.SetReadMode(4)
        self.cam.SetAcquisitionMode(5)

        self.cam.SetKineticCycleTime(0)
        self.cam.SetImage(1, 1, 1, self.height, 1, self.width)

        #self.cam.SetVideoScan()

    def set_frame_series(self):
        self.cam.SetReadMode(4)
        self.cam.SetAcquisitionMode(3)
        self.cam.SetImage(1, 1, 1, self.width, 1, self.height)

    def set_series_scan_param(self, N_acc, Nframes, acc_cycle_time,
                              KinCyclTime):
        """
        Sets the Parameters needed for taking a datacube. Number entered needs to be the number of frames.
        Can also change the kinectic cycle time by writing 'KinCyclTime=##' in (s).
        """
        self.cam.SetReadMode(4)
        self.cam.SetAcquisitionMode(3)
        self.cam.SetNumberAccumulations(N_acc)
        self.cam.SetAccumulationCycleTime(acc_cycle_time)
        self.cam.SetNumberKinetics(Nframes)
        self.numberframes = N_acc * Nframes
        self.cam.SetKineticCycleTime(KinCyclTime)

    def get_AcquisitionTimings(self):
        self.cam.GetAcquisitionTimings()
        self.pub.pprint("Actual exposure time is: " + str(self.cam.exp_time))
        self.pub.pprint("Actual accumulation cycle time is: " +
                        str(self.cam.accu_cycle_time))
        self.pub.pprint("Actual kinetic cycle time time is: " +
                        str(self.cam.kinetic_cycle_time))

    ## ADD MULTI-TRACK and RANDOM-TRACK FUNCTIONS HERE
    ## in progress...

    def set_multi_track(self, number, height, offset, bottom, gap):
        self.cam.SetReadMode(1)
        self.cam.SetMultiTrack(number, height, offset, bottom, gap)

    def set_camera_link_mode(self, mode):
        #if mode == 0:
        #    self.pub.pprint("Camera link is set off")

        #if mode == 1:
        #    self.pub.pprint("Camera link is set on")

        Set = self.cam.SetCameraLinkMode(mode)

        if self.cam.set_camera_link_mode_error == 20002:
            if mode == 0:
                self.pub.pprint("Camera link is set off")

            if mode == 1:
                self.pub.pprint("Camera link is set on")

        else:
            self.pub.pprint(
                "Camera link mode : Something went wrong. Error code =" +
                str(self.cam.set_camera_link_mode_error))

    def get_bits(self):
        self.cam.GetBitDepth()
        nbits = self.cam.bits
        self.pub.pprint("Number of bits is: " + str(nbits))

    #-------------------------------------------------------------------------
    #  Exposure time // Gain
    #-------------------------------------------------------------------------

    def set_exptime(self, exptime):
        '''
        Sets the camera exposure time in SECONDS.

        Example:
            a.set_exptime(0.01)

        the default exposure time at initialisation is set by a global variable:
        DEFAULT_EXP_TIME
        and is set to 0.001 - 1ms (1kHz)

        Executing this command will pause the video link while it updates then reactivate it.

        *WARNING* - Careful when subtracting darks as they will no longer match.
        '''

        self.exposure_time = exptime
        self.cam.GetEMCCDGain()
        gain = self.cam.gain
        # Stop the acquisition
        self.cam.AbortAcquisition()

        # Set the Read mode and the acquisition mode
        self.cam.SetReadMode(self.ReadMode)
        self.cam.SetAcquisitionMode(self.AcqMode)

        self.cam.SetKineticCycleTime(0)

        # Set the Image parameters
        self.cam.SetIsolatedCropMode(1, self.height, self.width, self.vbin,
                                     self.hbin)
        self.cam.SetImage(self.hbin, self.vbin, self.Lower_left_X,
                          self.Lower_left_X + np.int(self.width) - 1,
                          self.Lower_left_Y,
                          self.Lower_left_Y + np.int(self.height) - 1)
        self.cam.SetExposureTime(exptime)
        self.cam.SetShutter(0, 1, 50, 50)

        self.cam.GetEMGainRange()
        self.cam.GetNumberPreAmpGains()
        self.cam.GetPreAmpGain()
        self.cam.SetEMCCDGain(self.gain)
        self.cam.GetStatus()

        self.cam.GetAcquisitionTimings()
        self.cam.GetEMCCDGain()

        self.pub.pprint("Actual exposure time: " + str(self.cam.exp_time))
        #self.pub.pprint("Actual accu cycle time: "+str(self.cam.accu_cycle_time))
        self.pub.pprint("Actual kine cycle time: " +
                        str(self.cam.kinetic_cycle_time))
        self.pub.pprint("Gain: " + str(self.cam.gain))

        self.cam.StartAcquisition()

    def get_exptime(self):
        #exp_time = self.cam.GetExpTime()
        self.cam.GetAcquisitionTimings()
        self.pub.pprint("Exposure time is %f s." % self.cam.exp_time)
        self.exposure_time = self.cam.exp_time
        return self.cam.exp_time

    def set_gain(self, gain):
        '''
        TO DO
        '''

        self.cam.GetEMGainRange()
        if gain > self.cam.gainRange[1]:
            self.pub.pprint(
                "WARNING : Gain of " + str(self.gain) +
                " is too high. You need to lower your ambition ;-) ")
            self.pub.pprint("Highest available gain: " +
                            str(self.cam.gainRange[1]))

        else:
            self.gain = gain

            self.cam.GetAcquisitionTimings()
            exptime = self.cam.exp_time
            # Stop the acquisition
            self.cam.AbortAcquisition()

            # Set the Read mode and the acquisition mode
            self.cam.SetReadMode(self.ReadMode)
            self.cam.SetAcquisitionMode(self.AcqMode)

            self.cam.SetKineticCycleTime(0)

            # Set the Image parameters
            self.cam.SetIsolatedCropMode(1, self.height, self.width, self.vbin,
                                         self.hbin)
            self.cam.SetImage(self.hbin, self.vbin, self.Lower_left_X,
                              self.Lower_left_X + np.int(self.width) - 1,
                              self.Lower_left_Y,
                              self.Lower_left_Y + np.int(self.height) - 1)

            self.cam.SetExposureTime(exptime)
            self.cam.SetShutter(0, 1, 50, 50)

            self.cam.GetEMGainRange()

            self.cam.GetNumberPreAmpGains()
            self.cam.GetPreAmpGain()
            self.cam.SetEMCCDGain(self.gain)
            self.cam.GetStatus()
            self.cam.GetAcquisitionTimings()
            self.cam.GetEMCCDGain()
            self.pub.pprint("Actual exposure time: " + str(self.cam.exp_time))
            #self.pub.pprint("Actual accu cycle time: "+str(self.cam.accu_cycle_time))
            self.pub.pprint("Actual kine cycle time: " +
                            str(self.cam.kinetic_cycle_time))
            self.pub.pprint("Gain: " + str(self.cam.gain))

            self.cam.StartAcquisition()

    def get_gain(self):
        #exp_time = self.cam.GetExpTime()
        self.cam.GetEMCCDGain()
        self.pub.pprint("Camera gain is %f ." % self.cam.gain)
        self.gain = self.cam.gain
        return self.cam.gain

    #-------------------------------------------------------------------------
    #  Horizontal / Vertical speed
    #-------------------------------------------------------------------------

    def get_number_vs_speeds(self):
        self.cam.GetNumberVSSpeeds()
        self.number_vs_speeds = self.cam.number_vs_speeds
        self.pub.pprint("Number of vs speeds is %d.\n" % self.number_vs_speeds)

    def get_number_hs_speeds(self):
        self.cam.GetNumberHSSpeeds()
        self.number_hs_speeds = self.cam.number_hs_speeds
        self.pub.pprint("Number of hs speeds is %d.\n" % self.number_hs_speeds)

    def get_vs_speed(self):
        self.cam.GetVSSpeed()
        self.vs_speed = self.cam.vs_speed
        self.pub.pprint("VS speed is %d.\n" % self.vs_speed)

    def get_hs_speed(self):
        self.cam.GetHSSpeed()
        self.hs_speed = self.cam.hs_speed
        self.pub.pprint("HS speed is %d.\n" % self.hs_speed)

    def set_vs_speed(self, index):
        #
        self.cam.SetVSSpeed(index)

    def set_hs_speed(self, index):
        #
        self.cam.SetHSSpeed(index)

    def get_number_vertical_speeds(self):
        self.cam.GetNumberVerticalSpeeds()
        self.number_vertical_speeds = self.cam.number_vertical_speeds
        self.pub.pprint("Number of vertical speeds is %d.\n" %
                        self.number_vertical_speeds)

    def get_number_horizontal_speeds(self):
        self.cam.GetNumberHorizontalSpeeds()
        self.number_horizontal_speeds = self.cam.number_horizontal_speeds
        self.pub.pprint("Number of horizontal speeds is %d.\n" %
                        self.number_horizontal_speeds)

    def get_vertical_speed(self):
        self.cam.GetVerticalSpeed()
        self.index_vertical_speed = self.cam.index_vertical_speed
        self.vertical_speed = self.cam.vertical_speed
        self.pub.pprint("Vertical speed index is %d.\n" %
                        self.index_vertical_speed)
        self.pub.pprint("Vertical speed is %d.\n" % self.vertical_speed)

    def get_horizontal_speed(self):
        self.cam.GetHorizontalSpeed()
        self.index_horizontal_speed = self.cam.index_horizontal_speed
        self.horizontal_speed = self.cam.horizontal_speed
        self.pub.pprint("Horizontal speed index is %d.\n" %
                        self.index_horizontal_speed)
        self.pub.pprint("Horizontal speed is %d.\n" % (self.horizontal_speed))

    def set_vertical_speed(self, index):
        #
        self.cam.SetVerticalSpeed(index)

    def set_horizontal_speed(self, index):
        #
        self.cam.SetHorizontalSpeed(index)

    #-------------------------------------------------------------------------
    #  Display options
    #-------------------------------------------------------------------------

    def set_clims(self, c_min, c_max):
        '''
        Function to set the colour limits of the andor video display.
        Format:
            set_clims(intiger1, intiger2) - 2>1 always otherwise will give error.

        Example:
            a.set_clims(0,10000) - locks between 0 and 10k counts

        To make auto scaling colourmap, set both variables to 'None'
            a.set_clims(None,None)


        The video display should update in realtime your changes.
        '''
        if c_min > c_max:
            raise ValueError(
                "c_min > c_max, c_max has to be higher than c_min.")

        self.c_min = c_min
        self.c_max = c_max

    #-------------------------------------------------------------------------
    #  Data / Darks acquisition
    #-------------------------------------------------------------------------

    def acq_dark(self):
        self.cam.SetShutter(0, 2, 50, 50)
        time.sleep(0.2)
        self.cam.GetMostRecentImage(self.rawdata)
        self.ixiondark.set_data(
            np.reshape(
                self.cam.imageArray,
                (np.int(self.height / self.vbin), np.int(
                    self.width /
                    self.hbin))))  ## Somehow width and height are inverted
        self.cam.SetShutter(0, 1, 50, 50)

    def acq_cube(self, N_frames, filename=None):
        exptime = self.get_exptime()

        if filename is None:
            final_filename = str(int(1000 * time.time())) + "_datacube"
        else:
            final_filename = filename

        os.system(
            'python /home/first/Documents/lib/firstctrl/FIRST_Ixion/ixionSaveCube.py '
            + str(N_frames) + ' ' + str(exptime) + ' ' + str(self.cam.gain) +
            ' ' + str(self.cam.temperature) + ' ' + str(final_filename) + ' ' +
            str(SAVEFILEPATH))

    def acq_cube_multi(self, N_cubes, N_frames, filename=None):

        for i in range(N_cubes):

            print('Acquisition of cube ' + str(i + 1))

            if filename is None:
                final_filename = str(int(
                    1000 * time.time())) + "_datacube_" + str(i)
            else:
                final_filename = filename + '_' + str(i)

            self.acq_cube(N_frames, filename=final_filename)

    def acq_wavelength_cal(self, wavelength):
        if wavelength == 'Darks':
            self.pub.pprint("Starting darks for wavelength calibration")
            date = datetime.datetime.today().strftime('%Y%m%d')
            self.cam.SetShutter(0, 2, 50, 50)
            time.sleep(0.2)
            self.acq_cube(50, filename=date + '_WaveCals_Darks_0')
            self.cam.SetShutter(0, 1, 50, 50)

        else:
            self.pub.pprint("Starting calibration for " + str(wavelength) +
                            " nm")
            date = datetime.datetime.today().strftime('%Y%m%d')
            self.acq_cube(50,
                          filename=date + '_WaveCals_' + str(wavelength) +
                          'nm_0')

    def acq_dark_old(self):
        '''
        Acquires a new dark frame for automatic subtraction on the video feed.
        The Dark is taken of whatever is on the detector at the time so make sure you turn the source off.

        Example:
            a.acq_new_dark()

        This should be re-taken whenever you change exposure time.

        It will pause the video feed while it does this and keep it internally in a variable called 'a.dark'
        '''
        self.cam.AbortAcquisition()
        time.sleep(0.5)
        self.rawdark = []

        self.set_single_scan()
        self.cam.StartAcquisition()
        time.sleep(0.2)
        self.cam.GetMostRecentImage(self.rawdark)
        self.dark = np.reshape(self.rawdark, (self.height, self.width))
        self.cam.AbortAcquisition()
        self.ixiondark.set_data(self.dark.astype(np.float32))

        self.set_video_scan()
        time.sleep(0.2)
        self.cam.StartAcquisition()
        time.sleep(0.2)

    def acq_cube_old(self, N_frames, exptime, filename=None):
        self.set_exptime(exptime)
        ## WARNIING : WIDTH AND HEIGHT HAVE BEEN SWAPPED BECAUSE I TAKE TRANSPOSE OF EACH IMAGE
        #imCube   = np.zeros((N_frames, self.width, self.height))
        #count = 0
        #while count < N_frames:
        imCube = []
        for i in tqdm(range(N_frames)):
            img = np.zeros([self.width * self.height])
            self.cam.GetMostRecentImage(img)
            #img=[]
            #self.cam.GetMostRecentImage(img)
            getimerr = self.cam.GetMostRecentImage_error
            if getimerr == 20002:
                #imCube[count,:,:] = np.transpose(np.reshape(self.cam.imageArray, (self.height, self.width)))
                imCube.append(
                    np.transpose(
                        np.reshape(self.cam.imageArray,
                                   (self.height, self.width))))
                #count = count+1
                time.sleep(0.1 + exptime)
        imCube = np.array(imCube)

        if filename is None:
            final_filename = str(int(1000 * time.time())) + "_datacube"
        else:
            final_filename = filename

        self.pub.pprint('Acquisition over...')
        header = fits.Header()
        header['ExpTime'] = np.round(exptime, decimals=3)
        header['Gain'] = self.cam.gain
        header['Temp'] = self.cam.temperature
        fits.writeto(SAVEFILEPATH + final_filename + '.fits',
                     imCube,
                     header,
                     overwrite=True)
        self.pub.pprint("Image saved in '" + SAVEFILEPATH + final_filename +
                        ".fits'\n")

        os.system("ds9 " + SAVEFILEPATH + final_filename + ".fits &")
コード例 #7
0
from pyMilk.interfacing.isio_shmlib import SHM

import numpy as np

# 50x50 input
try:
    dmvolt = SHM('dmvolt')
except:
    dmvolt = SHM('dmvolt', np.zeros((50,50), dtype=np.uint16), shared=1, location=-1)

# 4096 linear output
dmout = SHM('dmvolt1', symcode=0)


# Row/Col mappings
dm_start_row = [18,15,13,11,10, 8, 7, 6, 5, 5, 4, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 8,10,11,13,15,18]
dm_end_row = [31,34,36,38,39,41,42,43,44,44,45,46,46,47,47,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,48,48,47,47,46,46,45,44,44,43,42,41,39,38,36,34,31]

pupil = np.zeros((50,50), dtype=np.bool)
for r in range(50):
    for c in range(50):
        if r >= dm_start_row[c] and r <= dm_end_row[c]:
            pupil[r,c] = True



# To flatten
dmvolt_map = dmvolt.get_data()
dmvolt_map_flat = dmvolt_map.flatten()

dm_optical_lut = np.array([
コード例 #8
0
N_frames = np.int(sys.argv[1])
exptime = np.float32(sys.argv[2])
gain = np.int(sys.argv[3])
temperature = np.int(sys.argv[4])
file_name = sys.argv[5]
SAVEFILEPATH = sys.argv[6]

date = datetime.datetime.today().strftime('%Y%m%d')
save_dir = SAVEFILEPATH + date + '/'
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

print(str(N_frames) + ' Frames ' + str(exptime) + ' ms each')

# Defines the shared mem where the images are + create image cube
im = SHM('ixionim')
imCube = im.multi_recv_data(N_frames, outputFormat=1)
#imCube = np.array(imCube)
imCube = imCube.transpose(0, 2, 1)

print('Cube acquisition over...')

# Save and display the cube
header = fits.Header()
header['ExpTime'] = np.round(exptime, decimals=3)
header['Gain'] = gain
header['Temp'] = temperature
fits.writeto(save_dir + file_name + '.fits', imCube, header, overwrite=True)
print("Image saved in '" + save_dir + file_name + ".fits'\n")

#os.system("ds9 " + save_dir + file_name + ".fits &")
コード例 #9
0
def get_mask():
    # use maps calculated from aol0_dmmap
    dmmask = SHM("aol0_dmmask").get_data(check=False)
    dmslaved = SHM("aol0_dmslaved").get_data(check=False)
    mask = dmmask.astype(bool) ^ dmslaved.astype(bool)  # XOR
    return mask
コード例 #10
0
def loop_offset(N, plot=True, maxiter=np.inf, **kwargs):
    # stream = SHM("aol0_modeval_ol")
    stream = SHM("dm00disp10")
    basis = SHM("aol0_DMmodes").get_data(check=False)

    mask = get_mask()

    offsets = []

    if plot:
        fig, axs = plt.subplots(2, 2)
        axs[0, 0].set_xlabel(r"$\Delta x$")
        axs[0, 1].set_xlabel(r"$\Delta y$")
        axs[1, 0].set_xlabel(r"$\Delta r$")
        axs[1, 1].set_xlabel(r"$\theta$")
        plt.tight_layout()

    i = 0
    # previous_modes = stream.get_data(check=True) # make sure to get data so semID exists
    # previous_frame = basis @ previous_modes
    logger.info("starting loop")
    while i < maxiter:
        # previous_frame = stream.get_data(check=True)
        # # wait for N frames (TODO async)
        # stream.IMAGE.semflush(stream.semID)
        # stream.IMAGE.semwait(stream.semID)
        # cnt = stream.IMAGE.md.cnt0
        # print(cnt)
        # for _ in range(N - 1 - (cnt % N)):
        #     stream.IMAGE.semwait(stream.semID)

        # current_modes = stream.get_data(check=True)

        # # calculate open-loop reconstruction
        # current_frame = basis @ current_modes

        # current_frame = stream.get_data(check=True)

        cube = stream.multi_recv_data(N + 1, outputFormat=1)
        previous_frame = cube[0]
        current_frame = cube[-1]

        # show frames
        plt.figure(fig_frames.number)
        frames[0].imshow(previous_frame * mask, origin="lower")
        frames[1].imshow(current_frame * mask, origin="lower")
        plt.pause(1e-5)

        # make offset measurement
        x, y, r, theta = measure_shift(previous_frame,
                                       current_frame,
                                       mask=mask)
        x /= N
        y /= N
        r /= N  # convert to average shift per frame
        logger.info(
            f"{i:03d}: x={x} m/s, y={y} m/s, r={r} m/s, theta={theta} deg")
        offsets.append(dict(x=x, y=y, r=r, theta=theta))

        # plotting
        if plot:
            axs[0, 0].scatter(i, x, c="C0")
            axs[0, 1].scatter(i, y, c="C1")
            axs[1, 0].scatter(i, r, c="C2")
            axs[1, 1].scatter(i, theta, c="C3")
            # fig.canvas.copy_from_bbox(ax.bbox) # blitting
            plt.figure(fig.number)
            plt.pause(1e-5)

        # loop updates
        i += 1
        previous_frame = current_frame

    return offsets
コード例 #11
0
class Mems(Thread):
    def __init__(self, publisher):
        super().__init__()

        # Define the attributes
        self._INITIALDIR = os.getcwd()
        self._connected = False
        self._pos = 0 * np.ones((core.NSEGMENTS, 3))
        self._off = np.c_[np.ones((core.NSEGMENTS, 2)) * core.TIPTILTMIN,
                          0 * np.ones((core.NSEGMENTS, 1))]
        self._on = 0 * np.ones((core.NSEGMENTS, 3))

        self.pub = publisher
        self.running = True
        self.milk_solution = True

        if self.milk_solution:
            # Prepare the maps to be ploted
            self._init_maps()
            self.flag_test = True

            # Prepare the shared memory
            self.data_plot = SHM(
                'irisaoim', ((self.map_width, self.map_height), np.float32),
                location=-1,
                shared=True)

            # Start the mems
            self.start()
        else:
            self.connect()
            self.flat()

    def __enter__(self):
        return self

    def __del__(self):
        self.flat()
        self.disconnect()

    __exit__ = __del__

    def _pprint(self, message):
        '''
        Print message with a color define in the class PColors.
        '''
        self.pub.pprint(PColors.MEMS + str(message) + PColors.ENDC)

    def start(self):
        # Start the mems
        self.connect()
        self.flat()

        # Start the py-milk live feed
        os.system("shmImshow.py irisaoim &")

        # Push the initial opd map
        self._init_figure()

        # Start the Thread
        super().start()

    def stop(self):
        self._pprint("    Closing mems...\n")
        time.sleep(1)
        self.running = False
        time.sleep(1)
        self.join()

    def connect(self):
        """
        Connects to the Mems
        """
        # already connected
        if self._connected:
            return 0
        # hack to CD to the folder with the cal files
        os.chdir(core.PATHCALMEMS)
        disableHardware = False
        self._mirror = IrisAO_API.MirrorConnect(core.MIRRORNUM, core.DRIVERNUM,
                                                disableHardware)
        # CD to previous folder
        os.chdir(self._INITIALDIR)
        self._connected = True

    def disconnect(self):
        """
        Disconnects the Mems
        """
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return 0
        self.flat()
        IrisAO_API.MirrorRelease(self._mirror)
        self._connected = False

    def exit(self):
        """
        Disconnects the Mems
        """
        self.disconnect()

    @property
    def connected(self):
        """
        If there is an active link to the Mems
        """
        return self._connected

    @connected.setter
    def connected(self, value):
        self._pprint("Read-only")

    @property
    def first_nseg(self):
        return len(core.FIRSTSEGS)

    @first_nseg.setter
    def first_nseg(self, value):
        self._pprint('Read-only')

    @property
    def first_seg(self):
        """
        The favorite segments of First
        """
        return core.FIRSTSEGS

    @first_seg.setter
    def first_seg(self, value):
        self._pprint('Read-only')

    def flat(self):
        """
        Sets all tip, tilt, piston to nil
        """
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return 0
        IrisAO_API.MirrorCommand(self._mirror, IrisAO_API.MirrorInitSettings)
        self._pos = np.zeros((core.NSEGMENTS, 3))

    def _moveit(self, arr, elm):
        elm, sz = self._clean_segment(elm)
        if elm is None:
            self._pprint(
                "Wrong input, should be int, list of int, 'first', or 'all'")
            return 0
        piston, tip, tilt = arr[:, :][core.mask_elm(elm)].T
        self.set_pos(elm=elm, piston=piston, tip=tip, tilt=tilt)

    def off(self, elm='all'):
        """
        Sets all piston to nil; sets tip & tilt to min range
        """
        self._moveit(self._off, elm)

    def on(self, elm='first'):
        """
        Sets all piston to nil; sets tip & tilt to min range
        """
        self._moveit(self._on, elm)

    def _clean_segment(self, elm):
        if isinstance(elm, int):
            return [elm], 1
        elif isinstance(elm, str):
            if elm.lower() == 'first':
                elm = core.FIRSTSEGS
            elif elm.lower() == 'all':
                elm = [i for i in range(1, core.NSEGMENTS + 1)]
        elif hasattr(elm, '__iter__'):
            elm = [
                item for item in core.clean_list(elm)
                if 0 < item <= core.NSEGMENTS
            ]
        else:
            return None, None
        return elm, len(elm)

    def get_pos(self, elm):
        """
        Gets the positions of the mems segments

        ex: tip, tilt, piston = m.get_pos('first')

        Input argument elm can be:
          * int -> 1 segment
          * list of int -> n segment
          * 'first' -> the first segments
          * 'all' -> all segments
        """
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return 0
        elm, sz = self._clean_segment(elm)
        if elm is None:
            self._pprint(
                "Wrong input, should be int, list of int, 'first', or 'all'")
            return 0
        # (tip, tilt, piston), locked, reachable
        return np.asarray(IrisAO_API.\
                  GetMirrorPosition(self._mirror, elm)[0]).T

    def set_pos(self, elm, piston=None, tip=None, tilt=None):
        """
        Sets the positions of the mems segments

        Input argument elm can be:
          * int -> 1 segment
          * list of int -> n segment
          * 'first' -> the first segments
          * 'all' -> all segments

        tip, tilt, piston can be left to None to remain unchanged
        if not None, tip, tilt and piston should be a list of floats
        with same size as elm
        """
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return
        elm, sz = self._clean_segment(elm)
        # check input

        if piston is None:
            piston = self._pos[:, 0][core.mask_elm(elm)]
        elif np.size(piston) != sz:
            self._pprint('Wrong size, should be same as elm: {}'.format(sz))
            return
        piston = core.clean_pos(piston, ax='piston')

        if tip is None:
            tip = self._pos[:, 1][core.mask_elm(elm)]
        elif np.size(tip) != sz:
            self._pprint('Wrong size, should be same as elm: {}'.format(sz))
            return
        tip = core.clean_pos(tip, ax='tiptilt')

        if tilt is None:
            tilt = self._pos[:, 2][core.mask_elm(elm)]
        elif np.size(tilt) != sz:
            self._pprint('Wrong size, should be same as elm: {}'.format(sz))
            return
        tilt = core.clean_pos(tilt, ax='tiptilt')

        new_val = np.vstack((piston, tip, tilt)).T
        self._pos[core.mask_elm(elm), :] = new_val
        new_val = [tuple(item) for item in new_val]
        # print(new_val)
        # replace in local values
        IrisAO_API.SetMirrorPosition(self._mirror, elm, new_val)
        IrisAO_API.MirrorCommand(self._mirror, IrisAO_API.MirrorSendSettings)

    def _shape_save(self, name, arr, override):
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return
        if os.path.isfile(name) and not bool(override):
            self._pprint("File '{}' already exists".format(name))
            return
        np.savetxt(name, arr, header="PISTON, TIP, TILT")
        self._pprint("Saved in '{}'".format(name))

    def shape_save(self, name, override=False):
        """
        Saves the current shape into a file

        Args:
          * name (str): the name of the file
          * override (bool): whether to override a file if already
            existing
        """
        name = core.make_filepath(name, core.SHAPEFILENAME)
        self._pos = self.get_pos('all').T
        self._shape_save(name, self._pos, override)

    def shape_on_save(self, name, override=False):
        """
        Saves the current shape ON into a file

        Args:
          * name (str): the name of the file
          * override (bool): whether to override a file if already
            existing
        """
        name = core.make_filepath(name, core.SHAPEONFILENAME)
        self._shape_save(name, self._pos, override)
        self._on = self._pos.copy()

    def shape_off_save(self, name, override=False):
        """
        Saves the current shape OFF into a file

        Args:
          * name (str): the name of the file
          * override (bool): whether to override a file if already
            existing
        """
        name = core.make_filepath(name, core.SHAPEOFFFILENAME)
        self._shape_save(name, self._pos, override)
        self._off = self._pos.copy()

    def shape_list(self):
        """
        Shows all available shape files saved
        """
        self._pprint("\n".join(core.list_filepath(core.SHAPEFILENAME)))

    def shape_on_list(self):
        """
        Shows all available shape ON files saved
        """
        self._pprint("\n".join(core.list_filepath(core.SHAPEONFILENAME)))

    def shape_off_list(self):
        """
        Shows all available shape OFF files saved
        """
        self._pprint("\n".join(core.list_filepath(core.SHAPEOFFFILENAME)))

    def _shape_delete(self, name):
        if os.path.isfile(name):
            os.remove(name)
            self._pprint("Removed: '{}'".format(name))
        else:
            self._pprint("File '{}' not found".format(name))

    def shape_delete(self, name):
        """
        Deletes a shape file saved

        Args:
          * name (str): the name of the file
        """
        self._shape_delete(core.make_filepath_nostamp(name,
                                                      core.SHAPEFILENAME))

    def shape_on_delete(self, name):
        """
        Deletes a shape ON file saved

        Args:
          * name (str): the name of the file
        """
        self._shape_delete(
            core.make_filepath_nostamp(name, core.SHAPEONFILENAME))

    def shape_off_delete(self, name):
        """
        Deletes a shape OFF file saved

        Args:
          * name (str): the name of the file
        """
        self._shape_delete(
            core.make_filepath_nostamp(name, core.SHAPEOFFFILENAME))

    def _shape_load(self, name):
        if not self._connected:
            self._pprint("ERROR: Not connected to Mems")
            return None
        if os.path.isfile(name):
            l = np.loadtxt(name)
            self._pprint("Loaded '{}'".format(name))
            return l
        else:
            self._pprint("File '{}' not found".format(name))
            return None

    def shape_load(self, name):
        """
        Loads a shape file previously saved

        Args:
          * name (str): the name of the file
        """
        name = core.make_filepath_nostamp(name, core.SHAPEFILENAME)
        res = self._shape_load(name)
        if res is not None:
            self._moveit(np.loadtxt(name), 'all')

    def shape_on_load(self, name):
        """
        Loads a shape ON file previously saved

        Args:
          * name (str): the name of the file
        """
        name = core.make_filepath_nostamp(name, core.SHAPEONFILENAME)
        res = self._shape_load(name)
        if res is not None:
            self._on = np.loadtxt(name)

    def shape_off_load(self, name):
        """
        Loads a shape OFF file previously saved

        Args:
          * name (str): the name of the file
        """
        name = core.make_filepath_nostamp(name, core.SHAPEOFFFILENAME)
        res = self._shape_load(name)
        if res is not None:
            self._off = np.loadtxt(name)

    ##### Seb & Nick's additions - Might be broke #########
    def piston_scan(self, elm, piston_begin, piston_end, step, wait_time):
        """
        Piston Scan function. Format is piston_scan(Seg#, Where to begin, Where to end, stepsize,wait time).
        It will then scan through once. 
        """
        nb_steps = int((abs(piston_end) + abs(piston_begin)) / step)
        # print(nb_steps)
        # print('Initiating ramp from '+str(piston_begin)+' to '+str(piston_end)+' with '+str(nb_steps)+' steps')
        self._pprint("MEMS Scanning....")
        for i in range(0, nb_steps + 1):
            self.set_pos(elm, piston_begin + i * step, 0, 0)
            # print(piston_begin+i*step)
            # print('Piston step nb '+str(i+1))
            time.sleep(wait_time)

    # Gui methods
    def run(self):
        if self.milk_solution:
            while self.running:
                if self.connected:
                    # Get pos of mems
                    piston, tip, tilt = self.get_pos('all')
                    if self.flag_test:
                        self.flag_test = False
                        np.savetxt(
                            FCTRLV2_PATH + "pisttiptilt_test.txt",
                            np.concatenate((np.array(piston), np.array(tip),
                                            np.array(tilt))).reshape((3, 37)))

                    # Compute the new opd map
                    self._update_map(piston, tip, tilt)

                    # Push data to the sahred memory
                    self.data_plot.set_data(self.map_opd.astype(np.float32))
                else:
                    self._init_figure()

    def _compute_radii(self):
        for pix_x in range(self.map_height):
            for pix_y in range(self.map_width):
                seg_ind = self.map_index[pix_x, pix_y]
                if seg_ind != 0:
                    radius_x = pix_x - self.map_centers[0, seg_ind - 1]
                    self.map_radius_x[pix_x, pix_y] = radius_x
                    radius_y = pix_y - self.map_centers[1, seg_ind - 1]
                    self.map_radius_y[pix_x, pix_y] = radius_y

    def _init_maps(self):
        self.map_index, self.map_index_h = fits.getdata(FCTRLV2_PATH +
                                                        MEMS_INDEX_NAME,
                                                        header=True)
        self.map_height, self.map_width = np.shape(self.map_index)
        self.map_opd = np.ones((self.map_height, self.map_width))
        self.map_opd[self.map_index == 0] = 0
        self.map_centers = np.loadtxt(FCTRLV2_PATH + MEMS_CENTERS_NAME,
                                      dtype=np.int)
        self.map_radius_x = np.ones((self.map_height, self.map_width))
        self.map_radius_y = np.ones((self.map_height, self.map_width))
        self._compute_radii()

    def _init_figure(self):
        self.data_plot.set_data(self.map_opd.astype(np.float32))

    def _update_map(self, piston_arr, tip_arr, tilt_ar):
        """
        Compute piston, tip and tilt in opd unit.
        """
        for seg_ind in range(37):
            tip_value = self.map_radius_x[self.map_index == seg_ind +
                                          1] * np.sin(
                                              tip_arr[seg_ind] * 10**(-3))
            tilt_value = self.map_radius_y[self.map_index == seg_ind +
                                           1] * np.sin(
                                               tilt_ar[seg_ind] * 10**(-3))
            self.map_opd[self.map_index == seg_ind +
                         1] = piston_arr[seg_ind] + tip_value + tilt_value
コード例 #12
0
def MEC_CDI():
    """
    interfaces with the shared memory buffer of remote DM

    Here we create the interface between the shm and this code to apply new offsets for the remote DM. The interfacing
    is handled by pyMILK found https://github.com/milk-org/pyMilk.

    We also create the probe by calling config_probe, and send that offset map to the shm in a loop based on the CDI
    settings in CDI_params. We read in the time the probe pattern was applied, and save it and other cdi params to a
    structure called out.

    You can set both cdi.end_probes_after_ncycles and cdi.end_probes_after_time, and the loop will break at the shorter
    of the two, but if it hits the time limit it finishes the last full cycle before breaking (eg will wait the full
    length to complete the probe cycle and null time if the cdi.end_probes_after_time hits in the middle of a cycle).

    :return: nothing explicitly returned but probe is applied (will persist on DM until it is externally cleared,
            eg by the RTC computer on SCExAO). DM flat is sent as last command after cycle is terminated.
    """
    # Create shared memory (shm) interface
    sp = ShmParams()
    MECshm = SHM(
        sp.shm_name)  # create c-type interface using pyMilk's ISIO wrapper
    data = MECshm.get_data(
    )  # used to determine size of struct (removes chance of creating wrong probe size)

    # Initialize
    cdi = CDI_params()
    cdi.gen_phaseseries()
    out = cdi.init_out(data.shape[0])

    # Create Flat
    flat = np.zeros((data.shape[0], data.shape[1]), dtype=np.float32)
    MECshm.set_data(flat)  # Apply flat probe to get start time
    pt_start = MECshm.IMAGE.md.lastaccesstime  # probe time start

    # Run Probe Cycles
    n_cycles = 0
    n_cmd = 0
    while n_cycles < cdi.end_probes_after_ncycles:
        olt = datetime.datetime.now()  # outer loop time
        if (olt - pt_start).total_seconds() > cdi.time_limit:
            # print(f'elasped={(olt-pt_start).total_seconds()}, total test time={cdi.time_limit},\n'
            #       f'ncycles={n_cycles}, n_cmds={n_cmd}')
            print('Max time Elapsed. Ending probe cycles')
            break
        for ip, theta in enumerate(cdi.phase_cycle):
            ilt = datetime.datetime.now()  # inner loop time
            probe = config_probe(cdi, theta, data.shape[0])
            MECshm.set_data(probe)  # Apply Probe
            pt_sent = MECshm.IMAGE.md.lastaccesstime  # probe time sent
            cdi.save_tseries(out, n_cmd, pt_sent)
            if n_cmd <= cdi.n_probes:
                cdi.save_probe(out, n_cmd, probe)
            n_cmd += 1
            while True:
                if (datetime.datetime.now() -
                        ilt).total_seconds() > cdi.phase_integration_time:
                    break

        # Send flat and wait until next cycle begins
        MECshm.set_data(flat)  # effectively clearing SHM
        pt_sent = MECshm.IMAGE.md.lastaccesstime  # probe time sent
        cdi.save_tseries(out, n_cmd, pt_sent)
        cdi.save_probe(out, n_cmd, flat)
        n_cmd += 1
        while True:
            if (datetime.datetime.now() -
                    pt_sent).total_seconds() > cdi.null_time:
                # print(f"n_cmd = {n_cmd}\n "
                #       f'cycle time = {(datetime.datetime.now() - olt).total_seconds()}s vs expected '
                #       f'probe+null time= {cdi.time_probe_plus_null:.2f}s')
                n_cycles += 1
                break

    # Wrapping up
    print(
        f'\ntotal time elapsed = {(datetime.datetime.now()-pt_start).total_seconds():.2f} sec'
    )
    out.ts.start = pt_start
    out.ts.n_cycles = n_cycles
    out.ts.n_cmds = n_cmd
    out.ts.cmd_tstamps = out.ts.cmd_tstamps[0:n_cmd]
    out.ts.elapsed_time = (datetime.datetime.now() - pt_start).total_seconds()

    # Make sure shm is clear
    MECshm.set_data(flat)

    # Saving Probe and timestamp together
    if cdi.save_to_disk:
        cdi.save_out_to_disk(out)

    # Fig
    if cdi.plot:
        plot_probe_cycle(out)
        # plot_probe_response_cycle(out)
        # plot_probe_response(out, 0)
        plot_quick_coord_check(out, 2)
        plt.show()

    return MECshm, out