Instantly share code, notes, and snippets.

Embed
What would you like to do?
Lens configuration calculator for a simple microscope
# finds possible lens configurations to make a working microscope given a set of available lenses and a couple of other parameters
# outputs the max and min magnification of each valid lens ordering and the total length of each lens system
lens = [25.4, 25.4, 25.4, 100.0, -75.0]
eye_dist = 270.00
# each lens adds one degree of freedom to the system; it's fully constrained
# with 2 lens but every additional lens adds a DoF
# so we'll brute force it by checking every possible combination of lengths
# between 10mm and 100mm and pick the best set of valid parameters
def calc_single_perf(lens_config, obj_dist):
if obj_dist == 0.0:
return None
if len(lens_config) <= 1:
return None
elif len(lens_config) == 2:
image_dist_inv = 1./lens_config[0] - 1./obj_dist
image_dist = 0.0
if image_dist_inv == 0.0:
image_dist = 1.e+12
else:
image_dist = 1./image_dist_inv
# image needs to looks like it's behind the lens instead of ahead of it
# so it's an addition here instead of subtraction
obj_dist_inv = 1./lens_config[1] + 1./eye_dist
obj_dist2 = 0.0
if obj_dist_inv == 0.0:
obj_dist2 = 1.e+12
else:
obj_dist2 = 1./obj_dist_inv
lens_dist = image_dist + obj_dist2
if lens_dist < 0.0:
return None
else:
mag = image_dist / obj_dist * -eye_dist / obj_dist2
return mag, [lens_dist]
else:
max_zoom = 0.0
max_zoom_length = None
for lens_dist in range(10, 100):
cur_lens = lens_config[0]
t = 1./cur_lens - 1./obj_dist
image_dist = 0.0
if t == 0.0:
image_dist = 1.e+12
else:
image_dist = 1./t
cur_zoom = -image_dist / obj_dist
r = calc_single_perf(lens_config[1:], lens_dist-image_dist)
if r is None:
continue
sub_zoom, sub_lengths = r
total_length = [lens_dist] + sub_lengths
zoom = cur_zoom * sub_zoom
if abs(zoom) > abs(max_zoom):
max_zoom = zoom
max_zoom_length = total_length
if max_zoom_length is not None:
return max_zoom, max_zoom_length
else:
return None
def calc_perf(lens_config):
zooms = []
total_lengths = []
for obj_dist in range(25, 100):
result = calc_single_perf(lens_config, obj_dist)
if result is None:
continue
zoom, lengths = result
zooms.append(zoom)
total_lengths.append(sum(lengths))
if len(zooms) > 0:
return max(zooms), min(zooms), max(lengths), min(lengths)
else:
return None
def try_comb(result_lenses, results, current_config, left):
if current_config not in result_lenses:
print(current_config)
result_lenses.append(current_config)
results.append(calc_perf(current_config))
if len(left) > 0:
for i in range(len(left)):
chosen = left[i]
new_left = left[:i]+left[i+1:]
#print("c", current_config)
try_comb(result_lenses, results, current_config, new_left)
new_config = current_config[:]
new_config.append(chosen)
#print("n", new_config)
try_comb(result_lenses, results, new_config, new_left)
result_lenses = []
results = []
try_comb(result_lenses, results, list(), lens)
for lens, r in zip(result_lenses, results):
if r is not None:
max_zoom, min_zoom, max_length, min_length = r
print(lens, min_zoom, max_zoom, min_length, max_length)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment