Esempio n. 1
0
def fit(data, num_terms=16, rms_norm=False, round_at=6):
    ''' Fits a number of Zernike coefficients to provided data by minimizing
        the root sum square between each coefficient and the given data.  The
        data should be uniformly sampled in an x,y grid.

    Args:

        data (`numpy.ndarray`): data to fit to.

        num_terms (`int`): number of terms to fit, fits terms 0~num_terms.

        rms_norm (`bool`): if true, normalize coefficients to unit RMS value.

        round_at (`int`): decimal place to round values at.

    Returns:
        numpy.ndarray: an array of coefficients matching the input data.

    '''
    if num_terms > len(zernmap):
        raise ValueError(f'number of terms must be less than {len(zernmap)}')

    # precompute the valid indexes in the original data
    pts = m.isfinite(data)

    # set up an x/y rho/phi grid to evaluate Zernikes on
    x, y = m.linspace(-1, 1, data.shape[1]), m.linspace(-1, 1, data.shape[0])
    xx, yy = m.meshgrid(x, y)
    rho = m.sqrt(xx**2 + yy**2)[pts].flatten()
    phi = m.arctan2(xx, yy)[pts].flatten()

    # compute each Zernike term
    zernikes = []
    for i in range(num_terms):
        func = z.zernikes[zernmap[i]]
        base_zern = func(rho, phi)
        if rms_norm:
            base_zern *= func.norm
        zernikes.append(base_zern)
    zerns = m.asarray(zernikes).T

    # use least squares to compute the coefficients
    coefs = m.lstsq(zerns, data[pts].flatten(), rcond=None)[0]
    return coefs.round(round_at)
Esempio n. 2
0
def image_dist_epd_to_na(image_distance, epd):
    """Compute the NA from an image distance and entrance pupil diameter.

    Parameters
    ----------
    image_distance : `float`
        distance from the image to the entrance pupil
    epd : `float`
        diameter of the entrance pupil

    Returns
    -------
    `float`
        numerical aperture.  The NA of the system.

    """
    image_distance = guarantee_array(image_distance)

    rho = epd / 2
    marginal_ray_angle = abs(m.arctan2(rho, image_distance))
    return marginal_ray_angle
Esempio n. 3
0
def cart_to_polar(x, y):
    '''Return the (rho,phi) coordinates of the (x,y) input points.

    Parameters
    ----------
    x : `numpy.ndarray` or number
        x coordinate
    y : `numpy.ndarray` or number
        y coordinate

    Returns
    -------
    rho : `numpy.ndarray` or number
        radial coordinate
    phi : `numpy.ndarray` or number
        azimuthal coordinate

    '''
    rho = m.sqrt(x**2 + y**2)
    phi = m.arctan2(y, x)
    return rho, phi
Esempio n. 4
0
def zernikes_to_magnitude_angle(coefs, namer):
    """Convert Fringe Zernike polynomial set to a magnitude and phase representation."""
    def mkary():  # default for defaultdict
        return m.zeros(2)

    # make a list of names to go with the coefficients
    names = [namer(i, base=0) for i in range(len(coefs))]
    combinations = defaultdict(mkary)

    # for each name and coefficient, make a len 2 array.  Put the Y or 0 degree values in the first slot
    for coef, name in zip(coefs, names):
        if name.endswith(('X', 'Y', '°')):
            newname = ' '.join(name.split(' ')[:-1])
            if name.endswith('Y'):
                combinations[newname][0] = coef
            elif name.endswith('X'):
                combinations[newname][1] = coef
            elif name[-2] == '5':  # 45 degree case
                combinations[newname][1] = coef
            else:
                combinations[newname][0] = coef
        else:
            combinations[name][0] = coef

    # now go over the combinations and compute the L2 norms and angles
    for name in combinations:
        ovals = combinations[name]
        magnitude = m.sqrt((ovals**2).sum())
        if 'Spheric' in name or 'focus' in name or 'iston' in name:
            phase = 0
        else:
            phase = m.degrees(m.arctan2(*ovals))
        values = (magnitude, phase)
        combinations[name] = values

    return dict(combinations)  # cast to regular dict for return
Esempio n. 5
0
def test_cart_to_polar(x, y):
    rho, phi = coordinates.cart_to_polar(x, y)
    assert np.allclose(rho, sqrt(x**2 + y**2))
    assert np.allclose(phi, arctan2(y, x))