ECEN 4616/5616 2/25/2013 Analysis Options in Zemax Chapter 7 in the Zemax manual covers the various ways an optical system can be analyzed via graphical or numerical outputs. Many of these analyses are also available as operands for the Merit Function Editor (MFE). Some, like the “Image Simulation” are more useful as “ground truth” tests of an optical system – what, exactly, will the output look like? Is it good enough? Often, an optical system may look bad from the perspective of analytic calculations, but will be perfectly OK for its intended use. Camera lens design by famous lens designer (Laikin): pg. 1 ECEN 4616/5616 2/25/2013 MTF, plotted to the diffraction limit of the lens: It doesn’t look so good. However, 820 lp/mm corresponds to a spot size of 2.4µm. Plotting the MTF to the Nyquist limit of a detector with 10µm pixels shows the lens is probably good enough – particularly when you consider that, for a Bayer Pattern detector, the real image limit is for a group of 4 pixels, or half the spatial frequency of the single pixel limit: pg. 2 ECEN 4616/5616 2/25/2013 Doing an image simulation for the appropriate size detector confirms this: Analyses available (from the Analysis menu): Layout: 2D Layout 3D Layout (rotate with arrow keys, or “settings” menu on window) Shaded Model (Realistic rendering – rotate with mouse): pg. 3 ECEN 4616/5616 2/25/2013 Element Drawings (What you would give to a fabricator) FANS: Ray aberration: Transverse Ray Aberration (TRA) for different fields and ray heights in the entrance pupil Optical Path error: Optical path difference (from Chief ray) vs. position in the entrance pupil for different fields. (This is a 2D slice of the “Wavefront Map” analysis window.) Pupil Aberration: This isn’t an error, but a measure of how much the pupil position and size as determined by real ray tracing varies from that determined by paraxial traces. If this is more than a few percent, you may need to turn on “Ray Aiming” under the “Gen” tab. This will slow down tracing by a factor of 2 – 3. Spot Diagrams: These are all based on geometric ray tracing, and are fairly selfexplanatory. For details, see the Manual. MTF (Modulation Transfer Function): The MTF plots are given as contrast (0 →1) vs spatial frequency. The meaning is that the optical system would image a sine pattern with a contrast of 1.0 (goes from white to black) and a particular spatial frequency (1/period) with the given contrast. At the diffraction limit spatial frequency, the contrast of a perfect lens would be zero – i.e., it wouldn’t be imaged. MTFs can be calculated three different ways: 1. Fourier (FFT): This is just the Fourier Transform of the wavelength errors in the exit pupil. No errors gives the diffraction limit MTF. Zemax will refuse to do this if it thinks you are undersampling the pupil, or the errors are too great. This also may not be very accurate if there is significant pupil aberration, but you won’t get a warning. 2. Geometric: This is what the geometric spot size is capable of imaging. You can think of it as the convolution of the geometric spot with each spatial frequency. There is an option for “Multiply by the Diffraction Limit” under the window’s “Settings” menu. It is recommended that you use this to avoid impossibly large MTFs in wellcorrected systems. 3. Huygens: This is loosely based on Christiaan Huygen’s method of propagating wavefronts he developed in 1678. Whereas Huygen proposed that each point on a wavefront was the source of spherical waves (with Lambertian directional fall off), Zemax uses the assumption that each ray traced to the image plane represents a plane wave with the ray’s path length at the point where the ray hits the image plane, but is otherwise spread over the entire image. The plane pg. 4 ECEN 4616/5616 2/25/2013 waves from each ray are coherently added (for each wavelength) to get the PSF, and hence the MTF. Zemax will always calculate the Huygen’s values, but they may be in significant error if the sampling rate is set too low (under the “Settings” menu on the window). The only way to find out is to keep increasing the sampling rate until the results don’t change. Huygen’s analyses in general, are more robust than the Fourier results, and more realistic than the Geometric results (which ignore diffraction). Again, if pupil aberration is significant, ray aiming should be turned on. PSF (Point Spread Function): This is the diffraction PSF – the geometric PSF is given by the “Spot Diagram” analysis above. This can be calculated either by Fourier or Huygen’s method, with the same cautions as in the MTF The MTF and PSF are related by 𝑀𝑇𝐹 = |𝐹𝑇{𝑃𝑆𝐹}| The other analyses we will be mostly concerned with are under the “Miscellaneous" heading: Field curvature/distortion: Two plots of useful, but largely unrelated values. Chromatic Focal Shift: This is the change in focal length vs wavelength for a given pupil zone. If the pupil zone is zero, it is the paraxial focal shift. The diffraction limited amount of shift is also given in the caption so you can judge if the correction is good enough. Lateral Color: This is based on the change in magnification vs wavelength. The plot gives the distance by which each wavelength spot is displaced from the central wavelength vs the height on the image plane. The Airy pattern size (to the first null) is also plotted to help decide if the correction is good ‘enough’. This plot does not relate to the actual size of the PSFs, but only to their location error. In deciding whether an optical system is corrected well enough, you must also take into account the detector type and the “acceptable blur size”. If the diffraction limited PSF (e.g., the Airy Pattern) is significantly smaller than the detector pixel size (as in the example on page 2 above), then the actual depth of focus may be significantly larger than the diffraction limited focal shift reported in the Chromatic focal Shift analysis window, and an acceptable degree of Lateral Color shift that is less than the pixel size may be much larger than the Airy Pattern. pg. 5 ECEN 4616/5616 2/25/2013 Analysis Windows for the Double Gauss lens: pg. 6 ECEN 4616/5616 2/25/2013 pg. 7 ECEN 4616/5616 2/25/2013 Outputing analysis results: 1. Copy to clipboard (Alt-PrtScr) and paste into a text document. 2. Export (various options) under the “Window” menu. 3. Write out a text file with the data, using the “Text” menu choice. Using analysis data in the Merit Function: (Almost) all analysis windows correspond to operands which can be inserted into the Merit Function Editor (MFE) – see Chapter 17 of the Zemax Manual, under “Optimization Operands”. Using analysis data in other programs: The easiest way to export is to write the data out as a text file (using the “Text” menu tab). Apendix A is a Matlab function that will read nearly all Zemax analysis text files into Matlab variables: Running Zemax from Matlab: Zemax supports the Dynamic Data Exchange (DDE) format, as does Matlab. Hence you can run Zemax from Matlab. This is most useful when the analysis of a merit function involves a significant amount of calculation (such as digital filtering). Assuming Zemax is already running on your computer, Matlab can command Zemax to load files, generate analyses, write them to text files, then read them in. Transferring data by text file is extremely fast on modern computers, since files are not written to disk by the program itself (e.g., Zemax), but sent to the disk controller where they are put into a queue. If the controlling program (e.g., Matlab) requests to read the file within a short time, the file will still be in memory and the transfer will happen as fast as if you went to the tedious and error-prone effort of reserving memory, passing pointers, etc – a task far more complicated than just using DDE. Appendix B contains some example Matlab code which can load files in Zemax and retrieve analysis data. The specific commands used are covered in the Zemax Manual in Chapter 26, “Zemax Extensions”. pg. 8 ECEN 4616/5616 2/25/2013 Appendix A (Reading Zemax files with Matlab) function [Ary,Hdr] = readZMX(F,SkipLines) %USAGE: [Ary,Hdr] = readZMX( Zemax_File,SkipLines ) %Reads data from Zemax text-output files % such as are written by the 'text' % option on most Zemax windows. %The function works by ignoring the text % headers of the file, and scanning down % to the data. %MODIFICATION: 13 May, 2008: % Code changed so that it can also read ZMX files with % only a single number per line. The function now % assumes the data start is at the first line that % contains only numbers. %MODIFIATION: 31 May, 2008: % Optional input argument "SkipLines" added. If this argument % is entered, the function skips the requested number of lines, % then reads as numerical with testing. % %INPUTS: % F: The Zemax-generated text file % SkipLine: If entered, the function skips this many lines, % and reads the rest without error checking. %OUTPUTS: % Ary: The 2-D data in the Zemax file % Hdr: If requested, this is a character matrix where each % row is a header line. % %Test for file: fid = -1; Fa = exist(F); if Fa == 2 %Open file: fid = fopen(F,'r'); end if fid == -1 disp(['File: ' F ' Not Found!']) return end %Test for requested "Fast Mode" read: if nargin == 1 %Not asked to skip lines SkipLines = -1; end % if SkipLines == -1 %Evaluate all lines %-- proceed with 'safe' read %Make array of valid ASCII codes for numbers only: Ncodes = '+-.0123456789Ee'; %Add space and tab to Ncodes (ASCII 32 and 9): Ncodes = [char(9) char(32) Ncodes]; %ASCII code for space: spc = double(' '); % Ary = []; Hdr = []; pg. 9 ECEN 4616/5616 2/25/2013 %Scan File: I = 1; while 1 %Read next line in file: line = fgetl(fid); %Test for End of Data: if ~isstr(line) %End of Data: quit function and return break %(jump out of while loop) end %Check for Headder Lines: if isempty(line) %Line is blank -- add to header array: Hdr = char(Hdr,line); elseif all(double(line)==spc) %Line is all spaces: add to header array: Hdr = char(Hdr,line); elseif isempty(setdiff(line,Ncodes)) %Line is all numbers: add to data array: Tmp = sscanf(line,'%f')'; Ary(I,:) = Tmp; I = I+1; else %Must be text header line: %Add to header array: Hdr = char(Hdr,line); end %(check line) end %(while: safe read) else %Fast Read: if SkipLines >=1 %Skip the header lines: for ii = 1:SkipLines line = fgetl(fid); end end %Read Data: Ary = []; Hdr = []; I = 1; %Scan File: while 1 %Read next line in file: line = fgetl(fid); %Test for End of Data: if ~isstr(line) %End of Data: quit function and return break %(jump out of while loop) end Tmp = sscanf(line,'%f')'; Ary(I,:) = Tmp; I = I+1; end %(while: fast read) end %Fast Read % %Close file and exit: fclose(fid); pg. 10 ECEN 4616/5616 2/25/2013 Appendix B (DDE examples from Matlab) Starting Zemax: function h = StartZemax(ZemaxFile) %USAGE: h = StartZemax(ZemaxFile); %Sets up a DDE connection to Zemax and loads % the specified file. %Note: With recent (2004) Zemax versions, an instance of Zemax % must already be running to use DDE from Matlab, although % a particular file need not be loaded. %INPUTS: % ZemaxFile: Zemax file name (and path) to be loaded % If not entered, no file is loaded, but % the channel handle, h, is still returned %OUTPUT: % h: The DDE channel to zemax % %START ZEMAX h = ddeinit('zemax','notopic'); if h == 0 error('Zemax not started') end % if nargin > 0 %LOAD ZEMAX FILE: loadstr = ['LoadFile,' ZemaxFile]; rc = ddereq(h,loadstr); if rc == -999 error('Zemax file load failed') elseif rc ~= 0 error('Zemax update failed') end end Getting a Zemax Analysis Text file: function [A,Hdr] = GetZText(channel,Type,SetFile) %USAGE: [A,Hdr] = GetZText(channel,Type,SetFile); %Get 2-D text file from Zemax system %INPUTS: % channel: The DDE channel to the Zemax system % (from "StartZemaxFile.m") % Type: A string with the three-letter identifier % indicating the Zemax analysis window to run. % Examples: % 'Fps' => Fourier Transform PSF % 'Wfm' => Wavefrpmt map % 'Mdm' => FFT Surface MTF % SetFile: A string with the path and name of the configuration % file to use for the Zemax analysis. Default is % the last saved configuration for the analysis. %OUTPUTS: % A: The 2D array from the Zemax analysis % Hdr: The header lines from the Zemax file % %Time to wait for Zemax (ms): pg. 11 ECEN 4616/5616 2/25/2013 Tout = 90e3; % %Pass data through temp text file in current directory: D = pwd; F = [D '\PSFText.txt']; % if nargin == 3 %(Use Settings File) reqstr = ['GetTextFile, "' F '" , ' Type ', "' SetFile '" , 1']; else %(Use Default config file) reqstr = ['GetTextFile, "' F '" , ' Type]; end rc = ddereq(channel,reqstr, [1 0], Tout); % %Read text file into Matlab array: [A,Hdr] = readZMX(F); %Delete temp file to ensure against false data: %delete(F); Changing Surface Data in Zemax: function Pval = PutSurfData(channel,Surf,Type,Val) %USAGE: Pval = PutSurfData(channel,Surf,Type,Val); %Inserts surface parameter into Zemax surface. %INPUTS: % channel: DDE channel to a Zemax file % Surf: the number of the surface to change. % Type: The parameter type to change. Valid values are % 'CURV', 'THIC', 'SDIA', and 'CONN' (same abrv. as Zemax) %OUTPUTS: % Pval: The newly set value. Might be slightly different % from Val due to significant digit effects. It is up % to the user to check to see if it is close enough. % %Set Accuracy of number insertion % (depends on editor "Decimals" setting) % SetErr = 1e-3; %(coarse) % SurfStr = num2str(Surf); reqstr0 = ['SetSurfaceData,' SurfStr ',']; switch Type case 'CURV' code = '2'; %Zemax data code for curvature case 'THIC' code = '3'; %Zemax data code for Thickness case 'SDIA' code = '5'; %Code for Semidiameter case 'CONN' code = '6'; %Code for conic constant end %(switch) reqstr = [reqstr0 code ',' num2str(Val)]; Pval = ddereq(channel,reqstr,[1 1]); %Pval = str2num(Pval); Er = ddereq(channel, 'GetUpdate',[1 1]); pg. 12 ECEN 4616/5616 2/25/2013 Getting Surface Data from Zemax: function X = GetParameter(channel,Surf,P) %USAGE: X = GetParameter(channel,Surf,P); %Gets values, X, from Zemax LDE parameter columns, P %INPUTS: % channel: Open DDE channel to Zemax (with file loaded) % P: A vector indicating which parameters to get. %OUTPUT: % X: A cell array with the requested data % %Set up the base DDE request string: L = 'GetSurfaceParameter,'; S = [num2str(Surf) ',']; fmt = [1 0]; %Return numeric data % for ii = 1:length(P) Pstr = num2str(P(ii)); %Set up the DDE request string: reqstr = [L S Pstr]; % %Get the parameter: rc = ddereq(channel, reqstr, fmt); X{ii} = rc; end %(over size(P)) % return pg. 13