Created
September 14, 2018 13:20
-
-
Save cactorium/2a042799ab60aba49a677b0f163bc3f0 to your computer and use it in GitHub Desktop.
Lens configuration calculator for a simple microscope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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