Example #1
0
 def set_phase_map(self, z_coef, rho_zern=1., PV_rescale=True, PV_goal=50):
     """
     Generates a phase map based on Zernike polynomials
     This usually represents an NCPA map
     Uses the fast methods implemented in zern_core.py
     :param z_coef: coefficient of the Zernike series expansion
     :param PV_goal: desired Peak-To-Valley [nm] of the phase map
     """
     # Construct the base phase map
     self.zern_model = zern.ZernikeNaive(mask=self.pupil_mask)
     phase_map = self.zern_model(coef=z_coef,
                                 rho=self.rho_m / rho_zern,
                                 theta=self.theta_m,
                                 normalize_noll=False,
                                 mode='Jacobi',
                                 print_option='Silent')
     if PV_rescale:
         # Compute the current PV and rescale the coefficients
         current_pv = np.max(phase_map[np.nonzero(phase_map)]) - np.min(
             phase_map[np.nonzero(phase_map)])
         # Remember that at this point the phase map is a 1D array (a masked 2D)
         phase_map = zern.rescale_phase_map(phase_map, peak=PV_goal / 2)
         self.ncpa_coef = self.zern_model.coef * (PV_goal / current_pv
                                                  )  # Save the coefficients
         self.phase_map = zern.invert_mask(phase_map, self.pupil_mask)
     else:
         self.phase_map = zern.invert_mask(phase_map, self.pupil_mask)
         self.ncpa_coef = self.zern_model.coef
Example #2
0
    def __init__(self, N_zern, initial_state):

        ### Zernike Wavefront
        x = np.linspace(-1, 1, self.N_pix, endpoint=True)
        xx, yy = np.meshgrid(x, x)
        rho, theta = np.sqrt(xx**2 + yy**2), np.arctan2(xx, yy)
        self.pupil = rho <= self.rho_aper
        rho, theta = rho[self.pupil], theta[self.pupil]
        zernike = zern.ZernikeNaive(mask=self.pupil)
        _phase = zernike(coef=np.zeros(N_zern + 3),
                         rho=rho / self.rho_aper,
                         theta=theta,
                         normalize_noll=False,
                         mode='Jacobi',
                         print_option='Silent')
        H_flat = zernike.model_matrix[:, 3:]  # remove the piston and tilts
        self.H_matrix = zern.invert_model_matrix(H_flat, self.pupil)

        # Update the number of aberrations to match the dimensions of H
        self.N = N_zern
        self.N_zern = self.H_matrix.shape[-1]

        self.PEAK = self.peak_PSF()

        # Keep track of the STATE of the system
        self.state = initial_state.copy()
def rand_zern(randker):
    N = 48
    N_zern = 10
    rho_max = 0.9
    eps_rho = 1.4
    randgen = RandomState(randker)
    extents = [-1, 1, -1, 1]

    # Construct the coordinates
    x = np.linspace(-rho_max, rho_max, N)
    rho_spacing = x[1] - x[0]
    xx, yy = np.meshgrid(x, x)
    rho = np.sqrt(xx ** 2 + yy ** 2)
    theta = np.arctan2(xx, yy)
    aperture_mask = rho <= eps_rho * rho_max
    rho, theta = rho[aperture_mask], theta[aperture_mask]
    rho_max = np.max(rho)
    extends = [-rho_max, rho_max, -rho_max, rho_max]

    # Compute the Zernike series
    coef = randgen.normal(size=N_zern)
    z = zern.ZernikeNaive(mask=aperture_mask)
    phase_map = z(coef=coef, rho=rho, theta=theta, normalize_noll=False, mode='Jacobi', print_option='Silent')
    phase_map = zern.rescale_phase_map(phase_map, peak=1)
    phase_2d = zern.invert_mask(phase_map, aperture_mask)

    return phase_2d
