Tolerancing - Compensators

[1]:
import numpy as np

from optiland import optic
from optiland.tolerancing.core import Tolerancing
from optiland.tolerancing.monte_carlo import MonteCarlo
from optiland.tolerancing.perturbation import DistributionSampler
[ ]:
class Singlet(optic.Optic):
    def __init__(self):
        super().__init__()

        # add surfaces
        self.surfaces.add(index=0, radius=np.inf, thickness=np.inf)
        self.surfaces.add(
            index=1,
            thickness=7,
            radius=19.93,
            is_stop=True,
            material="N-SF11",
        )
        self.surfaces.add(index=2, thickness=17.0695)
        self.surfaces.add(index=3)

        # add aperture
        self.set_aperture(aperture_type="EPD", value=25.4)

        # add field
        self.fields.set_type(field_type="angle")
        self.fields.add(y=0)
        self.fields.add(y=10)
        self.fields.add(y=14)

        # add wavelength
        self.wavelengths.add(value=0.48613270)
        self.wavelengths.add(value=0.58756180, is_primary=True)
        self.wavelengths.add(value=0.65627250)
[3]:
optic = Singlet()
optic.draw()
../../_images/gallery_tolerancing_compensators_3_0.png
[4]:
tolerancing = Tolerancing(optic)

Define perturbations:

[5]:
for k in range(1, 3):
    # X-tilt
    sampler = DistributionSampler("normal", loc=0, scale=0.01)
    tolerancing.add_perturbation("tilt", sampler, surface_number=k, axis="x")

    # Y-tilt
    sampler = DistributionSampler("normal", loc=0, scale=0.01)
    tolerancing.add_perturbation("tilt", sampler, surface_number=k, axis="y")

    # X-decenter
    sampler = DistributionSampler("normal", loc=0, scale=0.1)
    tolerancing.add_perturbation("decenter", sampler, surface_number=k, axis="x")

    # Y-decenter
    sampler = DistributionSampler("normal", loc=0, scale=0.1)
    tolerancing.add_perturbation("decenter", sampler, surface_number=k, axis="y")

Define operands:

[ ]:
input_data = {
    "optic": optic,
    "surface_number": -1,
    "Hx": 0,
    "Hy": 0.0,
    "wavelength": 0.55,
    "num_rays": 5,
}
tolerancing.add_operand("rms_spot_size", input_data, target=0)

Run Monte Carlo without compensator:

[7]:
monte_carlo = MonteCarlo(tolerancing)
monte_carlo.run(num_iterations=100)
[8]:
monte_carlo.view_histogram(kde=True)
../../_images/gallery_tolerancing_compensators_11_0.png

Add compensator:

[ ]:
# distance from last surface to image plane
tolerancing.add_compensator("thickness", surface_number=2)

Rerun Monte Carlo with compensator:

[10]:
monte_carlo = MonteCarlo(tolerancing)
monte_carlo.run(num_iterations=100)
[11]:
monte_carlo.view_histogram(kde=True)
../../_images/gallery_tolerancing_compensators_16_0.png

By comparing the distributions, we can see that adding compensator generally improved the RMS spot size. The histogram with the compensator shows a distribution with slightly smaller values, indicating that the compensator effectively reduced the impact of the perturbations on the RMS spot size.