def getImage(self, xpixel=256, ypixel=None, nrays=50): """ Get the knife edge image :param xpixel: xsize of image (Default = 256) :type xpixel: int :param ypixel: ysize of image (Deault = None ) same as xpixel :type ypixel: int or None :param nrays: number or rays, (Default = 50) :param nrays: int :return: OpticalImage """ # Make the raypencil pencil = ray.RayPencil().addBeam(self.lens, self.source, "array", nrays, self.wavelength) pencil *= self.lens # Propagate through lens. psf = self.lens.imagePoint(self.source, self.design) # Paraxial point location if self.refopt == 1: psf = Psf().setWithRays(pencil, psf.z) # Optimal positin in plane if self.refopt == 2: psf = Psf().optimalArea(pencil, psf.z) # Make optimal PSF self.knife.setPoint(psf) # Set the position of the knife # Set position of ouput plane, being one focal length beyond psf in direction from back nodal point fl = self.lens.backFocalLength(self.design) bn = self.lens.backNodalPoint(self.design) u = Unit3d(psf - bn) # Direction xsize = 3.0 * self.lens.entranceAperture( ).maxRadius # Size of output feild output = OpticalImage(psf.propagate(fl, u), xpixel, ypixel, xsize, xsize) pencil *= self.knife # propagate through knife edge pencil *= output # Then to output (will give shadow image) return output
def main(): # Get lens from database lens = DataBaseLens() # Get angle of beam and wavelnegth angle = getFloat("Angle in degrees", 0.0, 0.0, 15.0) u = Unit3d(Angle().setDegrees(angle)) # Angle as unit vectr w = getFloat("Wavelength", Default) # Make two ray pencils, one for spot diagram and one for display (vertical only) pencil = RayPencil().addBeam(lens, u, "array", wavelength=w) vpencil = RayPencil().addBeam(lens, u, "vl", wavelength=w).addMonitor(RayPath()) bf = lens.backFocalPlane() # Propagate through lens to back focal plane pencil *= lens vpencil *= lens vpencil *= bf # Get optimal area psf and create a SpotDiagram sd = SpotDiagram(pencil) # Go round loop plotting the sopt diagram as various zplane positions while True: zp = getFloat("Zplane", bf.getPoint().z) plane = OpticalPlane(zp) plt.subplot(2, 1, 1) lens.draw() vpencil.draw() plt.axis("equal") plt.title("Lens " + lens.title) plt.subplot(2, 1, 2) sd.draw(plane, True) plt.title("Spot diagram") plt.show(block=True)
def main(): # Get the materail type and make a prism of default angle, size and location n = MaterialIndex() prism = Prism(index=n) tprint(repr(prism)) # Get input point on prism and min deviation at Mercury_i line pt = prism.getInputPoint() dev = prism.minDeviation(Mercury_e) tprint("Min deviation : ", math.degrees(dev), " at : ", Mercury_e) tprint("Max resolutions is ", prism.maxResolution(Mercury_e)) tprint("Resolution with 20 mm diameter beam : ", prism.resolution(10, Mercury_e)) u = Unit3d().parseAngle(dev / 2) # Set ray input angle at half min deviation # Form np array of wavelength and angle wavelengths = np.linspace(Mercury_i, Helium_r, 50) angle = np.zeros(wavelengths.size) # Go through each wavelength, make a ray and trace it for i, wave in enumerate(wavelengths): ray = r.IntensityRay(pt, u, wave) ray *= prism # Extract angle of ray in degrees angle[i] = math.degrees(Angle(ray.director).theta) # Do the plotting plt.plot(wavelengths, angle) plt.title("Spectrometer Output angle") plt.xlabel("Wavelength in microns") plt.ylabel("Output angle in degrees") plt.grid() plt.show()
def main(): # Get lens from database lens = DataBaseLens() # Get angle of beam and wavelnegth angle = getFloat("Angle in degrees", 0.0, 0.0, 15.0) u = Unit3d(Angle().setDegrees(angle)) # Angle as unit vectr wave = getFloat("Wavelength", getDefaultWavelength()) # Get optimal area psf and create a SpotDiagram sd = SpotAnalysis(lens, u, 0, wavelength=wave) # Go round loop plotting the sopt diagram as various zplane positions while True: zp = getFloat("Delta", 0.0) sd.draw(zp, True) pos = sd.plane.getPoint().z print("Plane pos " + str(pos)) plt.title("Spot diagram") plt.show(block=True)
def main(): eye = Eye(0.0) print("Original Focalength : " + str(eye.backFocalLength(wl.PhotopicPeak))) #eye.setIris(0.5) eye.moveRetina(1.0) #eye.setNearPoint(300) #print("Modified Focalength : " + str(eye.backFocalLength(wl.PhotopicPeak))) theta = 10 u = Unit3d().parseAngle(math.radians(theta)) pencil = RayPencil().addBeam(eye, u, "vl", 10, wl.Red) pencil.addBeam(eye, u, "vl", 10, wl.Green) pencil.addBeam(eye, u, "vl", 10, wl.Blue) pencil.addMonitor(RayPath()) pencil *= eye eye.draw() pencil.draw() plt.axis("equal") plt.grid() plt.show()
def main(): doublet = AchromaticDoublet(0.0, 120, 20.0, ct=10) # 120mm, 20mm radius t.tprint("Focal length is :", doublet.backFocalLength()) u = Unit3d().parseAngle("5") # trace at 5 degrees # Make ray pencil of three coloured rays pencil = RayPencil().addBeam(doublet, u, nrays=5, wavelength=Red) pencil.addBeam(doublet, u, nrays=5, wavelength=Green) pencil.addBeam(doublet, u, nrays=5, wavelength=Blue) pencil.addMonitor(RayPath()) # Add monitor to all rays to allow plotting ip = doublet.backFocalPlane() # Back focal plane pencil *= doublet # Propagte through lens to back focal plane pencil *= ip # Draw the diagram doublet.draw(True, True) ip.draw() pencil.draw() plt.axis("equal") plt.grid() plt.title(repr(doublet)) plt.show()
def getWavelength(prism, inAngle, outAngle, wavelengths=[0.25, 1.0]): # Get prism point and angle of input at Unit3d # pt = prism.getInputPoint() u = Unit3d(Angle(inAngle)) # Guess at initial wavelngth wave = (wavelengths[1] - wavelengths[0]) / 2 # Make input ray at guess wavelength ray = IntensityRay(pt, u, wave) # Parameters for seaerch delta = 0.1 forward = True na = float("inf") # New angle while abs(na - outAngle) > 1.0e-9 / abs(outAngle): nray = ray * prism # New Ray through prism na = nray.getAngle() na = na.theta * math.cos(na.psi) # In radians if na < outAngle: # Less that target wave += delta forward = True else: if forward: # Half step delta *= 0.5 forward = False wave -= delta if wave < wavelengths[0] or wave > wavelengths[1]: print("Out of wavelength range :") return float("nan") ray.wavelength = wave # Update wavelength of ray return ray.getWavelength() # End of loop, so success
def __init__(self,pt = 0.0 ,type = Clear, index = None): """ Conststrucor for Optical plane """ FlatSurface.__init__(self,pt,Unit3d(0,0,1),type,index)
Set of classes to implement various types of optical surface. """ from poptics.vector import Vector2d,Vector3d,Unit3d from poptics.ray import SourcePoint from poptics.matrix import ParaxialGroup import math from matplotlib.pyplot import plot """ Define the three types of surface. """ Clear = 0 #: Define a clear surface. Refracting = 1 #: Define a refracting surface. Reflecting = 2 #: Define a reflecting surface, Blocked = Unit3d() #: Define blacoked as an invalid Units3d """ Define surface plotting parameter """ SurfacePlotPoints = 10 class SurfaceInteraction(object): """ Class to hold the interaction of a vector skew ray with a general surface. It contains all the information needed to calualte the interaction and update the ray. :param type: the type of surface, Clear = 0, Refracting = 1, Reflecting = 2. :type type: int :param point: the surface reference point in global coordinate. :type point: Vector3d
def drawAberrationPlot(self,angle,wavelength = None ,colour=["r","g","b"],legend = "lower left"): """ Form and draw the plots at specified angle :param angle: the ray angle :type angle: float or Angle or Unit3d :param colour: line colours is three elemnts list, Default = ["r","g","b"]) :param legend: location of ledgend, (Default = "lower left") :type legend: str """ if isinstance(angle,float): u = Unit3d(Angle(angle)) # direction of beam else: u = Unit3d(angle) angle = Angle(u).theta wavelength = getDefaultWavelength(wavelength) ref = self.lens.imagePoint(u,self.design) # Get image point at design wavelength ip = OpticalPlane(ref) # Image plane nrays = 50 ca = self.lens.entranceAperture() # Make list for plots mvals = [] # Meridional svalsx = [] # Sagittal x svalsy = [] # Sagittal y # Start of loop to make rays rscan = np.linspace(-ca.maxRadius,ca.maxRadius,nrays + 1) for r in rscan: # Make two rays mray = IntensityRay(ca.point + Vector3d(0.0, r, 0.0), u, wavelength) sray = IntensityRay(ca.point + Vector3d(r, 0.0, 0.0), u, wavelength) # Add to pencil and propagate both back to clear lens pencil = RayPencil(mray,sray).propagate(-ca.maxRadius) # propagate through lens to image surafce pencil *= self.lens pencil *= ip # If rays valid (so not blocked), abberations to list if mray: mpos = mray.position - ref mvals.append(mpos.y) else: mvals.append(float("nan")) if sray: spos = sray.position - ref svalsx.append(spos.x) svalsy.append(spos.y) else: svalsx.append(float("nan")) svalsy.append(float("nan")) # plots with suitable labels to the current axis. plt.plot(rscan,mvals, color = colour[0], label="Meridional") plt.plot(rscan,svalsx,color = colour[1], label="Sagittal x") plt.plot(rscan,svalsy,color = colour[2], label="Sagittal y") plt.title("{0:s}: a: {1:4.2f} w: {2:4.2f} d: {3:4.2f}".\ format(self.lens.title,math.degrees(angle),wavelength,\ self.design)) plt.legend(loc=legend,fontsize="small") plt.grid()
def valueChange(self): # For either spinned self.theta = self.thetaSpin.value() self.psi = self.psiSpin.value() u = Unit3d().setPolarDegrees(self.theta, self.psi) setCurrentAngle(u) self.unitLabel.setText(str(getCurrentAngle()))
def addBeam(self, ca, source, key="vl", nrays=10, wavelength=None, intensity=1.0, index=AirIndex(), path=False): """ Method to add a beam if intensity rays being either Collimated or Source Beam. The beam will fill the given circular aperture and will either come from a single SourcePoint or at a specified angle. :param ca: circular aperture to filled (any object with maxRadius attribute) :type ca: optics.surface.CircularAperture :param source: source or rays, either a SourcePoint or angle. :type source: SourcePoint or Vectore3d or Unit3d or Angle or float :param key: method of fill, allowed keys as "vl", "hl" and "array",(default is "vl") :type key: str :param nrays: number or rays across radius, (default = 10) :type nrays: int :param wavelenth: the wavelength, (default = Default) :type wavelength: float :param intensity: the ray intensity, (default = 1.0) only used for Collimated beam; for SourceBeam picked up from SourcePoint :type intensity: float :param index: the refratcive index, (Default = AirIndex()) :type index: RefractiveIndex :param path: record pathlength, (default = False) is pathlength of each ray recorded :type path: bool :return: self """ # Sort out aperture to fill. if not hasattr(ca, "maxRadius"): ca = ca.entranceAperture() pt = ca.getPoint() # Reference point radius = ca.maxRadius if isinstance(source, SourcePoint): # Rays from a source s = Vector3d(source) intensity = source.getIntensity(wavelength) else: s = Vector3d().setInvalid( ) # Set s unvalid (will be used for testing) u = Unit3d().parseAngle(source) rscan = linspace(-radius, radius, 2 * nrays + 1) # Point across radius (make sure one in centre) if key.startswith("ar"): xscan = rscan yscan = rscan elif key.startswith("vl"): xscan = [0.0] yscan = rscan elif key.startswith("hl"): xscan = rscan yscan = [0.0] else: print("Error") # Scan through making the rays for y in yscan: for x in xscan: if x * x + y * y <= radius * radius: # Ignore if outside radius of aperture p = Vector3d( pt.x + x, pt.y + y, pt.z) # Point in aperture in global coordinates if s: # From source u = Unit3d(p - s) ray = IntensityRay(s, u, wavelength, intensity, index) # Make source ray else: # Collimated beam dist = float(radius + x * u.x + y * u.y) p -= dist * u # Propagate point to make it look nicer ray = IntensityRay(p, u, wavelength, intensity, index) # Make collimated if path: ray.pathlength = 0.0 self.append(ray) # Append to self return self
""" Set of classes to hold rays for optical ray tracing. This includes Paraxial and Intensity rays. """ import math from poptics.vector import Vector3d, Vector2d, Unit3d, Angle from poptics.wavelength import Spectrum, AirIndex, WavelengthColour, getDefaultWavelength from poptics.matrix import ParaxialMatrix, ParaxialGroup, ParaxialPlane from matplotlib.pyplot import plot from numpy import linspace Clear = 0 #: Defeine a clear surface. Refracting = 1 #: Define a refracting surface. Reflecting = 2 #: Define a reflecting surface, # Global Current Angle (mainly used by GUI) CurrentAngle = Unit3d(0.0, 0.0, 1.0) def getCurrentAngle(): """ Get the current angle used in the package, typically called from GUI interface. The Default is (0,0,1) so along the optical axis. :return: The current angle global value """ return CurrentAngle def setCurrentAngle(u): """ Method to set a current angle, typivcally used by the GUI intreface