Calculations for a microlens array on the sensor
We analyze how to position microlenses with respect to the center of each pixel in order to optimize light gathering. If we create a microlens array for a particular optics (imaging lens also called the taking lens) and sensor, then we are analyzing where we should place each microlens.
This calculation is performed for a particular choice of the optics and a particular choice of the microlens. The optics parameters are set in the optical image (optics slot). The microlens parameters are set in the microlens structure.
See also: mlensCreate, mlAnalyzeArrayEtendue, plotSensorEtendue, mlensGet
Copyright Imageval LLC, 2015
Contents
- Create an oi with the default optics
- Analyze the light loss if we do not have a microlens
- Now what if each microlens is centered on the pixel
- If we have a microlens placed optimally ...
- Here is the optimal offset calculation
- Now for the whole sensor array
- What happens when we change the microlens fnumber?
- What happens when we change the source optics fnumber?
- Illustrate radiance for different chief ray angles
ieInit
Create an oi with the default optics
scene = sceneCreate; ieAddObject(scene); oi = oiCreate; ieAddObject(oi); % Create a sensor with default properties. sensor = sensorCreate; mlens = mlensCreate(sensor,oi); sensor = sensorSet(sensor,'microlens',mlens); % Then give the sensor a decent field of view fov = 20; sensor = sensorSetSizeToFOV(sensor,fov,oi); ieAddObject(sensor); % Here are the default specifications for the optics and sensor % iePTable(oi); % iePTable(sensor);
Analyze the light loss if we do not have a microlens
sensor = mlAnalyzeArrayEtendue(sensor,'no microlens'); plotSensorEtendue(sensor); title('No microlens') % If we make the stack height close to 0, the peak here should be close to % 1 and everything should flatten a bit.

Now what if each microlens is centered on the pixel
% This looks OK qualitatively. The center gets boosted by the microlens % because we are defeating pixel vignetting. sensor = mlAnalyzeArrayEtendue(sensor,'centered'); plotSensorEtendue(sensor) title('Microlens centered on each pixel')
ans = struct with fields: support: [1×1 struct] sensorEtendue: [398×488 double]

If we have a microlens placed optimally ...
sensor = mlAnalyzeArrayEtendue(sensor,'optimal'); plotSensorEtendue(sensor); title('Microlens placed optimally on each pixel')

Here is the optimal offset calculation
cra = sensorGet(sensor,'cra degrees'); % Chief ray angle rayAngles = linspace(0,max(cra(:)),10); % How many angles to sample mlens = sensorGet(sensor,'microlens'); pixel = sensorGet(sensor,'pixel'); offset = zeros(1,length(rayAngles)); focalLength = oiGet(oi,'optics focal length','meters'); for ii=1:length(rayAngles) mlens = mlensSet(mlens,'chief ray angle',rayAngles(ii),focalLength); offset(ii) = mlensGet(mlens,'optimal offset','microns'); end ieNewGraphWin; plot(rayAngles,offset,'k-o'); xlabel('Ray angle (deg)'); ylabel('Offset towards center (um)'); title('Optimal offset') grid on

Now for the whole sensor array
offsets = mlensGet(mlens,'optimal offsets',sensor); % Units are microns sSupport = sensorGet(sensor,'spatial support','um'); ieNewGraphWin; mesh(sSupport.y,sSupport.x,offsets); xlabel('Sensor position (um)'); ylabel('Sensor position (um)'); zlabel('Offset towards center (um)')

What happens when we change the microlens fnumber?
mlens0 = sensorGet(sensor,'microlens'); sSupport = sensorGet(sensor,'spatial support','um'); fnumber = mlensGet(mlens0,'ml fnumber'); mlens1 = mlensSet(mlens0,'ml fnumber',0.5*fnumber); mlens1 = mlensSet(mlens1,'name','Half fnumber'); ieNewGraphWin([],'tall'); offsets0 = mlensGet(mlens0,'optimal offsets'); % Units are microns subplot(2,1,1), mesh(sSupport.y,sSupport.x,offsets0); xlabel('Sensor position (um)'); ylabel('Sensor position (um)'); zlabel('Offset towards center (um)') title(sprintf('ml fnumber %.2f',mlensGet(mlens0,'ml fnumber'))); offsets1 = mlensGet(mlens1,'optimal offsets'); % Units are microns subplot(2,1,2), mesh(sSupport.y,sSupport.x,offsets1); xlabel('Sensor position (um)'); ylabel('Sensor position (um)'); zlabel('Offset towards center (um)'); title(sprintf('ml fnumber %.2f',mlensGet(mlens1,'ml fnumber'))); % How different is the largest offset (in um)? max(abs(offsets0(:) - offsets1(:)))
ans = 0.9649

What happens when we change the source optics fnumber?
ieNewGraphWin([],'tall'); mlens = mlensSet(mlens,'source fnumber',4); offsets0 = mlensGet(mlens,'optimal offsets'); % Units are microns subplot(2,1,1), mesh(sSupport.y,sSupport.x,offsets0); xlabel('Sensor position (um)'); ylabel('Sensor position (um)'); zlabel('Microlens offset (um)') title(sprintf('F/# %.1f',mlensGet(mlens,'source fnumber'))); sensor = sensorSet(sensor,'microlens',mlens1); mlens = mlensSet(mlens,'source fnumber',16); offsets1 = mlensGet(mlens,'optimal offsets'); % Units are microns subplot(2,1,2), mesh(sSupport.y,sSupport.x,offsets1); xlabel('Sensor position (um)'); ylabel('Sensor position (um)'); zlabel('Microlens offset (um)') title(sprintf('F/# %.1f',mlensGet(mlens,'source fnumber'))); max(abs(offsets0(:) - offsets1(:)))
ans = 0

Illustrate radiance for different chief ray angles
ieNewGraphWin([],'tall'); % Initialize the lens mlens = mlensCreate; mlens = mlensSet(mlens,'ml fnumber',8); % Make a blurry microlens % Select parameters for plotting chiefrays = (-10:5:10); nRays = length(chiefrays); for ii=1:nRays mlens = mlensSet(mlens,'chief ray angle',chiefrays(ii)); mlens = mlRadiance(mlens); x = mlensGet(mlens,'x coordinate'); subplot(nRays,1,ii) imagesc(x,x,mlensGet(mlens,'pixel irradiance')); axis image; h = hot(256); colormap(h(50:220,:)); grid on xlabel('Position (um)'); ylabel('Position (um)'); title(sprintf('%i deg',chiefrays(ii))); end
** Using current ISET sensor bayer-0 ** Using current ISET oi opticalimage1
