Beispiel #1
0
    def _make_mtf_vs_field_vs_focus(self, num_fields, focus_range, num_focus,
                                    freqs):
        ''' TODO: docstring
        '''
        self._uniformly_spaced_fields(num_fields)
        net_mtfs = [None] * num_fields
        for idx in range(num_fields):
            focus, net_mtfs[idx] = self._make_mtf_thrufocus(
                idx, focus_range, num_focus)

        fields = (self.fields[-1] * self.fov_y) * m.linspace(0, 1, num_fields)
        t_cube = m.empty((num_focus, num_fields, len(freqs)))
        s_cube = m.empty((num_focus, num_fields, len(freqs)))
        for idx, mtfs in enumerate(net_mtfs):
            for idx2, submtf in enumerate(mtfs):
                t = submtf.exact_polar(freqs, 0)
                s = submtf.exact_polar(freqs, 90)
                t_cube[idx2, idx, :] = t
                s_cube[idx2, idx, :] = s

        TCube = MTFvFvF(data=t_cube,
                        focus=focus,
                        field=fields,
                        freq=freqs,
                        azimuth='Tan')
        SCube = MTFvFvF(data=s_cube,
                        focus=focus,
                        field=fields,
                        freq=freqs,
                        azimuth='Sag')
        return TCube, SCube
Beispiel #2
0
    def mtf_vs_field(self, num_pts, freqs=[10, 20, 30, 40, 50]):
        ''' Generates a 2D array of MTF vs field values for the given spatial
            frequencies.

        Args:
            num_pts (`int`): Number of points to compute the MTF at.

            freqs (`iterable`): set of frequencies to compute at.

        Returns:
            `tuple` containing:

                `numpy.ndarray` (Tan) a 3D ndnarray where the columns
                    correspond to fields and the rows correspond to spatial
                    frequencies.

                `numpy.ndarray` (Sag) a 3D ndnarray where the columns
                    correspond to fields and the rows correspond to spatial
                    frequencies.

        '''
        self._uniformly_spaced_fields(num_pts)
        mtfs_t = m.empty((num_pts, len(freqs)))
        mtfs_s = m.empty((num_pts, len(freqs)))
        for idx in range(num_pts):
            mtf = self._make_mtf(idx)
            vals_t = mtf.exact_polar(freqs, 0)
            vals_s = mtf.exact_polar(freqs, 90)
            mtfs_t[idx, :] = vals_t
            mtfs_s[idx, :] = vals_s

        return mtfs_s, mtfs_t
Beispiel #3
0
def thrufocus_mtf_from_wavefront_array(focused_wavefront, sim_params):
    """Create a thru-focus T/S MTF curve at each frequency requested from a focused wavefront.

    TODO: refactor

    Parameters
    ----------
    focused_wavefront : `Pupil`
        a pupil object

    sim_params : `SimulationConfig`
        a SimulationConfig namedtuple

    Returns
    -------
    `pandas.DataFrame`
        dataframe of data

    Notes
    -----
    see marcros.DEFAULT_SIM_PARAMS for an example config.

    """
    s = sim_params
    focusdiv_wvs = m.linspace(-s.focus_range_waves, s.focus_range_waves, s.focus_planes)
    tt, ss = m.empty((s.focus_planes, len(s.freqs))), m.empty((s.focus_planes, len(s.freqs)))
    for idx, focus in enumerate(focusdiv_wvs):
        if s.focus_zernike:
            defocus = FringeZernike(base=1, Z4=focus, rms_norm=s.focus_normed, samples=s.samples,
                                    epd=s.efl / s.fno,
                                    wavelength=s.wvl)
        else:
            defocus = Seidel(W020=focus,
                             epd=s.efl / s.fno,
                             samples=s.samples,
                             wavelength=s.wvl)
        mtf = MTF.from_pupil(focused_wavefront + defocus, efl=s.efl)
        tan, sag = mtf_ts_extractor(mtf, s.freqs)
        tt[idx, :] = tan
        ss[idx, :] = sag

    return tt, ss
Beispiel #4
0
    def plot2d_rgbgrid(self,
                       axlim=25,
                       interp_method='lanczos',
                       pix_grid=None,
                       fig=None,
                       ax=None):
        """Create a 2D color plot of the PSF and R,G,B components.

        Parameters
        ----------
        axlim : `float`
            limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim)
        interp_method : `str`
            method used to interpolate the image between samples of the PSF
        pix_grid : float
            if not None, overlays gridlines with spacing equal to pix_grid.
            Intended to show the collection into camera pixels while still in
            the oversampled domain
        fig : `matplotlib.figure.Figure`, optional
            Figure containing the plot
        ax : `matplotlib.axes.Axis`, optional:
            Axis containing the plot

        fig : `matplotlib.figure.Figure`, optional
            Figure containing the plot
        ax : `matplotlib.axes.Axis`, optional:
            Axis containing the plot

        Notes
        -----
        Need to refine internal workings at some point.

        """
        # make the arrays for the RGB images
        dat = m.empty((self.samples_y, self.samples_x, 3))
        datr = m.zeros((self.samples_y, self.samples_x, 3))
        datg = m.zeros((self.samples_y, self.samples_x, 3))
        datb = m.zeros((self.samples_y, self.samples_x, 3))
        dat[:, :, 0] = self.R
        dat[:, :, 1] = self.G
        dat[:, :, 2] = self.B
        datr[:, :, 0] = self.R
        datg[:, :, 1] = self.G
        datb[:, :, 2] = self.B

        left, right = self.unit[0], self.unit[-1]
        ax_width = 2 * axlim

        # generate a figure and axes to plot in
        fig, ax = share_fig_ax(fig, ax)
        axr, axg, axb = make_rgb_axes(ax)

        ax.imshow(dat,
                  extent=[left, right, left, right],
                  interpolation=interp_method,
                  origin='lower')

        axr.imshow(datr,
                   extent=[left, right, left, right],
                   interpolation=interp_method,
                   origin='lower')
        axg.imshow(datg,
                   extent=[left, right, left, right],
                   interpolation=interp_method,
                   origin='lower')
        axb.imshow(datb,
                   extent=[left, right, left, right],
                   interpolation=interp_method,
                   origin='lower')

        for axs in (ax, axr, axg, axb):
            ax.set(xlim=(-axlim, axlim), ylim=(-axlim, axlim))
            if pix_grid is not None:
                # if pixel grid is desired, add it
                mult = m.m.floor(axlim / pix_grid)
                gmin, gmax = -mult * pix_grid, mult * pix_grid
                pts = m.arange(gmin, gmax, pix_grid)
                ax.set_yticks(pts, minor=True)
                ax.set_xticks(pts, minor=True)
                ax.yaxis.grid(True, which='minor')
                ax.xaxis.grid(True, which='minor')
        ax.set(xlabel=r'Image Plane X [$\mu m$]',
               ylabel=r'Image Plane Y [$\mu m$]')
        axr.text(-axlim + 0.1 * ax_width,
                 axlim - 0.2 * ax_width,
                 'R',
                 color='white')
        axg.text(-axlim + 0.1 * ax_width,
                 axlim - 0.2 * ax_width,
                 'G',
                 color='white')
        axb.text(-axlim + 0.1 * ax_width,
                 axlim - 0.2 * ax_width,
                 'B',
                 color='white')
        return fig, ax
Beispiel #5
0
    def plot2d(self,
               axlim=25,
               interp_method='lanczos',
               pix_grid=None,
               fig=None,
               ax=None):
        '''Create a 2D color plot of the PSF.

        Parameters
        ----------
        axlim : `float`
            limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim)
        interp_method : `str`
            method used to interpolate the image between samples of the PSF
        pix_grid : `float`
            if not None, overlays gridlines with spacing equal to pix_grid.
            Intended to show the collection into camera pixels while still in
            the oversampled domain
        fig : `matplotlib.figure.Figure`, optional
            Figure containing the plot
        ax : `matplotlib.axes.Axis`, optional:
            Axis containing the plot

        Returns
        -------
        fig : `matplotlib.figure.Figure`, optional
            Figure containing the plot
        ax : `matplotlib.axes.Axis`, optional:
            Axis containing the plot

        '''
        dat = m.empty((self.samples_x, self.samples_y, 3))
        dat[:, :, 0] = self.R
        dat[:, :, 1] = self.G
        dat[:, :, 2] = self.B

        left, right = self.unit_y[0], self.unit_y[-1]
        bottom, top = self.unit_x[0], self.unit_x[-1]

        fig, ax = share_fig_ax(fig, ax)

        ax.imshow(dat,
                  extent=[left, right, bottom, top],
                  interpolation=interp_method,
                  origin='lower')
        ax.set(xlabel=r'Image Plane X [$\mu m$]',
               ylabel=r'Image Plane Y [$\mu m$]',
               xlim=(-axlim, axlim),
               ylim=(-axlim, axlim))

        if pix_grid is not None:
            # if pixel grid is desired, add it
            mult = m.floor(axlim / pix_grid)
            gmin, gmax = -mult * pix_grid, mult * pix_grid
            pts = m.arange(gmin, gmax, pix_grid)
            ax.set_yticks(pts, minor=True)
            ax.set_xticks(pts, minor=True)
            ax.yaxis.grid(True, which='minor')
            ax.xaxis.grid(True, which='minor')

        return fig, ax
Beispiel #6
0
def radial_mtf_to_mtfffd_data(tan, sag, imagehts, azimuths, upsample):
    """Take radial MTF data and map it to inputs to the MTFFFD constructor.

    Performs upsampling/interpolation in cartesian coordinates

    Parameters
    ----------
    tan : `np.ndarray`
        tangential data
    sag : `np.ndarray`
        sagittal data
    imagehts : `np.ndarray`
        array of image heights
    azimuths : iterable
        azimuths corresponding to the first dimension of the tan/sag arrays
    upsample : `float`
        upsampling factor

    Returns
    -------
    out_x : `np.ndarray`
        x coordinates of the output data
    out_y : `np.ndarray`
        y coordinates of the output data
    tan : `np.ndarray`
        tangential data
    sag : `np.ndarray`
        sagittal data

    """
    azimuths = m.asarray(azimuths)
    imagehts = m.asarray(imagehts)

    if imagehts[0] > imagehts[-1]:
        # distortion profiled, values "reversed"
        # just flip imagehts, since spacing matters and not exact values
        imagehts = imagehts[::-1]
    amin, amax = min(azimuths), max(azimuths)
    imin, imax = min(imagehts), max(imagehts)
    aq = m.linspace(amin, amax, int(len(azimuths) * upsample))
    iq = m.linspace(imin, imax, int(
        len(imagehts) * 4))  # hard-code 4x linear upsample, change later
    aa, ii = m.meshgrid(aq, iq, indexing='ij')

    # for each frequency, build an interpolating function and upsample
    up_t = m.empty((len(aq), tan.shape[1], len(iq)))
    up_s = m.empty((len(aq), sag.shape[1], len(iq)))
    for idx in range(tan.shape[1]):
        t, s = tan[:, idx, :], sag[:, idx, :]
        interpft = RGI((azimuths, imagehts), t, method='linear')
        interpfs = RGI((azimuths, imagehts), s, method='linear')
        up_t[:, idx, :] = interpft((aa, ii))
        up_s[:, idx, :] = interpfs((aa, ii))

    # compute the locations of the samples on a cartesian grid
    xd, yd = m.outer(m.cos(m.radians(aq)),
                     iq), m.outer(m.sin(m.radians(aq)), iq)
    samples = m.stack([xd.ravel(), yd.ravel()], axis=1)

    # for the output cartesian grid, figure out the x-y coverage and build a regular grid
    absamin = min(abs(azimuths))
    closest_to_90 = azimuths[m.argmin(azimuths - 90)]
    xfctr = m.cos(m.radians(absamin))
    yfctr = m.cos(m.radians(closest_to_90))
    xmin, xmax = imin * xfctr, imax * xfctr
    ymin, ymax = imin * yfctr, imax * yfctr
    xq, yq = m.linspace(xmin, xmax, len(iq)), m.linspace(ymin, ymax, len(iq))
    xx, yy = m.meshgrid(xq, yq)

    outt, outs = [], []
    # for each frequency, interpolate onto the cartesian grid
    for idx in range(up_t.shape[1]):
        datt = griddata(samples,
                        up_t[:, idx, :].ravel(), (xx, yy),
                        method='linear')
        dats = griddata(samples,
                        up_s[:, idx, :].ravel(), (xx, yy),
                        method='linear')
        outt.append(datt.reshape(xx.shape))
        outs.append(dats.reshape(xx.shape))

    outt, outs = m.rollaxis(m.asarray(outt), 0,
                            3), m.rollaxis(m.asarray(outs), 0, 3)
    return xq, yq, outt, outs