4. Chirped Z-transform (CZT)

CZT allows, in a single step, to propagate to a near or far observation plane. IThe main advantage of CZT is that the region of interest and the sampling numbers can be arbitrarily chosen, endowing CZT with superior flexibility, and produces much faster results (acceleration > x100 with respect to RS algorithm) for focusing and far field diffraction patterns.

As the sampling area and pixels can be reduced to the desired observation area, the storage is also greatly reduced.

CZT algorithm allows to have a XY mask and compute in XY, Z, XZ, XYZ schemes, simply defining the output arrays.

4.1. X Scheme

[1]:
from diffractio import degrees, mm, um, nm
from diffractio import np, plt, sp

from diffractio.scalar_fields_X import Scalar_field_X
from diffractio.scalar_masks_X import Scalar_mask_X
from diffractio.scalar_sources_X import Scalar_source_X

from diffractio.scalar_fields_XZ import Scalar_field_XZ
from diffractio.scalar_fields_Z import Scalar_field_Z

from diffractio.scalar_masks_XY import Scalar_mask_XY
from diffractio.scalar_sources_XY import Scalar_source_XY
[2]:
size = 250 * um
xin = np.linspace(-size, size, 4096)
wavelength = 550 * nm
z = 2 * mm
[3]:
t0 = Scalar_mask_X(xin, wavelength)
t0.slit(x0=0, size=size / 2)
u0 = Scalar_source_X(xin, wavelength)
u0.plane_wave(A=1)

u1 = t0 * u0
u1.draw()
../../../_images/source_tutorial_scalar_algorithms_CZT_5_0.png

4.1.1. to just one data

[4]:
xout = 0.0
z = 2 * mm
[5]:
u2 = u1.CZT(z, xout)
print(u2)
[-0.60319534+0.63252658j]

4.1.2. to field_Z

[6]:
xout = 0
z = np.linspace(0.5 * mm, 10 * mm, 256)
[7]:
%%time
u2 = u1.CZT(z, xout, verbose=True)

CPU times: user 1.07 s, sys: 3 ms, total: 1.07 s
Wall time: 1.07 s
[8]:
u2.draw(z_scale="mm")
../../../_images/source_tutorial_scalar_algorithms_CZT_12_0.png

4.1.3. to field_X

[9]:
xout = np.linspace(-size, size, 256)
z = 2 * mm
[10]:
%%time
u2 = u1.CZT(z, xout)

CPU times: user 13.2 ms, sys: 839 µs, total: 14 ms
Wall time: 12.5 ms
[11]:
u2.draw()
../../../_images/source_tutorial_scalar_algorithms_CZT_16_0.png

4.1.4. to field_XZ

[12]:
xout = np.linspace(-size / 2, size / 2, 512)
z = np.linspace(1 * mm, 15 * mm, 128)
[13]:
%%time
u2 = u1.CZT(z, xout, verbose=True)

CPU times: user 1.17 s, sys: 4.33 ms, total: 1.17 s
Wall time: 1.17 s
[14]:
u2.draw(logarithm=0, z_scale="mm")
plt.colorbar()
../../../_images/source_tutorial_scalar_algorithms_CZT_20_0.png

4.1.5. to data

[15]:
xout = 0
yout = 0.0
z = 0.5 * mm
[16]:
%%time
u2 = u1.CZT(z, xout, yout)
print("{}".format(np.abs(u2)**2))

[0.95645892]
CPU times: user 10.9 ms, sys: 1.2 ms, total: 12.1 ms
Wall time: 9.2 ms

4.1.6. to field_X

[17]:
xout = np.linspace(-size, size, 512)
yout = 0.0
z = 0.5 * mm
[18]:
%%time
u2 = u1.CZT(z, xout, yout)
u2.draw()

CPU times: user 36.5 ms, sys: 873 µs, total: 37.3 ms
Wall time: 35.7 ms
../../../_images/source_tutorial_scalar_algorithms_CZT_26_1.png

4.1.7. to field_Z

The Z field is computed with a for loop, thus it is a bit slower.

[19]:
xout = -1.0
yout = 0.0
z = np.linspace(0.25 * mm, 1 * mm, 64)
[20]:
%%time
u2 = u1.CZT(z, xout, yout)
u2.draw()

CPU times: user 399 ms, sys: 786 µs, total: 399 ms
Wall time: 398 ms
../../../_images/source_tutorial_scalar_algorithms_CZT_30_1.png

4.1.8. to field_XZ

[21]:
xout = np.linspace(-100 * um, 100 * um, 256)
yout = 0.0
z = np.linspace(0.25 * mm, 1 * mm, 128)
[22]:
%%time
u2 = u1.CZT(z, xout, yout)
u2.draw()
plt.colorbar()

CPU times: user 1.5 s, sys: 0 ns, total: 1.5 s
Wall time: 1.53 s
../../../_images/source_tutorial_scalar_algorithms_CZT_33_1.png

4.2. CZT for reducing the output size

Chirped z-Transform algorithm is specially indicated for cases where the output field is much smaller than the input field, as you can choose the position and sampling of the field. An important example for this is the focusing of a lens.

4.2.1. X scheme

[23]:
size = 3 * mm
xin = np.linspace(-size, size, 2048)
wavelength = 550 * nm
focal = 250 * mm
[24]:
t0 = Scalar_mask_X(xin, wavelength)
t0.lens(x0=0, focal=focal)

u0 = Scalar_source_X(xin, wavelength)
u0.plane_wave(A=1)

u1 = t0 * u0
[25]:
xout = 0.0
z = np.linspace(focal - 30 * mm, focal + 30 * mm, 128)
[26]:
%%time
u2 = u1.CZT(z, xout, verbose=True)
u2.draw(z_scale='mm')

CPU times: user 473 ms, sys: 4.78 ms, total: 478 ms
Wall time: 481 ms
../../../_images/source_tutorial_scalar_algorithms_CZT_39_1.png
[27]:
xout = np.linspace(-150 * um, 150 * um, 256)
z = focal
[28]:
u2 = u1.CZT(focal, xout)
u2.draw()
../../../_images/source_tutorial_scalar_algorithms_CZT_41_0.png
[29]:
xout = np.linspace(-150 * um, 150 * um, 256)
z = np.linspace(focal - 20 * mm, focal + 20 * mm, 128)
[30]:
%%time
u2 = u1.CZT(z, xout, verbose=True)
u2.draw(logarithm=1e-1, z_scale='mm')

CPU times: user 781 ms, sys: 4.3 ms, total: 785 ms
Wall time: 782 ms
../../../_images/source_tutorial_scalar_algorithms_CZT_43_1.png

4.2.2. XY scheme

[31]:
size = 2 * mm
xin = np.linspace(-size, size, 256)
yin = np.linspace(-size, size, 512)
wavelength = 550 * nm
focal = 500 * mm
[32]:
t0 = Scalar_mask_XY(xin, yin, wavelength)
t0.lens(r0=(0 * um, 0 * um), focal=focal, radius=0)
t0.pupil()

u0 = Scalar_source_XY(xin, yin, wavelength)
u0.plane_wave(A=1)

u1 = t0 * u0
[33]:
xout = np.linspace(-250 * um, 250 * um, 100)
yout = np.linspace(-250 * um, 250 * um, 128)
z = focal
[34]:
u2 = u1.CZT(z, xout, yout, verbose=True)
u2.draw(logarithm=1e-1)
num x, num y, num z = 100, 128, 1
../../../_images/source_tutorial_scalar_algorithms_CZT_48_1.png