7.8. Focusing light with a lens
In this example, we will analyze how light is focused using a lens. We will use several algorithms. From an ondulatory point of view, a lens as a transmittance object
\(t(\xi,\eta)=P(\xi,\eta)\exp\left[-ik\frac{\left(\xi^{2}+\eta^{2}\right)}{2f'}\right]\)
where \(P(\xi,\eta)\) is the shape of the lens, \(k=2\pi/\lambda\) and f’ is the focal distance of the lens.
7.8.1. Lens in x mode
[1]:
from diffractio import degrees, mm, plt, sp, um, np
from diffractio.scalar_sources_X import Scalar_source_X
from diffractio.scalar_masks_X import Scalar_mask_X
from diffractio.utils_optics import beam_width_1D, FWHM1D, MTF_ideal, MTF_parameters
[2]:
focal = 25 * mm
diameter = 4 * mm
# Initial parameters
x0 = np.linspace(-diameter / 2 - 50 * um, diameter / 2 + 50 * um, 1024 * 32)
wavelength = 0.6238 * um
# Definition of source
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.plane_wave(A=1)
t0 = Scalar_mask_X(x=x0, wavelength=wavelength)
t0.lens(x0=0.0, focal=focal, radius=diameter / 2)
[4]:
u1 = t0 * u0
u2 = u1.RS(z=focal, verbose=False)
[5]:
u2.draw()
plt.xlim(-25, 25)
7.8.1.1. Beam width computation
[6]:
width, center = beam_width_1D(u2.u, u2.x)
[7]:
fwhm = FWHM1D(u2.x, np.abs(u2.u)**2, has_draw=True, percentage=0.5)
plt.xlim(-25, 25)
plt.ylim(bottom=0)
print(width, fwhm)
4.8440193446230575 3.610817918990506
7.8.1.2. MTF
[8]:
freq_real, mtf_norm = u2.MTF(has_draw=False)
freq_ideal = np.linspace(0, 350, 600)
mtf_ideal, freq_corte = MTF_ideal(freq_ideal,
wavelength=wavelength,
diameter=diameter,
focal=focal,
kind='1D',
has_draw=False,
verbose=True)
plt.figure(figsize=(12, 6))
plt.plot(freq_ideal, mtf_ideal, 'b', label='ideal')
plt.xlabel("$f_x\,(mm^{-1})$", fontsize=18)
plt.ylabel("MTF", fontsize=18)
plt.xlim(left=0, right=1.25 * freq_corte)
plt.ylim(bottom=0, top=1.1)
plt.title("$frec_c$ = {:2.1f} (l/mm)".format(freq_corte), fontsize=18)
plt.plot(freq_real, mtf_norm, 'r', label='numeric')
plt.legend(fontsize=16)
frecuencia de bin_level = 256.49 lineas/mm
7.8.1.3. Several rays
[9]:
# Definition of source
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.plane_waves_several_inclined(A=1, num_beams=7, max_angle=10 * degrees)
[10]:
us1 = t0 * u0
us2 = us1.RS(z=focal, verbose=False)
[11]:
us2.draw()
[12]:
us2.draw()
plt.xlim(-40, 40)
[13]:
us2.draw()
plt.xlim(1800, 1950)
7.8.1.4. Binary Fresnel lens
With the modules diffractio.scalar_sources_X, scalar_fields_X and scalar_masks_X for propagating a field generated by a scalar light only the propagation to a given distances is performed. If you need to visualize the z propagation it is better the use of diffractio.scalar_fields_XZ
, since it performs a for loop over a number of distances given by a linspace array. This for loop is executed, when possible, using multiprocessing, since there is not computational interaction between different
locations z.
[14]:
# initial data
x0 = np.linspace(-750 * um, 750 * um, 1024 * 32)
wavelength = 0.6238 * um
focal = 20 * mm
radius = 250 * um
#definition of source
u0 = Scalar_source_X(x0, wavelength)
u0.plane_wave(A=1, theta=0 * degrees)
[15]:
#definition of mask
t0 = Scalar_mask_X(x0, wavelength)
t0.fresnel_lens(x0=0 * um,
radius=radius,
focal=focal,
kind='amplitude',
phase=np.pi)
t0.draw(kind='intensity')
[16]:
u1 = t0.RS(z=20 * mm)
Good result: factor 254.34
[17]:
u1.draw(logarithm=1, normalize='intensity')
plt.xlim(-200, 200)
7.8.2. XZ lens: CZT scheme
[18]:
from diffractio import degrees, mm, plt, sp, um, np
from diffractio.scalar_sources_X import Scalar_source_X
from diffractio.scalar_masks_X import Scalar_mask_X
from diffractio.scalar_masks_XZ import Scalar_mask_XZ
[19]:
focal = 15 * mm
diameter = 4 * mm
x0 = np.linspace(-diameter / 2, diameter / 2, 1024)
wavelength = 0.6238 * um
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.plane_wave(A=1, theta=0 * degrees)
t0 = Scalar_mask_X(x=x0, wavelength=wavelength)
t0.lens(x0=0.0, radius=diameter / 2, focal=focal)
u1 = u0 * t0
[25]:
z0 = np.linspace(14.8 * mm, 15.2 * mm, 512)
This procedure is deprecated. It is more ineficient than with CZT algorithm.
It requires plt.xlim(-20,20) after drawing. The drawing is badly sampled.
[30]:
%%time
u2 = Scalar_mask_XZ(x=x0, z=z0, wavelength=wavelength)
u2.incident_field(u1)
u2.RS(num_processors=4);
CPU times: user 539 ms, sys: 303 ms, total: 842 ms
Wall time: 1.5 s
[31]:
%%time
xout=np.linspace(-20,20,256)
u2 = u1.CZT(z=z0, xout=xout)
CPU times: user 1.36 s, sys: 10.4 ms, total: 1.37 s
Wall time: 1.43 s
[32]:
u2.draw(logarithm=1e-1, z_scale='mm')
[33]:
x_f, z_f = u2.search_focus()
x = -0.235 um, z = 14999.609 um
[34]:
u2.profile_transversal(z0=z_f)
plt.xlim(-30, 30)
7.8.2.1. XZ lens: BPM scheme
[35]:
focal = 1 * mm
diameter = 1 * mm
x0 = np.linspace(-diameter / 2, diameter / 2, 1024 * 4)
z0 = np.linspace(-250 * um, focal + 2 * mm, 1024)
wavelength = 0.6238 * um
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.plane_wave(A=1, theta=0 * degrees)
u1 = Scalar_mask_XZ(x=x0, z=z0, wavelength=wavelength)
u1.incident_field(u0)
focal, _ = u1.lens_convergent(r0=(0, 0),
aperture=diameter / 1.25,
radius=(1 * mm, -1 * mm),
thickness=.25 * mm,
refractive_index=1.55,
angle=0 * degrees,
mask=(100 * um, 3 + 0.1j))
print(focal)
u1.draw_refractive_index()
edge_matrix = u1.borders
u1.smooth_refractive_index(type_filter=2, pixels_filtering=50)
870.4808704808705
[36]:
u1.BPM(verbose=False)
u1.draw(logarithm=True,
normalize='maximum',
draw_borders=True,
edge_matrix=edge_matrix)
[37]:
x_focus, z_focus = u1.search_focus()
x = -0.122 um, z = 1062.072 um
[38]:
width, z_center = u1.beam_widths(kind='sigma4', has_draw=(0, 0))
[39]:
plt.plot(u1.z, width, 'k')
plt.plot(u1.z, -width, 'k')
plt.xlim(z_focus - 100 * um, z_focus + 100 * um)
plt.ylim(-50, 50)
7.8.3. Effect of rotation
[40]:
x0 = np.linspace(-200 * um, 200 * um, 1024 * 2)
z0 = np.linspace(-50 * um, 400 * um, 1024 * 4)
wavelength = 0.6238 * um
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.plane_wave(A=1, theta=0 * degrees)
[41]:
u1 = Scalar_mask_XZ(x=x0, z=z0, wavelength=wavelength)
u1.incident_field(u0)
focal, _ = u1.lens_convergent(r0=(0, 0),
aperture=300 * um,
radius=(1000 * um, -250 * um),
thickness=100 * um,
refractive_index=2,
angle=15 * degrees,
mask=(10 * um, 3 + 0.05j))
print(focal)
u1.draw_refractive_index(scale='scaled')
edge_matrix = u1.borders
u1.smooth_refractive_index(pixels_filtering=25, type_filter=2)
192.30769230769232
[42]:
u1.BPM(has_edges=True, verbose=False)
u1.draw(logarithm=True,
normalize='maximum',
draw_borders=True,
scale='scaled',
edge_matrix=edge_matrix)
Here we see how several rays converge
[45]:
x0 = np.linspace(-200 * um, 200 * um, 1024 * 1)
z0 = np.linspace(-25 * um, 400 * um, 1024 * 4)
wavelength = 0.6238 * um
u0 = Scalar_source_X(x=x0, wavelength=wavelength)
u0.gauss_beams_several_parallel(A=1,
num_beams=15,
w0=5,
z0=10,
x_central=0.0,
x_range=300.0,
theta=0.0)
[46]:
u1 = Scalar_mask_XZ(x=x0, z=z0, wavelength=wavelength)
u1.incident_field(u0)
focal, _ = u1.lens_convergent(r0=(0, 0),
aperture=300 * um,
radius=(1000 * um, -250 * um),
thickness=100 * um,
refractive_index=2,
angle=0 * degrees,
mask=(10 * um, 3 + 0.05j))
print(focal)
u1.draw_refractive_index(scale='scaled')
edge_matrix = u1.borders
u1.smooth_refractive_index(pixels_filtering=25, type_filter=2)
192.30769230769232
[47]:
u1.BPM(verbose=False)
u1.draw(logarithm=True,
normalize='maximum',
draw_borders=True,
scale='scaled',
edge_matrix=edge_matrix)
7.8.3.1. XY scheme
[48]:
from diffractio import degrees, mm, plt, sp, um, np
from diffractio.scalar_fields_XY import Scalar_field_XY
from diffractio.scalar_masks_XY import Scalar_mask_XY
from diffractio.scalar_sources_XY import Scalar_source_XY
[49]:
diameter = 2 * mm
focal = 25 * mm
x0 = np.linspace(-diameter / 2, diameter / 2, 1024)
y0 = np.linspace(-diameter / 2, diameter / 2, 1024)
wavelength = 0.6238 * um
[50]:
u0 = Scalar_source_XY(x=x0, y=y0, wavelength=wavelength)
u0.plane_wave()
t0 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength)
t0.lens(r0=(0 * um, 0 * um),
radius=(diameter / 2, diameter / 2),
focal=(focal, focal))
[51]:
t0.draw('phase')
[52]:
u1 = u0 * t0
[53]:
u2 = u1.RS(z=focal)
[55]:
u2.cut_resample(x_limits=(-20, 20),
y_limits=(-20, 20),
num_points=(1024, 1024),
new_field=False,
interp_kind=(3, 1))
[56]:
u2.draw(logarithm=1e-2)
[57]:
u2.draw_profile(point1=(-25, 0),
point2=(25, 0),
npixels=2048,
kind='intensity',
order=2)
[58]:
def intensity_area(u, r0, radius, power=1, has_draw=True):
intensities = np.zeros_like(radius)
mask = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength)
for i, r in enumerate(radius):
mask.circle(r0=r0, radius=(r, r), angle=0)
masked_field = u * mask
intensities[i] = masked_field.intensity().sum()**power
intensities = intensities / intensities.max()
if has_draw is True:
plt.figure()
plt.plot(rs, intensities)
plt.ylim(bottom=0)
plt.xlim(left=0, right=rs[-1])
return intensities
[59]:
rs = np.linspace(1 * um, 400 * um, 51)
intensities = intensity_area(u2, r0=(0, 0), radius=rs, power=1)
[60]:
u2.beam_width_4s(has_draw=True)
7.8.4. Vector scheme
7.8.4.1. Linear polarization
[61]:
from diffractio import degrees, mm, plt, sp, um, np
from diffractio.scalar_fields_XY import Scalar_field_XY
from diffractio.scalar_masks_XY import Scalar_mask_XY
from diffractio.scalar_sources_XY import Scalar_source_XY
from diffractio.vector_sources_XY import Vector_source_XY
from diffractio.vector_masks_XY import Vector_mask_XY
from diffractio.vector_fields_XY import Vector_field_XY
[62]:
diameter = 2 * mm
x0 = np.linspace(-diameter / 2, diameter / 2, 1024)
y0 = np.linspace(-diameter / 2, diameter / 2, 1024)
wavelength = 0.6238 * um
[63]:
focal = 25 * mm
limit = 50 * um
[64]:
u0 = Scalar_source_XY(x0, y0, wavelength)
u0.plane_wave(A=1)
t0 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength)
t0.lens(r0=(0 * um, 0 * um),
radius=(diameter / 2, diameter / 2),
focal=(focal, focal))
u1 = u0 * t0
[65]:
EM0 = Vector_source_XY(x0, y0, wavelength)
EM0.constant_polarization(u1, v=[(1 - 1j) / 2, (1 + 1j) / 2])
[66]:
EM1 = EM0.VRS(z=focal)
[67]:
EM1.cut_resample(x_limits=(-limit / 2, limit / 2),
y_limits=(-limit / 2, limit / 2),
num_points=(1024, 1024),
new_field=False,
interp_kind=(3, 1))
[68]:
EM1.__draw_ellipses__(num_ellipses=(30, 30),
color_line='r',
amplification=0.75,
head_width=.25,
line_width=0.5)
7.8.4.2. Radial polarization
[69]:
diameter = 2 * mm
x0 = np.linspace(-diameter / 2, diameter / 2, 1024)
y0 = np.linspace(-diameter / 2, diameter / 2, 1024)
wavelength = 0.6238 * um
focal = 25 * mm
[70]:
u0 = Scalar_source_XY(x0, y0, wavelength)
u0.plane_wave(A=1)
t0 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength)
t0.lens(r0=(0 * um, 0 * um),
radius=(diameter / 2, diameter / 2),
focal=(focal, focal))
u1 = u0 * t0
[71]:
EM0 = Vector_source_XY(x0, y0, wavelength)
EM0.azimuthal_wave(u1)
[72]:
EM1 = EM0.VRS(z=focal)
[73]:
EM1.cut_resample(x_limits=(-limit / 2, limit / 2),
y_limits=(-limit / 2, limit / 2),
num_points=(1024, 1024),
new_field=False,
interp_kind=(3, 1))
[74]:
EM1.__draw_ellipses__(num_ellipses=(30, 30),
color_line='c',
amplification=0.75,
head_width=.25)
[ ]: