예제 #1
0
def _test_cross_zernikes(testj=4, nterms=10, npix=500):
    """Verify the functions are orthogonal, by taking the
    integrals of a given Zernike times N other ones.

    Parameters :
    --------------
    testj : int
        Index of the Zernike polynomial to test against the others
    nterms : int
        Test that polynomial against those from 1 to this N
    npix : int
        Size of array to use for this test
    """

    zj = zernike.zernike1(testj, npix=npix)
    assert np.sum(
        np.isfinite(zj)) > 0, "Zernike calculation failure; all NaNs."
    zbasis = zernike.zernike_basis(nterms=nterms, npix=npix)
    for idx, z in enumerate(zbasis):
        j = idx + 1
        if j == testj or j == 1:
            continue  # discard piston term and self
        prod = z * zj
        wg = np.where(np.isfinite(prod))
        cross_sum = np.abs(prod[wg].sum())
        assert cross_sum < 1e-9, (
            "orthogonality failure, Sum[Zernike(j={}) * Zernike(j={})] = {} (> 1e-9)"
            .format(j, testj, cross_sum))
예제 #2
0
def test_cached_zernike1(nterms=10):
    radius = 1.1

    osys = poppy_core.OpticalSystem()
    osys.addPupil(optics.CircularAperture(radius=radius))
    wave = osys.inputWavefront()

    y, x = wave.coordinates()
    rho = np.sqrt(y ** 2 + x ** 2) / radius
    theta = np.arctan2(y, x)

    cached_results = []

    for j in range(1, nterms + 1):
        cached_output = zernike.cached_zernike1(j, wave.shape, wave.pixelscale, radius, outside=0.0)
        cached_results.append(cached_output)
        uncached_output = zernike.zernike1(j, rho=rho, theta=theta, outside=0.0)
        assert np.allclose(cached_output, uncached_output)

    try:
        cached_output[0, 0] = np.nan
        assert False, "Shouldn't be able to assign to a cached output array!"
    except ValueError:
        pass

    # Check that we're getting cached copies
    for j, array_ref in enumerate(cached_results, start=1):
        cached_array_ref = zernike.cached_zernike1(j, wave.shape, wave.pixelscale, radius, outside=0.0)
        assert id(array_ref) == id(cached_array_ref), "cached_zernike1 returned a new object for the same arguments"
예제 #3
0
def _test_cross_zernikes(testj=4, nterms=10, npix=500):
    """Verify the functions are orthogonal, by taking the
    integrals of a given Zernike times N other ones.

    Parameters :
    --------------
    testj : int
        Index of the Zernike polynomial to test against the others
    nterms : int
        Test that polynomial against those from 1 to this N
    npix : int
        Size of array to use for this test
    """

    Zj = zernike.zernike1(testj, npix=npix)
    Zbasis = zernike.zernike_basis(nterms=nterms, npix=npix)
    for idx, Z in enumerate(Zbasis):
        j = idx + 1
        if j == testj or j == 1:
            continue  # discard piston term and self
        prod = Z * Zj
        wg = np.where(np.isfinite(prod))
        cross_sum = np.abs(prod[wg].sum())
        assert cross_sum < 1e-9, (
            "orthogonality failure, Sum[Zernike(j={}) * Zernike(j={})] = {} (> 1e-9)".format(
                j, testj, cross_sum)
        )
