pyoptics.fresnel¶
Fresnel lenses: design, ray tracing with real facets, and the way back.
A Fresnel lens keeps the surface slopes of a thick refracting lens (its “parent”, a sphere, conic or even asphere) and drops the material that only holds the surface at its height: the sag is cut into annular zones and every zone is lowered onto a common base plane. What remains is a plate with a sawtooth relief of facets (the active, refracting parts) and risers (the steps between the zones, also called drafts or groove walls). A. Fresnel proposed it in 1822 for lighthouse lenses; today Fresnel lenses are moulded in PMMA or polycarbonate for solar concentrators, overhead projectors, spotlights, field lenses of cameras and VR headsets and LED optics.
Geometry¶
In the local frame of a FresnelSurface the base plane is z = 0 and the
parent sag is z_p(r) (raytrace.Surface.sag). The zone radii are
0 = r_0 < r_1 < … < r_K, for a constant groove pitch (moulded lenses),
a constant groove depth (diamond turned lenses, kinoforms) or given
explicitly (zone_radii()). The facet of zone k is
curved facets: f_k(r) = z_p(r) - z_p(r_k),
flat facets: f_k(r) = s_k (r - r_k), s_k = (z_p(r_k+1) - z_p(r_k))/(r_k+1 - r_k),
so every facet starts on the base plane at the inner edge of its zone and
has the step height h_k = f_k(r_k+1) at the outer edge, where the riser
returns to the base plane. Flat facets are cones (a common way of cutting
moulds); the central zone always keeps the curved parent. A riser is
vertical (parallel to the axis), or, with a draft angle delta > 0 that
lets the mould release, a cone that leans by delta from the axis and covers
the start of the next facet over about |h_k| tan(delta). The last zone
continues beyond r_K without a step.
Ray tracing¶
Two models of a FresnelSurface:
model="ideal": the usual idealization of lens design programs (e.g. the “Fresnel” surface of Zemax OpticStudio): the rays meet the flat base plane and are refracted with the normal of the parent at the same radius. The ray directions are those of an infinitely fine Fresnel lens; the optical path is that of a plane plate, so the OPD of such a lens is not the wavefront of any real lens (the rays are not normal to it).model="facets": the real sawtooth. Each ray is intersected with the facets and risers of the zones it can reach and refracted with the normal of the piece it hits. The optical path includes the step heights, so the pupil phase jumps by about (n - n’) h_k at the zone edges. Rays are lost (vignetted, NaN) where a Fresnel lens loses light:riser hits: the ray meets a riser first (draft loss, for oblique incidence also the shadow of the vertical riser);
shadowing: after refraction at a facet, the ray hits the relief again (the next riser) before it leaves the grooves, which is the main loss on the exit side of fast lenses;
total internal reflection at the facet.
stray="refract"instead refracts riser hits with the riser normal and traces them on: the first order stray light, e.g. the halo around the focus of a solar concentrator. Rays that re-hit the relief are lost in either case (they would need a non sequential trace).
FresnelSurface.classify() and facet_losses() tell which of these
happens to each ray, raytrace.System.trace_polarization() adds the Fresnel
reflection losses at the facets.
The paraxial data (power, focal lengths, pupils) are those of the parent; the Seidel sums of a Fresnel surface are not computed (NaN, as for an ideal lens), since a plane carrying the parent’s slopes does not have the aberrations of the parent. A Fresnel surface is traced with NumPy (not by the compiled kernel).
Design and the way back¶
FresnelSurface.from_surface() collapses a thick lens surface into zones
and FresnelSurface.parent_surface() returns the thick lens surface again;
the zone radii and facet slopes are the whole description of the lens.
focusing_slopes() gives the exact facet slopes for a perfect focus of
the ideal model by the vector law of refraction (the facet normal is
parallel to n d - n’ d’); surface_from_slopes() fits an even asphere
(a parent) to slopes, e.g. to the facet angle table of a moulded lens or to
a design from focusing_slopes(). The parent of an aberration free Fresnel
lens is not the aberration free thick lens: a plano-convex lens that focuses
a collimated beam through its curved side without spherical aberration has
the hyperbola K = -n**2, the corresponding Fresnel lens a different conic
and aspheric terms, since its facets sit on the plane instead of on the
curved surface.
Waves: Fresnel lens vs. kinoform¶
The steps of a Fresnel lens are many wavelengths deep (a 0.3 mm deep groove
in PMMA is several hundred waves of path); the phase jumps between the zones
are arbitrary and the zones add up incoherently: the focus is that of the
rays, blurred by diffraction at the zone width. A kinoform is a Fresnel lens
with the groove depth lambda_0/(n - 1) (constant depth zones): every step
is one wave, the zones add up in phase and the lens is diffractive. At
other wavelengths the step is alpha = lambda_0 (n(lambda) - 1)/(lambda (n_0 - 1))
waves; the scalar efficiency of the diffraction order m is
sinc**2(alpha - m) (kinoform_efficiency()), its focal length
f m lambda_0/lambda and its Abbe number lambda_d/(lambda_F - lambda_C) = -3.45
(diffractive_abbe_number()), strong and of opposite sign to glass.
References¶
A. Fresnel, “Mémoire sur un nouveau système d’éclairage des phares”, Paris (1822).
R. Leutz and A. Suzuki, “Nonimaging Fresnel Lenses: Design and Performance of Solar Concentrators”, Springer (2001).
A. Davis and F. Kühnlenz, “Optical design using Fresnel lenses”, Optik & Photonik 2(4), 52-55 (2007).
W. T. Welford, “Aberrations of Optical Systems”, Adam Hilger (1986), ch. 13 (Fresnel lenses and diffractive surfaces).
D. A. Buralli, G. M. Morris and J. R. Rogers, “Optical performance of holographic kinoforms”, Appl. Opt. 28, 976-983 (1989).
D. C. O’Shea, T. J. Suleski, A. D. Kathman and D. W. Prather, “Diffractive Optics: Design, Fabrication, and Test”, SPIE Press (2004), ch. 4.
N. Sultanova, S. Kasarova and I. Nikolov, “Dispersion properties of optical polymers”, Acta Phys. Pol. A 116, 585-587 (2009) (PMMA).
Zemax OpticStudio User Manual, “Fresnel” surface type.
Classes
Fate of the rays at a Fresnel surface ( |
|
Fresnel surface: a parent surface collapsed into zones on a base plane. |
Functions
Abbe number lambda_d/(lambda_F - lambda_C) of a diffractive lens (-3.45). |
|
Classify the rays of a pupil grid at a Fresnel surface of a system. |
|
Exact facet slopes dz/dr that send rays through a point on the axis. |
|
Groove depth of a kinoform: order*lambda_0/(n - n_out). |
|
Scalar diffraction efficiency sinc**2(alpha - m) of a kinoform. |
|
Refractive index of PMMA (Sultanova et al. 2009, 437 to 1052 nm, n_d = 1.4906). |
|
Fit a parent surface (sphere or conic plus even aspheric terms) to slopes. |
|
n points spread uniformly over the unit disk (Vogel's sunflower spiral). |
|
Zone radii of a Fresnel lens collapsed from a surface. |
- class pyoptics.fresnel.FresnelSurface(R=inf, thickness=0.0, zones=None, pitch=None, depth=None, n_zones=None, radius=None, model='facets', facets='curved', draft=0.0, stray='lose', **kwargs)[source]¶
Bases:
SurfaceFresnel surface: a parent surface collapsed into zones on a base plane.
See the module docstring for the geometry and the two ray trace models.
- Parameters:
- R, thicknessnumbers, optional
Vertex radius of the parent and distance to the next vertex (from the base plane).
- zonessequence, optional
Zone radii 0 = r_0 < … < r_K (see
zone_radii()).- pitch, depth, n_zonesoptional
Instead of zones: build them with
zone_radii()up to radius.- radiusnumber, optional
Outer radius for pitch, depth or n_zones (default: semi_diameter).
- model{“facets”, “ideal”}, optional
Real sawtooth or the flat idealization.
- facets{“curved”, “flat”}, optional
Facets that follow the parent, or cones through the zone edges of the parent (central zone curved).
- draftnumber, optional
Draft angle of the risers (radians) from the axis.
- stray{“lose”, “refract”}, optional
Rays that hit a riser first are lost, or refracted at the riser.
- n_after, material, conic, aspheric, semi_diameter, mirror, decenter, tilt,
- coating, label, index_offsetoptional
As for
raytrace.Surface(conic and aspheric describe the parent).
- classmethod from_surface(surface, pitch=None, depth=None, n_zones=None, zones=None, radius=None, **kwargs)[source]¶
Fresnel version of a (thick lens) surface.
- Parameters:
- surfaceraytrace.Surface
The parent: radius, conic, aspheric terms, thickness, medium, semi diameter, decentre, tilt, coating and label are copied.
- pitch, depth, n_zones, zones, radiusoptional
Zones, see
zone_radii().- **kwargs
model, facets, draft, stray, or overrides of the copied values (e.g. thickness).
- Returns:
- FresnelSurface
- parent_surface(thickness=None)[source]¶
The thick lens surface (the parent) as a
raytrace.Surface.- Parameters:
- thicknessnumber, optional
Distance to the next vertex (default: that of the Fresnel surface; a parent in place of a Fresnel surface on the exit side of a plate needs the thickness changed by its sag at the rim).
- Returns:
- raytrace.Surface
- section(h, n_per_zone=12)[source]¶
Points (y, z) of the meridional section from -h to h, with the corners of the risers, for drawing.
- Parameters:
- hnumber
Half height of the section.
- n_per_zoneint, optional
Points per facet.
- Returns:
- y, zarrays
- intersect(P, d)[source]¶
Distance along the rays to the base plane (ideal model) or to the first facet or riser they hit (facets model).
- Parameters:
- P(N, 3) array
Start points relative to the vertex, in the local frame of the surface.
- d(N, 3) array
Unit directions.
- Returns:
- t(N,) array
NaN for rays that miss.
- normal(Q)[source]¶
Unit normals at the points Q: of the parent (ideal model) or of the facet or riser through Q.
- Parameters:
- Q(N, 3) array
Points on the surface, relative to the vertex.
- Returns:
- N(N, 3) array
Normals with N_z >= 0 (radial for vertical risers).
- deflect(Q, d, n1, n2)[source]¶
Refract (or reflect) the rays at the base plane (ideal) or at the pieces they hit (facets: lost rays NaN, see the module docstring).
- Parameters:
- Q(N, 3) array
Intersection points in the local frame.
- d(N, 3) array
Unit directions of the incident rays.
- n1, n2numbers
Refractive indices in front of and behind the surface.
- Returns:
- d2array
New unit directions.
- doplarray
Extra optical path (zero).
- classify(P, d, n1, n2)[source]¶
What happens to rays at the surface.
- Parameters:
- P(N, 3) array
Points on the rays in the local frame (in front of the surface).
- d(N, 3) array
Unit directions.
- n1, n2numbers
Refractive indices in front of and behind the surface.
- Returns:
- code(N,) int array
FACET (refracted by a facet and out), RISER (hits a riser first), SHADOWED (refracted by a facet, then hits the relief again), TIR (total internal reflection at the first piece) or MISS.
- Q(N, 3) array
First hits (NaN for misses).
- pyoptics.fresnel.zone_radii(surface, radius, pitch=None, depth=None, n_zones=None)[source]¶
Zone radii of a Fresnel lens collapsed from a surface.
- Parameters:
- surfaceraytrace.Surface or callable
The parent (its sag(r2)) or a function z(r2).
- radiusnumber
Outer radius of the lens.
- pitchnumber, optional
Constant zone width (groove pitch).
- depthnumber, optional
Constant groove depth: zone k ends where
|z_p(r) - z_p(0)|reaches (k + 1) depth (needs a monotonic sag; the last zone may be shallower).- n_zonesint, optional
Number of zones of equal width (alternative to pitch).
- Returns:
- rarray
0 = r_0 < r_1 < … < r_K = radius.
- pyoptics.fresnel.focusing_slopes(r, focus, n1, n2, d_in=(0.0, 0.0, 1.0), z=0.0, d_out=None)[source]¶
Exact facet slopes dz/dr that send rays through a point on the axis.
The facet normal is parallel to n1 d - n2 d’ (vector law of refraction) for the incident direction d and the direction d’ from the facet point to the focus. With z = 0, these are the slopes of an aberration free ideal Fresnel lens (flat base plane).
- Parameters:
- rarray
Radii of the facet points (meridional, y = r).
- focusnumber
z of the focus on the axis (local frame), or np.inf/-np.inf for a collimated output along +z/-z.
- n1, n2numbers
Indices in front of and behind the surface.
- d_in(3,) or (N, 3) array, optional
Incident directions (default: along the axis). A point source on the axis at z_s: d_in = (r, z - z_s)/norm, see the notebook.
- znumber or array, optional
Heights of the facet points.
- d_out(N, 3) array, optional
Wanted output directions instead of those to the focus (e.g. into a plate whose far side refracts them to the focus); focus is then ignored.
- Returns:
- slopearray
dz/dr at r (TIR or no solution: NaN).
- pyoptics.fresnel.surface_from_slopes(r, slope, n_aspheric=4, conic=0.0, weights=None, **kwargs)[source]¶
Fit a parent surface (sphere or conic plus even aspheric terms) to slopes.
Least squares fit of dz/dr of
raytrace.Surface(vertex curvature c and the coefficients A4, A6, … for a fixed conic) to the slopes, e.g. the facet angle table of a Fresnel lens or the result offocusing_slopes().- Parameters:
- r, slopearrays
Radii and slopes dz/dr.
- n_asphericint, optional
Number of aspheric coefficients (A4, …, A_{2 n_aspheric + 2}).
- conicnumber, optional
Fixed conic constant of the fit.
- weightsarray, optional
Weights of the slopes.
- **kwargs
Passed on to
raytrace.Surface(thickness, n_after, material, …).
- Returns:
- surfaceraytrace.Surface
- rmsnumber
RMS slope residual.
- pyoptics.fresnel.facet_losses(system, index, field=None, n_rays=20000, px=None, py=None)[source]¶
Classify the rays of a pupil grid at a Fresnel surface of a system.
- Parameters:
- systemraytrace.System
- indexint
Index of the FresnelSurface in system.surfaces.
- fieldoptional
Field (default: on axis).
- n_raysint, optional
Number of rays, on a Vogel (sunflower) spiral over the pupil: uniform in area and without the aliasing of a square grid against the narrow rings of the risers.
- px, pyarrays, optional
Pupil coordinates instead of the spiral.
- Returns:
- FacetLosses
- class pyoptics.fresnel.FacetLosses(px, py, code, r, fractions)¶
Bases:
tupleFate of the rays at a Fresnel surface (
facet_losses()).- px, pyarrays
Pupil coordinates of the rays.
- codeint array
FACET, RISER, SHADOWED, TIR or MISS for each ray (NaN rays in front of the surface: MISS).
- rarray
Radius of the first hit on the surface.
- fractionsdict
Fraction of the rays in each class, by name (“facet”, “riser”, “shadowed”, “TIR”, “miss”).
- code¶
Alias for field number 2
- fractions¶
Alias for field number 4
- px¶
Alias for field number 0
- py¶
Alias for field number 1
- r¶
Alias for field number 3
- pyoptics.fresnel.vogel_spiral(n)[source]¶
n points spread uniformly over the unit disk (Vogel’s sunflower spiral).
- Parameters:
- nint
- Returns:
- x, yarrays
- pyoptics.fresnel.kinoform_efficiency(order, wavelength, design_wavelength, n, n_design, n_out=1.0, design_order=1)[source]¶
Scalar diffraction efficiency sinc**2(alpha - m) of a kinoform.
- Parameters:
- orderint or array
Diffraction order m.
- wavelength, design_wavelengthnumbers or arrays
- n, n_designnumbers or arrays
Index of the relief at wavelength and at the design wavelength.
- n_outnumber, optional
Index in the grooves.
- design_orderint, optional
Design order (step of design_order waves at the design wavelength).
- Returns:
- etaarray
Efficiency with alpha = design_order lambda_0 (n - n_out)/((n_0 - n_out) lambda).
- pyoptics.fresnel.kinoform_depth(design_wavelength, n, n_out=1.0, order=1)[source]¶
Groove depth of a kinoform: order*lambda_0/(n - n_out).
- Parameters:
- design_wavelengthnumber
- n, n_outnumbers
Indices of the relief and of the medium in the grooves at lambda_0.
- orderint, optional
Design order (multi-order diffractive lenses: order > 1).
- Returns:
- depthnumber