Analysis of Three Lens Optical System with CMOS sensor

by jph

The constants and functions compiled in this document apply to the camera payload of a nano-satellite built at NTU.

Curvature of the three lenses

The two opposing surfaces of each lens are spheres. The cross section of such a surface is a partial circle. The location of each circle is determined by a radius and midpoint.

The optical system we discuss here consists of 3 lenses. That means their boundaries are determined by 6 circles. The midpoints of the 6 circles are all on a line. In the following we state the 6 radii and midpoints (as distances on the z-axis):

s1r=171.545;
s1z=0+s1r;
s2r=3900.000;
s2z=8.270-s2r;
s3r=134.600;
s3z=8.270+0.1+s3r;
s4r=223.475;
s4z=8.270+0.1+11.320-s4r;
s5r=245.360;
s5z=8.270+0.1+11.320+0.1-s5r;
s6r=760.000;
s6z=8.270+0.1+11.320+0.1+10.260+s6r;

Visualization of the three lenses

The first two lenses are made from Fluor Crown H-FK61, the third lens is made from Lanthanum Flint H-LAF4. The crowns cause a dispersion of the different wavelengths. The flint counter acts this effect as much as possible.

cl1=RGBColor[0.8,0.8,1];
cl2=RGBColor[0.65,0.65,1];
re1=RegionPlot[(x^2)+(((z-s1z))^2)<(s1r^2)&&(x^2)+(((z-s2z))^2)<(s2r^2),{x,-37,37},{z,-2,32},PlotStyle->cl1];
re2=RegionPlot[(x^2)+(((z-s3z))^2)<(s3r^2)&&(x^2)+(((z-s4z))^2)<(s4r^2),{x,-37,37},{z,-2,32},PlotStyle->cl1];
re3=RegionPlot[(x^2)+(((z-s5z))^2)>(s5r^2)&&(x^2)+(((z-s6z))^2)>(s6r^2),{x,-37,37},{z,-2,32},PlotStyle->cl2];
img=Show[{re1,re2,re3,Graphics[
{Text[Style["Lens 1 Fluor Crown H-FK61",FontSize->16],{0,4}],
Text[Style["Lens 2 Fluor Crown H-FK61",FontSize->16],{0,14}],
Text[Style["Lens 3 Lanthanum Flint H-LAF4",FontSize->16],{0,24.5}]}
]},{AspectRatio->Automatic,ImageSize->{256 2,256}}]

The light enters the midpoint of the surface of the first lens at coordinate (0,0).

Refractivity of the material at different wavelengths

The refractive index depends on the material and the wavelength of the light.

The refractive index for Fluor Crown H-FK61 is shown here:

The refractive index for Lanthanum Flint H-LAF4 is shown here:

From the plots we extract the refractive index for a selection of specific wavelengths:

Refractivity at blue, 0.460 μm:

rfkB=1.50279;
rlaB=1.77047;

Refractivity at green, 0.500 μm

rfkG=1.5005;
rlaG=1.76193;

Refractivity at skin color, 0.5876 μm

rfkS=1.497;
rlaS=1.7495;

Refractivity at red, 0.640 μm

rfkR=1.49553;
rlaR=1.7445;

The vector equation to refract a ray of initial direction d at a surface with normal n is according to Snell’s law
	(Subscript[d, out])=ρ d-(ρ n.d+(Sqrt[1-(ρ^2)(1-(((n.d))^2))]))n 
where ρ is the fraction of the outside and inside refractive indices, the vectors d and n are normalized, and w.l.o.g. the scalar product n.d<0 shall be negative. (Subscript[d, out]) denotes the direction of the ray after the refraction.

For ρ=1, the equation reduces to the identity 
	(Subscript[d, out])=1 d-(1 n.d+(Sqrt[1-1(1-(((n.d))^2))]))n
=d-(n.d)n-(Sqrt[1-1+(((n.d))^2))]))n
=d-(n.d)n-|n.d|n
=d+|n.d|n-|n.d|n
=d 
where we have used that n.d<0.

Refract[nrm_,dir_,rho_]:=Module[{prj=nrm.dir},
rho dir-(rho prj+(Sqrt[1-rho rho(1-prj prj)])) nrm]

Example from Wikipedia:

Refract[{0,1},{1,-1}/Norm[{1,-1}],0.9]

Equations to trace a ray of light

We solve the intersection of a circle with a ray as

crc=(cx^2)+(((cz-ch))^2)==(cr^2);
ray={px,pz}+{dx,dz} v;
sol=FullSimplify[Solve[crc/.{cx->ray[[1]],cz->ray[[2]]},{v}],{0<cr}]

The function “shoot” computes the refracted ray when a beam enters a medium with a different refractive index. In particular, the function applies to rays entering a lens as to exiting rays alike.