예제 #4
0
def test_cached_zernike1(nterms=10):
    radius = 1.1

    osys = poppy_core.OpticalSystem()
    osys.add_pupil(optics.CircularAperture(radius=radius))
    wave = osys.input_wavefront()

    y, x = wave.coordinates()
    rho = np.sqrt(y ** 2 + x ** 2) / radius
    theta = np.arctan2(y, x)

    cached_results = []

    for j in range(1, nterms + 1):
        cached_output = zernike.cached_zernike1(j, wave.shape, wave.pixelscale, radius, outside=0.0)
        cached_results.append(cached_output)
        uncached_output = zernike.zernike1(j, rho=rho, theta=theta, outside=0.0)
        assert np.allclose(cached_output, uncached_output)

    try:
        cached_output[0, 0] = np.nan
        assert False, "Shouldn't be able to assign to a cached output array!"
    except ValueError:
        pass

    # Check that we're getting cached copies
    for j, array_ref in enumerate(cached_results, start=1):
        cached_array_ref = zernike.cached_zernike1(j, wave.shape, wave.pixelscale, radius, outside=0.0)
        assert id(array_ref) == id(cached_array_ref), "cached_zernike1 returned a new object for the same arguments"
예제 #5
0
def test_zernikes_rms(nterms=10, size=500):
    """Verify RMS(Zernike[n,m]) == 1."""
    assert np.nanstd(zernike.zernike1(1)) == 0.0, "Zernike(j=0) has nonzero RMS"
    for j in range(2, nterms):
        n, m = zernike.noll_indices(j)
        z = zernike.zernike(n, m, npix=size)
        rms = np.nanstd(z)  # exclude masked pixels
        assert abs(1.0 - rms) < 0.001, "Zernike(j={}) has RMS value of {}".format(j, rms)
예제 #6
0
def test_zernikes_rms(nterms=10, size=500):
    """Verify RMS(Zernike[n,m]) == 1."""
    assert np.nanstd(zernike.zernike1(1)) == 0.0, "Zernike(j=0) has nonzero RMS"
    for j in range(2, nterms):
        n, m = zernike.noll_indices(j)
        Z = zernike.zernike(n, m, npix=size)
        rms = np.nanstd(Z)  # exclude masked pixels
        assert 1.0 - rms < 0.001, "Zernike(j={}) has RMS value of {}".format(j, rms)
예제 #7
0
def test_ones_zernikes(nterms=10):
    """Verify the radial scaling function is correctly normalized"""
    rho = np.ones(3)
    theta = np.array([0, 1, 2])
    for j in np.arange(nterms)+1:
        n, m = zernike.noll_indices(j)
        Z = zernike.zernike1(j, rho=rho, theta=theta)
        Rs = zernike.R(n, m, rho)
        print "j=%d\tZ_(%d,%d) [1] = \t %s" % (j, n, m, str(Rs))
        assert Rs[0] == Rs[1] == Rs[2], "Radial polynomial is not radially symmetric"
예제 #8
0
def test_ones_zernikes(nterms=10):
    """Verify the radial scaling function is correctly normalized"""
    rho = np.ones(3)
    theta = np.array([0, 1, 2])
    for j in np.arange(nterms)+1:
        n, m = zernike.noll_indices(j)
        Z = zernike.zernike1(j, rho=rho, theta=theta)
        Rs = zernike.R(n, m, rho)
        print "j=%d\tZ_(%d,%d) [1] = \t %s" % (j, n, m, str(Rs))
        assert Rs[0] == Rs[1] == Rs[2], "Radial polynomial is not radially symmetric"
