Beispiel #1
0
def CDIprobe(theta, iw):
    """
    apply a probe shape to DM to achieve CDI

    The probe applied to the DM to achieve CDI is that originally proposed in Giv'on et al 2011, doi: 10.1117/12.895117;
    and was used with proper in Matthews et al 2018, doi:  10.1117/1.JATIS.3.4.045001.

    The pupil coordinates used in those equations relate to the sampling of the pupil (plane of the DM). However, in
    Proper, the prop_dm uses a DM map that is the size of (n_ao_act, n_ao_act). This map was resampled from its
    original size to the actuator spacing, and the spacing in units of [m] is supplied as a keyword to the prop_dm
    function during the call. All that is to say, we apply the CDI probe using the coordinates of the DM actuators,
    and supply the probe height as an additive height to the DM map, which is passed to the prop_dm function.

    :param theta: desired phase of the probe
    :param iw: index of wavelength number in ap.wvl_range
    :return: height of phase probes to add to the DM map in adaptive.py
    """
    x = np.linspace(-1 / 2, 1 / 2, tp.ao_act)
    y = x
    X, Y = np.meshgrid(x, y)

    probe = cdip.probe_amp * np.sinc(cdip.probe_w * X) \
                           * np.sinc(cdip.probe_h * Y) \
                           * np.sin(2*np.pi*cdip.probe_center*X + theta)
    # dprint(f"CDI Probe: Min={np.min(probe)*1e9:.2f} nm, Max={np.max(probe)*1e9:.2f} nm")

    # if cdip.show_probe and iw == 0 and theta == cdip.phase_list[0]:
    # quick2D(probe, title=f"Phase Probe at " r'$\theta$' + f"={cdip.phase_list[iw]/np.pi:.2f}" + r'$\pi$',
    #         vlim=(-1e-6, 1e-6),
    #         colormap="YlGnBu_r")  # logZ=True)

    # Testing FF propagation
    if cdip.show_probe and iw == 0 and theta == cdip.phase_list[0]:
        probe_ft = (1 / np.square(2 * np.pi)) * np.fft.ifftshift(
            np.fft.fft2(np.fft.fftshift(probe)))

        # quick2D(probe_ft.real,
        #         title=f"Real FFT of CDI probe, " r'$\theta$' + f"={cdip.phase_list[iw]/np.pi:.2f}" + r'$\pi$',
        #         vlim=(-1e-6, 1e-6),
        #         colormap="YlGnBu_r")
        # quick2D(probe_ft.imag,
        #         title=f"Imag FFT of CDI probe, " r'$\theta$' + f"={cdip.phase_list[iw]/np.pi:.2f}" + r'$\pi$',
        #         vlim=(-1e-6, 1e-6),
        #         colormap="YlGnBu_r")
        quick2D(
            np.arctan2(probe_ft.imag, probe.real),
            title="Phase of Probe",
            # vlim=(-1e-6, 1e-6),
            colormap="YlGnBu_r")

    return probe
Beispiel #2
0
    def array_QE(self, plot=False):
        """Assigns each pixel a phase responsivity between 0 and 1"""
        dist = Distribution(gaussian(mp.g_mean, mp.g_sig,
                                     np.linspace(0, 1, mp.res_elements)),
                            interpolation=True)
        QE = dist(self.array_size[0] * self.array_size[1])[0] / float(
            mp.res_elements)
        if plot:
            plt.xlabel('Responsivity')
            plt.ylabel('#')
            plt.hist(QE)
            plt.show()
        QE = np.reshape(QE, self.array_size[::-1])
        if plot:
            quick2D(QE)  #plt.imshow(QE)
            # plt.show()

        return QE
