7. Designing with LensLab



7.1 Initializing Variables

7.2 Putting It All Together

7.3 Tracing a Ray through the System

7.4 The Full-Blown Ray Trace

7.5 Looking Closer

Introduction to Chapter 7

LensLab gives you the ability to determine component specifications and optical layout feasibility, enabling you to do breadboard prototyping before you purchase the necessary physical equipment. LensLab was originally developed to provide a means for creating a new holographic camera system. Through the course of several trial-and-error sessions using an early version of LensLab, the author determined that the initial design concept wasn't feasible, and proceeded to find an alternative design for the application. In the process, LensLab saved months of experimental trail and error with real optics, and more than a few dollars in wrong purchases. LensLab worked so well that the machining of the component mounting system, based on a blueprint given by LensLab, was finished long before the optical components were delivered. LensLab-generated diagrams were later used in several publications about the project.

This chapter contains a single example that demonstrates the basic design and layout techniques employed by the author for modeling more complex optical systems. It highlights most of the Move functions as well as the BranchingSurface object. This chapter is not intended to document the design process in detail, but rather to outline a possible design process using LensLab.

Loading LensLab

Make sure that the LensLab package is located either in the home directory, or on a directory path recognized by Mathematica for packages. The LensLab package is named LensLab.m and located in the LensLab directory, and the LensLab package is loaded with the following expression.



LensLab version 1.5 is now loaded.

This loading process should only take a few seconds. In addition to being loaded as a package, the LensLab.m file is formatted as a Mathematica notebook. The LensLab source code is made accessible so that you can develop new functions of your own by studying LensLab's built-in functions. This is particularly helpful when you wish to model new component ideas in LensLab. However, you should receive permission from Optica Software before distributing any user-created functions that are derived from the LensLab source code. The unauthorized distribution of LensLab-derived code may be a LensLab license agreement violation or a copyright infringement.

Go to list of topics

7.1 Initializing Variables

As a starting point for designing with LensLab, you should determine the necessary component specifications for the application as much as possible ahead of time. The remaining unknown component parameters and layout details can then be determined more easily in LensLab. A good first step is to "rough out" the physical measurements of the work space using a paper and pencil. Then to help make component choices prior to modeling the entire system, a series of shorter LensLab-based experiments on segments of the overall problem is recommended. After solutions have been found for the segmented system, the system is then modeled with all of the segments put together (see Section 5.2).

First, it is convenient to set up a symbolic measurement system that allows us the use of mixed units. Often, table position measurements are most conveniently given in inches, while component specifications are usually given in millimeters.


mm = 1/25.4;
in = 1.;

Assuming that you have determined a rough mental picture of the needed layout, the next step is to define components in Mathematica. By assigning short variable names to the evaluated component functions, the layout description becomes more manageable later. Further, subsequent calculations will run faster, since a significant portion of computer time is often spent creating the Component objects (see Section 6.2). For systems using few rays, the ray-tracing process itself may consume less time than the component creation process.

The variables used here correspond to labels given to the components in blueprint sketches.


M1 = Mirror[1 in,10 mm];
M2 = M1;
M3 = Mirror[{7 in,5 in},5 mm];
M4 = M1;
M5 = M1;
M6 = M1;


L1 = PlanoConvexLens[200.0 mm, 2 in, 5 mm, CurvatureDirection->Front];
L2 = PlanoConcaveLens[-15 mm, 8 mm, 5 mm, CurvatureDirection->Front];
L3 = PlanoConvexLens[1000.0 mm,150 mm ,30 mm, CurvatureDirection->Front];
L4 = PlanoConcaveLens[-30 mm, 20 mm, 8 mm, CurvatureDirection->Front];
L5 = PlanoConvexLens[450.0 mm,145 mm,15.5 mm, CurvatureDirection->Front];
L6 = L5;


BS = Move[Move[BeamSplitter[{10,90},{3.5 in,1 in},12 mm], {0,-1.25 in},45], -0.8 in, 180];

Note that we used the Move function twice in defining BS. This method was employed in order to break down the positioning of BS into two steps, and also to simplify the global positioning of BS later on. Each application of Move is essentially a transformation of coordinate systems for the component. In this particular case, we gave the beam splitter a new parametric origin and rotation, so that when we place BS in the whole optical system, it uses a built-in offset and rotation.

Go to list of topics

7.2 Putting It All Together

Next, we assign the list the components to a variable. In addition to Move, we use MoveLinear and MoveReflected to place components.