Example #4
0
    def __init__(self, N_zern, initial_state, DM_stroke=0.05):
        """
        Q-learning is based on DISCRETE actions. Therefore, if we want to correct for
        Zernike aberrations which are continuous, we have to discretize the action space

        :param N_zern: Number of Zernike aberrations we are expected to correct
        :param DM_stroke: Deformable Mirror correction step in waves
        """
        aberration_correction = [DM_stroke, -DM_stroke]
        self.ACTION = N_zern * aberration_correction

        ### Initialize Zernike polynomials

        x = np.linspace(-1, 1, self.N_pix, endpoint=True)
        xx, yy = np.meshgrid(x, x)
        rho, theta = np.sqrt(xx**2 + yy**2), np.arctan2(xx, yy)
        self.pupil = rho <= self.rho_aper
        rho, theta = rho[self.pupil], theta[self.pupil]
        zernike = zern.ZernikeNaive(mask=self.pupil)
        _phase = zernike(coef=np.zeros(N_zern + 3),
                         rho=rho / self.rho_aper,
                         theta=theta,
                         normalize_noll=False,
                         mode='Jacobi',
                         print_option='Silent')
        H_flat = zernike.model_matrix[:, 3:]  # remove the piston and tilts
        self.H_matrix = zern.invert_model_matrix(H_flat, self.pupil)

        # Update the number of aberrations to match the dimensions of H
        self.N_zern = self.H_matrix.shape[-1]

        self.PEAK = self.peak_PSF()
        self.initial_state = initial_state
        self.state = [initial_state]
        self.rewards = [0]
Example #5
0
        def create_model_matrix(self, N_zern):
            """
            Watch out because the matrices are in polar coordinates
            :param N_zern:
            :return:
            """

            _coef = np.zeros(N_zern)
            z = zern.ZernikeNaive(mask=np.ones((N, N)))
            _phase = z(coef=_coef,
                       rho=self.rho,
                       theta=self.theta,
                       normalize_noll=False,
                       mode='Jacobi',
                       print_option=None)
            self.model_matrix_flat = z.model_matrix
            self.model_matrix = zern.invert_model_matrix(
                z.model_matrix, np.ones((N, N)))
            self.N_zern = self.model_matrix.shape[-1]
Example #6
0
extents = [-1, 1, -1, 1]

# Construct the coordinates
x = np.linspace(-rho_max, rho_max, N)
rho_spacing = x[1] - x[0]
xx, yy = np.meshgrid(x, x)
rho = np.sqrt(xx**2 + yy**2)
theta = np.arctan2(xx, yy)
aperture_mask = rho <= eps_rho * rho_max
rho, theta = rho[aperture_mask], theta[aperture_mask]
rho_max = np.max(rho)
extends = [-rho_max, rho_max, -rho_max, rho_max]

# Compute the Zernike series
coef = randgen.normal(size=N_zern)
z = zern.ZernikeNaive(mask=aperture_mask)
phase_map = z(coef=coef,
              rho=rho,
              theta=theta,
              normalize_noll=False,
              mode='Jacobi',
              print_option=None)

# phase_map = zern.rescale_phase_map(phase_map, peak=1)
phase_2d = zern.invert_mask(phase_map, aperture_mask)

# Introduce some noise in the map
noised_phase_map = phase_map + 0.5 * np.random.normal(size=phase_map.shape[0])
noised_2d = zern.invert_mask(noised_phase_map, aperture_mask)

plt.figure()
if __name__ == "__main__":

    x = np.linspace(-Luv / 2, Luv / 2, N_pix, endpoint=True)

    xx, yy = np.meshgrid(x, x)
    r = np.sqrt(xx**2 + yy**2)
    theta = np.arctan2(xx, yy)

    pupil_mask = xx**2 + yy**2 <= rho**2
    r, theta = r[pupil_mask], theta[pupil_mask]

    # Initialize the ZernikeNaive to get access to the Model Matrix
    np.random.seed(123)
    coef = np.random.normal(size=N_zern)
    z = zern.ZernikeNaive(mask=pupil_mask)
    _phase = z(coef=coef,
               rho=r / rho_zern,
               theta=theta,
               normalize_noll=False,
               mode='Jacobi',
               print_option='Silent')

    # ==================================================================================================================
    """ Model matrix for Zernike polynomials """

    # H contains the Zernike Polynomials
    H = reshape_model_matrix(z.model_matrix, pupil_mask)
    N_zern = H.shape[-1]
    print('Using %d Zernikes' % N_zern)
