def find_actuator_defocus(self): i_ref = np.argwhere(self.wave_range == self.wave_ref)[0][0] PSF_nom = psf.PointSpreadFunction(self.raw_matrices[i_ref], N_pix=self.N_PIX, crop_pix=self.pix, diversity_coef=np.zeros(self.N_act)) # Create a Zernike model so we can mimic the defocus zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix( N_levels=5, rho_aper=self.rho_aper, rho_obsc=self.rho_obsc, N_PIX=self.N_PIX, radial_oversize=1.0) zernike_matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] plt.figure() plt.imshow(pupil_mask_zernike) PSF_zernike = psf.PointSpreadFunction(matrices=zernike_matrices, N_pix=self.N_PIX, crop_pix=self.pix, diversity_coef=np.zeros( zernike_matrix.shape[-1])) # Use Least Squares to find the actuator commands that mimic a Zernike defocus zernike_fit = calibration.Zernike_fit(PSF_zernike, PSF_nom, wavelength=self.wave_ref, rho_aper=self.rho_aper) defocus_zernike = np.zeros((1, zernike_matrix.shape[-1])) defocus_zernike[0, 1] = 1.0 defocus_actuators = zernike_fit.fit_zernike_wave_to_actuators( defocus_zernike, plot=True, cmap='bwr')[:, 0] # Update the Diversity Map on the actuator model so that it matches Defocus return defocus_actuators
if __name__ == """__main__""": plt.rc('font', family='serif') plt.rc('text', usetex=False) # (1) We begin by creating a Zernike PSF model with Defocus as diversity zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix( N_levels=5, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.1) zernike_matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] PSF_zernike = psf.PointSpreadFunction(matrices=zernike_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=np.zeros( zernike_matrix.shape[-1])) # Calculate the Actuator Centres centers = psf.actuator_centres(N_actuators, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, radial=True) N_act = len(centers[0]) psf.plot_actuators(centers, rho_aper=RHO_APER, rho_obsc=RHO_OBSC) plt.show() # Calculate the Actuator Model Matrix (Influence Functions) actuator_matrix, pupil_mask, flat_actuator = psf.actuator_matrix(
# Initialize the Zernike matrices zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix(N_levels=zernike_level, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.0) if row_by_row: # Select only a specific row (radial order) of Zernike # Number of polynomials in that last Zernike row poly_in_row = zernike_triangle[zernike_level] - zernike_triangle[zernike_level - 1] zernike_matrix = zernike_matrix[:, :, -poly_in_row:] # select only the high orders flat_zernike = flat_zernike[:, -poly_in_row:] N_zern = zernike_matrix.shape[-1] # Update the N_zern after removing Piston and Tilts matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] PSF_zern = psf.PointSpreadFunction(matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=np.zeros(N_zern)) ensquared = calculate_ensquared_energy(PSF_zern, wave, N_trials, N_rms, rms_amplitude, nominal_scale=SPAXEL_MAS, spaxel_scales=spaxel_scales) # maxes = [] # plt.figure() for data, scale, color in zip(ensquared, spaxel_scales, colors): ax.scatter(data[0], data[1], color=color, s=3, label=scale) # maxRMS = np.max(data[1]) # maxes.append(maxRMS) # maxRMS = int(np.max(maxes)) ax.set_xlabel(r'RMS wavefront [nm]') ax.set_ylabel(r'Relative Encircled Energy [per cent]') ax.legend(title='Spaxel [mas]', loc=3)
plt.rc('text', usetex=False) ### (0) Define a nominal PSF Zernike model with no anamorphic mag. Perfectly circular pupil zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix( N_levels=N_levels, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.0, anamorphic_ratio=1.0) N_zern = zernike_matrix.shape[-1] zernike_matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] PSF_zernike = psf.PointSpreadFunction(matrices=zernike_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=np.zeros( zernike_matrix.shape[-1])) defocus_zernike = np.zeros(zernike_matrix.shape[-1]) defocus_zernike[1] = diversity / (2 * np.pi) PSF_zernike.define_diversity(defocus_zernike) ### (1) Define a PSF Zernike model with anamorphic ratio of 2:1 anam_ratio = 0.5 anamorphic_matrices = psf.zernike_matrix(N_levels=N_levels, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.0, anamorphic_ratio=anam_ratio)
wave_zemax = wavelengths[0] # Rescale to physical units (* wave_zemax) then divide it to the reference wavelength # also divide by 2 Pi, since the way we compute the PSF is by multiplying the coefficients by 2 Pi test_coef = coefs * wave_zemax / WAVE / (2 * np.pi) test_coef = test_coef[:, 3:] # remove piston and tilts # (1) We begin by creating a Zernike PSF model with Defocus as diversity zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix(N_levels=N_levels, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.0) zernike_matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] N_zern = zernike_matrix.shape[-1] diversity_coef = np.zeros((zernike_matrix.shape[-1])) diversity_coef[1] = 1 / (2*np.pi) PSF_zernike = psf.PointSpreadFunction(matrices=zernike_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=diversity_coef) # For the Nominal HARMONI design, the performance is almost perfect # so if we do not rescale the coefficients, we'll get absurdly large Strehls to begin with # Thus, we should probably find a scaling law to "select" how much Strehl we want, # while keeping the same aberration content def calculate_average_strehl(alpha, coef): N_PSF = coef.shape[0] strehls = np.zeros(N_PSF) for k in range(N_PSF): p, _s = PSF_zernike.compute_PSF(alpha * coef[k]) strehls[k] = _s mean_strehl = np.mean(strehls) return mean_strehl
plt.rc('text', usetex=False) # Calculate the Actuator Centres centers = psf.actuator_centres(N_actuators, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, radial=True) N_act = len(centers[0]) psf.plot_actuators(centers, rho_aper=RHO_APER, rho_obsc=RHO_OBSC) # Calculate the Actuator Model Matrix (Influence Functions) actuator_matrix, pupil_mask, flat_actuator = psf.actuator_matrix(centres=centers, alpha_pc=alpha_pc, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX) actuator_matrices = [actuator_matrix, pupil_mask, flat_actuator] diversity_actuators = 2 / (2 * np.pi) * np.random.uniform(-1, 1, size=N_act) # Create the PSF model using the Actuator Model for the wavefront PSF_actuators = psf.PointSpreadFunction(matrices=actuator_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=diversity_actuators) plt.show() # Generate training and test datasets (clean PSF images) train_PSF, train_coef, test_PSF, test_coef = calibration.generate_dataset(PSF_actuators, N_train, N_test, coef_strength=0.25, rescale=0.5) random_order = np.arange(N_train) np.random.shuffle(random_order) # Shuffle the training set shuffle_train_PSF = np.zeros_like(train_PSF) shuffle_train_coef = np.zeros_like(train_coef) for i in range(N_train): _psf = train_PSF[random_order[i]] _c = train_coef[random_order[i]]
# Calculate the Actuator Model Matrix (Influence Functions) actuator_matrix, pupil_mask, flat_actuator = psf.actuator_matrix( centres=centers, alpha_pc=alpha_pc, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX) actuator_matrices = [actuator_matrix, pupil_mask, flat_actuator] ones_diversity = np.random.uniform(-1, 1, size=N_act) diversity_actuators = diversity * ones_diversity # Create the PSF model using the Actuator Model for the wavefront PSF_actuators = psf.PointSpreadFunction(matrices=actuator_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=diversity_actuators) train_PSF, train_coef, test_PSF, test_coef = calibration.generate_dataset( PSF_actuators, N_train, N_test, coef_strength, rescale) calib = calibration.Calibration(PSF_model=PSF_actuators) calib.create_cnn_model(layer_filers, kernel_size, name='CALIBR', activation='relu') losses = calib.train_calibration_model(train_PSF, train_coef, test_PSF, test_coef, N_loops,
# Find the Wavelength at which you have 4 mas, if you have 4 * (1 + eps) at 1.5 SPAX_ERR = 0.05 # Percentage of error [10%] WAVE_BAD = WAVE * (1 + SPAX_ERR) # Double-check that is the correct wavelength # utils.check_spaxel_scale(rho_aper=RHO_APER*(1 + SPAX_ERR), wavelength=WAVE) centers_multiwave = psf.actuator_centres_multiwave(N_actuators=N_actuators, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_waves=N_WAVES, wave0=WAVE, waveN=WAVE_BAD, wave_ref=WAVE) N_act = len(centers_multiwave[0][0]) rbf_matrices = psf.actuator_matrix_multiwave(centres=centers_multiwave, alpha_pc=alpha_pc, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_waves=N_WAVES, wave0=WAVE, waveN=WAVE_BAD, wave_ref=WAVE, N_PIX=N_PIX) PSF_nom = psf.PointSpreadFunction(rbf_matrices[0], N_pix=N_PIX, crop_pix=pix, diversity_coef=np.zeros(N_act)) # Create a Zernike model so we can mimic the defocus zernike_matrix, pupil_mask_zernike, flat_zernike = psf.zernike_matrix(N_levels=5, rho_aper=RHO_APER, rho_obsc=RHO_OBSC, N_PIX=N_PIX, radial_oversize=1.0) zernike_matrices = [zernike_matrix, pupil_mask_zernike, flat_zernike] PSF_zernike = psf.PointSpreadFunction(matrices=zernike_matrices, N_pix=N_PIX, crop_pix=pix, diversity_coef=np.zeros(zernike_matrix.shape[-1])) # Use Least Squares to find the actuator commands that mimic a Zernike defocus zernike_fit = calibration.Zernike_fit(PSF_zernike, PSF_nom, wavelength=WAVE, rho_aper=RHO_APER) defocus_zernike = np.zeros((1, zernike_matrix.shape[-1])) defocus_zernike[0, 1] = 1.0 defocus_actuators = zernike_fit.fit_zernike_wave_to_actuators(defocus_zernike, plot=True, cmap='bwr')[:, 0]