opticalLayout =
    {    MoveReflected[M1,
            {90 in,50 in},{90 in,23 in},{78 in,23 in}],
        Move[BS,{78 in,22.5 in}],
        Move[L1,{78 in,27 in},90],
        MoveReflected[M2, {78 in,22.5 in},{78 in,40 in},{74 in,40 in}],
        Move[L2,{74 in,40 in - 1.6 mm}],
        Move[BaffleWithHole[{400mm,200mm},135mm,3mm], {74 in - 950 mm,40 in}],
        Move[L3,{74 in - 1000 mm,40 in}],
        MoveReflected[M3,{74 in - 1000 mm,40 in},
            {N[(40 in - 22.5 in)/Tan[50 Degree]],40 in},
            {6 in,22.5 in}],
            {78 in,22.5 in + 4 mm},{73 in,22.7 in},
            {68 in,7.5 in}],
        MoveReflected[M5,{73 in,22.5 in},{68 in,7.5 in},
            {63 in,22.7 in}],
            {68 in,7.5 in},14.5 in,{63 in,22.5 in}],
        MoveReflected[M6,{68 in,7.5 in},{63 in,22.5 in},
            {63 in - 400 mm,22.5 in}],
        Move[L5,{63 in-400 mm,22.5 in}],
        Move[L6,{6 in,22.5 in},45],
        Boundary[{-15in,0,-10in}, {100in,50in,10in}]};

LensLab can also help you determine where light baffles will need to be placed in the optical system, a task nearly impossible using pencil and paper sketches. After we traced rays through the system, we discovered some stray rays going outside L3. So we went back to the component listing above and inserted BaffleWithHole to contain the stray rays.

Go to list of topics

7.3 Tracing a Ray through the System

Before tracing any rays, we first draw the system without the rays, and we check for parameter entry mistakes as well as rough component positioning. You can check the component coordinates by selecting the rendered drawing and then holding down the Command key and pointing with the mouse on the diagram. You can then read off the coordinates from the bottom of the window. You can also store the coordinate points in memory by sequentially clicking on the mouse button at points of interest while holding down the Command key. The selected coordinates show up on the plot as dots. Then you can recover the list of coordinates from memory by using Command-C and Command-V keystrokes to copy and paste in the results. In this way, the you can directly determine the rough placement of additional components in the system.




Next, we trace a single ray through the system. This speeds up the ray-tracing time, allowing for faster interactive tweeking of component positions and orientations. Not shown, you can also use RunningCommentary->True to see if the rays are tracing through the expected component list positions. However, this significantly decreases ray-tracing speeds.


    {Move[Ray[],{90 in,50 in},-90],


Go to list of topics

7.4 The Full-Blown Ray Trace

Finally, we carry out the full-blown ray trace.


system = DrawSystem[
    {Move[LineOfRays[2.75 mm, NumberOfRays->7],{90 in,50 in},-90],
    opticalLayout}, PlotType->TopView];


Finally, we examine the three-dimensional view.




Go to list of topics

7.5 Looking Closer

We next examine various surface/ray intersections using PlotType->Surface.







You can use ShowRange to magnify a small region of the system and examine how the local rays and components are interacting. Here we look closely at the beam-splitter area.




In this chapter, we have examined a method for designing complex optical systems. While LensLab is a useful tool for laying out new systems, perhaps the most valuable function of LensLab is in providing a means for understanding the systems being designed.

Go to list of topics

Copyright Statement

LensLab is a trademark of Optica Software.
Mathematica ® is a registered trademark of Wolfram Research, Inc. All other product names mentioned are trademarks of their producers. Mathematica is not associated with Mathematica Policy Research, Inc. or MathTech, Inc.
Copyright ©1995-2005 by Optica Software, Urbana, Illinois, Champaign, Illinois.

All rights reserved. No part of this document may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, electronic, mechanical, photocopying, recording or otherwise, without prior written permission of the author, Optica Software.

Optica Software is the holder of the copyright to the LensLab package software and documentation ("Product") described in this document, including without limitation such aspects of the Product as its code, structure, sequence, organization, "look and feel", programming language and compilation of command names. Use of the Product, unless pursuant to the terms of a license granted by Optica Software. or as otherwise authorized by law, is an infringement of the copyright.

Optica Software makes no representations, express or implied, with respect to this Product, including without limitations, any implied warranties of merchantability or fitness for a particular purpose, all of which are expressly disclaimed. Users should be aware that included in the terms and conditions under which Optica Software is willing to license the Product is a provision that the author, Optica Software and distribution licensees, distributors and dealers shall in no event be liable for any indirect, incidental or consequential damages, and that liability for direct damages shall be limited to the amount of the purchase price paid for the Product.

In addition to the foregoing, users should recognize that all complex software systems and their documentation contain errors and omissions. Optica Software shall not be responsible under any circumstances for providing information on or corrections to errors and omissions discovered at any time in this document or the package software it describes, whether or not they are aware of the errors or omissions. Optica Software does not recommend the use of the software described in this document for applications in which errors or omissions could threaten life, injury or significant loss.

Created by Mathematica  (November 3, 2005)