Example #8
0
def evaluate_wavefront_performance(N_zern,
                                   test_coef,
                                   guessed_coef,
                                   zern_list,
                                   twisted=False,
                                   show_predic=False):
    """
    Evaluates the performance of the ML method regarding the final
    RMS wavefront error. Compares the initial RMS NCPA and the residual
    after correction
    """

    # Transform the ordering to match the Zernike matrix
    new_test_coef = transform_zemax_to_noll(test_coef, twisted=False)
    new_guessed_coef = transform_zemax_to_noll(guessed_coef, twisted)

    x = np.linspace(-1, 1, 512, endpoint=True)
    xx, yy = np.meshgrid(x, x)
    rho, theta = np.sqrt(xx**2 + yy**2), np.arctan2(xx, yy)
    pupil = rho <= 1.0
    rho, theta = rho[pupil], theta[pupil]
    zernike = zern.ZernikeNaive(mask=pupil)
    _phase = zernike(coef=np.zeros(new_test_coef.shape[1] + 3),
                     rho=rho,
                     theta=theta,
                     normalize_noll=False,
                     mode='Jacobi',
                     print_option='Silent')
    H_flat = zernike.model_matrix[:, 3:]  # remove the piston and tilts
    H_matrix = zern.invert_model_matrix(H_flat, pupil)
    # print(H_flat.shape)

    # Elliptical mask
    ellip_mask = (xx / 0.5)**2 + (yy / 1.)**2 <= 1.0

    H_flat = H_matrix[ellip_mask]
    # print(H_flat.shape)

    N = test_coef.shape[0]
    initial_rms = np.zeros(N)
    residual_rms = np.zeros(N)

    for k in range(N):
        phase = np.dot(H_flat, new_test_coef[k])
        residual_phase = phase - np.dot(H_flat, new_guessed_coef[k])
        before, after = np.std(phase), np.std(residual_phase)
        initial_rms[k] = before
        residual_rms[k] = after

    average_initial_rms = np.mean(initial_rms)
    average_residual_rms = np.mean(residual_rms)
    improvement = (average_initial_rms -
                   average_residual_rms) / average_initial_rms * 100

    print('\nWAVEFRONT PERFORMANCE DATA')
    print('\nNumber of samples in TEST dataset: %d' % N)
    print('Average INITIAL RMS: %.3f waves (%.1f nm @1.5um)' %
          (average_initial_rms, average_initial_rms * wave_nom))
    print('Average RESIDUAL RMS: %.3f waves (%.1f nm @1.5um)' %
          (average_residual_rms, average_residual_rms * wave_nom))
    print('Improvement: %.2f percent' % improvement)

    if show_predic == True:

        plt.figure()
        plt.scatter(range(N),
                    initial_rms * wave_nom,
                    c='red',
                    s=6,
                    label='Before')
        plt.scatter(range(N),
                    residual_rms * wave_nom,
                    c='blue',
                    s=6,
                    label='After')
        plt.xlabel('Test PSF')
        plt.xlim([0, N])
        plt.ylim(bottom=0)
        plt.ylabel('RMS wavefront [nm]')
        # plt.title(r'$\lambda=1.5$ $\mu$m (defocus: 0.20 waves)')
        plt.legend(title='Calibration stage')

        N_ok = (np.argwhere(residual_rms * wave_nom < 100)).shape[0]
        plt.figure()
        plt.scatter(initial_rms * wave_nom,
                    residual_rms * wave_nom,
                    c='blue',
                    s=8)
        plt.axhline(y=100, linestyle='--')
        plt.xlabel('Initial RMS [nm]')
        plt.ylabel('Residual RMS [nm]')
        plt.title('%d / %d cases with RMS < 100 nm' % (N_ok, N))
        plt.ylim(bottom=0)

        plt.figure()
        n_bins = 20
        for k in range(N_zern):
            guess = guessed_coef[:, k]
            coef = test_coef[:, k]
            residual = coef - guess
            mu, s2 = np.mean(residual), (np.std(residual))
            label = zern_list[k] + r'  ($\mu$=%.3f, $\sigma$=%.2f)' % (mu, s2)
            plt.hist(residual, histtype='step', label=label)
        plt.legend(title=r'Residual aberrations [waves]', loc=2)
        plt.xlabel(r'Residual [waves]')
        plt.xlim([-0.075, 0.075])

        for k in range(N_zern):
            guess = guessed_coef[:, k]
            coef = test_coef[:, k]

            colors = wave_nom * residual_rms
            colors -= colors.min()
            colors /= colors.max()
            colors = cm.rainbow(colors)

            plt.figure()
            ss = plt.scatter(coef, guess, c=colors, s=20)
            x = np.linspace(-0.10, 0.10, 10)
            # plt.colorbar(ss)
            plt.plot(x, x, color='black', linestyle='--')
            title = zern_list[k]
            plt.title(title)
            plt.xlabel('True Value [waves]')
            plt.ylabel('Predicted Value [waves]')
            plt.xlim([-0.10, 0.10])
            plt.ylim([-0.10, 0.10])

    return initial_rms, residual_rms
