mirror of
https://github.com/yosata/fourierOptics.git
synced 2026-10-29 20:51:10 +00:00
Added off-axis propagation, SPIE scripts
This commit is contained in:
1 parent
61ca707689
commit
04eb56d529
20 files changed
+2068
-39
No files matched your search
@@ -0,0 +1,190 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to analyse the shift of the PSF centroid as a function
|
||||
of the RMS value of the WFE. Higher wavefront errors will
|
||||
result in a larger shift of the centroid.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('axes', labelsize='large')
|
||||
|
||||
# Setting some input parameters
|
||||
dpix = 160
|
||||
n, m = 1001, 1001
|
||||
l = 1.49e-3 # wavelength
|
||||
zern_rms = 25e-5 # RMS of the zernike component of the WFE
|
||||
midspat_rms = 25e-5 # RMS of the PSD component of the WFE
|
||||
rmsList = 10**np.linspace(-6, -3, 25) # 1 to 1000 nm WFE RMS in mm, equidistant in log-space
|
||||
input_field_location = './data/ADC_input_field_1001x1001_1.49_onaxis_obscured.pkl'
|
||||
|
||||
# Initiate ELT-MICADO and wavefront error objects
|
||||
mcd = ParaxialMICADO(l=l, n=n, m=m, dpix=dpix, entrance_pupil='open')
|
||||
wfe = WavefrontError(n,m)
|
||||
|
||||
print ('Your resolution is {}x{} with a pixel size of {}'.format(n,m,dpix))
|
||||
|
||||
# Do the unperturbed propagation for a reference PSF
|
||||
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
# Generate a PSD surface
|
||||
psd_surface = wfe.generate_height_map(midspat_rms, 2, 1)
|
||||
|
||||
# Fit the PSD surface using zernike terms
|
||||
# Generating a normalized grid for the Zernike evaluation
|
||||
yz,xz = np.mgrid[-1:1:wfe.n*1j, -1:1:wfe.m*1j]
|
||||
_r = np.sqrt(xz**2 + yz**2)
|
||||
_mask = _r > 1
|
||||
coeffic = wfe.fit_zernike_coefficients(psd_surface, modes=66)
|
||||
|
||||
# StrehlList_zern, StrehlList_psd = [], []
|
||||
rms_zern_list, rms_psd_list = [], []
|
||||
|
||||
# psd lists
|
||||
popt_airy_list_psd, pcov_airy_list_psd = [], []
|
||||
popt_cust_list_psd, custom_var_list_psd, strehl_list_psd = [], [], []
|
||||
Exyzlist_psd = []
|
||||
|
||||
# zern lists
|
||||
popt_airy_list_zern, pcov_airy_list_zern = [], []
|
||||
popt_cust_list_zern, custom_var_list_zern, strehl_list_zern = [], [], []
|
||||
Exyzlist_zern = []
|
||||
|
||||
# Now iterate over the wavefront rms values.
|
||||
for rms in rmsList:
|
||||
# Print results
|
||||
print('RMS: {:.3f} nm'.format(rms*1e6))
|
||||
|
||||
|
||||
########################################
|
||||
# WFE described by Zernike polynomials #
|
||||
########################################
|
||||
# Make a new perturbed wavefront error with the required RMS
|
||||
coeffic = wfe.scale_zernike_coefficients(coeffic, rms)
|
||||
hzern = wfe.zernike_cartesian(coeffic, xz, yz)
|
||||
|
||||
# Add the new wavefront error
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(hzern)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_zern,xzern,yzern = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
psfFit_zern = PSFFitter(xzern.real,yzern.real,np.abs(Exyz_zern)**2)
|
||||
Exyzlist_zern.append(Exyz_zern)
|
||||
|
||||
# Fit using airy pattern
|
||||
amplitude_guess = np.max(np.abs(Exyz_zern))**2
|
||||
airyFitted, popt_airy, pcov_airy = psfFit_zern.fit_fixed_obscuration_airy_PSF(initialGuess=(amplitude_guess, 0.0, 0.0, 0.0, 0.03))
|
||||
popt_airy_list_zern.append(popt_airy)
|
||||
pcov_airy_list_zern.append([ np.sqrt(pcov_airy[i][i]) for i in range(len(pcov_airy)) ])
|
||||
strehl_list_zern.append( np.abs(psfFit_zern.get_coupling(E, Exyz_zern))**2 )
|
||||
########################################
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
# WFE described by PSD profile #
|
||||
########################################
|
||||
factor = rms / midspat_rms
|
||||
h_psd = wfe.scale_rms(factor, data=psd_surface)
|
||||
|
||||
# Add the new wavefront error
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(h_psd)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_psd,xpsd,ypsd = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
psfFit_psd = PSFFitter(xpsd.real,ypsd.real,np.abs(Exyz_psd)**2)
|
||||
|
||||
# Fit using coupling integral
|
||||
Exyzlist_psd.append(Exyz_psd)
|
||||
|
||||
# Fit using airy pattern
|
||||
amplitude_guess = np.max(np.abs(Exyz_psd))**2
|
||||
airyFitted, popt_airy, pcov_airy = psfFit_psd.fit_fixed_obscuration_airy_PSF(initialGuess=(amplitude_guess, 0.0, 0.0, 0.0, 0.03))
|
||||
popt_airy_list_psd.append(popt_airy)
|
||||
pcov_airy_list_psd.append([ np.sqrt(pcov_airy[i][i]) for i in range(len(pcov_airy)) ])
|
||||
strehl_list_psd.append( np.abs(psfFit_psd.get_coupling(E, Exyz_psd))**2 )
|
||||
########################################
|
||||
|
||||
|
||||
# Find the RMS value of the wavefront errros
|
||||
rms_zern = np.sqrt(np.mean(np.asarray(hzern[~_mask])**2))
|
||||
rms_psd = np.sqrt(np.mean(np.asarray(h_psd)**2))
|
||||
rms_zern_list.append(rms_zern)
|
||||
rms_psd_list.append(rms_psd)
|
||||
|
||||
print('Strehl: {:.3f} ... {:.3f}'.format(strehl_list_psd[-1], strehl_list_zern[-1]))
|
||||
|
||||
|
||||
|
||||
# PSD
|
||||
# Optimum fit parameters for all scaled surface errors
|
||||
_, x0_airy_psd, y0_airy_psd, _, _ = np.asarray(popt_airy_list_psd).T
|
||||
|
||||
# Errors in the optimum fit parameters for all scaled surface errors
|
||||
_, x0_airy_psd_err, y0_airy_psd_err, _, _ = np.asarray(pcov_airy_list_psd).T
|
||||
|
||||
# Distance from original centroid at (0,0)
|
||||
r_airy_psd = np.sqrt(x0_airy_psd**2+y0_airy_psd**2)
|
||||
r_err_psd_airy = np.sqrt( (x0_airy_psd**2*x0_airy_psd_err**2+y0_airy_psd**2*y0_airy_psd_err**2) / (x0_airy_psd**2+y0_airy_psd**2))
|
||||
|
||||
rms_psd_nm = np.asarray(rms_psd_list)*1e6
|
||||
r_airy_psd_mas = r_airy_psd * mcd.platescale * 1000
|
||||
r_err_psd_airy_mas = r_err_psd_airy * mcd.platescale * 1000
|
||||
|
||||
|
||||
# Zernikes
|
||||
# Optimum fit parameters for all scaled surface errors
|
||||
_, x0_airy_zern, y0_airy_zern, _, _ = np.asarray(popt_airy_list_zern).T
|
||||
|
||||
# Errors in the optimum fit parameters for all scaled surface errors
|
||||
_, x0_airy_zern_err, y0_airy_zern_err, _, _ = np.asarray(pcov_airy_list_zern).T
|
||||
|
||||
# Distance from original centroid at (0,0)
|
||||
r_airy_zern = np.sqrt(x0_airy_zern**2+y0_airy_zern**2)
|
||||
r_err_zern_airy = np.sqrt( (x0_airy_zern**2*x0_airy_zern_err**2+y0_airy_zern**2*y0_airy_zern_err**2) / (x0_airy_zern**2+y0_airy_zern**2))
|
||||
|
||||
rms_zern_nm = np.asarray(rms_zern_list)*1e6
|
||||
r_airy_zern_mas = r_airy_zern * mcd.platescale * 1000
|
||||
r_err_zern_airy_mas = r_err_zern_airy * mcd.platescale * 1000
|
||||
|
||||
save_variable('./data/centroid_shift_zernikes.pkl', (rms_zern_nm, r_airy_zern_mas, r_err_zern_airy_mas, strehl_list_zern))
|
||||
save_variable('./data/centroid_shift_psd.pkl', (rms_psd_nm, r_airy_psd_mas, r_err_psd_airy_mas, strehl_list_psd))
|
||||
|
||||
|
||||
# Plot some of the point spread functions
|
||||
fig = plt.figure(figsize=(9,3))
|
||||
ax1 = fig.add_subplot(131)
|
||||
ax1.imshow(np.abs(Exyzlist_zern[0][450:550,450:550]), cmap='hot', interpolation='bicubic')
|
||||
ax1.set_xticks([])
|
||||
ax1.set_yticks([])
|
||||
ax2 = fig.add_subplot(132)
|
||||
ax2.imshow(np.abs(Exyzlist_zern[-5][450:550,450:550]), cmap='hot', interpolation='bicubic')
|
||||
ax2.set_xticks([])
|
||||
ax2.set_yticks([])
|
||||
ax4 = fig.add_subplot(133)
|
||||
ax4.imshow(np.abs(Exyzlist_psd[-5][450:550,450:550]), cmap='hot', interpolation='bicubic')
|
||||
ax4.set_xticks([])
|
||||
ax4.set_yticks([])
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/PSF_shape.png', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/PSF_shape.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.show()
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to generate two plots of the footprint on MCD-CAM lens,
|
||||
showing the impact of the WFEs on the amplitude and phase
|
||||
near the exit pupil.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('font', family='serif')
|
||||
|
||||
# Initializing MICADO paraxial model
|
||||
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50)
|
||||
wfe = WavefrontError(mcd.n, mcd.m)
|
||||
|
||||
# Setup
|
||||
l = 1.49e-3
|
||||
|
||||
# Set field points
|
||||
hxList = [-1,-1,0, 1,1]
|
||||
hyList = [-1, 1,0,-1,1]
|
||||
|
||||
# Propagate through the field positions without any WFEs
|
||||
for i in range(len(hxList)):
|
||||
hx = hxList[i]
|
||||
hy = hyList[i]
|
||||
print('hx: {} - hy: {}'.format(hx,hy) )
|
||||
|
||||
# Propagate through the MICADO system
|
||||
prop_surf = 4
|
||||
E, x, y = mcd.propagate(l=l,surface=prop_surf, zoom=False, show=False,
|
||||
print_progress=False, hx=hx, hy=hy)
|
||||
# Save the resulting 'perfect' PSF for later
|
||||
if prop_surf == 4:
|
||||
# Don't show anything outside the clear aperture.
|
||||
mask = np.sqrt(x**2 + y**2) > mcd.ELT_ADC.p1.CA/2
|
||||
|
||||
# Plot P1
|
||||
footprint_p1 = E.copy()
|
||||
footprint_p1[mask]=np.nan
|
||||
# figp1, axp1, axp2 = plot_results(footprint_p1[850:2150,850:2150], x[850:2150,850:2150], y[850:2150,850:2150],
|
||||
# fig_size=(12,5), show=False)
|
||||
figp1, axp1 = plot_real_valued_results(np.abs(footprint_p1)[850:2150,850:2150], x[850:2150,850:2150], y[850:2150,850:2150],
|
||||
labeltext='Amplitude', show=False, fig_size=None)
|
||||
plt.savefig('./figures/ELT-MCD-ADC_footprint_no_wfe_{}_{}.pdf'.format(hx,hy), bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ELT-MCD-ADC_footprint_no_wfe_{}_{}.png'.format(hx,hy), bbox_inches='tight', transparent=True)
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
# Load in the WFEs and set them to the corresponding ADC surfaces
|
||||
wfe_p1 = load_variable('./data/ADC_tWFE_p1_psd_25nm.pkl')
|
||||
wfe_p2 = load_variable('./data/ADC_tWFE_p2_psd_25nm.pkl')
|
||||
wfe_p3 = load_variable('./data/ADC_tWFE_p3_psd_25nm.pkl')
|
||||
wfe_p4 = load_variable('./data/ADC_tWFE_p4_psd_25nm.pkl')
|
||||
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(wfe_p1)
|
||||
mcd.ELT_ADC.p2.add_wavefront_error(wfe_p2)
|
||||
mcd.ELT_ADC.p3.add_wavefront_error(wfe_p3)
|
||||
mcd.ELT_ADC.p4.add_wavefront_error(wfe_p4)
|
||||
|
||||
|
||||
|
||||
# Iterating over the field positions.
|
||||
print('\nPropagation with Wavefront Errors applied')
|
||||
prop_surf = 4
|
||||
for i in range(len(hxList)):
|
||||
hx = hxList[i]
|
||||
hy = hyList[i]
|
||||
print('hx: {} - hy: {}'.format(hx,hy) )
|
||||
|
||||
# Propagate through the MICADO system
|
||||
Ep, xp, yp = mcd.propagate(l=l,surface=prop_surf+4, zoom=False, show=False,
|
||||
print_progress=False, hx=hx, hy=hy)
|
||||
|
||||
if prop_surf == 4:
|
||||
# Don't show anything outside the clear aperture.
|
||||
mask = np.sqrt(x**2 + y**2) > mcd.ELT_ADC.p1.CA/2
|
||||
|
||||
# Plot P1
|
||||
footprint_p1 = Ep.copy()
|
||||
figp1, axp1, axp2 = plot_results(footprint_p1[1050:1350,1150:1450], x[1050:1350,1150:1450], y[1050:1350,1150:1450],
|
||||
fig_size=(12,5), show=False)
|
||||
plt.savefig('./figures/ELT-MCD-COL_footprint_with_wfe_{}_{}_zoom.pdf'.format(hx,hy), bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ELT-MCD-COL_footprint_with_wfe_{}_{}_zoom.png'.format(hx,hy), bbox_inches='tight', transparent=True)
|
||||
plt.show()
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to propagate an input field to a surface in the
|
||||
ELT-MICADO system. Here we propagate to the first ADC
|
||||
surface and save the result, saving us a lot of time
|
||||
in later analyses.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
|
||||
# Setting some input parameters
|
||||
dpix = 160
|
||||
n, m = 1001, 1001
|
||||
l = 1.49e-3 # wavelength
|
||||
input_field_location = './data/ADC_input_field_{}x{}_{:.2f}_onaxis_obscured.pkl'.format(n,m,l*1e3)
|
||||
|
||||
|
||||
# Initiate ELT-MICADO and wavefront error objects
|
||||
mcd = ParaxialMICADO(l=l, n=n, m=m, dpix=dpix, entrance_pupil='obscured')
|
||||
|
||||
print ('Your resolution is {}x{} with a pixel size of {}'.format(n,m,dpix))
|
||||
|
||||
# Propagation up to the first ADC surface.
|
||||
E, x, y = mcd.propagate(l=l,surface=3, zoom=False, show=True,
|
||||
print_progress=True, hx=0, hy=0)
|
||||
save_variable(input_field_location, (E,x,y))
|
||||
@@ -0,0 +1,21 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to generate the ray traced plot of the paraxial
|
||||
ELT-MICADO model.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('font', family='serif')
|
||||
|
||||
# Initializing MICADO paraxial model
|
||||
mcd = ParaxialMICADO(l=1.49e-3, n=3001, m=3001, dpix=50)
|
||||
mcd.plot_ray_trace()
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to compare the Strehl ratio of 50 different instances
|
||||
of a generated WFE. Higher spatial frequency perturbations
|
||||
should follow the Marechal approximation more closely than
|
||||
lower order shape errors only. We verify this using Power
|
||||
Spectral Density and Zernike modes (66 coefficients).
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
|
||||
def expected_strehl2(rms, l):
|
||||
return np.exp( -(2*np.pi*rms/l)**2 )
|
||||
|
||||
|
||||
def append_to_existing_data(A, filename):
|
||||
if os.path.exists(filename):
|
||||
A_o = load_variable(filename)
|
||||
A2 = np.append(A, A_o)
|
||||
else:
|
||||
A2 = A
|
||||
return A2
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setting some input parameters
|
||||
dpix = 160
|
||||
n, m = 1001, 1001
|
||||
l = 1.49e-3 # wavelength
|
||||
zern_rms = 25e-5 # RMS of the zernike component of the WFE
|
||||
midspat_rms = 25e-5 # RMS of the PSD component of the WFE
|
||||
rmsList = np.linspace(1e-6, 1e-3, 25) # 1 to 1000 nm WFE RMS in mm
|
||||
number_of_iterations = 50
|
||||
input_field_location = './data/ADC_input_field_1001x1001_1.49_onaxis_obscured.pkl'
|
||||
|
||||
|
||||
# Initiate ELT-MICADO and wavefront error objects
|
||||
mcd = ParaxialMICADO(l=l, n=n, m=m, dpix=dpix, entrance_pupil='open')
|
||||
wfe = WavefrontError(n,m)
|
||||
|
||||
print ('Your resolution is {}x{} with a pixel size of {}'.format(n,m,dpix))
|
||||
|
||||
# Propagate unperturbed field
|
||||
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
# Initiate psf fitter object to calculate the strehl ratios
|
||||
psf = PSFFitter(x, y, E)
|
||||
|
||||
# Create some empty lists for later
|
||||
strehl_zern_complete, strehl_psd_complete = [], []
|
||||
rms_zern_list_complete, rms_psd_list_complete = [], []
|
||||
|
||||
|
||||
# Repeat the analysis 50 times
|
||||
for i in range(number_of_iterations):
|
||||
|
||||
print('Iteration {}/{}'.format(i+1,number_of_iterations))
|
||||
|
||||
# Generate a PSD surface
|
||||
psd_surface = wfe.generate_height_map(midspat_rms, 2, 1)
|
||||
|
||||
# Fit the PSD surface using zernike terms
|
||||
# Generating a normalized grid for the Zernike evaluation
|
||||
yz,xz = np.mgrid[-1:1:wfe.n*1j, -1:1:wfe.m*1j]
|
||||
_r = np.sqrt(xz**2 + yz**2)
|
||||
_mask = _r > 1
|
||||
coeffic = wfe.fit_zernike_coefficients(psd_surface, modes=66)
|
||||
|
||||
StrehlList_zern, StrehlList_psd = [], []
|
||||
rms_zern_list, rms_psd_list = [], []
|
||||
|
||||
|
||||
# Compare results at different RMS values
|
||||
for rms in rmsList:
|
||||
|
||||
########################################
|
||||
# WFE described by Zernike polynomials #
|
||||
########################################
|
||||
# Make a new perturbed wavefront error with the required RMS
|
||||
coeffic = wfe.scale_zernike_coefficients(coeffic, rms)
|
||||
hzern = wfe.zernike_cartesian(coeffic, xz, yz)
|
||||
|
||||
# Add the new wavefront error
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(hzern)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_zern,xzern,yzern = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
Strehl_zern = np.abs(psf.get_coupling(E, Exyz_zern))**2
|
||||
StrehlList_zern.append(Strehl_zern)
|
||||
########################################
|
||||
|
||||
|
||||
########################################
|
||||
# WFE described by PSD profile #
|
||||
########################################
|
||||
factor = rms / midspat_rms
|
||||
h_psd = wfe.scale_rms(factor, data=psd_surface)
|
||||
|
||||
# Add the new wavefront error
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(h_psd)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_psd,xpsd,ypsd = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
Strehl_psd = np.abs(psf.get_coupling(E, Exyz_psd))**2
|
||||
StrehlList_psd.append(Strehl_psd)
|
||||
########################################
|
||||
|
||||
# Find the RMS value of the wavefront errros
|
||||
rms_zern = np.sqrt(np.mean(np.asarray(hzern[~_mask])**2))
|
||||
rms_psd = np.sqrt(np.mean(np.asarray(h_psd)**2))
|
||||
rms_zern_list.append(rms_zern)
|
||||
rms_psd_list.append(rms_psd)
|
||||
|
||||
# Print results
|
||||
print('RMS: {:.3f}, S_zern: {:.3f}, S_psd: {:.3f}, \
|
||||
RMS_zern: {:.3f}, RMS_psd: {:.3f}'.format(
|
||||
rms*1e6, Strehl_zern, Strehl_psd, rms_zern*1e6, rms_psd*1e6))
|
||||
|
||||
|
||||
# Put the results in the correct list
|
||||
strehl_zern_complete.append(StrehlList_zern)
|
||||
strehl_psd_complete.append(StrehlList_psd)
|
||||
rms_zern_list_complete.append(rms_zern_list)
|
||||
rms_psd_list_complete.append(rms_psd_list)
|
||||
|
||||
rms_zern_list_complete = np.asarray(rms_zern_list_complete)
|
||||
rms_psd_list_complete = np.asarray(rms_psd_list_complete)
|
||||
|
||||
# Import old results if they are available and append them to the results.
|
||||
rmsList_present = rmsList.copy()
|
||||
rmsList = append_to_existing_data(rmsList, './data/SR_RMS_values_obscured.pkl')
|
||||
strehl_zern_complete = append_to_existing_data(strehl_zern_complete, './data/SR_strehl_zern_obscured.pkl')
|
||||
strehl_psd_complete = append_to_existing_data(strehl_psd_complete, './data/SR_strehl_psd_obscured.pkl')
|
||||
rms_zern_list_complete = append_to_existing_data(rms_zern_list_complete, './data/SR_rms_zern_complete_obscured.pkl')
|
||||
rms_psd_list_complete = append_to_existing_data(rms_psd_list_complete, './data/SR_rms_psd_complete_obscured.pkl')
|
||||
|
||||
mean_strehl_zern = np.mean(strehl_zern_complete, axis=0)
|
||||
err_strehl_zern = np.std(strehl_zern_complete, axis=0)
|
||||
mean_strehl_psd = np.mean(strehl_psd_complete, axis=0)
|
||||
err_strehl_psd = np.std(strehl_psd_complete, axis=0)
|
||||
|
||||
save_variable('./data/SR_RMS_values_obscured.pkl', rmsList)
|
||||
save_variable('./data/SR_strehl_zern_obscured.pkl', strehl_zern_complete)
|
||||
save_variable('./data/SR_strehl_psd_obscured.pkl', strehl_psd_complete)
|
||||
save_variable('./data/SR_rms_zern_complete_obscured.pkl', rms_zern_list_complete)
|
||||
save_variable('./data/SR_rms_psd_complete_obscured.pkl', rms_psd_list_complete)
|
||||
@@ -0,0 +1,88 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
from pdb import set_trace
|
||||
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to generate the wavefront errors that will be used for
|
||||
the ADC prisms during all subsequent analyses. Script made for
|
||||
the SPIE manuscript.
|
||||
'''
|
||||
|
||||
def main():
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('font', family='serif')
|
||||
# Initializing MICADO paraxial model
|
||||
|
||||
l = 1.49e-3
|
||||
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50)
|
||||
wfe = WavefrontError(mcd.n, mcd.m)
|
||||
|
||||
# Get x3 and y3 (the coordinates to apply the ADC WFE to):
|
||||
_, x3, y3 = mcd.propagate(l=l,surface=4, zoom=False, show=False,
|
||||
print_progress=False)
|
||||
|
||||
# Apply a set of wavefront errors to each ADC surface.
|
||||
print('\nSetting the wavefront errors...')
|
||||
wfe_p1 = ADC_surfaces(x3,y3)
|
||||
wfe_p2 = ADC_surfaces(x3,y3)
|
||||
wfe_p3 = ADC_surfaces(x3,y3)
|
||||
wfe_p4 = ADC_surfaces(x3,y3)
|
||||
|
||||
wfe_p1.generate_ADC_wfe(zernRMS=20e-6, psdRMS=15e-6)
|
||||
wfe_p2.generate_ADC_wfe(zernRMS=20e-6, psdRMS=15e-6)
|
||||
wfe_p3.generate_ADC_wfe(zernRMS=20e-6, psdRMS=15e-6)
|
||||
wfe_p4.generate_ADC_wfe(zernRMS=20e-6, psdRMS=15e-6)
|
||||
|
||||
mask = np.sqrt(wfe_p1.xz**2 + wfe_p1.yz**2) > 1
|
||||
|
||||
# Plot P1
|
||||
|
||||
surf_p1 = wfe_p1.latest_surface.copy()
|
||||
surf_p1[mask]=np.nan
|
||||
figp1, axp1 = plot_real_valued_results(surf_p1[850:2150,850:2150]*1e6, x3[850:2150,850:2150], y3[850:2150,850:2150],
|
||||
colormap='jet', labeltext='Surface height (nm)', fig_size=None, show=False)
|
||||
plt.savefig('./figures/ADC_tWFE_p1_zern_20nm_psd_15nm.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ADC_tWFE_p1_zern_20nm_psd_15nm.png', bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
# Plot P2
|
||||
surf_p2 = wfe_p2.latest_surface.copy()
|
||||
surf_p2[mask]=np.nan
|
||||
figp2, axp2 = plot_real_valued_results(surf_p2[850:2150,850:2150]*1e6, x3[850:2150,850:2150], y3[850:2150,850:2150],
|
||||
colormap='jet', labeltext='Surface height (nm)', fig_size=None, show=False)
|
||||
plt.savefig('./figures/ADC_tWFE_p2_zern_20nm_psd_15nm.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ADC_tWFE_p2_zern_20nm_psd_15nm.png', bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
# Plot P3
|
||||
surf_p3 = wfe_p3.latest_surface.copy()
|
||||
surf_p3[mask]=np.nan
|
||||
figp3, axp3 = plot_real_valued_results(surf_p3[850:2150,850:2150]*1e6, x3[850:2150,850:2150], y3[850:2150,850:2150],
|
||||
colormap='jet', labeltext='Surface height (nm)', fig_size=None, show=False)
|
||||
plt.savefig('./figures/ADC_tWFE_p3_zern_20nm_psd_15nm.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ADC_tWFE_p3_zern_20nm_psd_15nm.png', bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
# Plot P4
|
||||
surf_p4 = wfe_p4.latest_surface.copy()
|
||||
surf_p4[mask]=np.nan
|
||||
figp4, axp4 = plot_real_valued_results(surf_p4[850:2150,850:2150]*1e6, x3[850:2150,850:2150], y3[850:2150,850:2150],
|
||||
colormap='jet', labeltext='Surface height (nm)', fig_size=None, show=False)
|
||||
plt.savefig('./figures/ADC_tWFE_p4_zern_20nm_psd_15nm.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/ADC_tWFE_p4_zern_20nm_psd_15nm.png', bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
# Get the wavefront errors and save them for later use.
|
||||
save_variable('./data/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl', wfe_p1.latest_surface)
|
||||
save_variable('./data/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl', wfe_p2.latest_surface)
|
||||
save_variable('./data/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl', wfe_p3.latest_surface)
|
||||
save_variable('./data/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl', wfe_p4.latest_surface)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,162 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
sys.path.insert(0, '/home/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to generate the geometric distortions due to WFEs
|
||||
off the ADC prisms. The distortions are produced by measuring
|
||||
the offset of the PSF centroid with and without WFE as a
|
||||
function of field position.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
def plot_distortions():
|
||||
# Coordinates without WFEs
|
||||
xe = load_variable('./data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
|
||||
ye = load_variable('./data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
|
||||
|
||||
# Coordinates with WFEs
|
||||
xf = load_variable('./data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
|
||||
yf = load_variable('./data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
|
||||
|
||||
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
|
||||
|
||||
n = xe.shape[0]
|
||||
X = xe.flatten()
|
||||
Y = ye.flatten()
|
||||
dX = xf - xe
|
||||
dY = yf - ye
|
||||
dx = dX.flatten()
|
||||
dy = dY.flatten()
|
||||
|
||||
# Magnitude of the distortions
|
||||
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
|
||||
|
||||
# Dummy figure, used for the colorbar colors in the quiver plot
|
||||
im = plt.imshow(np.reshape(R, (n,n)))
|
||||
plt.close()
|
||||
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot()
|
||||
for i in range(len(xe)):
|
||||
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
|
||||
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
|
||||
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=.5, units='dots')
|
||||
ax.quiver(X,Y,dx,dy,R, alpha=.5, units='dots')
|
||||
ax.set_aspect('equal', adjustable='box')
|
||||
ax.set_xlabel('x (mm)')
|
||||
ax.set_ylabel('y (mm)')
|
||||
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
|
||||
plt.savefig('./figures/GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# plt.rc('text', usetex=True)
|
||||
# plt.rc('font', family='serif')
|
||||
|
||||
# Setup of simulation
|
||||
l = 1.49e-3
|
||||
Elist, Eplist = [], []
|
||||
xlist, ylist = [], []
|
||||
xplist, yplist = [], []
|
||||
x_expected_list, y_expected_list = [], []
|
||||
x_centroid_list, y_centroid_list = [], []
|
||||
|
||||
# Set field points
|
||||
hxList, hyList = np.mgrid[-1:1:11j,-1:1:11j]-(1/300)
|
||||
hxList = hxList.flatten()
|
||||
hyList = hyList.flatten()
|
||||
|
||||
# Loading in the WFEs
|
||||
wfe_p1 = load_variable('./data/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
|
||||
wfe_p2 = load_variable('./data/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
|
||||
wfe_p3 = load_variable('./data/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
|
||||
wfe_p4 = load_variable('./data/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
|
||||
|
||||
# Propagate through the field positions without any WFEs
|
||||
for i in range(len(hxList)):
|
||||
hx = hxList[i]
|
||||
hy = hyList[i]
|
||||
print('hx: {} - hy: {}'.format(hx,hy) )
|
||||
|
||||
# Initializing MICADO paraxial model
|
||||
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, entrance_pupil='obscured')
|
||||
|
||||
# Propagate through the MICADO system
|
||||
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=hx, hy=hy)
|
||||
|
||||
# Find approximation for the centroid and amplitude as a first
|
||||
# guess for the Obscured Airy pattern fit.
|
||||
amplitude_guess = np.max(np.abs(E))**2
|
||||
xbc, ybc, _, _ = mcd.centroid_shift(method='Barycenter')
|
||||
print('Barycenter guess: ', xbc, ybc)
|
||||
|
||||
# Do the Obscured Airy Pattern Fit for the unperturbed PSF
|
||||
xe, ye, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xbc, ybc, 0.0, 0.03))
|
||||
print('Airy result: ', xe, ye)
|
||||
x_expected_list.append(xe)
|
||||
y_expected_list.append(ye)
|
||||
|
||||
|
||||
|
||||
# Load in the WFEs and set them to the corresponding ADC surfaces
|
||||
print('\nSetting the wavefront errors...')
|
||||
# null_wfe = np.zeros((3001,3001))
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(wfe_p1)
|
||||
mcd.ELT_ADC.p2.add_wavefront_error(wfe_p2)
|
||||
mcd.ELT_ADC.p3.add_wavefront_error(wfe_p3)
|
||||
mcd.ELT_ADC.p4.add_wavefront_error(wfe_p4)
|
||||
|
||||
|
||||
# Propagate through the MICADO system
|
||||
print('Propagating with Wavefront Errors applied...')
|
||||
Ep, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=hx, hy=hy)
|
||||
|
||||
# Do the Obscured Airy Pattern Fit for the perturbed PSF
|
||||
xf, yf, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xe, ye, 0.0, 0.03))
|
||||
|
||||
# Resulting centroid shift due to the WFE
|
||||
x_centroid_list.append(xf)
|
||||
y_centroid_list.append(yf)
|
||||
R = np.sqrt( (xf-xe)**2 + (yf-ye)**2 ) * mcd.platescale * 1e6
|
||||
print('xf: {}, yf: {}, shift (uas): {}'.format(xf,yf, R))
|
||||
|
||||
# Clear the memory by emptying the large arrays
|
||||
mcd = None
|
||||
wfe = None
|
||||
E, x, y = None, None, None
|
||||
Ep, xp, yp = None, None, None
|
||||
|
||||
|
||||
# Reshaping the arrays
|
||||
shape = (int(np.sqrt(len(x_expected_list))), int(np.sqrt(len(x_expected_list))))
|
||||
x_expected = np.asarray(x_expected_list).reshape(shape)
|
||||
y_expected = np.asarray(y_expected_list).reshape(shape)#.T
|
||||
|
||||
# Saving the arrays
|
||||
save_variable('./data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl', x_expected)
|
||||
save_variable('./data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl', y_expected)
|
||||
|
||||
|
||||
# Reshaping the arrays
|
||||
shape = (int(np.sqrt(len(x_centroid_list))), int(np.sqrt(len(x_centroid_list))))
|
||||
x_centroid = np.asarray(x_centroid_list).reshape(shape)
|
||||
y_centroid = np.asarray(y_centroid_list).reshape(shape)
|
||||
|
||||
# Saving the arrays
|
||||
save_variable('./data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl', x_centroid)
|
||||
save_variable('./data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl', y_centroid)
|
||||
|
||||
plot_distortions()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.cm as cm
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to plot the results of the centroid shift analysis.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
|
||||
def plot_colourline(x,y,c, ax):
|
||||
'''
|
||||
Source: https://stackoverflow.com/questions/36505587/color-line-by-third-variable-python
|
||||
Function to colour a line according to a thrid variable.
|
||||
In our case, this will be the Strehl ratio
|
||||
'''
|
||||
c = cm.plasma_r(c)
|
||||
for i in np.arange(len(x)-1):
|
||||
ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i])
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
|
||||
# Load in the results from centroid_shift_analysis.py
|
||||
rms_zern_nm, r_airy_zern_mas, r_err_zern_airy_mas, strehl_list_zern = load_variable('./data/centroid_shift_zernikes.pkl')
|
||||
rms_psd_nm, r_airy_psd_mas, r_err_psd_airy_mas, strehl_list_psd = load_variable('./data/centroid_shift_psd.pkl')
|
||||
|
||||
# Convert the errors to logarithmic space, assuming small errors.
|
||||
log_err_zern_airy_mas = 0.434 * r_err_zern_airy_mas / r_airy_zern_mas
|
||||
log_err_psd_airy_mas = 0.434 * r_err_psd_airy_mas / r_airy_psd_mas
|
||||
|
||||
|
||||
# Plot the resulting WFE scaling relation
|
||||
fig = plt.figure(figsize=(9,7))
|
||||
ax1 = fig.add_subplot(111)
|
||||
ax1.errorbar((0.8138)*rms_zern_nm, r_airy_zern_mas, yerr=log_err_zern_airy_mas, color='k',
|
||||
linestyle='none', capsize=3,
|
||||
markeredgewidth=1)
|
||||
ax1.errorbar((0.8138)*rms_psd_nm, r_airy_psd_mas, yerr=log_err_psd_airy_mas, color='k',
|
||||
linestyle='none', capsize=3,
|
||||
markeredgewidth=1)
|
||||
ax1.scatter((0.8138)*rms_zern_nm, r_airy_zern_mas, c=strehl_list_zern, marker='v', label='Zernikes', cmap='plasma_r')
|
||||
|
||||
im = ax1.scatter((0.8138)*rms_psd_nm, r_airy_psd_mas, c=strehl_list_psd, marker='o', label='PSD', cmap='plasma_r')
|
||||
|
||||
# We colour the lines by their Strehl ratio
|
||||
plot_colourline((0.8138)*rms_zern_nm, r_airy_zern_mas, strehl_list_zern, ax=ax1)
|
||||
plot_colourline((0.8138)*rms_psd_nm, r_airy_psd_mas, strehl_list_psd, ax=ax1)
|
||||
ax1.set_xscale('log')
|
||||
ax1.set_yscale('log')
|
||||
ax1.set_xlabel('$\\sigma_{\\mathrm{WFE}}$ (nm)', fontsize=18)
|
||||
ax1.set_ylabel('Centroid shift (mas)', fontsize=18)
|
||||
ax1.set_xlim([np.min(rms_zern_nm)*(0.8138), np.max(rms_zern_nm)*(0.8138)])
|
||||
ax1.legend(fontsize=18)
|
||||
ax1.grid(True, alpha=0.3, which='major')
|
||||
ax1.grid(True, alpha=0.1, which='minor')
|
||||
ax1.tick_params(labelsize=18)
|
||||
cb = fig.colorbar(im, ax=ax1)
|
||||
cb.set_label(label='Strehl', size=18)
|
||||
cb.ax.tick_params(labelsize=18)
|
||||
plt.savefig('./figures/WFE_scaling_relation_obscured_airy.png', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/WFE_scaling_relation_obscured_airy.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to plot the results of the geometric distortion analysis.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
|
||||
# Full field
|
||||
xe = load_variable('../SPIE/data/GD full field (Obscured Airy zern psd)/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
|
||||
ye = load_variable('../SPIE/data/GD full field (Obscured Airy zern psd)/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
|
||||
xp = load_variable('../SPIE/data/GD full field (Obscured Airy zern psd)/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
|
||||
yp = load_variable('../SPIE/data/GD full field (Obscured Airy zern psd)/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
|
||||
|
||||
# Shape of the arrays
|
||||
n = xe.shape[0]
|
||||
|
||||
# Reshaping of the arrays so that they can be used for the quiver plot.
|
||||
X = xe.flatten()
|
||||
Y = ye.flatten()
|
||||
dX = xp-xe
|
||||
dY = yp-ye
|
||||
|
||||
dx = dX.flatten()
|
||||
dy = dY.flatten()
|
||||
|
||||
# Two values are comparatively (extremely large), they are set to 0
|
||||
# to be able to see the other values.
|
||||
R = (np.sqrt(dx**2 + dy**2) * 100.13151872258219 * 1000) # Magnitude of the shift in micro arcseconds
|
||||
print('RMS of the PSF shifts: {:.4f} uas.'.format(np.sqrt(np.mean((R)**2))))
|
||||
|
||||
|
||||
# Dummy figure
|
||||
im = plt.imshow(np.reshape(R, (n,n)))
|
||||
plt.close()
|
||||
|
||||
# Actual plotting of the figure
|
||||
fig = plt.figure(figsize=(9,7))
|
||||
ax = fig.add_subplot()
|
||||
for i in range(len(xe)):
|
||||
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
|
||||
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
|
||||
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=1)
|
||||
ax.quiver(X,Y,dx,dy,R, alpha=1)
|
||||
ax.set_aspect('equal', adjustable='box')
|
||||
ax.set_xlabel('x (mm)', fontsize=18)
|
||||
ax.set_ylabel('y (mm)', fontsize=18)
|
||||
ax.set_xlim([-340,340])
|
||||
ax.set_ylim([-340,340])
|
||||
ax.tick_params(labelsize=18)
|
||||
cb = fig.colorbar(im, ax=ax)
|
||||
cb.set_label(label='PSF centroid shift ($\\mu$as)', size=18)
|
||||
cb.ax.tick_params(labelsize=18)
|
||||
plt.savefig('./figures/GD_full_field_obscured_Airy_psd_zern.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/GD_full_field_obscured_Airy_psd_zern.png', bbox_inches='tight', transparent=True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
@@ -0,0 +1,79 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to generate the plots of the relation between the
|
||||
Strehl ratio and the RMS of the Wavefront Error. A comparison
|
||||
with the Marechal approximation is made.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
def expected_strehl2(rms, l):
|
||||
return np.exp( -(2*np.pi*rms/l)**2 )
|
||||
|
||||
|
||||
def append_to_existing_data(A, filename):
|
||||
if os.path.exists(filename):
|
||||
A_o = load_variable(filename)
|
||||
A = np.append(A, A_o)
|
||||
return A
|
||||
|
||||
|
||||
def plot_some_stuff():
|
||||
fig = plt.figure(figsize=(9,7))
|
||||
ax = fig.add_subplot(111)
|
||||
ax2 = ax.twiny()
|
||||
|
||||
rmsValues = rmsList[:25]
|
||||
for i in range(len(rms_zern_list_complete)):
|
||||
ax.plot((0.8138)*rms_zern_list_complete[i]*1e6, strehl_zern_complete[i], 'y-',
|
||||
alpha=0.1, linewidth=.5)
|
||||
ax.plot((0.8138)*rms_psd_list_complete[i]*1e6, strehl_psd_complete[i], 'b-',
|
||||
alpha=0.1, linewidth=.5)
|
||||
|
||||
ax.plot(np.linspace(1e-6,1e-3,100)*1e6, expected_strehl2(np.linspace(1e-6,1e-3,100),l),'k--',
|
||||
label='$S=\\exp[-(2\\pi\\sigma/\\lambda)^2]$')
|
||||
ax.errorbar((0.8138)*rmsValues*1e6, mean_strehl_zern, yerr=err_strehl_zern, color='y',
|
||||
linestyle='-', label='Zernikes', capsize=3, markeredgewidth=1)#,
|
||||
# linewidth=1)
|
||||
ax.errorbar((0.8138)*rmsValues*1e6, mean_strehl_psd, yerr=err_strehl_psd, color='b',
|
||||
linestyle='-', label='PSD', capsize=3, markeredgewidth=1)#,
|
||||
# linewidth=1)
|
||||
ax.set_xlabel('$\\sigma_{\\mathrm{WFE}}$ (nm)', fontsize=18)
|
||||
ax.set_ylabel('Strehl', fontsize=18)
|
||||
ax.set_ylim([0,1])
|
||||
ax.set_xlim([np.min(rmsValues)*1e6*(0.8138), np.max(rmsValues)*1e6*(0.8138)])
|
||||
ax2.set_xlim([np.min(rmsValues*(0.8138)/l), np.max(rmsValues*(0.8138)/l)])
|
||||
ax2.set_xlabel('$\\sigma/\\lambda$', fontsize=18)
|
||||
ax.legend(fontsize=18)
|
||||
ax.grid(True, alpha=0.3)
|
||||
ax.tick_params(labelsize=18)
|
||||
ax2.tick_params(labelsize=18)
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/SR_relation_WFE_on_ADC_p1_obscured.png', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/SR_relation_WFE_on_ADC_p1_obscured.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('axes', labelsize='large')
|
||||
|
||||
l = 1.49e-3
|
||||
rmsList = load_variable('./data/SR_RMS_values_obscured.pkl')
|
||||
strehl_zern_complete = load_variable('./data/SR_strehl_zern_obscured.pkl')
|
||||
strehl_psd_complete = load_variable('./data/SR_strehl_psd_obscured.pkl')
|
||||
rms_zern_list_complete = load_variable('./data/SR_rms_zern_complete_obscured.pkl')
|
||||
rms_psd_list_complete = load_variable('./data/SR_rms_psd_complete_obscured.pkl')
|
||||
|
||||
mean_strehl_zern = np.mean(strehl_zern_complete, axis=0)
|
||||
err_strehl_zern = np.std(strehl_zern_complete, axis=0)
|
||||
mean_strehl_psd = np.mean(strehl_psd_complete, axis=0)
|
||||
err_strehl_psd = np.std(strehl_psd_complete, axis=0)
|
||||
|
||||
plot_some_stuff()
|
||||
@@ -0,0 +1,97 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to plot the results of the analysis where the shift
|
||||
of the PSF centroid as a function of the RMS value of the
|
||||
WFE was investigated.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('text', usetex=True)
|
||||
plt.rc('axes', labelsize='large')
|
||||
|
||||
# Optical system constant
|
||||
platescale = 100.13151872258219
|
||||
|
||||
###############################
|
||||
### Lowpass filter analysis ###
|
||||
###############################
|
||||
|
||||
# Load in the data
|
||||
r_airy, r_err_airy = load_variable('./data/lowpass_frequency_filter_airy_distance.pkl')
|
||||
x0_airy, y0_airy, x0_airy_err, y0_airy_err = load_variable('./data/lowpass_frequency_filter_airy_locations.pkl')
|
||||
central_frequencies = np.asarray([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20, 25,
|
||||
30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200,
|
||||
220, 250, 280, 310, 340, 370, 400, 450, 500])
|
||||
|
||||
r_airy_mas = r_airy * platescale
|
||||
r_err_airy_mas = r_err_airy * platescale
|
||||
|
||||
# Plotting the centroid shift for all bandpasses
|
||||
fig = plt.figure(figsize=(9,7))
|
||||
ax1 = fig.add_subplot(111)
|
||||
ax1.scatter(central_frequencies, r_airy_mas, edgecolor='k', facecolors='none', alpha=0.7)
|
||||
ax1.set_xscale('log')
|
||||
ax1.set_xlabel('Cut-off Frequency of the lowpass filter ($\\rho/\\rho_c$)', fontsize=18)
|
||||
ax1.set_ylabel('Centroid shift (mas)', fontsize=18)
|
||||
ax1.tick_params(labelsize=18)
|
||||
ax1.grid(True, alpha=0.3, which='major')
|
||||
ax1.grid(True, alpha=0.1, which='minor')
|
||||
ax1.set_xlim([0.3,550])
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/wfe_frequency_analysis/lowpass_spatial_freq_distance.png', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/wfe_frequency_analysis/lowpass_spatial_freq_distance.pdf', bbox_inches='tight', transparent=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################
|
||||
### Bandpass filter analysis ###
|
||||
################################
|
||||
|
||||
# Load in the data
|
||||
r_airy, r_err_airy = load_variable('./data/bandpass_frequency_filter_airy_distance.pkl')
|
||||
x0_airy, y0_airy, x0_airy_err, y0_airy_err = load_variable('./data/bandpass_frequency_filter_airy_locations.pkl')
|
||||
central_frequencies = load_variable('./data/bandpass_frequency_filter_central_frequencies.pkl')
|
||||
print(central_frequencies, len(central_frequencies), len(r_airy))
|
||||
r_airy_mas = r_airy * platescale
|
||||
r_err_airy_mas = r_err_airy * platescale
|
||||
|
||||
|
||||
# Fit a line in Logarithmic space
|
||||
log_cf = np.log10(central_frequencies)
|
||||
log_r = np.log10(r_airy_mas)
|
||||
coefficients = np.polyfit(log_cf[2:], log_r[2:], 1)
|
||||
best_fit_fnc = np.poly1d(coefficients)
|
||||
best_fit_y = best_fit_fnc(log_cf)
|
||||
|
||||
|
||||
# Plotting the centroid shift for all bandpasses
|
||||
fig = plt.figure(figsize=(9,7))
|
||||
ax1 = fig.add_subplot(111)
|
||||
ax1.scatter(central_frequencies, r_airy_mas, edgecolor='k', facecolors='none', alpha=0.7)
|
||||
ax1.plot(central_frequencies[2:], 10**best_fit_y[2:], 'b-', alpha=0.5, label='Best fit: $y = 0.030 x^{-0.602}$')
|
||||
ax1.set_xscale('log')
|
||||
ax1.set_yscale('log')
|
||||
ax1.set_xlabel('Central Frequency of the bandpass filter ($\\rho/\\rho_c$)', fontsize=18)
|
||||
ax1.set_ylabel('Centroid shift (mas)', fontsize=18)
|
||||
ax1.tick_params(labelsize=18)
|
||||
ax1.grid(True, alpha=0.3, which='major')
|
||||
ax1.grid(True, alpha=0.1, which='minor')
|
||||
ax1.set_xlim([0.3,550])
|
||||
ax1.set_ylim([10**-6, 10**0])
|
||||
ax1.legend(fontsize=18)
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/wfe_frequency_analysis/bandpass_spatial_freq_distance.png', bbox_inches='tight', transparent=True)
|
||||
plt.savefig('./figures/wfe_frequency_analysis/bandpass_spatial_freq_distance.pdf', bbox_inches='tight', transparent=True)
|
||||
plt.show()
|
||||
@@ -0,0 +1,252 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
|
||||
from fourierOptics import *
|
||||
|
||||
'''
|
||||
Author: Joost van den Born, PhD student at University of Groningen
|
||||
Contact: born@astro.rug.nl
|
||||
Description: Script to analyse the shift of the PSF centroid as a
|
||||
function of the RMS value of the WFE.
|
||||
Script made for the SPIE manuscript.
|
||||
'''
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
plt.rc('font', family='serif')
|
||||
plt.rc('axes', labelsize='large')
|
||||
|
||||
# Pick a wavelength
|
||||
l = 1.49e-3
|
||||
input_field_location = './data/ADC_input_field_1001x1001_1.49_onaxis_circular.pkl'
|
||||
|
||||
# Initializing MICADO paraxial model
|
||||
mcd = ParaxialMICADO(n=1001, m=1001, dpix=160, entrance_pupil='open')
|
||||
|
||||
# Propagation of the unperturbed system.
|
||||
Exyz_og, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
# Generate the wavefront error that will be used.
|
||||
wfe = WavefrontError(mcd.n,mcd.m)
|
||||
wfe.generate_height_map(5e-5, 2, 1) # 50 nm RMS for standard, power slope 2, cut-off 1
|
||||
h_data = wfe.data
|
||||
|
||||
# Plotting the WFE, PSD and image planes
|
||||
oC = [np.min(xp), np.max(xp), np.min(yp), np.max(yp)]
|
||||
|
||||
# Mask out areas where the ADC prism isn't
|
||||
_, xadc, yadc = mcd.propagate(l=l,surface=3, zoom=False, show=False,
|
||||
print_progress=True, hx=0, hy=0)
|
||||
mask = np.sqrt(xadc**2 + yadc**2) > 62.5
|
||||
|
||||
# Setting up empty lists for fitting process
|
||||
popt_airy_list, popt_cust_list = [], []
|
||||
pcov_airy_list, custom_var_list = [], []
|
||||
Exyzlist, PSDlist, surfacelist = [], [], []
|
||||
central_frequencies = []
|
||||
|
||||
# Bins in LogSpace
|
||||
x = mcd.x
|
||||
flist = np.asarray([0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20, 25,
|
||||
30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200,
|
||||
220, 250, 280, 310, 340, 370, 400, 450, 500])
|
||||
plt.imshow(wfe.data*1e6, cmap='jet');plt.colorbar();plt.show()
|
||||
|
||||
|
||||
###############################
|
||||
### Lowpass filter analysis ###
|
||||
###############################
|
||||
|
||||
# Do the analysis for each frequency in flist
|
||||
for fmax in flist:
|
||||
print('Lowpass filter - Freq.: {} - Sample {:02d}/{:02d}'.format(fmax, flist.tolist().index(fmax) + 1, len(flist) ) )
|
||||
if fmax == flist[0]:
|
||||
wfe.set_lowpass_filter(fmax)
|
||||
else:
|
||||
i = flist.tolist().index(fmax) - 1
|
||||
wfe.set_lowpass_filter(flist[i])
|
||||
|
||||
scal = wfe.filteredData
|
||||
|
||||
# Adding the wavefront error
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(scal)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_psd,xp,yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
# Set up fitting object
|
||||
psfFit_psd = PSFFitter(xp.real,yp.real,np.abs(Exyz_psd)**2)
|
||||
|
||||
# Fit airy pattern and coupling integral
|
||||
amplitude_guess = np.max(np.abs(Exyz_psd))**2
|
||||
airyFitted, popt_airy, pcov_airy = psfFit_psd.fit_airy_PSF(initialGuess=(amplitude_guess, 0.0, 0.0, 0.0, 0.03))
|
||||
popt_airy_list.append(popt_airy)
|
||||
pcov_airy_list.append([ np.sqrt(pcov_airy[i][i]) for i in range(len(pcov_airy)) ])
|
||||
|
||||
# Other properties
|
||||
original_PSD_curve = wfe.PSD2D[int((mcd.n-1)/2),int((mcd.n-1)/2):]
|
||||
wfe.calculate_1D_PSD(filteredDataFlag=True)
|
||||
PSDlist.append(wfe.filteredPSD2D[int((mcd.n-1)/2),int((mcd.n-1)/2):])
|
||||
surfacelist.append(wfe.filteredData)
|
||||
|
||||
# Plot of the surface profile
|
||||
fig2 = plt.figure(figsize=(12,3))
|
||||
axi1 = fig2.add_subplot(1, 3, 1)
|
||||
wavefrontmap = wfe.filteredData.copy()*1e6
|
||||
wavefrontmap[mask] = np.nan
|
||||
imi1 = axi1.imshow(wavefrontmap, cmap='jet', origin='lower', extent=[xadc.min(), xadc.max(), yadc.min(), yadc.max()])
|
||||
axi1.set_xlabel('x (mm)')
|
||||
axi1.set_ylabel('y (mm)')
|
||||
axi1.set_xlim([-65,65])
|
||||
axi1.set_ylim([-65,65])
|
||||
fig2.colorbar(imi1, ax=axi1, label='Surface height (nm)')
|
||||
|
||||
# Plot of the PSD
|
||||
axi2 = fig2.add_subplot(1, 3, 2)
|
||||
axi2.loglog(original_PSD_curve, 'k-')
|
||||
axi2.loglog(PSDlist[-1], 'y-')
|
||||
axi2.grid(which='major', alpha=0.3)
|
||||
axi2.grid(which='minor', alpha=0.1)
|
||||
axi2.set_xlabel('Normalized Radial Frequency ($\\rho/\\rho_c$)')
|
||||
axi2.set_ylabel('PSD (mm$^4$)')
|
||||
|
||||
# Plot of the PSF
|
||||
axi3 = fig2.add_subplot(1, 3, 3)
|
||||
differential_amplitude = np.abs(Exyz_og) - np.abs(Exyz_psd)
|
||||
if (differential_amplitude == 0).all():
|
||||
norm_par = None
|
||||
else:
|
||||
norm_par = LogNorm()
|
||||
imi3 = axi3.imshow(differential_amplitude, extent=oC, cmap='gray', origin='lower', norm=norm_par)
|
||||
fig2.colorbar(imi3, ax=axi3, label='Differential amplitude')
|
||||
axi3.set_xlim([-1,1])
|
||||
axi3.set_ylim([-1,1])
|
||||
axi3.set_xlabel('x (mm)')
|
||||
axi3.set_ylabel('y (mm)')
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/wfe_frequency_analysis/lowpass_spatial_freq_{:.0f}.png'.format(flist.tolist().index(fmax) + 1), bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
|
||||
# Optimum fit parameters for all scaled surface errors
|
||||
amplitude_airy, x0_airy, y0_airy, R_airy, offset_airy = np.asarray(popt_airy_list).T
|
||||
amplitude_airy_err, x0_airy_err, y0_airy_err, R_airy_err, offset_airy_err = np.asarray(pcov_airy_list).T
|
||||
|
||||
# Distance from original centroid at (0,0)
|
||||
r_airy = np.sqrt(x0_airy**2+y0_airy**2)
|
||||
r_err_airy = np.sqrt( (x0_airy**2*x0_airy_err**2+y0_airy**2*y0_airy_err**2) / (x0_airy**2+y0_airy**2))
|
||||
r_airy_mas = r_airy * mcd.platescale * 1000
|
||||
r_err_airy_mas = r_err_airy * mcd.platescale * 1000
|
||||
|
||||
save_variable('./data/lowpass_frequency_filter_airy_distance.pkl', (r_airy, r_err_airy))
|
||||
save_variable('./data/lowpass_frequency_filter_airy_locations.pkl', (x0_airy, y0_airy, x0_airy_err, y0_airy_err))
|
||||
print('Platescale in mas/mm: ', mcd.platescale * 1000)
|
||||
|
||||
|
||||
|
||||
################################
|
||||
### Bandpass filter analysis ###
|
||||
################################
|
||||
|
||||
# Setting up empty lists for fitting process
|
||||
popt_airy_list, popt_cust_list = [], []
|
||||
pcov_airy_list, custom_var_list = [], []
|
||||
Exyzlist, PSDlist, surfacelist = [], [], []
|
||||
central_frequencies = []
|
||||
|
||||
# Do the analysis for each frequency in flist
|
||||
for fmax in flist:
|
||||
print('Bandpass - Freq.: {} - Sample {:02d}/{:02d}'.format(fmax, flist.tolist().index(fmax) + 1, len(flist) ) )
|
||||
if fmax == flist[0]:
|
||||
# Use a lowpass filter only for the very first element in flist
|
||||
wfe.set_lowpass_filter(fmax)
|
||||
central_frequencies.append(fmax)
|
||||
else:
|
||||
# Set a bandpass between the current and previous frequency element
|
||||
i = flist.tolist().index(fmax) - 1
|
||||
wfe.set_bandpass_filter(flist[i], fmax)
|
||||
central_frequencies.append(np.mean([flist[i],fmax]))
|
||||
|
||||
|
||||
# Adding the wavefront error
|
||||
scal = wfe.filteredData
|
||||
mcd.ELT_ADC.p1.add_wavefront_error(scal)
|
||||
|
||||
# Performing the propagation using Fresnel approximation to the focal plane.
|
||||
Exyz_psd,xp,yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
|
||||
print_progress=False, hx=0, hy=0,
|
||||
load_up_to_adc=input_field_location)
|
||||
|
||||
# Set up fitting object
|
||||
psfFit_psd = PSFFitter(xp.real,yp.real,np.abs(Exyz_psd)**2)
|
||||
|
||||
# Fit airy pattern and coupling integral
|
||||
amplitude_guess = np.max(np.abs(Exyz_psd))**2
|
||||
airyFitted, popt_airy, pcov_airy = psfFit_psd.fit_airy_PSF(initialGuess=(amplitude_guess, 0.0, 0.0, 0.0, 0.03))
|
||||
popt_airy_list.append(popt_airy)
|
||||
pcov_airy_list.append([ np.sqrt(pcov_airy[i][i]) for i in range(len(pcov_airy)) ])
|
||||
|
||||
# Other properties
|
||||
original_PSD_curve = wfe.PSD2D[int((mcd.n-1)/2),int((mcd.n-1)/2):]
|
||||
wfe.calculate_1D_PSD(filteredDataFlag=True)
|
||||
PSDlist.append(wfe.filteredPSD2D[int((mcd.n-1)/2),int((mcd.n-1)/2):])
|
||||
surfacelist.append(wfe.filteredData)
|
||||
|
||||
# Plot of the surface profile
|
||||
fig2 = plt.figure(figsize=(12,3))
|
||||
axi1 = fig2.add_subplot(1, 3, 1)
|
||||
wavefrontmap = wfe.filteredData.copy()*1e6
|
||||
wavefrontmap[mask] = np.nan
|
||||
imi1 = axi1.imshow(wavefrontmap, cmap='jet', origin='lower', extent=[xadc.min(), xadc.max(), yadc.min(), yadc.max()])
|
||||
axi1.set_xlabel('x (mm)')
|
||||
axi1.set_ylabel('y (mm)')
|
||||
axi1.set_xlim([-65,65])
|
||||
axi1.set_ylim([-65,65])
|
||||
fig2.colorbar(imi1, ax=axi1, label='Surface height (nm)')
|
||||
|
||||
# Plot of the PSD
|
||||
axi2 = fig2.add_subplot(1, 3, 2)
|
||||
axi2.loglog(original_PSD_curve, 'k-')
|
||||
axi2.loglog(PSDlist[-1], 'y-')
|
||||
axi2.grid(which='major', alpha=0.3)
|
||||
axi2.grid(which='minor', alpha=0.1)
|
||||
axi2.set_xlabel('Normalized Radial Frequency ($\\rho/\\rho_c$)')
|
||||
axi2.set_ylabel('PSD (mm$^4$)')
|
||||
|
||||
# Plot of the PSF
|
||||
axi3 = fig2.add_subplot(1, 3, 3)
|
||||
differential_amplitude = np.abs(Exyz_og) - np.abs(Exyz_psd)
|
||||
if (differential_amplitude == 0).all():
|
||||
norm_par = None
|
||||
else:
|
||||
norm_par = LogNorm()
|
||||
imi3 = axi3.imshow(differential_amplitude, extent=oC, cmap='gray', origin='lower', norm=norm_par)
|
||||
fig2.colorbar(imi3, ax=axi3, label='Differential amplitude')
|
||||
axi3.set_xlim([-1,1])
|
||||
axi3.set_ylim([-1,1])
|
||||
axi3.set_xlabel('x (mm)')
|
||||
axi3.set_ylabel('y (mm)')
|
||||
plt.tight_layout()
|
||||
plt.savefig('./figures/wfe_frequency_analysis/bandpass_spatial_freq_{:.0f}.png'.format(flist.tolist().index(fmax) + 1), bbox_inches='tight', transparent=True)
|
||||
plt.close()
|
||||
|
||||
# Optimum fit parameters for all scaled surface errors
|
||||
amplitude_airy, x0_airy, y0_airy, R_airy, offset_airy = np.asarray(popt_airy_list).T
|
||||
amplitude_airy_err, x0_airy_err, y0_airy_err, R_airy_err, offset_airy_err = np.asarray(pcov_airy_list).T
|
||||
|
||||
# Distance from original centroid at (0,0)
|
||||
r_airy = np.sqrt(x0_airy**2+y0_airy**2)
|
||||
r_err_airy = np.sqrt( (x0_airy**2*x0_airy_err**2+y0_airy**2*y0_airy_err**2) / (x0_airy**2+y0_airy**2))
|
||||
r_airy_mas = r_airy * mcd.platescale * 1000
|
||||
r_err_airy_mas = r_err_airy * mcd.platescale * 1000
|
||||
|
||||
save_variable('./data/bandpass_frequency_filter_airy_distance.pkl', (r_airy, r_err_airy))
|
||||
save_variable('./data/bandpass_frequency_filter_airy_locations.pkl', (x0_airy, y0_airy, x0_airy_err, y0_airy_err))
|
||||
save_variable('./data/bandpass_frequency_filter_central_frequencies.pkl', central_frequencies)
|
||||
print('Platescale in mas/mm: ', mcd.platescale * 1000)
|
||||
|
||||
Reference in new issue
Block a user