Shoot[{pos_,dir_},rad_,hei_,rho_]:=Module[{ndr,sub,tip,nrm,ct1,ct2,out,res},
ndr=dir/Norm[dir];
sub={px->pos[[1]],pz->pos[[2]],dx->ndr[[1]],dz->ndr[[2]],cr->rad,ch->hei};
tip=ray/.sub/.v->Min[Select[v/.sol/.sub,0<#&]];
nrm=tip-{0,hei};
nrm=nrm/Norm[nrm];
nrm=If[0<nrm.ndr,-nrm,nrm];
{tip,Refract[nrm,ndr,rho]}]

The function “shootpath” traces a ray that enters the first lens all the way to the CMOS sensor and consists of 6 calls to the function “shoot”.

ShootPath[{pos_,dir_},rho1_,rho2_]:=Module[{t0c,t1c,t2c,t3c,t4c,t5c,t6c},
t0c={pos-10 dir,dir};
t1c=Shoot[t0c,s1r,s1z,1/rho1];
t2c=Shoot[t1c,s2r,s2z,rho1];
t3c=Shoot[t2c,s3r,s3z,1/rho1];
t4c=Shoot[t3c,s4r,s4z,rho1];
t5c=Shoot[t4c,s5r,s5z,1/rho2];
t6c=Shoot[t5c,s6r,s6z,rho2];
{t0c[[1]],t1c[[1]],t2c[[1]],t3c[[1]],t4c[[1]],t5c[[1]],t6c[[1]],t6c[[1]]+210 t6c[[2]]}]

Location of CMOS sensor

The function “pixelHit” establishes where a ray ends up on the CMOS sensor (in mm).

PixelHit[pth_,ahg_]:=Module[{t,p1x,p1z,p2x,p2z,pix,loc,sub,eqs,lst},
loc={p1x,p1z}+t {p2x-p1x,p2z-p1z}-{pix,ahg};
lst=Length[pth];
sub={p1x->pth[[lst-1,1]],p1z->pth[[lst-1,2]],p2x->pth[[lst,1]],p2z->pth[[lst,2]]};
eqs=#==0&/@loc/.sub;
pix/.Solve[eqs][[1]]]

The distance between CMOS sensor array and the lens surface closest to the array is 179.7 mm. The distance between the midpoint of the surface of the first lens at coordinate (0,0) to the surface of the CMOS sensor is 209.75.

On top of the passive layer, there is an optional layer named polyimide. Between the photodiode and the polyimide, there are the normal metal interconnection layers. From bottom to top, they are:

Dielectric Layers	Thickness(A)	Inside Metal
ILD			6000		POLY
IMD1			8200		M1
IMD2			8200		M2
IMD3			8200		M3
IMD4			8200		M4
IMD5a		11800		M5
IMD5b		3500		M5
PASS1			13900		M6
PASS2			2000		M6

In total this amounts to 7 μm of coating.

10^3 (6000.+4 8200+11800+3500+13900+2000)10^-10

Animation for different angles

DrawWith[α_]:=Module[{ahg=s6z-s6r+179.8,lnsG,gfx,pro,cms=3,tol=0.15+0.1,pxw=0.0065},
lnsG=Table[ShootPath[{{k,0},{Sin[α],Cos[α]}},rfkG,rlaG],{k,-35,35,2}];
gfx={{Black,Line[{{-cms,ahg-0.007},{cms,ahg-0.007}}],Text[Style[Round[α 180./π 1000]/1000.,Large,Bold,Red],{-30,180},Automatic,{0,1}],Dashed,Table[Line[{{k pxw,ahg-pxw},{k pxw,ahg+2pxw}}],{k,-768/2,768/2}]}};
pro={AspectRatio->Automatic,PlotRange->{{-37,37},{-5,210}},Frame->True,Axes->False,ImageSize->{360,640}};
Show[{re1,re2,re3,Graphics[{gfx,{Thickness[0.002],RGBColor[0,0,0,0.2],Line/@lnsG}}]},pro]];
Manipulate[DrawWith[α],{α,-6 π/180,6 π/180}]

ofs=1000;len=15 15;
Table[Print[Export["d:\\video\\lens\\r"<>ToString[k]<>".png",ImageRotate[DrawWith[(((k-ofs)/len)10-5)π/180],Right]]],{k,ofs,ofs+len}];

Animation for different wavelengths

s6z-s6r+ofs/.ofs->179.762

DrawWith[α_,ofs_]:=Module[{ahg=s6z-s6r+ofs,lnsR,lnsG,lnsB,mid,gfx,pro,cms=3,tol=0.15+0.1,pxw=0.0065},
lnsR=Table[ShootPath[{{k,0},{Sin[α],Cos[α]}},rfkR,rlaR],{k,-35,35,2}];
lnsG=Table[ShootPath[{{k,0},{Sin[α],Cos[α]}},rfkG,rlaG],{k,-35,35,2}];
lnsB=Table[ShootPath[{{k,0},{Sin[α],Cos[α]}},rfkB,rlaB],{k,-35,35,2}];
mid=PixelHit[lnsR[[Round[(Length[lnsR]+1)/2]]],ahg];
gfx={{Black,Line[{{-cms,ahg-0.007},{cms,ahg-0.007}}],Table[Text[k,{k,ahg-0.02}],{k,0,3,0.1}],Dashed,Table[Line[{{k pxw,ahg-pxw},{k pxw,ahg+2pxw}}],{k,-768/2,768/2}]}};
pro={AspectRatio->Automatic,PlotRange->{{mid-tol 2.3/4,mid+tol 2.3/4},{ahg-tol,ahg+tol}}};
Show[GraphicsGrid[{{
Graphics[{gfx,{Thickness[0.01],RGBColor[1,0,0,0.1],Line/@lnsR}},pro],
Graphics[{gfx,{Thickness[0.01],RGBColor[0,1,0,0.1],Line/@lnsG}},pro],
Graphics[{gfx,{Thickness[0.01],RGBColor[0,0,1,0.1],Line/@lnsB}},pro]}}],ImageSize->{640,360}
]];
Manipulate[DrawWith[α,ofs],{α,0,0.9 π/180},{ofs,179.5,180.0}]
DrawWith[0.5 π/180,179.75]

ofs=1226;len=15 12;
Table[Print[Export["d:\\video\\lens\\r"<>ToString[k]<>".png",DrawWith[((k-ofs)/len)0.9 π/180,179.75]]],{k,ofs,ofs+len}];

Quantification of Spread

LensBlur[α_,err_]:=Module[{pxw=0.0065,ahg=s6z-s6r+179.75+err,stp=1/10,dir={Sin[α],Cos[α]},smp,lnsR,lnsG,lnsB,mid,pixR,pixG,pixB,binR,binG,binB},
lnsR=Table[ShootPath[{{k,0},dir},rfkR,rlaR],{k,-35,35,stp}];
lnsG=Table[ShootPath[{{k,0},dir},rfkG,rlaG],{k,-35,35,stp}];
lnsB=Table[ShootPath[{{k,0},dir},rfkB,rlaB],{k,-35,35,stp}];
mid=PixelHit[lnsR[[(Length[lnsR]+1)/2]],ahg];
pixR=PixelHit[#,ahg]&/@lnsR;
pixG=PixelHit[#,ahg]&/@lnsG;
pixB=PixelHit[#,ahg]&/@lnsB;
smp={-30.5pxw+mid,30.5pxw+mid,pxw};
binR=BinCounts[pixR,smp];
binG=BinCounts[pixG,smp];
binB=BinCounts[pixB,smp];
{smp,{binR,binG,binB}}];
ListPlot[LensBlur[0.8 π/180,-0.4][[2]],{PlotRange->All,Axes->False}]

TODO 3d !!!

max=0.9 π/180;
tab=Table[LensBlur[α,-0.0625]//Flatten,{α,0,max,max/80}];
Export["d:\\blurn00625.mat",tab]
tab=Table[LensBlur[α,-0.075]//Flatten,{α,0,max,max/80}];
Export["d:\\blurn0075.mat",tab]

Details about the CMOS sensor

The CMOS sensor has a resolution of 768 x 512. The satellite is estimated to be 650 km.

pixeldim={768,512};
pixelwid=6.5 (10^(-6));(* unit: meter *)
lensdist=0.2;
altitude=650000;

Thus, one pixels corresponds to 21 m on ground.

gndwidth=x/.Solve[(pixelwid/lensdist)==(x/altitude)][[1]]

The field of view in degree is 1.43 degree along the width of the array and 0.95 degree along the height of the array.

(180/π)2ArcTan[(1/2)pixeldim gndwidth/altitude]

xlen=0.026;
lensdist=0.317-0.153

lensdiam=(Sqrt[2(((2xlen))^2)])

fnumber=lensdist/lensdiam

Optics on ground WRONG!

lensdiamG=0.015;
lensdistG=0.0015;
fnumberG=lensdistG/lensdiamG

human eye: f/8.3 brightly lit places
f/2.1 in dark places (or f/3.2)

Vacuum !!! different focal length!

pixelwid pixeldim 1000

Heat catastrophy

area=(0.035^2)π;
ENG=area 1800 Watt;
t=1 sec;
mass=1 gramm;
coef=0.703 (Joule/(gramm Kelvin));
((ENG t)/(coef mass))/.Joule->Watt sec