This article describes how to use a ZPL macro to determine the perturbation values assigned by OpticStudio during a Monte Carlo tolerance analysis.
Authored By Sanjay Gangadhara
Downloads
Introduction
Tolerance analysis is an important part of any optical design as it allows the designer to determine the sensitivity of the system to errors introduced during manufacturing. In OpticStudio, these errors may be introduced and analyzed either individually (Sensitivity) or simultaneously (Monte Carlo).
The goal of a Monte Carlo analysis is to determine the variation in system performance that arises from the simultaneous application of tolerance errors in a statistical fashion. However, there may be times when it is useful to know the values for the individual perturbations; for example, when some set of perturbations could be used to enhance system performance. We can analyze our system in such a way by saving the Monte Carlo files and extracting the data with a ZPL macro.
Step 1: Performing the Monte Carlo tolerance analysis
To analyze a large number of files - like what is output following a Monte Carlo analysis - it is best to use a ZPL macro. In the Knowledgebase article entitled "How to open consecutively-names lens files using a ZPL macro", information is given on how to extract information from multiple Monte Carlo files and can be expanded upon to obtain tolerance perturbations.
Tolerance perturbations may be significantly different from one system to the next. Thus, it is difficult to develop a macro that can be used to extract Monte Carlo data from any general file. In this article, a macro has been developed which is suited to a particular system that is being analyzed. However, the general structure of the macro can be replicated and subsequently customized for most files of interest.
The first step in creating the macro is to determine what tolerance perturbations will be evaluated in the system. The example used for this article is a Cooke triplet (as given in the sample file {Zemax}\Samples\Sequential\Objectives\Cooke 40 degree field.zmx. The default set of tolerances will be used in the analysis:
Some minor changes to this default set are made in the Tolerance Data Editor. Namely:
- Intermediate thickness compensation is turned off (Adjust = Surf for all of the TTHI operands)
- Surface decenters are referenced to the back surface for each lens (all TSDX and TSDY operands are deleted for surfaces 2, 4, and 6)
The resulting system may be found in the archive (.ZAR) file attached to this article.
There are 41 perturbations to be analyzed in this system:
- 6 radii of curvature
- 5 thicknesses (back focal length is used as a compensator)
- 3 element decenters in X
- 3 element decenters in Y
- 3 element tilts about X
- 3 element tilts about Y
- 3 surface decenters in X
- 3 surface decenters in Y
- 6 surface irregularities
- 3 refractive indices
- 3 Abbe numbers
corresponding to the 41 tolerance operands found in the Tolerance Data Editor. The macro we will write must therefore store data for these 41 perturbations for all of the Monte Carlo runs.
The Monte Carlo analysis is then performed. For this example, RMS spot radius is chosen as the tolerance criterion:
and 100 Monte Carlo runs are performed:
Remember that we must save each of the runs in order to extract the desired data. The name of the files will be “MC_Txxxx”, where "xxxx" corresponds to the run number.
Step 2: Creating the ZPL macro
The macro used to extract data from the Monte Carlo runs for this specific example is provided as an article attachment. The first step is to specify the number of runs that were performed:
! Define number of MC runs
n_files = 100
Data arrays are then defined to store the perturbation values for each run. Arrays are created to hold data for the 6 radii of curvature (trad1_per, …, trad6_per), the 5 thicknesses (tthi1_per, …, tthi5_per), etc. For surface irregularities – which in this example have been modeled using the TIRR
operand – arrays are defined to store the magnitude of the irregularity (tirrm1_per, …, tirrm6_per) as well as the angle of the astigmatism error (tirra1_per, …, tirra6_per). An array is also defined to hold the criterion value for each run (tcrit_per).
The nominal values for each of the perturbations (radii, thicknesses, etc.) are then obtained, using the TOLV
function:
! Get nominal values for radii, thicknesses, indices, and Abbe numbers
! (all other perturbations have a nominal value of zero)
trad1_nom = TOLV(3,90)
trad2_nom = TOLV(4,90)
trad3_nom = TOLV(5,90)
trad4_nom = TOLV(6,90)
trad5_nom = TOLV(7,90)
trad6_nom = TOLV(8,90)
tthi1_nom = TOLV(9,90)
tthi2_nom = TOLV(10,90)
tthi3_nom = TOLV(11,90)
tthi4_nom = TOLV(12,90)
tthi5_nom = TOLV(13,90)
tind1_nom = TOLV(38,90)
tind3_nom = TOLV(39,90)
tind5_nom = TOLV(40,90)
tabb1_nom = TOLV(41,90)
tabb3_nom = TOLV(42,90)
tabb5_nom = TOLV(43,90)
As indicated in the macro comment, in this case the nominal values are all zero for the perturbations not listed (e.g. element tilts).
We are now ready to loop through all of the Monte Carlo files and extract the desired perturbation data. We first get the full file name for our nominal file, so that we may re-load this file at the end of our loop:
N$ = $FILEPATH()
We then define a string variable which will be the basis for the Monte Carlo file name (with full path included – we have assumed that all of the Monte Carlo files are in the same directory as the nominal file):
A$ = $PATHNAME()
B$ = A$+"\MC_T"
A FORMAT
keyword is then used to specify the format in which the file number will be added to the file name, to be consistent with the OpticStudio file numbering system:
FORMAT "%#04i" LIT
This keyword will only work is the number of Monte Carlo files is < 10,000, which seems like a reasonable limit for the type of analysis we are performing. Finally, the FOR
loop is started:
FOR i, 1, n_files, 1
Inside of the loop, we generate the string which will contain the full file name of the Monte Carlo file, and then load the file using the LOADLENS
keyword:
F$ = B$+$STR(i)+".zmx"
LOADLENS F$
Then the desired data are extracted from the file, using the MFCN
function (for the tolerance criterion value), the RADI
function (for the radii of curvature), the THIC
function (for the thicknesses), the PARM
function (for the surface and element decenters, element tilts, and surface irregularities), and the SOLV
function (for the refractive indices and Abbe numbers). In the appropriate cases, the nominal values were subtracted from the obtained value, in order to calculate the perturbation value.
We see that the surface number inputs to the macro functions have been hard-wired into the code, and that in all cases the surface numbers differ from the numbers in the nominal file. This is because the Monte Carlo file will have additional surfaces relative to the nominal file, in order to model element tilts and decenters (via Coordinate Break surfaces). To determine the appropriate surface numbers in each case, one of the Monte Carlo files was manually opened and investigated.
Once the FOR
loop is complete, we reload the nominal file. We then print the results to the screen, using another FOR
loop, with FORMAT
keywords also placed to control the numerical precision of the printed data:
! Print the results
PRINT "Run# Criterion ",
PRINT "RAD1 RAD2 RAD3 RAD4 RAD5 RAD6 ",
PRINT "THI1 THI2 THI3 THI4 THI5 ",
PRINT "TEDX12 TEDY12 TETX12 TETY12 ",
PRINT "TEDX34 TEDY34 TETX34 TETY34 ",
PRINT "TEDX56 TEDY56 TETX56 TETY56 ",
PRINT "TSDX1 TSDX3 TSDX5 TSDY1 TSDY3 TSDY5 ",
PRINT "TIRRM1 TIRRM2 TIRRM3 ",
PRINT "TIRRM4 TIRRM5 TIRRM6 ",PRINT "TIRRA1 TIRRA2 TIRRA3 TIRRA4 TIRRA5 TIRRA6 ",
PRINT "TIND1 TIND3 TIND5 ",
PRINT "TABB1 TABB3 TABB5"
FOR i, 1, n_files, 1
FORMAT "%#04i" LIT
PRINT i, " ",
FORMAT 10.5 EXP
PRINT tcrit_per(i), " ",
FORMAT 10.5
PRINT trad1_per(i), " ", trad2_per(i), " ", trad3_per(i), " ",
PRINT trad4_per(i), " ", trad5_per(i), " ", trad6_per(i), " ",
PRINT tthi1_per(i), " ", tthi2_per(i), " ", tthi3_per(i), " ",
PRINT tthi4_per(i), " ", tthi5_per(i), " ",
PRINT tedx12_per(i), " ", tedy12_per(i), " ",
PRINT tetx12_per(i), " ", tety12_per(i), " ",
PRINT tedx34_per(i), " ", tedy34_per(i), " ",
PRINT tetx34_per(i), " ", tety34_per(i), " ",
PRINT tedx56_per(i), " ", tedy56_per(i), " ",
PRINT tetx56_per(i), " ", tety56_per(i), " ",
PRINT tsdx1_per(i), " ", tsdx3_per(i), " ", tsdx5_per(i), " ",
PRINT tsdy1_per(i), " ", tsdy3_per(i), " ", tsdy5_per(i), " ",
FORMAT "%+10.5e" LIT
PRINT tirrm1_per(i), " ", tirrm2_per(i), " ", tirrm3_per(i), " ",
PRINT tirrm4_per(i), " ", tirrm5_per(i), " ", tirrm6_per(i), " ",
FORMAT 10.5
PRINT tirra1_per(i), " ", tirra2_per(i), " ", tirra3_per(i), " ",
PRINT tirra4_per(i), " ", tirra5_per(i), " ", tirra6_per(i), " ",
PRINT tind1_per(i), " ", tind3_per(i), " ", tind5_per(i), " ",
PRINT tabb1_per(i), " ", tabb3_per(i), " ", tabb5_per(i), " "
NEXT i
Finally, the memory associated with each array is freed using the RELEASE
keyword.
This macro is customized for the file provided in this example. However, the basic structure of the macro may remain the same even as the file and/or the tolerance perturbations differ.
Step 3: Running the macro
Once the macro is complete, it can be run to generate the desired data:
This output may then be sent to a text file for future analysis.
KA-01435
Comments
Please sign in to leave a comment.