Skip to content

Commit 5e99de0

Browse files
committed
Merge branch 'master' of github.com:mikeireland/pyxao
Almost have chara.py working again.
2 parents bff243f + bfe9e0a commit 5e99de0

9 files changed

+195
-390
lines changed

chara.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
import numpy as np
55
import matplotlib.pyplot as plt
66
import matplotlib.cm as cm
7-
import pdb
7+
try:
8+
import ipdb
9+
except:
10+
#The following ling is dodgy, but still enables set_trace()
11+
import pdb as ipdb
12+
813
plt.ion()
914
#from PyQt4 import QtGui
1015
#from PyQt4 import QtCore
@@ -32,7 +37,7 @@
3237
#dm = pyxao.DeformableMirror(wavefronts=[wf_sense,wf_image],actuator_pitch=0.135,geometry='hexagonal', plotit=True,central_actuator=True)
3338
#wfs = pyxao.ShackHartmann(wavefronts=[wf_sense],lenslet_pitch = 0.17,plotit=True, central_lenslet=True)
3439

35-
#pdb.set_trace()
40+
#ipdb.set_trace()
3641
#print("Click to continue")
3742
#dummy=plt.ginput(1)
3843

@@ -48,16 +53,17 @@
4853
#See if the reconstructor works!
4954
#sensors,ims = aos.correct_twice()
5055

51-
im_mn, im_perfect = aos.run_loop(dt=0.001,plotit=True,niter=260,nframesbetweenplots=50)
56+
im_mn= aos.run_loop(dt=0.001,plotit=True,niter=260,nframesbetweenplots=50)
5257

58+
#im_perfect = ??? #How do we compute Strehl now?
5359

5460
#Uncomment the line below instead to see uncorrected seeing.
5561
#im_mn = aos.run_loop(plotit=True,gain=0.0)
5662

5763
#Strehl: Regrid in order to sample finely the peak.
58-
strehl = np.max(ot.utils.regrid_fft(im_mn,(1024,1024)))/np.max(ot.utils.regrid_fft(im_perfect,(1024,1024)))
64+
#strehl = np.max(ot.utils.regrid_fft(im_mn,(1024,1024)))/np.max(ot.utils.regrid_fft(im_perfect,(1024,1024)))
5965

