def generate_psf(coeffs): coeffs = np.insert(coeffs, 0, 0) # Declare physical constants radius = 2e-3 wavelength = 1500e-9 FOV_pixels = 512 #Increase this (finer) 1st. h = 60e-6 / 2 #Increase this (wider) 2nd f = 4.5e-3 * 2 theta = np.arctan(h / f) / np.pi * 180 * 60 * 60 # in arcsec pixscale = theta / FOV_pixels #somehow resize this after - bilinear reduction of resolution coeffs = (np.asarray(coeffs) / 2) * 1e-6 # Create PSF osys = poppy.OpticalSystem() circular_aperture = poppy.CircularAperture(radius=radius) osys.add_pupil(circular_aperture) thinlens = poppy.ZernikeWFE(radius=radius, coefficients=coeffs) osys.add_pupil(thinlens) osys.add_detector(pixelscale=pixscale, fov_pixels=FOV_pixels) psf_with_zernikewfe, all_wfs = osys.calc_psf(wavelength=wavelength, display_intermediates=False, return_intermediates=True) pupil_wf = all_wfs[1] #this one *** final_wf = all_wfs[-1] #sometimes referred to as wf # psf = psf_with_zernikewfe[0].data return pupil_wf.phase, final_wf.amplitude**2
def makePSF(self, makePSFInputDict: dict, makePSFOptions: zernikeoptions): coeffs = makePSFInputDict["coeffs"] show = makePSFOptions["show"] units = makePSFOptions["units"] extraPlots = makePSFOptions["extraPlots"] if units is "microns": coeffs = np.asarray(coeffs) * 1e-6 osys = poppy.OpticalSystem() circular_aperture = poppy.CircularAperture(radius=self.radius) osys.add_pupil(circular_aperture) thinlens = poppy.ZernikeWFE(radius=self.radius, coefficients=coeffs) osys.add_pupil(thinlens) # osys.add_detector(pixelscale=self.pixscale, fov_arcsec=self.FOV) osys.add_detector(pixelscale=self.pixscale, fov_pixels=self.FOV_pixels) if extraPlots: plt.figure(1) # psf_with_zernikewfe, final_wf = osys.calc_psf(wavelength=self.wavelength, display_intermediates=show, # return_final=True) psf_with_zernikewfe, all_wfs = osys.calc_psf( wavelength=self.wavelength, display_intermediates=show, return_intermediates=True, ) final_wf = all_wfs[-1] pupil_wf = all_wfs[1] if extraPlots: psf = psf_with_zernikewfe psfImage = psf[0].data # plt.figure(2) # plt.clf() # poppy.display_psf(psf, normalize='peak', cmap='viridis', scale='linear', vmin=0, vmax=1) plt.figure(3) wf = final_wf wf = pupil_wf plt.clf() plt.pause(0.001) plt.subplot(1, 2, 1) plt.imshow(wf.amplitude**2) plt.title("Amplitude ^2") plt.colorbar() plt.subplot(1, 2, 2) plt.imshow(wf.phase) plt.title("Phase") plt.colorbar() plt.tight_layout() poppy.display_psf(psf_with_zernikewfe, title="PSF") self.psf = psf_with_zernikewfe self.wf = final_wf self.complex_psf = self.wf.amplitude * np.exp(1j * self.wf.phase) self.osys_obj = osys self.pupil_wf = pupil_wf
def makeZernikePSF(self, coeffs=(0, 0, 0, 0, 0), show=False, units='microns', extraPlots=False): # RADIUS = 1.0 # meters # WAVELENGTH = 1500e-9 # meters # PIXSCALE = 0.01 # arcsec / pix # FOV = 1 # arcsec # NWAVES = 1.0 # FOV_PIXELS = 128 if units == 'microns': coeffs = np.asarray(coeffs) * 1e-6 osys = poppy.OpticalSystem() circular_aperture = poppy.CircularAperture(radius=self.radius) osys.add_pupil(circular_aperture) thinlens = poppy.ZernikeWFE(radius=self.radius, coefficients=coeffs) osys.add_pupil(thinlens) #osys.add_detector(pixelscale=self.pixscale, fov_arcsec=self.FOV) osys.add_detector(pixelscale=self.pixscale, fov_pixels=self.FOV_pixels) if extraPlots: plt.figure(1) # psf_with_zernikewfe, final_wf = osys.calc_psf(wavelength=self.wavelength, display_intermediates=show, # return_final=True) psf_with_zernikewfe, all_wfs = osys.calc_psf(wavelength=self.wavelength, display_intermediates=show, return_intermediates=True) final_wf = all_wfs[-1] pupil_wf = all_wfs[1] #this one *** if extraPlots: psf = psf_with_zernikewfe psfImage = psf[0].data plt.figure(2) plt.clf() poppy.display_psf(psf, normalize='peak', cmap='viridis', scale='linear', vmin=0, vmax=1) plt.pause(0.001) plt.figure(3) wf = final_wf wf = pupil_wf plt.clf() plt.pause(0.001) plt.subplot(1, 2, 1) plt.imshow(wf.amplitude ** 2) plt.title('Amplitude ^2') plt.colorbar() plt.subplot(1, 2, 2) plt.imshow(wf.phase) plt.title('Phase') plt.colorbar() plt.tight_layout() self.psf = psf_with_zernikewfe self.wf = final_wf self.osys_obj = osys self.pupil_wf = pupil_wf
def __init__(self, optic=None, radius=1 * u.m, include_factor_of_two=False, **kwargs): name = optic.name + " on a tip/tilt stage" super().__init__(name=name, **kwargs) self.optic = optic self.include_factor_of_two = include_factor_of_two self.tilt_optic = poppy.ZernikeWFE(coefficients=[0, 0, 0], radius=radius) self.pupil_diam = 2 * radius
psf_results = [] zernike_coeff = [] file_h5, group_h5 = init_h5(save_dir) for image_idx in range(n_set): osys = poppy.FresnelOpticalSystem(pupil_diameter=10 * radius, npix=256, beam_ratio=SAMPLING) osys.add_optic(aperture) # The system pupil coefficients = generate_coefficients(wavelength, wf_error_budget) zernike_wfe = poppy.ZernikeWFE(radius=radius, coefficients=coefficients, name='Aberrated Wavefront') osys.add_optic(zernike_wfe) # Non ideality osys.add_optic(objective, distance=fl_obj) osys.add_detector(pixelscale=pix_size / u.pixel, fov_pixels=n_pix, distance=fl_obj + delta) # System description just one time if image_idx == 1: print('\nOptical System description:') osys.describe() print('\n')
def calculate_rms(number_of_zerinke_modes, number_of_scans, max_coeff_value, seed): # create_coeffs_list(number_of_scans, number_of_zerinke_modes, max_coeff_value, seed) coeffs_list = create_coeffs_list(number_of_scans, number_of_zerinke_modes, max_coeff_value, seed) # coeffs_list = specify_coeffs_list() radius = 2e-3 wavelength = 1500e-9 FOV_pixels = 512 h = 60e-6 / 2 f = 4.5e-3 * 2 theta = np.arctan(h / f) / np.pi * 180 * 60 * 60 # in arcsec pixscale = theta / FOV_pixels rms_list = [] peak_to_valley_list = [] plot = False # rms_list.append(poppy.ZernikeWFE(radius=2e-3, coefficients=coeffs).peaktovalley()) for coeffs in coeffs_list: # print(coeffs) coeffs = np.asarray(coeffs) * 1e-6 osys = poppy.OpticalSystem() circular_aperture = poppy.CircularAperture(radius=radius) osys.add_pupil(circular_aperture) thinlens = poppy.ZernikeWFE(radius=radius, coefficients=coeffs) osys.add_pupil(thinlens) osys.add_detector(pixelscale=pixscale, fov_pixels=FOV_pixels) psf_with_zernikewfe, all_wfs = osys.calc_psf( wavelength=wavelength, display_intermediates=False, return_intermediates=True) pupil_wf = all_wfs[1] #this one *** if plot: final_wf = all_wfs[-1] #sometimes referred to as wf psf = psf_with_zernikewfe[0].data # plt.figure(1) # plt.imshow(psf) # plt.figure(2) # poppy.display_psf(psf_with_zernikewfe, normalize='peak', cmap='viridis', scale='linear', vmin=0, vmax=1) # plt.show() plt.figure(1, figsize=[9, 3]) plt.subplot(131) plt.imshow(pupil_wf.phase) plt.title('Pupil Phase') plt.colorbar() plt.subplot(132) plt.imshow(final_wf.amplitude**2) plt.title('PSF intensity') plt.colorbar() plt.subplot(133) plt.imshow(final_wf.phase) plt.title('PSF phase') plt.colorbar() plt.figure(2) plt.imshow(psf) plt.title('PSF') plt.colorbar() plt.show() # print(np.std(pupil_wf.phase)) rms_list += [np.std(pupil_wf.phase)] peak_to_valley_list += [ np.amax(pupil_wf.phase) - np.amin(pupil_wf.phase) ] # input('') # print(len(rms_list)) # print(max(rms_list), min(rms_list)) # print(np.average(rms_list)) return rms_list, peak_to_valley_list
import astropy.units as u import matplotlib.pyplot as plt radius = 6 * u.mm f = 20 * u.mm coefficients_sequence = [0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0.0, 0.0] * u.um osys = poppy.FresnelOpticalSystem(pupil_diameter=2 * radius, npix=256, beam_ratio=0.25) osys.add_optic(poppy.CircularAperture(radius=radius, name='pupil')) # The system pupil zernikewfe = poppy.ZernikeWFE(radius=radius, coefficients=coefficients_sequence) osys.add_optic(zernikewfe) m1 = poppy.QuadraticLens(f, name='objective lens') osys.add_optic(m1, distance=f) #osys.add_optic(poppy.CircularAperture(radius=diam/2, name='aperture0'), distance = 0*u.mm) #m2 = poppy.QuadraticLens(fl_sec, name='Secondary') #osys.add_optic(m2, distance=d_pri_sec) #osys.add_optic(poppy.ScalarTransmission(name='free space'), distance=f1); delta = 8 * u.um osys.add_detector(pixelscale=0.1 * u.um / u.pixel, fov_pixels=256, distance=f + delta)
def csvFresnel(rx_csv, samp, oversamp, axis, break_plane, source_ZWFE_coeff, irisAOmap, irisAOstatus): EP_radius = rx_csv['Radius_m'][ 2] * u.m # Element [2] is IrisAO because Element [0] is the diverging source, [1] is OAP1 irisAO_radius = rx_csv['Radius_m'][6] * u.m sys_build = poppy.FresnelOpticalSystem(pupil_diameter=2 * EP_radius, npix=samp, beam_ratio=oversamp) #sys_build = poppy.OpticalSystem(pupil_diameter=2*EP_radius, npix=samp, beam_ratio=oversamp) # Entrance Aperture sys_build.add_optic(poppy.CircularAperture(radius=EP_radius)) # Apply if off-axis LGS is used if axis == 'LGS': src_aberr = poppy.ZernikeWFE(radius=irisAO_radius.value, coefficients=source_ZWFE_coeff) sys_build.add_optic(src_aberr) # if the on-axis target is used, then a source aberration will not be applied (hence on-axis and at infinity) # Build LGS optical system from CSV file to the break plane for n_optic, optic in enumerate(rx_csv): # n_optic: count, optic: value #print('n_optic = ', n_optic) dz = optic[ 'Distance_m'] * u.m # Propagation distance from the previous optic (n_optic-1) fl = optic[ 'Focal_Length_m'] * u.m # Focal length of the current optic (n_optic) #print('Check PSD file for %s: %s' % (optic['Name'], optic['surf_PSD'])) # if PSD file present if optic['surf_PSD_filename'] != 'none': # make a string insertion for the file location surf_file_loc = optic['surf_PSD_folder'] + optic[ 'surf_PSD_filename'] + '.fits' # call surfFITS to send out surface map optic_surface = mf.surfFITS(file_loc=surf_file_loc, optic_type=optic['optic_type'], opdunit=optic['OPD_unit'], name=optic['Name'] + ' surface') # Add generated surface map to optical system sys_build.add_optic(optic_surface, distance=dz) if fl != 0: # powered optic with PSD file present sys_build.add_optic(poppy.QuadraticLens(fl, name=optic['Name'])) # no distance; surface comes first sys_build.add_optic( poppy.CircularAperture(radius=optic['Radius_m'] * u.m, name=optic['Name'] + " aperture")) elif optic[ 'Type'] != 'pupil': # non-powered optic but has PSD present that is NOT the pupil sys_build.add_optic( poppy.CircularAperture(radius=optic['Radius_m'] * u.m, name=optic['Name'] + " aperture")) # if no PSD file present (DM, focal plane, testing optical surface) else: #print('Enter no PSD file condition') # if powered optic is being tested if fl != 0: #print('Enter powered optic condition') sys_build.add_optic(poppy.QuadraticLens(fl, name=optic['Name']), distance=dz) if n_optic > 0: sys_build.add_optic( poppy.CircularAperture(radius=optic['Radius_m'] * u.m, name=optic['Name'] + " aperture")) # if building IrisAO segmented DM elif optic['Name'] == 'IrisAO': #print('Enter build IrisAO map') if irisAOstatus == True: #print('IrisAO present') #sys_build.add_optic(poppy.MultiHexagonAperture(name='IrisAO DM', rings=3, side=7e-4, gap=7e-6, center=True), distance=dz) sys_build.add_optic(irisAOmap) else: #print('IrisAO not present') sys_build.add_optic(poppy.ScalarTransmission( planetype=PlaneType.intermediate, name=optic['Name']), distance=dz) sys_build.add_optic( poppy.CircularAperture(radius=optic['Radius_m'] * u.m, name=optic['Name'] + " aperture")) # for DM, flat mirrors elif optic['Type'] == 'mirror' or optic['Type'] == 'DM': #print('Enter mirror or DM conditon') sys_build.add_optic(poppy.ScalarTransmission( planetype=PlaneType.intermediate, name=optic['Name']), distance=dz) sys_build.add_optic( poppy.CircularAperture(radius=optic['Radius_m'] * u.m, name=optic['Name'] + " aperture")) else: # for focal plane, science plane, lyot plane #print('Enter focal plane conditon') if optic['Type'] == 'fplane': # Apply focal plane correction distance dz = optic['Distance_m'] * u.m + optic['Correction_m'] * u.m sys_build.add_optic(poppy.ScalarTransmission( planetype=PlaneType.intermediate, name=optic['Name']), distance=dz) # if the most recent optic studied was the break plane, break out of loop. if optic['Name'] == break_plane: #print('Finish building FresnelOpticalSystem at %s' % break_plane) break return sys_build
def make_coronagraph(wfe_coeffs,npix_pupil=512,npix_detector=128,wavelength=1e-6*u.m,oversample=4,pixelscale=0.01,sensor_defocus=0.5,vortex_charge=2,llowfs=False,mask_type='fqpm',obscuration=False,lyot_factor=0.9): #sensor_defocus: defocus of llowfs detector in waves peak-to-valley #these values are picked rather arbitrarily, but seem to work aperture_radius = 3*u.m #lyot_radius=2.6*u.m lyot_radius=lyot_factor*aperture_radius pupil_radius = 3*aperture_radius #create the optical system osys = poppy.OpticalSystem("LLOWFS", oversample=oversample, npix=npix_pupil, pupil_diameter=2*pupil_radius) ap = poppy.CircularAperture(radius=aperture_radius) if obscuration: obsc = poppy.SecondaryObscuration(secondary_radius=0.5*u.m, n_supports=0) osys.add_pupil(poppy.CompoundAnalyticOptic(opticslist=[ap,obsc])) #osys.add_pupil(poppy.AsymmetricSecondaryObscuration(secondary_radius=0.5,support_width=0.2*u.meter,support_angle=(0,120,240))) else: osys.add_pupil(ap) error = poppy.ZernikeWFE(radius=aperture_radius, coefficients=wfe_coeffs) osys.add_pupil(error) #inject wavefrotn error at the pupil #correct for fqpm (and vvc) alignment osys.add_pupil(poppy.FQPM_FFT_aligner()) osys.add_image() #helper for plotting intermediates #select mask type if mask_type is 'fqpm': cgph_mask = poppy.IdealFQPM(wavelength=wavelength,name='FQPM Mask') elif mask_type is 'vortex': cgph_mask = VortexMask(charge=vortex_charge,wavelength=wavelength,name='Vortex Mask') else: raise ValueError("mask_type must be 'fqpm' or 'vortex'") cgph_mask._wavefront_display_hint='phase' osys.add_image(cgph_mask) #correct alignment back the other way osys.add_pupil(poppy.FQPM_FFT_aligner(direction='backward')) #osys.add_pupil() lyot = poppy.CircularAperture(radius=lyot_radius,name='Lyot Stop') lyot._wavefront_display_hint='intensity' if obscuration: lyot_obsc = poppy.InverseTransmission(poppy.SquareAperture(size=1.4*u.m)) lyot = poppy.CompoundAnalyticOptic(opticslist=[lyot,lyot_obsc]) if llowfs: #take the rejected light for the LLOWFS lyot_reflection = poppy.InverseTransmission(lyot) lyot_extent = poppy.CircularAperture(radius=pupil_radius) lyot = poppy.CompoundAnalyticOptic(opticslist = [lyot_reflection,lyot_extent]) lyot._wavefront_display_hint='intensity' osys.add_pupil(lyot) #if obscuration: # obsc = poppy.InverseTransmission(obsc) # osys.add_pupil(obsc) #Add a defocus term to the sensor #Calc of peak-to-valley WFE: https://poppy-optics.readthedocs.io/en/stable/wfe.html defocus_coeff = sensor_defocus*wavelength.to(u.m).value sensor_defocus_wfe = poppy.ZernikeWFE(radius=pupil_radius,coefficients=[0,0,0,defocus_coeff]) osys.add_pupil(sensor_defocus_wfe) #osys.add_pupil() osys.add_detector(pixelscale=pixelscale, fov_pixels=npix_detector, oversample=1) else: #add lyot stop osys.add_pupil(lyot) osys.add_detector(pixelscale=pixelscale, fov_arcsec=1) return osys