Пример #1
0
def cie_1976_wavelength_annotations(wavelengths, fig=None, ax=None):
    ''' Draws lines normal to the spectral locust on a CIE 1976 diagram and
        writes the text for each wavelength.

    Args:
        wavelengths (`iterable`): set of wavelengths to annotate.

        fig (`matplotlib.figure.Figure`): figure to draw on.

        ax (`matplotlib.axes.Axis`): axis to draw in.

    Returns:

        `tuple` containing:

            `matplotlib.figure.Figure`: figure containing the annotations.

            `matplotlib.axes.Axis`: axis containing the annotations.

    Notes:
        see SE:
        https://stackoverflow.com/questions/26768934/annotation-along-a-curve-in-matplotlib

    '''
    # some tick parameters
    tick_length = 0.025
    text_offset = 0.06

    # convert wavelength to u' v' coordinates
    wavelengths = np.asarray(wavelengths)
    idx = np.arange(1, len(wavelengths) - 1, dtype=int)
    wvl_lbl = wavelengths[idx]
    uv = XYZ_to_uvprime(wavelength_to_XYZ(wavelengths))
    u, v = uv[..., 0][idx], uv[..., 1][idx]
    u_last, v_last = uv[..., 0][idx - 1], uv[..., 1][idx - 1]
    u_next, v_next = uv[..., 0][idx + 1], uv[..., 1][idx + 1]

    angle = atan2(v_next - v_last, u_next - u_last) + pi / 2
    cos_ang, sin_ang = cos(angle), sin(angle)
    u1, v1 = u + tick_length * cos_ang, v + tick_length * sin_ang
    u2, v2 = u + text_offset * cos_ang, v + text_offset * sin_ang

    fig, ax = share_fig_ax(fig, ax)
    tick_lines = LineCollection(np.c_[u, v, u1, v1].reshape(-1, 2, 2), color='0.25', lw=1.25)
    ax.add_collection(tick_lines)
    for i in range(len(idx)):
        ax.text(u2[i], v2[i], str(wvl_lbl[i]), va="center", ha="center", clip_on=True)

    return fig, ax
Пример #2
0
def image_dist_epd_to_na(image_distance, epd):
    '''Computes the NA from an image distance and entrance pupil diameter

    Args:
        image_distance (float): distance from the image to the entrance pupil.

        epd (float): diameter of the entrance pupil.

    Returns:
        numerical aperture.  The NA of the system.

    '''
    image_distance = guarantee_array(image_distance)

    rho = epd / 2
    marginal_ray_angle = abs(atan2(rho, image_distance))
    return marginal_ray_angle
Пример #3
0
def _get_cost_rmswfe_rrmswfe_coma_or_ast_angle(db, doc_ids, other='coma'):
    cost, rmswfe, rrmswfe, angle = [], [], [], []
    xidx, yidx = _get_idxs(other)
    for did in doc_ids:
        doc = db.get_document(did)
        tp = doc['truth_params']
        cost.append(doc['cost_final'])
        rmswfe.append(doc['truth_rmswfe'])
        rrmswfe.append((doc['rrmswfe_final']))
        angle.append(np.degrees(atan2(tp[xidx], tp[yidx])))

    cost = np.asarray(cost)
    rmswfe = np.asarray(rmswfe)
    rrmswfe = np.asarray(rrmswfe)
    angle = np.asarray(angle)

    return cost, rmswfe, rrmswfe, angle
Пример #4
0
def Luv_to_chroma_hue(luv):
    ''' Converts L*u*v* coordiantes to a chroma and hue.

    Args:
        luv (`numpy.ndarray`): array with last dimension L*, u*, v*.

    Returns:
        `numpy.ndarray` with last dimension corresponding to C* and h.

    '''
    luv = np.asarray(luv)
    u, v = luv[..., 1], luv[..., 2]
    C = sqrt(u**2 + v**2)
    h = atan2(v, u)

    shape = luv.shape
    return np.stack((C, h), axis=len(shape))
Пример #5
0
def cart_to_polar(x, y):
    ''' Returns the (rho,phi) coordinates of the (x,y) input points.

    Args:
        x (float): x coordinate.

        y (float): y coordinate.

    Returns:
        `tuple` containing:

            `float` or `numpy.ndarray`: radial coordinate.

            `float` or `numpy.ndarray`: azimuthal coordinate.

    '''
    rho = sqrt(x**2 + y**2)
    phi = atan2(y, x)
    return rho, phi
Пример #6
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(zernfcns):
        raise ValueError(f'number of terms must be less than {len(zernfcns)}')

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

    # set up an x/y rho/phi grid to evaluate zernikes on
    x, y = np.linspace(-1, 1, data.shape[1]), np.linspace(-1, 1, data.shape[0])
    xv, yv = np.meshgrid(x, y)
    rho = sqrt(xv**2 + yv**2)[pts].flatten()
    phi = atan2(xv, yv)[pts].flatten()

    # compute each zernike term
    zernikes = []
    for i in range(num_terms):
        zernikes.append(zernwrapper(i, rms_norm, rho, phi))
    zerns = np.asarray(zernikes).T

    # use least squares to compute the coefficients
    coefs = np.linalg.lstsq(zerns, data[pts].flatten())[0]
    return coefs.round(round_at)
Пример #7
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, atan2(y, x))