matlab/matlab-model-optics
> Build, import, analyze, tolerate, and optimize optical systems using the Optical Design and Simulation Library. Use when the user asks about optical systems, ray tracing, geometric optics, Zemax import, optical coatings, tolerancing, or optical design optimization.
npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-model-optics
Use this skill when the user is working with the Optical Design and Simulation Library to build, import, analyze, tolerate, or optimize optical systems in MATLAB.
This library may also be referred to as:
Use Optical Design and Simulation Library as the canonical name in responses unless the user explicitly uses a different name.
Use this skill when the user asks about:
references/dynamic-optical-systems-simulink.md)Do not use this skill when:
When helping a user who is new to the library, start with discovery:
help optics
To get more details for a specific function:
help lensDistortion
doc lensDistortion
Many optics APIs are class methods. For class methods, use:
help className/functionName
doc className/functionName
Example:
help opticalSystem/add
Use examples in the documentation when the user asks for a larger end-to-end workflow.
The Optical Design and Simulation Library ships sample Zemax (.zmx) files in the opticsdata folder within the support package install location. To find the path:
spkgRoot = fullfile(matlabshared.supportpkg.getSupportPackageRoot, "toolbox", "images", "supportpackages", "opticsdata");
dir(fullfile(spkgRoot, "*.zmx"))
When a user asks to work with a standard optical system (e.g., "a Cooke triplet", "a doublet", "a telephoto lens") but does not provide their own file:
.zmx files in the opticsdata folderzmximportThis avoids asking the user for a file path when a suitable sample already exists.
opticalSystem is the central object representing a physical optical system.
opsys = opticalSystem(Wavelengths=[486.134 587.562 656.281]);
opticalMaterial represents a glass or optical material.
mat = opticalMaterial([1.5168 64.17]);
mat = pickGlass("N-BK7");
opticalCoating represents a thin-film coating applied to surfaces.
oc = opticalCoating(CoatingMaterial=["MgF2" "TiO2"], LayerMaterialIndex=[1 2 1 2], LayerThickness=[1 0.5 1 0.5], PrimaryWavelength=550);
oc = pickCoating("AR_MgF2_VIS");
addCoating(opsys, oc);
addCoating(opsys, oc, CoatingSide="front");
Refer to the MATLAB Documentation page called "Coordinate Systems in Optical Design" to learn about the coordinate system conventions used to construct optical systems.
When creating a field point with fieldPoint(Angles=[Hy Hx]):
Hy — vertical field angle (degrees)Hx — horizontal field angle (degrees)Example — a field point at 10 degrees vertical:
fp = fieldPoint(Angles=[10 0]);
A field point at 10 degrees horizontal:
fp = fieldPoint(Angles=[0 10]);
TiltAngles=[Rx Ry Rz] specifies rotations in degrees about each axis:
Rx (first element) — rotation about the X-axisRy (second element) — rotation about the Y-axisRz (third element) — rotation about the Z-axisExample — a mirror tilted 45 degrees about the X-axis:
addMirror(opsys, TiltAngles=[45 0 0]);
Many user requests follow this sequence:
%% 1. Build
opsys = opticalSystem(Wavelengths=587.562);
addRefractiveSurface(opsys, Radius=50, Material=pickGlass("N-BK7"), SemiDiameter=10, DistanceToNext=5);
addRefractiveSurface(opsys, Radius=-50, SemiDiameter=10, DistanceToNext=20);
addImagePlane(opsys, SemiDiameter=10);
opsys.FieldPoints = fieldPoint(Angles=[0 0; 10 0]);
%% 2. Visualize
h2 = view2d(opsys);
%% 3. Analyze
tra = rayAberration(opsys);
hra = show(tra);
Many analyses follow a compute first, visualize second pattern.
spotResult = spot(opsys);
spotDiagram(spotResult);
ldResult = lensDistortion(opsys);
show(ldResult);
Use this pattern when the user wants both a numeric result and a plot.
Explicitly create a fresh copy of the original system if you want to use it as a starting point for multiple different changes. This is particularly useful for tolerancing and sensitivity analysis, where parameters of the original system are mutated repeatedly.
newSys = copy(opsys);
This avoids accumulating perturbations across trials unless accumulation is explicitly intended.
Sequential optical systems are often specified as prescription tables (common in patent documents, textbooks, and optical design references).
Each row represents a surface or optical element, with columns such as:
Users may provide this data as a screenshot, an Excel sheet, or a manually entered table.
| Surface | Radius | Thickness | Material | Type |
|--------|--------|----------|----------|------|
| 1 | 50 | 5 | N-BK7 | Refractive |
| 2 | -50 | 5 | Air | Refractive |
| 3 | — | 5 | — | Stop |
| 4 | 40 | 5 | N-BK7 | Refractive |
| 5 | -40 | 20 | Air | Refractive |
| 6 | Inf | 0 | Image | ImagePlane |
opticalSystemaddRefractiveSurfaceaddDiaphragmaddImagePlaneDistanceToNext for preceding elementopsys = opticalSystem(Wavelengths=587.562);
% Surface 1
addRefractiveSurface(opsys, Radius=50, Material=pickGlass("N-BK7"), DistanceToNext=5);
% Surface 2
addRefractiveSurface(opsys, Radius=-50, DistanceToNext=5);
% Stop (explicit element)
addDiaphragm(opsys, DistanceToNext=5);
% Surface 4
addRefractiveSurface(opsys, Radius=40, Material=pickGlass("N-BK7"), DistanceToNext=5);
% Surface 5
addRefractiveSurface(opsys, Radius=-40,DistanceToNext=20);
% Image plane
addImagePlane(opsys);
h2initial = view2d(opsys, Parent=figure);
The semi-diameters of all the surfaces is set to the default value because the table does not provide this value. Instead, system descriptions usually provide a field of view (FOV).
After building the optical system:
help updateSemiDiameters for valid constraint options.FOV = 20; % degrees
targetFieldAngle = FOV / 2;
updateSemiDiameters(opsys, "EntryPupilRadius", 5, TargetFieldAngle=targetFieldAngle);
h2Final = view2d(opsys, Parent=figure);
Users often build optical systems by combining off-the-shelf components (e.g., vendor-provided designs such as singlets, doublets, or lens groups).
This workflow involves:
% Load existing system
opsysCooke = zmximport("CookeTriplet.zmx");
% Step 1: Remove image plane (if present)
remove(opsysCooke);
% Step 2: Removing a component does NOT remove the gap. Zero out the trailing gap
changeGap(opsysCooke, numel(opsysCooke.Components), 0);
% Step 3: Import singlet component
opsysSinglet = zmximport("singlet.zmx");
% Step 4: Create a new optical System with these two
opsys = opticalSystem(Name="Combined System");
add(opsys, opsysCooke);
changeGap(opsys, numel(opsys.Components), 3, GapLocation="after");
% Step 4: Append singlet to system
add(opsys, opsysSinglet);
h2 = view2d(opsys);
Use addMirror when the user wants to model reflective systems.
This periscope folds the beam in the Y-Z plane using X-axis rotations:
opsys = opticalSystem();
addMirror(opsys, Radius=0, SemiDiameter=10, TiltAngles=[45 0 0]);
addGap(opsys, 50);
addMirror(opsys, Radius=0, SemiDiameter=10, TiltAngles=[-45 0 0]);
addGap(opsys, 20);
addImagePlane(opsys, SemiDiameter=10);
h = view2d(opsys);
addRays(h);
To fold in the X-Z plane instead, use Y-axis rotations: TiltAngles=[0 45 0].
Use this when the analysis user is looking for is not available out of the box and the user has to derive it themselves using the RayData that is available as part of the RayBundle.
Pattern — plot incident angles on a specific surface using pupil coordinates:
% Import a Cooke triplet
opsys = zmximport("CookeTriplet.zmx");
% Trace from 10-degree field point with incident angle data
fp = fieldPoint(Angles=[10 0]);
sg = samplingGrid("Hexapolar", 8);
rb = traceRays(opsys, FieldPoints=fp, Wavelengths=587.562, SamplingGrid=sg, RayProperties="IncidentAngle");
rd = rb(1).RayData;
% OrientedGrid gives normalized pupil XY for each ray
xy = rd.OrientedGrid;
% Incident angles on surface 4
angles = rd.IncidentAngle(:, 4);
% Scatter plot: position from pupil grid, size and color from angle
figure;
scatter(xy(:,1), xy(:,2), abs(angles)*5, angles, 'filled');
colorbar;
xlabel("Pupil X"); ylabel("Pupil Y");
title("Incident Angle on Surface 4 — Field Angle 10°");
axis equal;
Use design optimization when the user wants to improve performance starting from an initial optical system. See references/optical-system-design.md for detailed patterns, code templates, and optimizer selection guidance.
General workflow:
x2opsys) to convert the vector back to an opticalSystemlsqnonlin for multi-objective, fmincon for scalar)paraxialInfo, spot, and view2dAlways call updateSemiDiameters inside the parameter-to-system conversion to maintain the aperture constraint after every parameter change.
Use this when the user wants to design, analyze, or optimize thin-film optical coatings (AR coatings, bandpass filters, longpass/shortpass filters, notch filters). See references/optical-coating-design.md for detailed patterns and optimization templates.
General workflow:
pickCoatingMaterialLayerMaterialIndex (alternating high/low index)opticalCoating and layer thicknessesfresnelCoefficientsKey functions:
pickCoatingMaterial("SiO2") — load a coating materialopticalCoating(...) — create multi-layer coatingfresnelCoefficients(oc, Wavelengths=..., IncidentAngles=...) — compute transmittance/reflectancefq.Ta (total transmittance), fq.Ra (total reflectance), or polarization-resolved propertiesUse this when the user wants to evaluate manufacturing sensitivity or yield of a coating design. See references/optical-coating-tolerance.md for detailed patterns and Monte Carlo templates.
General workflow:
fresnelCoefficientsKey considerations:
parfor for Monte Carlo trials (each trial is independent)imref2d can be useful when converting physical locations on a 2D plane into pixel locations.references/dynamic-optical-systems-simulink.mdWhen placing view3d or view2d inside a uifigure layout, use a uigridlayout (not a uipanel) as the parent so the viewer chart fills the available space:
gl = uigridlayout(parentContainer, [1 1], Padding=[0 0 0 0]);
osv3d = view3d(opsys, Parent=gl);
Chart objects auto-stretch to fill grid layout cells but do not auto-resize inside plain uipanel containers.
----
Copyright 2026 The MathWorks, Inc.
----
Take matlab/matlab-model-optics from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.