Replies: 3 comments 1 reply
-
Hmm. After playing around a bit, I notice that my exit pupil location should probably be equal to the front focal length with an infinite conjugate image plane. That's easy enough to do with ray-optics. After that, my problem is then: (here, again, I just found the fields with manual iteration) |
Beta Was this translation helpful? Give feedback.
-
Hello @lkangas, You can use an image space height specification, there was a problem with updating the first order data out of sequence that made this look wrong. There is a lot of distortion and field curvature/astigmatism in this system so I've shown how to calculate and plot those quantities. I've included a spot diagram that shows the lateral color in the eyepiece as well. I can't think of a quicker way to find out the maximum field than trial and error. In practice, there'll be vignetting as you go off axis so you'll want to decide how much vignetting to tolerate at the edge of the field. Hope this helps. Mike %matplotlib inline from rayoptics.environment import *
from rayoptics.raytr.trace import setup_pupil_coords, trace_astigmatism opm = OpticalModel()
sm = opm['seq_model']
osp = opm['optical_spec']
pm = opm['parax_model']
em = opm['ele_model']
pt = opm['part_tree']
ar = opm['analysis_results'] # open up the aperture to match a big DOB
osp['pupil'] = PupilSpec(osp, key=('image', 'f/#'), value=4)
osp['fov'] = FieldSpec(osp, key=('image', 'height'), value=25,
flds=[0, 1/np.sqrt(2), 1], is_relative=True)
# add wavelengths to look at chromatic aberrations
osp['wvls'] = WvlSpec([('F', 0.5), ('d', 1.0), ('C', 0.5)], ref_wl=1) sm.do_apertures = False
sm.gaps[0].thi = 1e10
# set lens spacing and shape
gap = 2
bending = -0.2
# set eye relief (location of exit pupil)
opm.add_dummy_plane()
sm.set_stop()
sm.gaps[-1].thi = 24
opm.add_part(elements.create_cemented_doublet, power=1/180, th=14.8, sd=53.5/2, t=gap, bending=bending)
opm.add_part(elements.create_cemented_doublet, power=1/180, th=14.8, sd=53.5/2, t=gap, bending=bending)
opm.add_part(elements.create_cemented_doublet, power=1/180, th=14.8, sd=53.5/2, t=gap, bending=bending)
opm.add_part(elements.create_cemented_doublet, power=1/180, th=14.8, sd=53.5/2, t=gap, bending=bending)
opm.flip(em.elements[4])
opm.flip(em.elements[8]) opm.update_model()
fod = ar['parax_data'].fod
enp_radius = fod.enp_radius
sm.ifcs[1].set_max_aperture(enp_radius)
bfl = fod.bfl
sm.gaps[-1].thi = bfl
# the initial model has an object and image surface already defined.
#opm.add_dummy_plane(sd=30)
# set the desired semi-diameter on the image surface.
sm.ifcs[-1].set_max_aperture(30)
opm.update_model()
print('eyepiece focal length:', f'{opm.analysis_results['parax_data'].fod.efl:.2f}')
layout_plt = plt.figure(FigureClass=InteractiveLayout, opt_model=opm,
do_draw_rays=True,
do_draw_beams=True,
do_draw_edge_rays=False,
do_draw_ray_fans=True,
num_rays_in_fan=5,
do_paraxial_layout=False
).plot()
pm.first_order_data()
Compare paraxial and real image heightsTrace chief ray at the edge of the field. list_ray(ray_r1_f2:=trace_ray(opm, [0, 0], osp['fov'].fields[2], osp['wvls'].central_wvl))
Compute distortion(ray_r1_f2.pkg.ray[-1][mc.p][1]-fod.img_ht)/fod.img_ht
pm.list_model()
sm.list_model()
Calculate Distortion and Astigmatism across the fieldUse setup_pupil_coords() to trace the chief ray at each field. The function trace_astigmatism() traces close rays around the chief ray to measure the sagittal and tangential focal shifts. wvl = osp['wvls'].central_wvl
print(" paraxial real ray % sagittal tangential")
print(" height height distortion focus focus")
frac = []
sag_foc = []
tan_foc = []
distort = []
for f in np.linspace(0.001, 1, 11):
fld = Field(y=f, fov=osp['fov'])
ref_sphere, cr_pkg = setup_pupil_coords(opm, fld, wvl, 0)
y_img = cr_pkg[0].ray[-1][mc.p][1]
ht = f*osp['fov'].value
dist = 100*(y_img - ht)/ht
s_foc, t_foc = trace_astigmatism(opm, fld, wvl, 0)
print(f"{f:4.2f}: {ht:10.5f} {y_img:10.5f} {dist:6.2f}% {s_foc:10.5f} {t_foc:10.5f}")
frac.append(f)
distort.append(dist)
sag_foc.append(s_foc)
tan_foc.append(t_foc)
Plot % distortionThere is negative or barrel distortion present. plt.plot(distort, frac)
plt.xlabel("% Distortion")
plt.ylabel("Fractional Height")
plt.title("Distortion")
Plot the astigmatic fociThe astigmatism dominates the eyepiece performance. plt.plot(sag_foc, frac, label='sagittal focus', c='blue')
plt.plot(tan_foc, frac, label='tangential focus', c='red')
plt.xlabel("Focus Shift")
plt.ylabel("Fractional Height")
plt.title("Astigmatism Curves")
plt.legend()
Plot the transverse ray aberrationsabr_plt = plt.figure(FigureClass=RayFanFigure, opt_model=opm, data_type='Ray', scale_type=Fit.All_Same, dpi=150).plot() Third Order Seidel aberrationsThe distortion magnitude swwamps the other aberration types to_pkg = compute_third_order(opm)
to_pkg
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
Bar chart for surface by surface third order aberrationsfig, ax = plt.subplots()
ax.set_xlabel('Surface')
ax.set_ylabel('third order aberration')
ax.set_title('Surface by surface third order aberrations')
to_pkg.plot.bar(ax=ax, rot=0)
ax.grid(True)
fig.tight_layout() Plot Spot DiagramFull scale is about +/-1 mrad or +/-3.4 arc min. spot_dgm_fig = plt.figure(FigureClass=SpotDiagramFigure, opt_model=opm,
scale_type=Fit.User_Scale, user_scale_value=0.5, num_rays=31, dpi=150).plot() |
Beta Was this translation helpful? Give feedback.
-
Awesome! Thank you so much for these examples, very educating. I will have a thorough go at playing with all of these calculations. I think what I was trying to do is find out the edge of the unvignetted field. If there are no established tools for that, maybe it wouldn't be too hard to use some scipy.optimize functions that increase the field until an edge ray from a field point reaches the edge at one of the surfaces. I'll give it a try. What also got me confused was that the chief rays from the pupil weren't parallel to the axis at the image, but now the reason is obvious: it's spherical aberration of the exit pupil. Since all of the rays are traced from a fixed pupil location, even though its position slightly changes by field angle. So the reason for kidney bean effect on early Naglers. I'm about to assemble a first test with these lenses, to see what the astigmatism and distortion look like in practice with a C11. Maybe it's well worth the ten bucks for the binocular parts, vs. the thousand bucks for a similar spec Ethos. :) I also wouldn't be too worried about the performance at f/4 since that produces an exit pupil of 13 mm anyway (but maybe stopping down won't help with astigmatism and distortion). trace_astigmatism() seems like exactly what I need for another design as well (a simple solar projector). I can post that as an example for others, once everything's in place. |
Beta Was this translation helpful? Give feedback.
-
Some astronomy stuff for fun.
I try to model an RDP (Red's Double Plössl) eyepiece that is constructed from four achromatic doublet objective lenses salvaged from old 7x50 binoculars. The lenses are stacked in a double symmetrical configuration. The reason for using four lenses is that a single objective is usually around f/4 which is f=180-200 mm for a 50 mm binocular, and just stacking two in a symmetrical Plössl setup would yield inconveniently large focal length eyepieces. Four gives you a nice low power wide field eyepiece for big scopes and 2" focusers. I recommend looking up Red's Youtube channel and Facebook group "A Second Look: Reusing Old Lenses for Astronomy" if interested.
I'm using the method suggested in Bruce Walker's "Optical design for visual systems", where the object is at infinity and the image surface is the telescope image. This works very nice and was surprisingly easy to set up. Even coming up with a model for the achromats was unexpectedly easy. But some questions follow at the bottom.
Here I figured out how to match the telescope's speed (f/10) by defining the pupil by f-number at the image plane.
However, I still had to set the eye relief (distance of exit pupil, or rather the entry pupil in this arrangement) to 24 manually. I experimented to get the ray fans approximately axial in the image space.
How should I compute the location of the exit pupil automatically? Should I trace a chief ray (?) backwards from the image plane and calculate the axial crossing? What would be the easiest way to do that?
After the correct pupil location is found, where in the PupilSpec could I find the resulting diameter of the pupil? In the plot, I can see the pupil is of the expected diameter of EFL/(f/#) = 50.7mm/10 = approx. 5 mm.
Additionally, I also explicitly defined the (half) field angle to be 27 degrees. Commented out is an attempt to define it based on the image height, but with no success. How could I define the field in the image space, and how do I get the resulting angle in degrees?
Having access to a tool like this is unbelievably helpful in understanding how these lenses work. I was previously not at all aware that a high performance eyepiece would be this easy to build, with only stock parts and without too much fine tuning. It's great to be able to confirm the performance this easy.
Beta Was this translation helpful? Give feedback.
All reactions