Tutorial 8b - Tolerancing, Monte Carlo
In this tutorial, we will continue to explore the tolerancing capabilities of Optiland and will introduce Monte Carlo analysis. Monte Carlo analysis involves simulating a large number of random variations of an optical system, which helps to understand the statistical distribution of potential performance outcomes for a system. It is particularly valuable for understanding the impact of manufacturing defects and environmental conditions.
The Monte Carlo analysis in Optiland is fundamentally similar to the sensitivity analysis, which was introduced in tutorial 8a. We require the following components to perform a Monte Carlo analysis:
Optic - the optical system to be analyzed.
Operands - the metrics which are assessed e.g., wavefront error.
Perturbations - the variations applied to the optic or a surface of an optic e.g., surface tilt.
Compensators - a parameter of the optical system that can be adjusted to counteract the effects of a perturbation.
In this example, we will perform a Monte Carlo analysis on a Cooke triplet to understand how common variations, such as surface decenter and tilt, can impact the optical performance.
[1]:
from optiland.samples.objectives import CookeTriplet
from optiland.tolerancing.core import Tolerancing
from optiland.tolerancing.monte_carlo import MonteCarlo
from optiland.tolerancing.perturbation import DistributionSampler
Defining the tolerancing object
The first step is to define our optic and pass it to a Tolerancing object.
[2]:
optic = CookeTriplet()
[3]:
tolerancing = Tolerancing(optic)
Adding perturbations
The Monte Carlo anlaysis requires that we apply random perturbations to optical properties of our system. We will apply both random tilt and random decenter to every surface of the triplet, so 6 surfaces in total.
We will apply perturbations to every surface and in both the x and y axes.
Properties for tilt perturbation:
Normal distribution, mean = 0, standard deviation = 0.01 radians
Properties for decenter perturbation:
Normal distribution, mean = 0, standard deviation = 0.1 mm
[4]:
# loop through all surfaces and add perturbations
for k in range(1, 7):
# 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")
Adding operands
We wish to monitor the impact of perturbations on our triplet. We choose to monitor the following metrics:
RMS spot size for (Hx, Hy) = (0, 1) field
mean OPD difference for (Hx, Hy) = (0, 1) field
real y-intercept on image plane for (Hx, Hy) = (0, 1) field
The syntax used here follows that used in the optimization module when variables are defined. In general, we pass the following arguments to the “add_operand” method to create a new operand:
operand type - see optiland.optimization.operand for complete list of options.
input_data - a dictionary containing the optic instance at a minimum, and generally other parameters related to the operand, such as wavelength.
target (optional) - if an operand has a target, we may specify it here. This is only used when we apply compensation, or optimize the system to counteract perturbations.
weight (optional) - if an operand is more important than others, it may be given a larger weight during compensation.
We define the 3 operands as follows:
[5]:
input_data = {
"optic": optic,
"surface_number": -1,
"Hx": 0,
"Hy": 1,
"wavelength": 0.55,
"num_rays": 5,
}
tolerancing.add_operand("rms_spot_size", input_data, target=0)
input_data = {"optic": optic, "Hx": 0, "Hy": 1, "wavelength": 0.55, "num_rays": 5}
tolerancing.add_operand("OPD_difference", input_data)
input_data = {
"optic": optic,
"surface_number": -1,
"Hx": 0,
"Hy": 1,
"Px": 0,
"Py": 0,
"wavelength": 0.55,
}
tolerancing.add_operand("real_y_intercept", input_data)
Run Monte Carlo analysis
We are now ready to run our Monte Carlo analysis. We first define our Monte Carlo analysis:
[6]:
monte_carlo = MonteCarlo(tolerancing)
We can then run our Monte Carlo analysis. We choose to run 1000 iterations.
[7]:
monte_carlo.run(num_iterations=1000)
View and analyze results
There are several ways to view the output data of a Monte Carlo analysis:
Plot the distributions of the performance metrics
Plot the cumulative distribution function (CDF) of the metrics
Plot a heatmap showing the correlations between the perturbations and the metrics
[8]:
monte_carlo.view_histogram(kde=False)
[8]:
(<Figure size 1200x400 with 3 Axes>,
array([<Axes: xlabel='0: rms spot size', ylabel='Count'>,
<Axes: xlabel='1: OPD difference', ylabel='Count'>,
<Axes: xlabel='2: real y intercept', ylabel='Count'>], dtype=object))
[9]:
monte_carlo.view_cdf()
[9]:
(<Figure size 1200x400 with 3 Axes>,
array([<Axes: title={'center': '0: rms spot size'}, xlabel='0: rms spot size'>,
<Axes: title={'center': '1: OPD difference'}, xlabel='1: OPD difference'>,
<Axes: title={'center': '2: real y intercept'}, xlabel='2: real y intercept'>],
dtype=object))
[10]:
monte_carlo.view_heatmap(vmin=-0.2, vmax=0.2, figsize=(10, 10))
[10]:
(<Figure size 1000x1000 with 2 Axes>, <Axes: >)
The heatmap gives an indication of the correlation between the metrics and the various pertrurbations applied. The strongest correlations exist between the real y-intercept and several of the surface tilts and decenters.
As with the sensitivity analysis, we can also retrieve the Monte Carlo results for further analysis:
[11]:
df = monte_carlo.get_results()
[12]:
df.head()
[12]:
| Tilt X, Surface 1 | Tilt Y, Surface 1 | Decenter X, Surface 1 | Decenter Y, Surface 1 | Tilt X, Surface 2 | Tilt Y, Surface 2 | Decenter X, Surface 2 | Decenter Y, Surface 2 | Tilt X, Surface 3 | Tilt Y, Surface 3 | ... | Tilt Y, Surface 5 | Decenter X, Surface 5 | Decenter Y, Surface 5 | Tilt X, Surface 6 | Tilt Y, Surface 6 | Decenter X, Surface 6 | Decenter Y, Surface 6 | 0: rms spot size | 1: OPD difference | 2: real y intercept | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.009207 | -0.011025 | -0.002190 | -0.016223 | 0.007428 | 0.013438 | 0.014421 | 0.060301 | 0.005314 | 0.010278 | ... | -0.006306 | -0.046377 | -0.157831 | 0.021742 | 0.000021 | -0.018989 | 0.106433 | 0.141910 | 0.692562 | 18.645609 |
| 1 | 0.008905 | -0.005739 | 0.089045 | 0.025248 | 0.019523 | -0.011740 | 0.000440 | 0.014264 | 0.003392 | 0.006186 | ... | 0.000579 | 0.013588 | 0.058864 | -0.003734 | 0.011204 | 0.150248 | -0.018275 | 0.102292 | 0.566152 | 18.339462 |
| 2 | 0.008308 | -0.002635 | -0.188853 | 0.001050 | -0.003705 | -0.011522 | -0.183701 | 0.049986 | -0.004468 | -0.000680 | ... | -0.001322 | 0.075018 | 0.020952 | -0.000958 | -0.012948 | -0.030341 | 0.141852 | 0.120303 | 0.515046 | 18.346219 |
| 3 | -0.002685 | 0.011072 | 0.109082 | -0.088453 | -0.001039 | 0.004737 | 0.244410 | 0.041029 | 0.009125 | 0.004283 | ... | -0.001073 | -0.090255 | -0.125393 | 0.013556 | -0.002803 | 0.052818 | -0.149199 | 0.039382 | 0.189649 | 18.189990 |
| 4 | -0.000320 | -0.004726 | 0.098729 | 0.059416 | 0.000899 | 0.007604 | 0.070222 | -0.027400 | -0.022558 | -0.003621 | ... | 0.006263 | 0.038823 | -0.244502 | 0.011454 | -0.005382 | -0.002485 | -0.075603 | 0.118383 | 0.744495 | 18.791629 |
5 rows × 27 columns
Conclusions
This tutorial demonstrated Monte Carlo analyses in Optiland.
Monte Carlo analysis is a statistical technique to explore possible system performance variations due to manufacturing tolerances or environmental conditions.
Several plotting functions are available via the Monte Carlo analysis object, including plotting of distributions, CDFs, and heatmaps.