Beispiel #3
0
    def responvisity_scaling_map(self, plot=False):
        """Assigns each pixel a phase responsivity between 0 and 1"""
        dist = Distribution(gaussian(mp.r_mean, mp.r_sig,
                                     np.linspace(0, 2, mp.res_elements)),
                            interpolation=True)
        responsivity = dist(self.array_size[0] *
                            self.array_size[1])[0] / float(mp.res_elements) * 2
        if plot:
            plt.xlabel('Responsivity')
            plt.ylabel('#')
            plt.hist(responsivity)
            plt.show()
        responsivity = np.reshape(responsivity, self.array_size)
        if plot:
            quick2D(responsivity)  #plt.imshow(QE)
            # plt.show()

        return responsivity
Beispiel #4
0
def retro_wfs(star_fields, wfo, plane_name='wfs'):
    """
    Retrospective wfs (measure an old field)

    :param star_fields:
    :param wfo:
    :param plane_name:
    :return:
    """
    WFS_map = np.zeros((len(star_fields), sp.grid_size, sp.grid_size))
    from skimage.restoration import unwrap_phase
    for iw in range(len(star_fields)):
        quick2D(np.angle(star_fields),
                title='before mask',
                colormap='sunlight')
        phasemap = np.angle(star_fields[iw])
        masked_phase = np.ma.masked_equal(phasemap, 0)
        quick2D(masked_phase, title='before unwrap', colormap='sunlight')
        WFS_map[iw] = unwrap_phase(masked_phase, wrap_around=[False, False])
        WFS_map[iw][phasemap == 0] = 0
        quick2D(WFS_map[iw], title='after')
    if 'retro_closed_wfs' in sp.save_list:
        wfo.save_plane(location='WFS_map')

    return WFS_map
        planet_photons = np.array(planet_photons).T.astype(np.float32)
        planet_photons = np.insert(planet_photons,
                                   obj=1,
                                   values=cam.phase_cal(ap.wvl_range[0]),
                                   axis=0)
        planet_photons[0] = (planet_photons[0] + abs_step) * sp.sample_time
        photons = np.concatenate((star_photons, planet_photons), axis=1)

        # cam.save_photontable(photonlist=photons, index=None, populate_subsidiaries=False)
        stem = cam.arange_into_stem(photons.T,
                                    (cam.array_size[1], cam.array_size[0]))
        stem = list(map(list, zip(*stem)))
        stem = cam.remove_close(stem)
        photons = cam.ungroup(stem)
        photons = photons[[0, 1, 3, 2]]
        # grid(cam.rebin_list(photons), show=False)
        cam.populate_photontable(photons=photons, finalise=False)
    cam.populate_photontable(photons=[], finalise=True)
    grid(cam.rebin_list(photons), show=False)

    # to look at the photontable
    obs = Photontable(iop.photonlist)
    print(obs.photonTable)

    # to plot an image of all the photons on the array
    image = obs.getPixelCountImage(integrationTime=None)['image']
    quick2D(image, show=False, title='Const planet photons')

    plt.show(block=True)
Beispiel #6
0
    fp_sampling = np.copy(sampling[cpx_sequence.shape[1] - 1, :])
    # numpy arrays have some weird effects that make copying the array necessary

    # =======================================================================
    # Plotting
    # =======================================================================
    # White Light, Last Timestep
    if sp.show_wframe:
        # vlim = (np.min(spectralcube) * 10, np.max(spectralcube))  # setting z-axis limits
        img = np.sum(focal_plane[sp.numframes - 1],
                     axis=0)  # sum over wavelength
        quick2D(
            opx.extract_center(img),  #focal_plane[sp.numframes-1]),
            title=f"White light image at timestep {sp.numframes} \n"  # img
            f"AO={tp.use_ao}",
            # f"Grid Size = {sp.grid_size}, Beam Ratio = {sp.beam_ratio} ",
            # f"sampling = {sampling*1e6:.4f} (um/gridpt)",
            logZ=True,
            dx=fp_sampling[0],
            vlim=(1e-7, 1e-3))

    # Plotting Spectra at last tstep
    if sp.show_spectra:
        tstep = sp.numframes - 1
        view_spectra(
            focal_plane[sp.numframes - 1],
            title=f"Intensity per Spectral Bin at Timestep {tstep} \n"
            f" AO={tp.use_ao}",
            # f"Beam Ratio = {sp.beam_ratio:.4f}",#  sampling = {sampling*1e6:.4f} [um/gridpt]",
            logZ=True,
            subplt_cols=sp.spectra_cols,
Beispiel #7
0
def deformable_mirror(wf,
                      WFS_map,
                      iter,
                      previous_output=None,
                      apodize=False,
                      plane_name='',
                      debug=False):
    """
    combine different DM actuator commands into single map to send to prop_dm

    prop_dm needs an input map of n_actuators x n_actuators in units of actuator command height. quick_ao will handle
    the conversion to actuator command height, and the CDI probe must be scaled in cdi.probe_amp in params in
    units of m. Each subroutine is also responsible for creating a map of n_actuators x n_actuators spacing. prop_dm
    handles the resampling of this map onto the wavefront, including the influence function. Its some wizardry that
    happens in c, and presumably it is taken care of so you don't have to worry about it.

    In the call to proper.prop_dm, we apply the flag tp.fit_dm, which switches between two 'modes' of proper's DM
    surface fitting. If FALSE, the DM is driven to the heights specified by dm_map, and the influence function will
    act on these heights to define the final surface shape applied to the DM, which may differ substantially from
    the initial heights specified by dm_map. If TRUE, proper will iterate applying the influence function to the
    input heights, and adjust the heights until the difference between the influenced-map and input map meets some
    proper-defined convergence criterea. Setting tp.fit_dm=TRUE will obviously slow down the code, but will (likely)
    more accurately represent a well-calibrated DM response function.

    much of this code copied over from example from Proper manual on pg 94

    :param wf: single wavefront
    :param WFS_map: wavefront sensor map, should be in units of phase delay
    :param previous_output:
    :param iter: the current index of iteration (which timestep this is)
    :param plane_name: name of plane (should be 'woofer' or 'tweeter' for best functionality)
    :return: nothing is returned, but the probe map has been applied to the DM via proper.prop_dm. DM plane post DM
        application can be saved via the sp.save_list functionality
    """
    assert np.logical_xor(WFS_map is None, previous_output is None)

    # AO Actuator Count from DM Type
    if plane_name == 'tweeter' and hasattr(tp, 'act_tweeter'):
        nact = tp.act_tweeter
    elif plane_name == 'woofer' and hasattr(tp, 'act_woofer'):
        nact = tp.act_woofer
    else:
        nact = tp.ao_act

    # DM Coordinates
    nact_across_pupil = nact - 2  # number of full DM actuators across pupil (oversizing DM extent)
    dm_xc = (
        nact / 2
    )  # The location of the optical axis (center of the wavefront) on the DM in
    dm_yc = (
        nact / 2
    )  # actuator units. First actuator is centered on (0.0, 0.0). The 0.5 is a
    #  parameter introduced/tuned by Rupert to remove weird errors (address this).
    # KD verified this needs to be here or else suffer weird errors 9/19
    # TODO address/remove the 0.5 in DM x,y coordinates

    ############################
    # Creating DM Surface Map
    ############################
    d_beam = 2 * proper.prop_get_beamradius(wf)  # beam diameter
    act_spacing = d_beam / nact_across_pupil  # actuator spacing [m]

    #######
    # AO
    #######
    if previous_output is not None and WFS_map is None:
        dm_map = update_dm(previous_output)
    else:
        dm_map = quick_ao(wf, nact, WFS_map[wf.iw])

    #########
    # Waffle
    #########
    if tp.satelite_speck['apply'] and plane_name is not 'woofer':
        waffle = make_speckle_kxy(tp.satelite_speck['xloc'],
                                  tp.satelite_speck['yloc'],
                                  tp.satelite_speck['amp'],
                                  tp.satelite_speck['phase'])
        waffle += make_speckle_kxy(tp.satelite_speck['xloc'],
                                   -tp.satelite_speck['yloc'],
                                   tp.satelite_speck['amp'],
                                   tp.satelite_speck['phase'])
        dm_map += waffle

    #######
    # CDI
    ######
    if cdi.use_cdi and plane_name == cdi.which_DM:
        theta = cdi.phase_series[iter]
        if not np.isnan(theta):
            # dprint(f"Applying CDI probe, lambda = {wfo.wsamples[iw]*1e9:.2f} nm")
            cdi.save_tseries(iter, datetime.datetime.now())
            probe = config_probe(theta, nact, iw=wf.iw, ib=wf.ib, tstep=iter)
            dm_map = dm_map + probe  # Add Probe to DM map

    #########################
    # Applying Piston Error
    #########################
    if tp.piston_error:
        mean_dm_map = np.mean(np.abs(dm_map))
        var = 1e-4  # 1e-11
        dm_map = dm_map + np.random.normal(0, var,
                                           (dm_map.shape[0], dm_map.shape[1]))

    #########################
    # proper.prop_dm
    #########################
    dmap = proper.prop_dm(wf, dm_map, dm_xc, dm_yc, act_spacing,
                          FIT=tp.fit_dm)  #

    if debug and wf.iw == 0 and wf.ib == 0 and iter == 0:
        dprint(plane_name)
        check_sampling(wf,
                       iter,
                       plane_name + ' DM pupil plane',
                       getframeinfo(stack()[0][0]),
                       units='mm')

        quick2D(WFS_map[wf.iw],
                title=f"WFS map after masking",
                zlabel='unwrapped phase (rad)',
                vlim=[-3 * np.pi, 3 * np.pi])

        fig, ax = plt.subplots(1, 1)
        cax = ax.imshow(dm_map * 1e9, interpolation='none', origin='lower')
        plt.title(f'{plane_name} dm_map (actuator coordinates)')
        cb = plt.colorbar(cax)
        cb.set_label('nm')

        plt.show()

        post_ao = unwrap_phase(
            proper.prop_get_phase(wf)) * wf.lamda / (2 * np.pi)
        # quick2D(pre_ao_dist*1e9, title='unwrapped wavefront before DM', zlabel='nm', show=False)  # , vlim=(-0.5e-7,0.5e-7))
        # quick2D(np.abs(pre_ao_amp)**2, title='Pre-AO Intensity', show=False)#, vlim=(-0.5e-7,0.5e-7))
        # quick2D(dmap, title='the phase map prop_dm is applying', zlabel='distance (m)', show=False)#, vlim=(-0.5e-7,0.5e-7))
        # plt.figure()
        # plt.plot(pre_ao_dist[len(pre_ao_dist)//2], label=f'pre_ao 1D cut, row {len(pre_ao_dist)//2}')
        # plt.plot(2*dmap[len(dmap)//2], label=f'dmap 1D cut (x2), row {len(dmap)//2}')
        # plt.plot((pre_ao_dist + (2*dmap))[len(dmap)//2], label='difference')
        # plt.legend()
        # plt.xlim(sp.grid_size//2*np.array([1-sp.beam_ratio*1.1, 1+sp.beam_ratio*1.1]))
        # quick2D(pre_ao + (2*dmap), title='diff', zlabel='m', show=False, vlim=(-0.5e-7,0.5e-7))
        # quick2D(post_ao, title='unwrapped wavefront after DM', zlabel='m', show=True, vlim=(-0.5e-7,0.5e-7))
        # quick2D(np.abs(proper.prop_get_amplitude(wf))**2, title='wavefront after DM intensity', show=False)
        # quick2D(proper.prop_get_phase(wf), title='wavefront after DM in phase units', zlabel='Phase',
        #          show=True)  # colormap='sunlight',

    if apodize:
        hardmask_pupil(wf)

    return dmap
Beispiel #8
0
        # grid(photons, title='Spectra with MKIDs', vlim=[0,800], cmap='YlGnBu_r')

    ## =======================================================================
    # Plotting
    # =======================================================================
    # White Light, Last Timestep
    if sp.show_wframe:
        if not mp.convert_photons:
            img = np.sum(focal_plane[sp.numframes - 1],
                         axis=0)  # sum over wavelength
            quick2D(
                opx.extract_center(img),  # focal_plane[sp.numframes-1]),
                title=f"White light image at timestep {sp.numframes} \n"  # img
                f"CDI={cdi.use_cdi}, Atmos={tp.use_atmos}, Aberrations={tp.use_aber}",
                # f"Grid Size = {sp.grid_size}, Beam Ratio = {sp.beam_ratio} ",
                # f"sampling = {sampling*1e6:.4f} (um/gridpt)",
                logZ=True,
                dx=fp_sampling[0],
                vlim=(None, None),
                show=False)  # (1e-3, 1e-1)
        else:
            img = np.sum(photons[sp.numframes - 1], axis=0)
            quick2D(
                img,  # focal_plane[sp.numframes-1]),
                title=f"MEC White Light Image \n",  # img
                # f"AO={tp.use_ao}, CDI={cdi.use_cdi} ",
                # f"Grid Size = {sp.grid_size}, Beam Ratio = {sp.beam_ratio} ",
                # f"sampling = {sampling*1e6:.4f} (um/gridpt)",
                logZ=False,
                # dx=fp_sampling[0],
                zlabel='photon counts',
Beispiel #9
0
class vel():
    def __init__(self, num_samp=3):
        self.median_val = 10
        # self.multiplier = np.logspace(np.log10(0.1), np.log10(10), num_samp)
        self.multiplier = np.array([0])
        self.vals = self.multiplier * self.median_val

if __name__ == '__main__':
    metric_config = vel()
    for i, val in enumerate(metric_config.vals):
        atmp.vel = val
        name = f'{TESTDIR}/{val}'
        sim = RunMedis(name=name, product=product)
        observation = sim()

        if product == 'fields':
            grid(observation['fields'], show=False)#, vlim=(-2e-7,2e-7))

        elif product == 'photons':
            grid(sim.cam.rebin_list(observation['photons']), show=False)

            # to look at the photontable
            obs = ObsFile(iop.photonlist)
            print(obs.photonTable)
            # to plot an image of all the photons on the array
            image = obs.getPixelCountImage(integrationTime=None)['image']
            quick2D(image, show=False, title=f'{val}')

    plt.show(block=True)

Beispiel #10
0
#     np.vstack((dist, np.zeros((4)))),
#     np.vstack((np.zeros((4)), dist)),
#     -np.vstack((dist, np.zeros((4)))),
#     -np.vstack((np.zeros((4)), dist))
#  )).T
# # ap.contrast = 10**np.repeat([-3.5,-4,-4.5,-5],4)
atmp.cn_sq = 5e-11
# # ap.star_flux *= 20
# ap.contrast = np.repeat([4, 2, 1, 0.5],4)*1e-4
ap.companion = False
# tp.use_atmos = False
tp.use_ao = True
ap.star_flux *= 0.1
# sp.debug = True
sp.quick_detect = False

name = f'{TESTDIR}'
sim = RunMedis(name=name, product='fields')
observation = sim()
# grid(observation['fields'], show=False, nstd=5)#, vlim=(-2e-7,2e-7))
cam = Camera(usesave=sp.save_to_disk, product=product)
# fields = [observation['fields'][0]]*100
# fields = np.repeat(observation['fields'], 100, 0)
# dprint(fields.shape)
observation = cam(observation['fields'])
# grid(cam.rebinned_cube)
Ic = np.sum(cam.rebinned_cube, axis=(0, 1))
np.save(os.path.join(iop.testdir, 'Ic.npy'), Ic)
quick2D(Ic)
Ic = np.load(os.path.join(iop.testdir, 'Ic.npy'))
quick2D(Ic)