60-
sz = im_mn.shape[0]
61-
plt.clf()
62-
plt.imshow(im_mn[sz//2-20:sz//2+20,sz//2-20:sz//2+20],interpolation='nearest', cmap=cm.gist_heat)
63-
print("Strehl: {0:6.3f}".format(strehl))
66+
#sz = im_mn.shape[0]
67+
#plt.clf()
68+
#plt.imshow(im_mn[sz//2-20:sz//2+20,sz//2-20:sz//2+20],interpolation='nearest', cmap=cm.gist_heat)
69+
#print("Strehl: {0:6.3f}".format(strehl))

minerva_red.py

100644100755
+30-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import numpy as np
55
import matplotlib.pyplot as plt
66
import matplotlib.cm as cm
7-
import pdb
7+
try:
8+
import ipdb
9+
except:
10+
import pdb
811
plt.ion()
912
np.random.seed(1)
1013

@@ -13,43 +16,53 @@
1316
#Strehl:
1417
#np.max(ot.utils.regrid_fft(im_mn_on,(1024,1024)))/np.max(ot.utils.regrid_fft(im_mn,(1024,1024)))
1518

19+
"""
20+
Observations:
21+
- it's different for different sampling values because of how ot.kmf() computes the phase screen
22+
"""
23+
1624
#Initialize some wavefronts. 0.56 to 0.76 microns sense (average 0.66 microns)
1725
#0.77 to 0.93 microns science (average 0.85 microns). For such a narrow field of
1826
#view, we can assume monochromatic
1927
pupil={'type':"annulus", 'dout':0.7,'din':0.32}
2028
# Wavefront sensor wavelength
21-
wf_sense = pyxao.Wavefront(wave=0.66e-6,m_per_px=0.01,sz=128,pupil=pupil)
29+
scale_factor = 1
30+
wf_sense = pyxao.Wavefront(wave=0.66e-6,m_per_px=0.01/scale_factor,sz=256*scale_factor,pupil=pupil)
2231
# Science wavelength
23-
wf_image = pyxao.Wavefront(wave=0.85e-6,m_per_px=0.01,sz=128,pupil=pupil)
32+
wf_image = pyxao.Wavefront(wave=0.85e-6,m_per_px=0.01/scale_factor,sz=256*scale_factor,pupil=pupil)
2433

2534
dm = pyxao.DeformableMirror(wavefronts=[wf_sense,wf_image],actuator_pitch=0.115,geometry='square', plotit=False,central_actuator=True)
26-
wfs = pyxao.ShackHartmann(wavefronts=[wf_sense],lenslet_pitch = 0.105,central_lenslet=False,sampling=1,plotit=False,geometry='hexagonal')
35+
wfs = pyxao.ShackHartmann(wavefronts=[wf_sense],lenslet_pitch = 0.105,central_lenslet=False,sampling=1,plotit=False,geometry='hexagonal',N_phot = 1600 * 1e4 * 1/2000 * 0.90 * 1000)
2736

2837
#Add an atmosphere model to our wavefronts.
29-
atm = pyxao.Atmosphere(sz=1024, m_per_px=wf_sense.m_per_px,r_0=[0.1,0.1,0.1]) #For 1.7" seeing, try: ,r_0=[0.1,0.1,0.1])
38+
atm = pyxao.Atmosphere(sz=512*scale_factor, m_per_px=wf_sense.m_per_px,r_0=[0.1,0.1,0.1],v_wind=[0,0,0],seed=5) #For 1.7" seeing, try: ,r_0=[0.1,0.1,0.1])
3039

3140
aos = pyxao.SCFeedBackAO(dm,wfs,atm,image_ixs=1)
32-
aos.find_response_matrix()
33-
aos.compute_reconstructor(threshold=0.1)
41+
# aos.find_response_matrix()
42+
# aos.compute_reconstructor(threshold=0.1)
43+
# np.save('minerva_red_response_matrix', aos.response_matrix)
44+
# np.save('minerva_red_reconstructor', aos.reconstructor)
3445

46+
# ipdb.set_trace()
47+
aos.reconstructor = np.load('minerva_red_reconstructor.npy')
48+
aos.response_matrix = np.load('minerva_red_response_matrix.npy')
3549

36-
wf_sense.add_atmosphere(atm)
37-
wf_image.add_atmosphere(atm)
50+
# Want 1600 photons/cm2/s for the LGS.
51+
# = photons/m/s = 1600 * 1e4
52+
# photons in im = 1600 * 1e4 * D * 1/2000
3853

3954
#See if the reconstructor works!
4055
#sensors,ims = aos.correct_twice()
4156

42-
# pdb.set_trace()
43-
psfs = aos.run_loop(plotit=True,dt=0.002,niter=50,mode='integrator',plate_scale_as_px=0.1,psf_ix = 1,nframesbetweenplots=10)
57+
# ipdb.set_trace()
58+
psfs = aos.run_loop(plotit=True,dt=0.002,niter=1,mode='open loop',plate_scale_as_px=0.1,psf_ix = 1,nframesbetweenplots=1)
4459
psf_mn = np.mean(psfs,axis=0)
45-
#Uncomment the line below instead to see uncorrected seeing.
46-
# im_mn = aos.run_loop(plotit=True,dt=0.002,nphot=1e4,niter=50,mode='dodgy_damping',dodgy_damping=0.0,gain=0.0,plate_scale_as_px=0.125)[-2]
4760

4861
#Strehl: Regrid in order to sample finely the peak.
4962
psf_dl = aos.psf_dl(plate_scale_as_px=0.1,psf_ix=1)
5063
strehl = np.max(ot.utils.regrid_fft(psf_mn,(1024,1024)))/np.max(ot.utils.regrid_fft(psf_dl,(1024,1024)))
5164

52-
sz = psf_mn.shape[0]
53-
plt.figure()
54-
plt.imshow(im_mn[sz//2-20:sz//2+20,sz//2-20:sz//2+20],interpolation='nearest', cmap=cm.gist_heat)
55-
print("Strehl: {0:6.3f}".format(strehl))
65+
# sz = psf_mn.shape[0]
66+
# plt.figure()
67+
# plt.imshow(psf_mn[sz//2-20:sz//2+20,sz//2-20:sz//2+20],interpolation='nearest', cmap=cm.gist_heat)
68+
# print("Strehl: {0:6.3f}".format(strehl))

pyxao/ao_system.py

100644100755
+28-58
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
import numpy as np
55
import matplotlib.pyplot as plt
66
from matplotlib.ticker import FormatStrFormatter
7-
import pdb
7+
try:
8+
import ipdb
9+
except:
10+
#The following ling is dodgy, but still enables set_trace()
11+
import pdb as ipdb
812
import scipy.ndimage as nd
913
import scipy.linalg as la
1014
import matplotlib.cm as cm
@@ -87,6 +91,8 @@ def __init__(self,
8791
self.wfs = wfs
8892
self.atm = atm
8993
self.dm_poke_scale = dm_poke_scale
94+
self.response_matrix = None
95+
self.reconstructor = None
9096

9197
#Add an atmosphere to all wavefronts.
9298
for wf in self.wavefronts:
@@ -95,7 +101,6 @@ def __init__(self,
95101
#############################################################################################################
96102
def psf_dl(self, plate_scale_as_px,
97103
psf_ix = None,
98-
band = None,
99104
crop = True, # Whether or not to crop the PSF. If set to False, the below two arguments are irrelevant.
100105
psf_sz_cropped = None, # Size of the PSF. By default cropped at the 10th Airy ring
101106
psf_sigma_limit_N_os = TENTH_AIRY_RING, # Corresponds to 10 Airy rings
@@ -163,7 +168,7 @@ def find_response_matrix(self,mode='onebyone',amplitude=1e-7):
163168
#Check that poking in both directions is equivalent!
164169
if (np.sum(wfs_plus*wfs_minus)/np.sum(wfs_plus*wfs_plus) > -0.9):
165170
print("WARNING: Poking the DM is assymetric!!!")
166-
# pdb.set_trace()
171+
# ipdb.set_trace()
167172

168173
# Taking the mean response value.
169174
self.response_matrix[i] = 0.5*(wfs_plus - wfs_minus).flatten()
@@ -264,8 +269,6 @@ def correct_twice(self,plotit=False):
264269
return [measurements0,measurements1,measurements2],[im0,im1,im2]
265270

266271

267-
268-
269272
#############################################################################################################
270273
def run_loop(self, dt,
271274
mode = 'integrator',
@@ -339,19 +342,30 @@ def run_loop(self, dt,
339342
else:
340343
psf_sz_cropped = psf_sz
341344

345+
#Make plate_scale_as_px for Nyquist sampling of the full size.
346+
#See XXX below for a bug.
347+
if not plate_scale_as_px:
348+
plate_scale_rad_px = self.wavefronts[psf_ix].wave / (self.wavefronts[psf_ix].sz * self.wavefronts[psf_ix].m_per_px)
349+
plate_scale_as_px = np.degrees(plate_scale_rad_px) * 3600
350+
plate_scale_as_px_in = None
351+
else:
352+
plate_scale_as_px_in = plate_scale_as_px
353+
342354
# Arrays to hold images
343355
psfs_cropped = np.zeros((niter, psf_sz_cropped, psf_sz_cropped))# at the psf_ix wavelength
344356

345357
""" AO Control loop """
346358
print("Starting the AO control loop with control logic mode '%s'..." % mode)
347359
for k in range(niter):
348-
#------------------ AO CONTROL ------------------#
349-
print("Iteration %d..." % (k+1))
350-
# Evolve the atmosphere & update the wavefront fields to reflect the new atmosphere.
360+
#------------------ EVOLVING THE ATMOSPHERE ------------------#
361+
if ((k / niter) * 100) % 10 == 0:
362+
print("{:d}% done...".format(int((k / niter) * 100)))
363+
# Evolve the atmosphere & update the wavefront fields to reflect the new atmosphere.
351364
self.atm.evolve(dt * k)
352365
for wf in self.wavefronts:
353366
wf.atm_field()
354367

368+
#------------------ AO CONTROL ------------------#
355369
if mode == 'open loop':
356370
# We still measure the wavefront for plotting.
357371
self.wfs.sense()
@@ -374,13 +388,14 @@ def run_loop(self, dt,
374388
raise UserWarning
375389
coefficients_current = coefficients_next; # Update the DM coefficients.
376390

391+
#-------------------- SAVING PSF ----------------------#
377392
# Create the PSF
378-
psf = self.wavefronts[psf_ix].image(plate_scale_as_px = plate_scale_as_px)
379-
psf /= sum(psf.flatten())
380-
# Saving the PSF.
393+
# NB if the following line has non-none, then we have a uint 8 error XXX
394+
psf = self.wavefronts[psf_ix].image(plate_scale_as_px = plate_scale_as_px_in)
395+
psf /= np.sum(psf.flatten())
381396
psfs_cropped[k] = centre_crop(psf, psf_sz_cropped)
382397

383-
# Plotting
398+
#------------------ PLOTTING ------------------#
384399
if plotit & ((k % nframesbetweenplots) == 0):
385400
if k == 0:
386401
axes = []
@@ -405,6 +420,7 @@ def run_loop(self, dt,
405420
plt.gca().xaxis.set_major_formatter(FormatStrFormatter('%.2f\"'))
406421
plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f\"'))
407422
plt.colorbar(plots[-1],fraction=COLORBAR_FRACTION, pad=COLORBAR_PAD)
423+
ipdb.set_trace()
408424
else:
409425
# Update the plots
410426
plot_wfs.set_data(self.wfs.im)
@@ -416,51 +432,5 @@ def run_loop(self, dt,
416432

417433
return psfs_cropped
418434

419-
#############################################################################################################
420-
def _plot_ao_loop_iteration(self, k, plot_sz_px):
421-
""" Plot the WFS detector image, phase and psf in an iteration of the AO loop. """
422-
if k == 0:
423-
axes = []
424-
plots = []
425-
plt.rc('text', usetex=True)
426-
427-
# WFS plot
428-
fig_wfs = mu.newfigure(2,2)
429-
ax_wfs = fig_wfs.add_subplot(111) # WFS detector image
430-
ax_wfs.title.set_text(r'WFS detector')
431-
ax_wfs.axis( [0,self.wavefronts[0].sz,0,self.wavefronts[0].sz] )
432-
plot_wfs = ax_wfs.imshow(self.wfs.im,interpolation='nearest',cmap=cm.gray)
433-
434-
fig = mu.newfigure(width=2,height=1)
435-
436-
# Phase
437-
axes.append(fig.add_subplot(N_science_imgs,2,2*j+1))
438-
axes[-1].title.set_text(r'Corrected phase ($\lambda$ = %d nm)' % (self.wavefronts[self.image_ixs[j]].wave*1e9))
439-
plots.append(axes[-1].imshow(np.angle(self.wavefronts[self.image_ixs[j]].field)*self.wavefronts[self.image_ixs[j]].pupil,interpolation='nearest', cmap=cm.gist_rainbow, vmin=-np.pi, vmax=np.pi))
440-
mu.colourbar(plots[-1])
441-
442-
# Science image
443-
axes.append(fig.add_subplot(N_science_imgs,2,2*j+2))
444-
axes[-1].title.set_text(r'Science Image ($\lambda$ = %d nm)' % (self.wavefronts[self.image_ixs[j]].wave*1e9))
445-
pad_x = max((imsize - plot_sz_px[0]) // 2, 0)
446-
pad_y = max((imsize - plot_sz_px[1]) // 2, 0)
447-
im_cropped = psf_science[j,pad_x:pad_x + min(imsize, plot_sz_px[0]),pad_y:pad_y + min(imsize, plot_sz_px[1])]
448-
plots.append(axes[-1].imshow(im_cropped,interpolation='nearest', cmap=cm.gist_heat, norm=LogNorm()))
449-
mu.colourbar(plots[-1])
450-
else:
451-
# Update the plots
452-
plot_wfs.set_data(self.wfs.im)
453-
fig.suptitle(r'AO-corrected phase and science images, $k = %d, K_i = %.2f, K_{leak} = %.2f$' % (k, K_i, K_leak))
454-
for j in range(N_science_imgs):
455-
plots[2*j].set_data(np.angle(self.wavefronts[self.image_ixs[j]].field)*self.wavefronts[self.image_ixs[j]].pupil)
456-
pad_x = max((imsize - plot_sz_px[0]) // 2, 0)
457-
pad_y = max((imsize - plot_sz_px[1]) // 2, 0)
458-
im_cropped = im_science[j,pad_x:pad_x + min(imsize, plot_sz_px[0]),pad_y:pad_y + min(imsize, plot_sz_px[1])]
459-
plots[2*j+1].set_data(im_cropped)
460-
461-
plt.draw()
462-
plt.pause(0.00001) # Need this to plot on some machines.
463-
464-
465435

466436

pyxao/atmosphere.py

100644100755
+6-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import matplotlib.pyplot as plt
55
import matplotlib.cm as cm
66
import scipy.ndimage as nd
7-
import pdb
7+
try:
8+
import ipdb
9+
except:
10+
import pdb
811

912
class Atmosphere():
1013
"""A model of the atmosphere, including a fixed phase screen.
@@ -59,7 +62,7 @@ def __init__(self,sz = 1024,
5962
if ( (len(elevations) != len(v_wind)) |
6063
(len(v_wind) != len(r_0)) |
6164
(len(r_0) != len(angle_wind)) ):
62-
pdb.set_trace()
65+
ipdb.set_trace()
6366
print("ERROR: elevations, v_wind, r_0 and angle_wind must all be the same length")
6467
raise UserWarning
6568

@@ -73,7 +76,7 @@ def __init__(self,sz = 1024,
7376
self.delays0 = np.empty( (len(r_0),sz,sz) )
7477
for i in range(self.nlayers):
7578
self.delays0[i] = ot.kmf(sz,seed) * np.sqrt(6.88*(m_per_px/r_0[i])**(5.0/3.0)) * wave_ref / 2 / np.pi
76-
79+
7780
#Delays in meters at another time.
7881
self.delays = self.delays0.copy()
7982

pyxao/deformable_mirror.py

100644100755
+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import numpy as np
44
import matplotlib.pyplot as plt
55
import scipy.ndimage as nd
6-
import pdb
6+
try:
7+
import ipdb
8+
except:
9+
import pdb
710

811
class DeformableMirror():
912
"""A deformable mirror.

0 commit comments

Comments
 (0)