示例#1
0
def test_thinlens_hopkins_agree():
    # F/10 beam
    x, y = coordinates.make_xy_grid(128, diameter=10)
    dx = x[0, 1] - x[0, 0]
    r = np.hypot(x, y)
    amp = geometry.circle(5, r)
    phs = polynomials.hopkins(0, 2, 0, r / 5, 0, 1) * (
        1.975347661 * HeNe * 1000)  # 1000, nm to um
    wf = propagation.Wavefront.from_amp_and_phase(amp, phs, HeNe, dx)

    # easy case is to choose thin lens efl = 10,000
    # which will result in an overall focal length of 99.0 mm
    # solve defocus delta z relation, then 1000 = 8 * .6328 * 100 * x
    #                                  x = 1000 / 8 / .6328 / 100
    #                                    = 1.975347661
    psf = wf.focus(efl=100, Q=2).intensity

    no_phs_wf = propagation.Wavefront.from_amp_and_phase(amp, None, HeNe, dx)
    # bea
    tl = propagation.Wavefront.thin_lens(10_000, HeNe, x, y)
    wf = no_phs_wf * tl
    psf2 = wf.focus(efl=100, Q=2).intensity

    # lo and behold all ye who read this test, the lies of physical optics modeling
    # did the beam propagate 100, or 99 millimeters?
    # is the PSF we're looking at in the z=100 plane, or the z=99 plane?
    # the answer is simply a matter of interpretation,
    # if the phase screen for the thin lens is in your mind as a way of going
    # to z=99, then we are in the z=99 plane.
    # if the lens is really there, we are in the z=100 plane.
    assert np.allclose(psf.data, psf2.data, rtol=1e-5)
示例#2
0
def test_circle_correct_area():
    x, y = coordinates.make_xy_grid(256, diameter=2)
    r, _ = coordinates.cart_to_polar(x, y)
    mask = geometry.circle(1, r)
    expected_area_of_circle = x.size * 3.14
    # sum is integer quantized, binary mask, allow one half quanta of error
    assert pytest.approx(mask.sum(), expected_area_of_circle, abs=0.5)
示例#3
0
def test_diffprop_matches_airydisk(efl, epd, wvl):
    fno = efl / epd
    x, y = make_xy_grid(128, diameter=epd)
    r, t = cart_to_polar(x, y)
    amp = circle(epd/2, r)
    wf = Wavefront.from_amp_and_phase(amp/amp.sum(), None, wvl, x[0, 1] - x[0, 0])
    psf = wf.focus(efl, Q=3)
    s = psf.intensity.slices()
    u_, sx = s.x
    u_, sy = s.y
    analytic = airydisk(u_, fno, wvl)
    assert np.allclose(sx, analytic, atol=PRECISION)
    assert np.allclose(sy, analytic, atol=PRECISION)
示例#4
0
def test_diffprop_matches_analyticmtf(efl, epd, wvl):
    fno = efl / epd
    x, y = make_xy_grid(128, diameter=epd)
    r, t = cart_to_polar(x, y)
    amp = circle(epd/2, r)
    wf = Wavefront.from_amp_and_phase(amp, None, wvl, x[0, 1] - x[0, 0])
    psf = wf.focus(efl, Q=3).intensity
    mtf = mtf_from_psf(psf.data, psf.dx)
    s = mtf.slices()
    u_, sx = s.x
    u_, sy = s.y

    analytic_1 = diffraction_limited_mtf(fno, wvl, frequencies=u_)
    analytic_2 = diffraction_limited_mtf(fno, wvl, frequencies=u_)
    assert np.allclose(analytic_1, sx, atol=PRECISION)
    assert np.allclose(analytic_2, sy, atol=PRECISION)
示例#5
0
def test_array_orientation_consistency_tilt():
    """The pupil array should be shaped as arr[y,x], as should the psf and MTF.

        A linear phase error in the pupil along y should cause a motion of the
        PSF in y.  Specifically, for a positive-signed phase, that should cause
        a shift in the +y direction.
    """
    N = 128
    wvl = .5
    Q = 3
    x, y = make_xy_grid(N, diameter=2.1)
    r, t = cart_to_polar(x, y)
    amp = circle(1, r)
    wf = Wavefront.from_amp_and_phase(amp, None, wvl, x[0, 1] - x[0, 0])
    psf = wf.focus(1, Q=Q).intensity
    idx_y, idx_x = np.unravel_index(psf.data.argmax(), psf.data.shape)  # row-major y, x
    assert idx_x == (N*Q) // 2
    assert idx_y > N // 2
psize = pixel_pitch / oversampling

# PSF_domain_res will be output_res*oversampling
# Pupil domain samples will be (PSF_domain_res)/Q_forward
samples = ceil(output_res * oversampling / Q_forward)

# Find pupil dx from wanted psize
pup_dx = psf_sample_to_pupil_sample(psize, samples, wlen, f)

# Construct pupil grid, convert to polar, construct normalized r for phase
xi, eta = make_xy_grid(samples, dx=pup_dx)
r, theta = cart_to_polar(xi, eta)
norm_r = r / lens_R

# Construct amplitude function of pupil function
amp = circle(lens_R, r)
amp = amp / amp.sum()

# Construct phase mode
aber = zernike_nm(4, 0, norm_r, theta)  # spherical aberration
# Scale phase mode to desired opd
phase = aber * wlen / 16 * 1e3

# Construct pupil function from amp and phase functions, propagate to PSF plane, take square modulus.
P = Wavefront.from_amp_and_phase(amp, phase, wlen, pup_dx)
coherent_PSF = P.focus(f, Q=Q_forward)
PSF = coherent_PSF.intensity

# Plot PSF
PSF_radius = 1.22 * wlen * fno
PSF.plot2d(xlim=5 * PSF_radius, cmap='gray', clim=(0, .1))
示例#7
0
def sample_i_mutate():
    i = Interferogram.from_zygo_dat(sample_files('dat'))
    return i.mask(circle(
        40,
        i.r)).crop().remove_piston().remove_tiptilt().remove_power().fill()
示例#8
0
def test_crop_mask_works():
    z = np.random.rand(32, 32)
    i = Interferogram(z, dx=1)
    i.mask(circle(10, i.r))
    i.crop()
    assert i