예제 #9
0
    def zern_seg(self, segment, vmax=150, unit='nm'):
        """ Show the Zernike terms applied to a given segment"""

        # the actual wavefront is always in units of microns.
        if unit == 'nm':
            scalefact = 1000.
        elif unit =='micron':
            scalefact = 1.0
        else:
            raise ValueError("unknown unit keyword")




        nzerns = 11
        title = "Zernike components for "+segment
        zerns = np.zeros((nzerns))
        if segment+"-decenter" in self.state.keys():
            zerns += self._move(segment, type='decenter', vector=self.state[segment+"-decenter"], return_zernikes=True)
            title += ", displacement=[%.2e, %.2e, %.2e] um" % tuple(self.state[segment+"-decenter"])
        if segment+"-tilt" in self.state.keys():
            zerns += self._move(segment, type='tilt', vector=self.state[segment+"-tilt"], return_zernikes=True)
            title += ", tilts =[%.5f, %.5f, %.5f] urad" % tuple(self.state[segment+"-tilt"])

        _log.info("Zerns: "+str(zerns))
        fig = plt.gcf()
        fig.clf()

        npix=200
        hexap = zernike.hex_aperture(npix)
        hexap[np.where(hexap == 0)] = np.nan
        cmap = matplotlib.cm.jet
        cmap.set_bad('0.5', alpha=0.0)

        for j in np.arange(nzerns)+1:
            ax = fig.add_subplot(3, 4, j, frameon=False, xticks=[], yticks=[])
            # n, m = zernike.noll_indices(j)
            Z = zernike.zernike1(j, npix=npix)
            ax.imshow(Z * zerns[j-1] * hexap*scalefact, vmin=-1*vmax, vmax=vmax, cmap=cmap)
            ax.text(npix*0.95, npix*0.8, "$Z%d$" % (j), fontsize=20, horizontalalignment='right')
            ax.text(npix*0.95, npix*0.1, "%.2e" % (zerns[j-1]), fontsize=15, horizontalalignment='right')

        fig.text(0.5, 0.95, title, horizontalalignment='center', fontsize=15)
        fig.text(0.95, 0.15, 'Segment RMS WFE = %.2f %s ' % (self.rms(segment)*(scalefact/1000), unit), fontsize=10, horizontalalignment='right')
        #fig.text(0.95, 0.05, 'OPDs scaled from %.2e - %.2e um' % (-vmax, vmax), horizontalalignment='right', fontsize=10)
        fig.text(0.95, 0.05, 'OPDs scaled from %.2f - %.2f %s' % (-vmax, vmax, unit), horizontalalignment='right', fontsize=10)

        plt.draw()
예제 #10
0
    def _apply_zernikes_to_seg(self, segment, zernike_coeffs):
        """ Apply Zernike perturbations to a given segment """
        assert(segment in self.segnames)

        iseg = np.where(self.segnames == segment)[0][0]+1  # segment index from 1 - 18
        wseg = np.where(self._segment_masks == iseg)

        # determine the X and Y zernike coefficients for each segment
        # determine the center of each segment, as the mean of the min and max X and Y values
        Y, X = np.indices(self._opdHDU.data.shape)
        cx = np.mean([X[wseg].min(), X[wseg].max()])
        cy = np.mean([Y[wseg].min(), Y[wseg].max()])

        seg_radius = (X[wseg].max()-X[wseg].min())/2.0

        _log.debug("Segment %s is centered at pixel loc (%.1f, %.1f) with radius %.1f pix" % (segment, cx, cy, seg_radius))

        Xw = X[wseg].astype(np.float64)
        Yw = Y[wseg].astype(np.float64)
        Yw -= cy
        Xw -= cx
        ang = self._rotations[segment]*np.pi/180  # This definitely has to be a positive sign,
                                                 # to get the right X, Y for locally-defined zernikes
        Xr = Xw * np.cos(ang) + Yw * np.sin(ang)
        Yr = Xw *-np.sin(ang) + Yw * np.cos(ang)

        theta = np.arctan2(Yr, Xr)
        Rw = np.sqrt(Xr**2 + Yr**2)/seg_radius

        #zernike_coeffs *= 0
        #zernike_coeffs[2]=1
        if self.remove_piston_tip_tilt:
            zernike_coeffs[0:3] = 0
        for i in range(len(zernike_coeffs)):
            zern = zernike.zernike1(i+1, rho=Rw, theta=theta, outside=0.0) * zernike_coeffs[i]
            #print "Z%d = %f" % (i+1, zernike_coeffs[i])
            self._opdHDU.data[wseg] += zern
            #self._opdHDU.data[wseg] = Yw

        outtxt="Zs=["+", ".join(['%.1e'%z for z in zernike_coeffs])+"]"
        #print outtxt
        _log.debug("     "+outtxt)