Available Optical Element Classes¶
There are many available predefined types of optical elements in poppy. In addition you can easily specify your own custom optics.
- Pupils and Aperture Stops
- Image Plane Elements
- General Purpose Elements
- Wavefront Errors
- Deformable Mirrors
- Supplying Custom Optics from Files or Arrays
Pupils and Aperture Stops¶
These optics have dimensions specified in meters, or other units of length. They can be used in the pupil planes of a Fraunhofer optical system, or any plane of a Fresnel optical system. All of these may be translated or rotated around in the plane by setting the rotation
, shift_x
or shift_y
parameters.
CircularAperture¶
A basic aperture stop.
[3]:
optic = poppy.CircularAperture(radius=1)
optic.display(what='both');
SquareAperture¶
A square stop. The specified size is the length across any one side.
[4]:
optic = poppy.SquareAperture(size=1.0)
optic.display(what='both');
RectangularAperture¶
Specify the width and height to define a rectangle.
[5]:
optic = poppy.RectangleAperture(width=0.5*u.m, height=1.0*u.m)
optic.display(what='both');
HexagonAperture¶
For instance, one segment of a segmented mirror.
[6]:
optic = poppy.HexagonAperture(side=1.0)
optic.display(what='both');
MultiHexagonAperture¶
Arbitrarily many hexagons, in rings. You can adjust the size of each hex, the gap width between them, and whether any hexes are missing (in particular the center one).
[7]:
optic = poppy.MultiHexagonAperture(side=1, rings=1, gap=0.05, center=True)
optic.display(what='both');
NgonAperture¶
Triangular apertures or other regular polygons besides hexagons are uncommon, but a generalized N-gon aperture allows modeling them if needed.
[8]:
optic = poppy.NgonAperture(nsides=5)
optic.display(what='both');
SecondaryObscuration¶
This class adds an obstruction which is supported by a regular evenly-spaced grid of identical struts, or set n_supports=0
for a free-standing obscuration.
[9]:
optic = poppy.SecondaryObscuration(secondary_radius=1.0,
n_supports=4,
support_width=5*u.cm)
optic.display(what='both');
AsymmetricSecondaryObscuration¶
This class allows making more complex “spider” support patterns than the SecondaryObscuration class. Each strut may individually be adjusted in angle, width, and offset in x and y from the center of the aperture. Angles are given in a convention such that the +Y axis is 0 degrees, and increase counterclockwise (based on the typical astronomical convention that north is the origin for position angles, increasing towards east.)
[10]:
optic = poppy.AsymmetricSecondaryObscuration(secondary_radius=0.3*u.m,
support_angle=(40, 140, 220, 320),
support_width=[0.05, 0.03, 0.03, 0.05],
support_offset_x=[0, -0.2, 0.2, 0],
name='Complex secondary')
optic.display(what='both');
ThinLens¶
This models a lens or powered mirror in the thin-lens approximation, with the retardance specified in terms of a number of waves at a given wavelength. The lens is perfectly achromatic.
[11]:
optic = poppy.ThinLens(nwaves=1, reference_wavelength=1e-6*u.m, radius=10*u.cm)
optic.display(what='both');
GaussianAperture¶
This Gaussian profile can be used for instance to model an apodizer in the pupil plane, or to model a beam launched from a fiber optic.
[12]:
optic = poppy.GaussianAperture(fwhm=1*u.m)
optic.display(what='both');
KnifeEdge¶
A knife edge is an infinite opaque half-plane.
[13]:
optic = poppy.optics.KnifeEdge(rotation=0)
optic.display(what='both');
Image Plane Elements¶
Image plane classes have dimensions specified in units of arcseconds projected onto the sky. These classes can be placed in image planes in either Fraunhofer or Fresnel optical systems.
RectangularFieldStop¶
This class can be used to implement a spectrograph slit, for instance.
[15]:
optic = poppy.RectangularFieldStop()
optic.display(what='both');
AnnularFieldStop¶
You can also use this as a circular field stop by setting radius_inner=0
.
[16]:
optic = poppy.optics.AnnularFieldStop(radius_inner=1, radius_outer=3)
optic.display(what='both');
BarOcculter¶
This is an opaque bar or line.
[20]:
optic = poppy.optics.BarOcculter(width=1, height=10)
optic.display(what='both');
Four Quadrant Phase Mask¶
The class is named IdealFQPM
because this implements a notionally perfect 4QPM at some given wavelength; it has precisely half a wave retardance at the reference wavelength.
[22]:
optic = poppy.IdealFQPM(wavelength=1*u.micron)
optic.display(what='both');
General Purpose Elements¶
ScalarTransmission¶
This class implements a uniformly multiplicative transmission factor, i.e. a neutral density filter.
[3]:
optic = poppy.ScalarTransmission(transmission=0.85)
optic.display(what='both');
Inverse Transmission¶
This optic acts on another to flip the transmission: Areas which were 0 become 1 and vice versa. This operation is not meant as a representative of some real physical process itself, but can be useful in building certain types of compound optics.
[4]:
circ = poppy.CircularAperture(radius=1)
ax1= plt.subplot(121)
circ.display(what='amplitude', ax=ax1)
ax2= plt.subplot(122)
inverted_circ = poppy.InverseTransmission(circ)
inverted_circ.display(grid_size=3, what='amplitude', ax=ax2)
Wavefront Errors¶
Wavefront error classes can be used to represent various forms of phase delay, typically at a pupil plane. Further documentation on these classes can be found here.
ZernikeWFE¶
Wavefront errors can be specified by giving a list of Zernike coefficients, which are ordered using the Noll indexing convention. The different Zernikes are then added together to make an overall wavefront map.
Note that while the Zernikes are defined with respect to some notional circular aperture of a given radius, by default this class just implements the wavefront error part, not the aperture stop.
[17]:
optic = poppy.ZernikeWFE(radius=1*u.cm,
coefficients=[0.1e-6, 3e-6, -3e-6, 1e-6, -7e-7, 0.4e-6, -2e-6],
aperture_stop=False)
optic.display(what='both', opd_vmax=1e-5, grid_size=0.03);
You can optionally set the parameter aperture_stop=True
to ZernikeWFE if you want it to also act as a circular aperture stop.
[18]:
optic = poppy.ZernikeWFE(radius=1*u.cm,
coefficients=[0, 2e-6, 3e-6, 2e-6, 0, 0.4e-6, 1e-6],
aperture_stop=True)
optic.display(what='both', opd_vmax=1e-5, grid_size=0.03);
SineWaveWFE¶
A sinusoidal ripple across a mirror, for instance a deformable mirror. Specify the ripple by the spatial frequency (i.e. cycles per meter). Use the amplitude
, rotation
and phaseoffset
parameters to adjust the sine wave.
[16]:
optic = poppy.SineWaveWFE(spatialfreq=5/u.meter,
amplitude=1*u.micron,
rotation=20)
optic.display(what='both', opd_vmax=1*u.micron);
StatisticalPSDWFE¶
A wavefront error from a random phase with a power spectral density from a power law of index -index
. The seed
parameter allows to reinitialize the pseudo-random number generator
[3]:
optic = poppy.wfe.StatisticalPSDWFE(index=3.0, wfe=50*u.nm, radius=7*u.mm, seed=None)
optic.display(what='both', opd_vmax=150*u.nm);
Deformable Mirrors¶
Continuous Deformable Mirrors¶
Represents a continuous phase-sheet DM, such as from Boston Micromachines or AOA Xinetics. Individual actuators in the DM can be addressed and poked with the set_actuator
function. That function takes 3 parameters: set_actuator(x_act, y_act, piston)
.
[3]:
dm = poppy.dms.ContinuousDeformableMirror(dm_shape=(16,16), actuator_spacing=0.3*u.mm, radius=2.3*u.mm)
dm.set_actuator(2, 4, 1e-6)
dm.set_actuator(12, 12, -1e-6)
dm.display(what='both', opd_vmax=1*u.micron);
You can also set all actuators in the entire DM surface at once by calling set_surface
with a suitably-sized array.
[4]:
dm = poppy.dms.ContinuousDeformableMirror(dm_shape=(32,32), actuator_spacing=0.3*u.mm, radius=4.9*u.mm)
target_surf = fits.getdata('dm_example_surface.fits')
dm.set_surface(target_surf);
dm.display(what='both');
The DM class has much more functionality than currently shown here, including loading measured influence functions and models of high-spatial-frequency actuator print-through. These features are not yet fully documented but please contact Marshall if you’re interested.
Hexagonally Segmented Deformable Mirrors¶
For instance, one of the devices made by Iris AO.
In this case, the set_actuator
function takes 4 parameters: set_actuator(segment_number, piston, tip, tilt)
.
[5]:
hexdm = poppy.dms.HexSegmentedDeformableMirror(rings=3)
hexdm.set_actuator(12, 0.5*u.micron, 0, 0)
hexdm.set_actuator(18, -0.25*u.micron, 0, 0)
hexdm.set_actuator(6, 0, -0.25*u.microradian, 0)
for i in range (19, 37, 3): hexdm.set_actuator(i, 0, 0, 2*u.microradian)
hexdm.display(what='both');
[ ]: