General Raytrace

Matlab code

raytrace.m

function [ pos, dir, q ] = raytrace(pos_in, dir_in, cv, th, rn)
%
% RAYTRACE
%
nsurf = length(th);
opl = 0.0;
pos = pos_in;
dir = dir_in;

fprintf('%4s%10s%10s%10s%8s%8s%8s%12s\n','n','X','Y','Z','kx','ky','kz','OPL');
fprintf('%4d%10.3f%10.3f%10.3f%8.4f%8.4f%8.4f\n',0,pos,dir);
for (n=2:nsurf-1)
   [pos dir q(n)] = surf_trace(pos,dir,cv(n),th(n-1),rn(n),rn(n-1));
   fprintf('%4d%10.3f%10.3f%10.3f%8.4f%8.4f%8.4f%12.8f\n',n-1,pos,dir,q(n));
   opl = opl + rn(n-1)*rn(n-1)*q(n);
end
[pos dir qt] = surf_trace(pos,dir,cv(nsurf),th(nsurf-1),rn(nsurf),rn(nsurf-1));
fprintf('%4d%10.3f%10.3f%10.3f%8.4f%8.4f%8.4f\n',n,pos,dir);

surf_trace.m

Trace ray through single surface (used by raytrace)

function [pos, dir, q]  = surf_trace(pos_in, dir_in, cv, th, rno, rni)
% SURF_TRACE  trace ray through single spherical surface
%    [POS DIR Q] = SURF_TRACE(POS_IN, DIR_IN, CV, TH, RNO, RNI)
%			CV surface curvature
%        TH axial distance to current surface
%        RNO index of refraction after surface
%        RNI index of refraction before surface
%        POS_IN  initial ray position at previous surface
%        DIR_IN  optical direction cosines of initial ray
%
%  Output variables:
%        POS  ray position at current surface
%        DIR  optical direction cosines after refraction
%        Q    reduced distance to current surface
%

pos = pos_in;
pos(3) = pos(3) - th;
% intersect current surface
if (cv ~= 0)
   A = cv*rni*rni;
   B = dir_in(3) - cv*dot(pos,dir_in);
   C = cv*dot(pos,pos)-2.0*pos(3);
   D = B*B-A*C;
   %fprintf('Quadratic (A = %g, B = %g, C = %g, D = %g)\n',A,B,C,D);
   D = sqrt(D);
   if (B<0)
      D = -D;
   end
   q = C/(B+D);
else
   q = -pos(3)/dir_in(3);
end
%  calculate point of intersection
pos = pos + q*dir_in;

% calculate surface normal
norm = -cv*pos;
norm(3) = 1.0 + norm(3);
%fprintf('surface normal %g %g %g\n',norm);

% refract ray into surface
gcosi = dot(dir_in,norm);
root = gcosi*gcosi + (rno+rni)*(rno-rni);
gcosr = sqrt(root);
if (gcosi<0.0) 
   gcosr = -gcosr;
end

% calculate refracted ray direction
power = gcosr - gcosi;
dir = dir_in + power * norm;

% calculate optical path length
q = q * rni*rni;

Example

First we define the optical system.

% define optical system
cv = [ 0 1/34.53 -1/21.98 -1/214.63 0];
th = [ 0 9 2.5 43.567826 0];
rn = [ 1 1.670028 1.72825 1 1 ];

Then we define the starting ray

pos = [0 12.5 0];
dir = [0 0 1];

Call raytrace to do the work

[pos dir q] = raytrace(pos,dir,cv,th,rn);

This produces

   n         X         Y         Z      kx      ky      kz         OPL
   0     0.000    12.500     0.000  0.0000  0.0000  1.0000
   1     0.000    12.500     2.342  0.0000 -0.2527  1.6508  2.34194476
   2     0.000    12.029    -3.584  0.0000 -0.2105  1.7154  5.19366516
   3     0.000    11.319    -0.299  0.0000 -0.2500  0.9683 10.07334993
   4     0.000    -0.005     0.000  0.0000 -0.2500  0.9683

Display the intersection of the ray with the image plane

fprintf('image plane: (y = %.6f, x = %.6f)',pos(2),pos(1));

The final result is

image plane: (y = -0.004580, x = 0.000000)

OPD Example

Add a non-refracting reference surface as the last surface in the optical system

cv = [ 0 1/34.53 -1/21.98 -1/214.63 1/43.567826 0];
th = [ 0 9 2.5 0 43.567826 0];
rn = [ 1 1.670028 1.72825 1 1 1 ];

Trace a ray through the edge of the aperture, as before. This time display the values of the optical pathlength array q.

pos = [0 12.5 0];
dir = [0 0 1];
[pos dir q] = raytrace(pos,dir,cv,th,rn);
fprintf('image plane: (y = %.6f, x = %.6f)\n',pos(2),pos(1));
disp(q);

The results are

   n         X         Y         Z      kx      ky      kz         OPL
   0     0.000    12.500     0.000  0.0000  0.0000  1.0000
   1     0.000    12.500     2.342  0.0000 -0.2527  1.6508  2.34194476
   2     0.000    12.029    -3.584  0.0000 -0.2105  1.7154  5.19366516
   3     0.000    11.319    -0.299  0.0000 -0.2500  0.9683 10.07334993
   4     0.000    10.886     1.382  0.0000 -0.2500  0.9683  1.73561739
   5     0.000    -0.005     0.000  0.0000 -0.2500  0.9683
image plane: (y = -0.004580, x = 0.000000)

q =  0    2.3419    5.1937   10.0733    1.7356

Now trace a central ray. The optical pathlength array is named qc.

pos = [ 0 0 0];
dir = [ 0 0 1];
[pos dir qc] = raytrace(pos,dir,cv,th,rn);
disp(qc);

The results are

   n         X         Y         Z      kx      ky      kz         OPL
  0     0.000     0.000     0.000  0.0000  0.0000  1.0000
   1     0.000     0.000     0.000  0.0000  0.0000  1.6700  0.00000000
   2     0.000     0.000    -0.000  0.0000  0.0000  1.7283 15.03025200
   3     0.000     0.000     0.000  0.0000  0.0000  1.0000  4.32062500
   4     0.000     0.000     0.000  0.0000  0.0000  1.0000  0.00000000
   5     0.000     0.000     0.000  0.0000  0.0000  1.0000

qc =   0         0   15.0303    4.3206         0

The final optical path is the sum of the differences in optical path length

opd = qc - q
opd = sum(opd);
fprintf('total opd %g\n',opd);

wvl = 0.00058756;
fprintf('total opd %g wave\n',opd/wvl);

The final results are

opd =  0   -2.3419    9.8366   -5.7527   -1.7356

total opd 0.00629975
total opd 10.7219 wave


Maintained by John Loomis, last updated 6 Feb 2003