Example #9
0
"""

import numpy as np
import matplotlib.pyplot as plt
import zern_core as zern

# Parameters
N = 1024
N_zern = 100
rho_max = 1.0
mask = []

# Construct the coordinates
rho = np.linspace(0., rho_max, N)

Z_naive = zern.ZernikeNaive(mask)

# Zernike orders
n_list = [40, 44, 48]
m = 0
n_max = 101

# for n in n_list:
#     # Compute the Radial Zernike R_nm
#     R_naive = Z_naive.R_nm(n, m, rho)
#     R_jacobi = Z_naive.R_nm_Jacobi(n, m, rho)
#
#     plt.figure()
#     plt.plot(rho, R_naive, label='Standard')
#     plt.plot(rho, R_jacobi, label='Jacobi')
#     plt.legend()
    randgen = RandomState(1234)

    coef = randgen.normal(size=N_zern)
    print('First 10 Zernike coefficients')
    print(coef[:10])

    # --------------------------------------------------------------------
    """ Plot the Wavefront in Polar coordinates """

    rho_1 = np.linspace(0.0, 1.0, N, endpoint=True)
    theta_1 = np.linspace(0.0, 2 * np.pi, N)

    rr, tt = np.meshgrid(rho_1, theta_1)
    rho, theta = rr.flatten(), tt.flatten()

    z = zern.ZernikeNaive(mask=np.ones((N, N)))
    phase = z(coef=coef, rho=rho, theta=theta, normalize_noll=False, mode='Jacobi', print_option=None)
    phase_map = phase.reshape((N, N))

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.imshow(phase_map, origin='lower', cmap='viridis', extent=[0, 1, 0, 2 * np.pi])
    ax.set_aspect('auto')
    plt.xlabel(r'Radius $\rho$')
    plt.ylabel(r'Angle $\theta$')
    # plt.title('Wavefront map in Polar Coordinates')

    # --------------------------------------------------------------------
    """ Plot the Wavefront in Cartesian coordinates """

    xx = rr * np.cos(tt)
Example #11
0
    path_prelim = os.path.abspath(
        'D:/Thesis/LAM/POP/Slicer/0 Preliminary Tasks')
    N_slices = len(list_slices)

    # ===================

    x = np.linspace(-1, 1, 1024, endpoint=True)
    xx, yy = np.meshgrid(x, x)
    rho_circ, theta_circ = np.sqrt((xx)**2 + yy**2), np.arctan2(xx, yy)
    rho_elli, theta_elli = np.sqrt((xx)**2 + (2 * yy)**2), np.arctan2(xx, yy)
    pupil_circ = rho_circ <= 1.0
    pupil_elli = rho_elli <= 1.0

    ### Clipped Defocus
    rho_circ, theta_circ = rho_circ[pupil_circ], theta_circ[pupil_circ]
    zernike = zern.ZernikeNaive(mask=pupil_circ)
    _phase = zernike(coef=np.zeros(50),
                     rho=rho_circ,
                     theta=theta_circ,
                     normalize_noll=False,
                     mode='Jacobi',
                     print_option='Silent')
    H_flat = zernike.model_matrix  # remove the piston and tilts
    H_matrix = zern.invert_model_matrix(H_flat, pupil_circ)
    defocus_circ = H_matrix[:, :, 4].copy()

    ### Elliptic
    rho_elli, theta_elli = rho_elli[pupil_elli], theta_elli[pupil_elli]
    zernike = zern.ZernikeNaive(mask=pupil_elli)
    _phase = zernike(coef=np.zeros(25),
                     rho=rho_elli,
Example #12
0
    spaxel_scale = 0.5  # mas
    RHO_APER = rho_spaxel_scale(spaxel_scale, wavelength=wave)
    check_spaxel_scale(RHO_APER, wave)
    FWHM = compute_FWHM(wave)  # mas
    crop_pix = 5 * FWHM / spaxel_scale  # How many pixels to cover enough FWHMs
    crop_pix = int(np.ceil(crop_pix))
    """ Impact of Defocus on a Round PSF - Evolution of Rings """
    # How does the defocus intensity affect the Peak and Rings of the PSF?

    x = np.linspace(-1, 1, N_PIX, endpoint=True)
    xx, yy = np.meshgrid(x, x)
    rho, theta = np.sqrt(xx**2 + (2 * yy)**2), np.arctan2(xx, yy)
    pupil = rho <= RHO_APER
    rho, theta = rho[pupil], theta[pupil]
    zernike = zern.ZernikeNaive(mask=pupil)
    _phase = zernike(coef=np.zeros(10),
                     rho=rho / RHO_APER,
                     theta=theta,
                     normalize_noll=False,
                     mode='Jacobi',
                     print_option='Silent')
    H_flat = zernike.model_matrix[:, 3:]  # remove the piston and tilts
    H_matrix = zern.invert_model_matrix(H_flat, pupil)

    # Rescale by 1/2 to have a Peak-To-Valley of 1 wave
    defocus = 0.5 * H_matrix[:, :, 1].copy()

    # Compute nominal PSF -> Pupil = Aperture * exp(2 PI wavefront)
    pupil_nom = pupil * np.exp(2 * np.pi * 1j * np.zeros_like(pupil))
    image_nom = (np.abs(fftshift(fft2(pupil_nom))))**2
Example #13
0
    print('N_pixels: %d' % N_pix)
    print('D_ELT/L = %.2f' % eps)
    print('Wavelenght: %.1f [microns]' % wave)
    print('T exposure: %.2f' % t_exp)
    print('Max Zernikes: %d' % max_N_zern)
    print('====================================================\n')

    pupil_mask = mt.elt_mask(eps, xx, yy)

    # WATCH OUT because this rho_masked is renormalized to 1
    # so that the zern_model.model_matrix follows the convention of giving
    # Z = 1 at the borders (i.e the typical Zernike map)
    rho_masked, theta_masked = rho[pupil_mask] / eps, theta[pupil_mask]

    # Initialize the Zernike Model
    zern_model = zern.ZernikeNaive(mask=pupil_mask)
    # Use a Random vector to run it once and thus
    # initiliaze the Model Matrix H
    _coef = np.random.normal(size=max_N_zern)
    zern_model(_coef,
               rho_masked,
               theta_masked,
               normalize_noll=False,
               mode='Jacobi',
               print_option='Silent')
    H_matrix = zern_model.model_matrix
    """ ++++++++++++++++++++++++++++++++++++++++++++++++++++++ """
    """                     MACHINE LEARNING                   """
    """ ++++++++++++++++++++++++++++++++++++++++++++++++++++++ """

    smart_psf = fz.SmartPSF(zern_model=zern_model,
Example #14
0
    # Compare the IDEAL and the TRUE PSFs
    plt.figure()
    plt.subplot(121)
    plt.imshow(nom_psf, extent=extends, cmap='jet')
    plt.xlabel('X [mm]')
    plt.ylabel('Y [mm]')
    plt.title('Nominal PSF (Slicer)')

    plt.subplot(122)
    plt.imshow(pop.crop_array(image, N_pix), extent=extends, cmap='jet')
    plt.xlabel('X [mm]')
    plt.title('Ideal PSF')

    # Show an example of NCPA map
    zern_model = zern.ZernikeNaive(mask=aper_mask)
    zern_coef = np.zeros(10)
    zern_coef[4] = 0.25
    zz = zern_model(coef=zern_coef,
                    rho=rho,
                    theta=theta,
                    mode='Standard',
                    print_option=None)
    phase = zern.invert_mask(zz, aper_mask)

    H = zern_model.model_matrix

    plt.figure()
    plt.imshow(zern.invert_mask(H[:, 4], aper_mask), extent=[-1, 1, -1, 1])
    plt.xlim([-1.1 * eps, 1.1 * eps])
    plt.ylim([-1.1 * eps, 1.1 * eps])