def value(self, x, y, z): """ Value of complex amplitude at coordinates (x,y,z). (x,y,z) is a cartesian coordinate frame centered at the waist. z lies along the propagation axis. ========Input========= x : Radial horizontal distance from z axis y : Radial vertical distance from z axis z : Axial distance from waist ========Output======== u : Complex amplitude of beam at coordinates (x,y,z) """ q = self.q(z) W = self.width(z) env = 1j * self.zO * self.A * tl.exp(-0.5j * self.k * (x**2 + y**2) / q) / q env *= tl.eval_hermite(self.l, tl.sqrt(2) * x / W) * tl.eval_hermite( self.m, tl.sqrt(2) * y / W) * tl.exp( 1j * (self.l + self.m) * self.gouy_phase(z)) u = env * tl.exp(-1j * self.k * z) return u
def SigmoidNormal(f, new_min=0., new_max=1.): """ ~ Normalizes f to interval [new_min,new_max] using a sigmoid function ~ If the input array is complex, only affects its norm ========Input========= f : Input array new_min : Minimum value in normalization interval (default 0) new_max : Maximum value in normalization interval (default 1) ========Output======== g : Normalized input array """ if tl.iscomplex(f).any(): g = 1 / (1 + tl.exp(-(abs(f) - tl.mean(abs(f))) / (tl.maxx(abs(f)) - tl.minn(abs(f))))) * ( new_max - new_min) + new_min g *= tl.exp(1j * tl.angle(f)) else: g = 1 / (1 + tl.exp(-(f - tl.mean(f)) / (tl.maxx(f) - tl.minn(f)))) * (new_max - new_min) + new_min return g
def value(self, r, p, z): """ Value of complex amplitude at coordinates (r,p,z). (r,p,z) is a cylindrical coordinate frame centered at the waist. z lies along the propagation axis. ========Input========= r : Radial distance from z axis p : Azimuth angle z : Axial distance from waist ========Output======== u : Complex amplitude of beam at coordinates (r,p,z) """ q = self.q(z) W = self.width(z) env = 1j * self.zO * self.A * tl.exp(-0.5j * self.k * r**2 / q) / q env *= (r / W)**self.l * tl.eval_genlaguerre( self.m, self.l, 2 * (r / W)**2) * tl.exp(1j * (self.l + 2 * self.m) * self.gouy_phase(z) - 1j * self.l * p) u = env * tl.exp(-1j * self.k * z) return u
def Fresnel2S(f, z, wl, L1, L2): """ ~ Propagates input 2D array in free space using the two-step Fresnel propagator Voelz D. Computational Fourier Optics: A MATLAB Tutorial. 2011. ========Input========= f : Input complex amplitude profile (2D complex array) z : Propagation distance wl : Central wavelenght of the field L1 : Input sample plane side lenght L2 : Output sample plane side lenght ========Output======== h : Propagated complex amplitude profile (2D complex array) """ if (tl.ndim(f) != 2): raise TypeError("Input array must be a 2D square array") m, n = tl.shape(f) if (m != n): raise ValueError("Input array must be a 2D square array") k = 2 * tl.pi / wl # Source plane dx1 = L1 / m x1 = tl.arange(-L1 / 2., L1 / 2., dx1) X, Y = tl.meshgrid(x1, x1) F = f * tl.exp(1j * k / (2. * z * L1) * (L1 - L2) * (X**2 + Y**2)) F = tl.fft.fft2(tl.fft.fftshift(F)) # Dummy plane fx1 = tl.arange(-1. / (2 * dx1), 1. / (2 * dx1), 1. / L1) fx1 = tl.fft.fftshift(fx1) FX1, FY1 = tl.meshgrid(fx1, fx1) G = F * tl.exp(-1j * tl.pi * wl * z * L1 / L2 * (FX1**2 + FY1**2)) g = tl.fft.ifftshift(tl.fft.ifft2(G)) # Observation plane dx2 = L2 / m x2 = tl.arange(-L2 / 2., L2 / 2., dx2) X, Y = tl.meshgrid(x2, x2) g = (L2 / L1) * g * tl.exp(-1j * k / (2. * z * L2) * (L1 - L2) * (X**2 + Y**2)) g = g * (dx1 / dx2)**2 return g
def Fraunhofer(f, z, wl, dx=1.): """ ~ Propagates input 2D array in free space using the Fraunhofer propagator Voelz D. Computational Fourier Optics: A MATLAB Tutorial. 2011. ========Input========= f : Input complex amplitude profile (2D complex array) z : Propagation distance wl : Central wavelenght of the field dx : Sampling interval (default value is unit of measurement) ========Output======== g : Propagated complex amplitude profile (2D complex array) oL : Observation plane side lenght """ n, m = tl.shape(f) oL = wl * z / dx # Observation plane side lenght odx = oL / m ody = oL / n # Observation plane sample interval x = tl.arange(-oL / 2, oL / 2, odx) y = tl.arange(-oL / 2, oL / 2, ody) X, Y = tl.meshgrid(x, y) g = -1j / (wl * z) * tl.exp(1j * tl.pi / (wl * z) * (X**2 + Y**2)) g = g * FFT2(f) * dx * dx return g, oL
def FresnelIR(f, z, wl, dx): """ ~ Propagates f in free space sampling the Impulse Response Voelz D. Computational Fourier Optics: A MATLAB Tutorial. 2011. ========Input========= f : Input complex amplitude profile (2D complex array) z : Propagation distance wl : Central wavelenght of the field dx : Sampling interval (default value is unit of measurement) ========Output======== h : Propagated complex amplitude profile (2D complex array) """ n, m = tl.shape(f) Lx = dx * n Ly = dx * m F = FFT2(f) x = tl.arange(-Lx / 2, Lx / 2, dx) y = tl.arange(-Ly / 2, Ly / 2, dx) X, Y = tl.meshgrid(x, y) g = tl.exp(1j * tl.pi / (wl * z) * (X**2 + Y**2)) / (1j * wl * z) G = FFT2(g) * dx * dx h = IFFT2(F * G) return h
def Lens(F, R, wl, shape, dx=1.): """ ~ Samples the trasmittance function of a thin lens with focal lenght f for a wave with central wavelenght wl with sampling interval dx ========Input========= F : Focal lenght of thin lens R : Radius of the lens wl : Central wavelenght shape : Array shape dx : Sampling interval (default value is unit of measurement) ========Raises========= TypeError : If f isn't a 2D array ========Output======== t : Thin lens complex transmittance """ if (len(shape) != 2): raise TypeError('Shape must be 2D') n, m = shape x = tl.arange(-m * dx / 2, m * dx / 2, dx) y = tl.arange(-n * dx / 2, n * dx / 2, dx) X, Y = tl.meshgrid(x, y) t = tl.exp(-1j * (tl.pi / (wl * F)) * (X**2 + Y**2)) t *= Pupil(R, shape, dx) return t
def FresnelTF(f, z, wl, dx): """ ~ Propagates f in free space sampling the Transfer Function Voelz D. Computational Fourier Optics: A MATLAB Tutorial. 2011. ========Input========= f : Input complex amplitude profile (2D complex array) z : Propagation distance wl : Central wavelenght of the field dx : Sampling interval (default value is unit of measurement) SBC : Use the source bandwidth criterion for large propagation regime ========Output======== h : Propagated complex amplitude profile (2D complex array) """ n, m = tl.shape(f) Lx = dx * n Ly = dx * m F = FFT2(f) fx = tl.arange(-1 / (2 * dx), 1 / (2 * dx), 1 / Lx) fy = tl.arange(-1 / (2 * dx), 1 / (2 * dx), 1 / Ly) FX, FY = tl.meshgrid(fx, fy) G = tl.exp((-1j * wl * tl.pi * z) * (FX**2 + FY**2)) h = IFFT2(F * G) return h
def Tilt(alpha, theta, wl, shape, dx=1.): """ ~ Simulates the trasmittance function of a tilt (a prism for instance) ========Input========= alpha : Tilt polar angle theta : Tilt azimuth angle wl : Central wavelenght shape : Array shape dx : Sampling interval (default value is unit of measurement) ========Raises========= TypeError: If f isn't a 2D array ========Output======== t : Pinhole transmittance """ if (len(shape) != 2): raise TypeError('f must be a 2D array') n, m = shape x = tl.arange(-m * dx / 2, m * dx / 2, dx) y = tl.arange(-n * dx / 2, n * dx / 2, dx) X, Y = tl.meshgrid(x, y) t = tl.exp(2j * tl.pi / wl * (X * tl.cos(theta) + Y * tl.sin(theta)) * tl.tan(alpha)) return t
def LinearNormal(f, new_min=0., new_max=1.): """ ~ Linearly normalizes f to interval [new_min,new_max] ~ If the input array is complex, only affects its norm ========Input========= f : Input array new_min : Minimum value in normalization interval (default 0) new_max : Maximum value in normalization interval (default 1) ========Output======== g : Normalized input array """ if tl.iscomplex(f).any(): fnorm = tl.abss(f) if ((fnorm == tl.mean(fnorm)).all()): g = 1. else: g = (fnorm - tl.minn(fnorm)) / (tl.maxx(fnorm) - tl.minn(fnorm) ) * (new_max - new_min) + new_min g *= tl.exp(1j * tl.angle(f)) else: if ((f == tl.mean(f)).all()): g = tl.ones(tl.shape(f)) else: g = (f - tl.minn(f)) / (tl.maxx(f) - tl.minn(f)) * (new_max - new_min) + new_min return g
def FresnelCS(f, z, wl, dx=1., SBC=False): """ ~ Propagates input 2D array in free space using the critical sampling criterion ~ Samples either the Impulse Response or the Transfer Function given the critic sampling criterion Voelz D. Computational Fourier Optics: A MATLAB Tutorial. 2011. ========Input========= f : Input complex amplitude profile (2D complex array) z : Propagation distance wl : Central wavelenght of the field dx : Sampling interval (default value is unit of measurement) SBC : Use the source bandwidth criterion for large propagation regime ========Output======== h : Propagated complex amplitude profile (2D complex array) """ n, m = tl.shape(f) # Array dimensions Lx = dx * m Ly = dx * n # Source plane side lenghts zc = dx * Lx / wl # Critic sampling propagation distance F = FFT2(f) if (SBC): # Check the source bandwidth criterion B = GetRBW(f, dx) SBC = B <= min([Lx, Ly]) / (wl * z) if (abs(z) > zc and not SBC): # Propagating using Impulse Response x = tl.arange(-Lx / 2., Lx / 2., dx) y = tl.arange(-Ly / 2., Ly / 2., dx) X, Y = tl.meshgrid(x, y) g = tl.exp(1j * tl.pi / (wl * z) * (X**2 + Y**2)) / (1j * wl * z) G = FFT2(g) * dx * dx if (abs(z) <= zc): # Propagating using Transfer Function F = 0.5 / dx # Nyquist frequency fx = tl.arange(-F, F, 1. / Lx) fy = tl.arange(-F, F, 1. / Ly) FX, FY = tl.meshgrid(fx, fy) G = tl.exp((-1j * wl * tl.pi * z) * (FX**2 + FY**2)) h = IFFT2(F * G) return h
def value(self, r, z): """ Value of complex amplitude at coordinates (r,z). (r,z) is a cylindrical coordinate frame centered at the waist. z lies along the propagation axis. ========Input========= r : Radial distance from z axis z : Axial distance from waist ========Output======== u : Complex amplitude of beam at coordinates (r,z) """ q = self.q(z) env = 1j * self.zO * self.A * tl.exp(-0.5j * self.k * r**2 / q) / q u = env * tl.exp(-1j * self.k * z) return u
def value(self, r, p, z): """ Value of complex amplitude at coordinates (r,p,z). (r,p,z) is a cylindrical coordinate frame centered at the waist. z lies along the propagation axis. ========Input========= r : Radial distance from z axis p : Azimuth angle z : Axial distance from waist ========Output======== u : Complex amplitude of beam at coordinates (r,z) """ env = self.A * tl.jv(self.m, self.kT * r) * tl.exp(1j * self.m * p) u = env * tl.exp(-1j * self.b * z) return u
def value(self, r, z): """ Value of complex amplitude at coordinates (r,z). (r,z) is a cylindrical coordinate frame centered at the waist. z lies along the propagation axis. ========Input========= r : Radial distance from z axis z : Axial distance from waist ========Output======== u : Complex amplitude of beam at coordinates (r,z) """ q = self.q(z) env = 1j * self.zO * self.A * tl.exp( -0.5j * self.k * (r**2 + (self.b * z / self.k)**2) / q) / q env *= tl.jv(0, self.b * r / (1. + 1j * z / self.zO)) u = env * tl.exp(-1j * (self.k - self.b**2 / (2. * self.k)) * z) return u
def value(self, r): """ Value of complex amplitude at a distance r from wave source. ========Input========= r : Radial coordinate centered at wave source ========Output======== u : Complex amplitude of beam at coordinate r """ u = tl.zeros_like(r, dtype='complex') u[r == 0.] = tl.inf u[r != 0.] = self.A * tl.exp(-1j * self.k * r[r != 0.]) / r[r != 0.] return u
def value(self, x, y, z): """ Value of complex amplitude at coordinates (x,y,z). (x,y,z) is a cartesian coordinate frame. The wavevector defines the propagation axis. ========Input========= x : Horizontal cartesian coordinate y : Vertical cartesian coordinate z : Default axis cartesian coordinate ========Output======== u : Complex amplitude of beam at coordinates (x,y,z) """ u = self.A * tl.exp(-1j * (self.kx * x + self.ky * y + self.kz * z)) return u
def Gauss(sx, sy, shape, x=0., y=0., angle=0., use_pxc=False): """ ~ Creates a sampled 2D Gaussian distribution signal ~ (x,y) coordinates are given in a centered cartesian frame ========Input========= sx : Gaussian RMS width sy : Gaussian RMS height shape: Output array shape x : Horizontal center of ellipse (Default for horizontally centered) y : Vertical center of ellipse (Default for vertically centered) angle : Angle defining the width direction (Default for horizontal direction) use_pxc : Use pixel as unit of measurement (Default for shape as unit of measurement) ========Output======== f : 2D float array """ x += 0.5 y += 0.5 if (use_pxc == False): sx *= shape[1] sy *= shape[0] x *= shape[1] y *= shape[0] X = range(shape[1]) Y = range(shape[0]) X, Y = tl.meshgrid(X, Y) f = tl.exp(-0.5 * (((X - x) * tl.cos(angle) - (Y - y) * tl.sin(angle)) / sx)**2 - 0.5 * (((Y - y) * tl.cos(angle) + (X - x) * tl.sin(angle)) / sy)**2) return f