Source code for diffractio.scalar_masks_X

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This module generates Scalar_mask_X class for definingn masks. Its parent is Scalar_field_X.

The main atributes are:
    * self.u - field
    * self.x - x positions of the field
    * self.wavelength - wavelength of the incident field. The field is monocromatic

*Class for unidimensional scalar masks*

*Functions*
    * mask_from_function, mask_from_array
    * slit, double slit
    * two_levels, gray_scale
    * prism, biprism_fresnel, biprism_fresnel_nh
    * lens, lens_spherical, aspheric, fresnel_lens
    * roughness, dust, dust_different_sizes
    * sine_grating, ronchi_grating, binary_grating, blazed_grating
    * chriped_grating, chirped_grating_p, chirped_grating_q
    * I0s
"""

from scipy.interpolate import interp1d

from . import degrees, np, plt, um
from .scalar_fields_X import Scalar_field_X
from .utils_math import cut_function, fft_convolution1d, nearest, nearest2
from .utils_optics import roughness_1D


[docs] class Scalar_mask_X(Scalar_field_X): """Class for unidimensional scalar masks. Parameters: x (numpy.array): linear array with equidistant positions. The number of data is preferibly :math:`2^n` . wavelength (float): wavelength of the incident field n_background (float): refraction index of background info (str): String with info about the simulation Attributes: self.x (numpy.array): linear array with equidistant positions. The number of data is preferibly :math:`2^n` . self.wavelength (float): wavelength of the incident field. self.u (numpy.array): equal size than x. complex field self.quality (float): quality of RS algorithm self.info (str): description of data self.type (str): Class of the field self.date (str): date when performed """ def __init__(self, x=None, wavelength=None, n_background=1, info=""): """equal than Scalar_field_X""" super().__init__(x, wavelength, n_background, info) self.type = 'Scalar_mask_X'
[docs] def filter(self, mask, new_field=True, binarize=False, normalize=False): """Widens a field using a mask. Parameters: mask (diffractio.Scalar_mask_X): filter new_field (bool): If True, develope new Field binarize (bool, float): If False nothing, else binarize in level normalize (bool): If True divides the mask by sum: """ f1 = np.abs(mask.u) if normalize is True: f1 = f1 / f1.sum() covolved_image = fft_convolution1d(f1, np.abs(self.u)) if binarize is not False: covolved_image[covolved_image > binarize] = 1 covolved_image[covolved_image <= binarize] = 0 if new_field is True: new = Scalar_field_X(self.x, self.wavelength) new.u = covolved_image return new else: self.u = covolved_image
[docs] def mask_from_function(self, index=1.5, f1=0, f2=0, v_globals={}, x0=0 * um, radius=0 * um): """Phase mask defined between two surfaces :math:`f_1` and :math:`f_2`: :math:`h(x,y)=f_2(x,y)-f_1(x,y)`, :math:`t(x)=mask(x)e^{i\,k\,(n-1)(f_{2}-f_{1})}` Parameters: index (float): refraction index of the mask f1 (str): first surface f2 (str): second surface v_globals (dict): variable definitions mask (bool): True if a mask is defined to block areas x0 (float): center of mask radius (float): radius of the mask """ k = 2 * np.pi / self.wavelength if radius > 0: amplitude = Scalar_mask_X(self.x, self.wavelength) amplitude.slit(x0, radius) t = amplitude.u else: t = 1 v_locals = {'self': self, 'np': np, 'degrees': degrees} F2 = eval(f2, v_globals, v_locals) F1 = eval(f1, v_globals, v_locals) self.u = t * np.exp(1.j * k * (index - 1) * (F2 - F1)) self.u[t == 0] = 0
[docs] def mask_from_array(self, index=1.5, array1=None, array2=None, interp_kind='quadratic', radius=0 * um, x0=0 * um): """Phase mask defined between two surfaces defined by arrays: array1 and array2, :math:`t(x)=mask(x)e^{i\,k\,(n-1)(array2(x,z)-array1(x,z))}` Parameters: index (float): refraction index of the mask array1 (numpy.array): array of data (x,z) for the first surface array2 (numpy.array): array of data (x,z) for the second surface interp_kind (str): 'linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic' mask (bool): True if a mask is defined to block areas x0 (float): center of mask radius (float): radius of the mask """ k = 2 * np.pi / self.wavelength if radius > 0: amplitude = Scalar_mask_X(self.x, self.wavelength) amplitude.slit(x0, radius) t = amplitude.u else: t = 1 f1_interp = interp1d(array1[:, 0], array1[:, 1], kind=interp_kind, bounds_error=False, fill_value=0) f2_interp = interp1d(array2[:, 0], array2[:, 1], kind=interp_kind, bounds_error=False, fill_value=0) # interpolates all the range F1 = f1_interp(self.x) F2 = f2_interp(self.x) self.u = t * np.exp(1.j * k * (index - 1) * (F2 - F1)) self.u[t == 0] = 0
[docs] def dots(self, x0): """Generates 1 or several point masks at positions x0 Parameters: x0 float or np.array: x point or points where mask is 1. """ u = np.zeros_like(self.x) if type(x0) in (int, float): i_x0, _, _ = nearest(self.x, x0) u[i_x0] = 1 else: i_x0s, _, _ = nearest2(self.x, x0) for i_x0 in i_x0s: u[i_x0] = 1 self.u = u
[docs] def slit(self, x0, size): """Slit: 1 inside, 0 outside Parameters: x0 (float): center of slit size (float): size of slit """ xmin = x0 - size / 2 xmax = x0 + size / 2 u = np.zeros_like(self.x) ix = (self.x < xmax) & (self.x > xmin) u[ix] = 1 self.u = u return u
[docs] def double_slit(self, x0, size, separation): """double slit: 1 inside, 0 outside Parameters: x0 (float): center of slit size (float): size of slit separation (float): separation between slit centers """ slit1 = Scalar_mask_X(self.x, self.wavelength) slit2 = Scalar_mask_X(self.x, self.wavelength) # Definicion de las dos slits slit1.slit(x0=x0 - separation / 2, size=size) slit2.slit(x0=x0 + separation / 2, size=size) self.u = slit1.u + slit2.u return self.u
[docs] def two_levels(self, level1=0, level2=1, x_edge=0): """Divides the image in two levels. Parameters: level1 (float): value of level1 level2 (float): value of level2 x_edge (float): position of separation of levels """ # Definicion de un primer level de unos self.u = level1 * np.ones(self.x.shape) # Aquellos points cuyo mayor sea mayor que el value de bin_level, adquieren # el value del level2 self.u[self.x > x_edge] = level2
[docs] def gray_scale(self, num_levels, levelMin=0, levelMax=1): """Divides the mask in n, vertical levels. Parameters: num_levels (int): number of levels levelMin (float): minimum value of levels levelMax (float): maximum value of levels """ t = np.zeros(self.x.shape, dtype=float) xpos = np.linspace(self.x[0], self.x[-1], num_levels + 1) height_levels = np.linspace(levelMin, levelMax, num_levels) ipos, _, _ = nearest2(self.x, xpos) ipos[-1] = len(self.x) for i, h_level in enumerate(height_levels): t[ipos[i]:ipos[i + 1]] = h_level self.u = t
[docs] def prism(self, x0, n, angle): """Prism. Parameters: x0 (float): vertex of prism n (float): refractive_index angle (float): angle of prism """ k = 2 * np.pi / self.wavelength h = (self.x - x0) * np.tan(angle) self.u = np.exp(1j * k * (n - 1) * h) h = h - h.min() return h
[docs] def biprism_fresnel(self, angle, x0, radius=0): """Fresnel biprism. Parameters: angle (float): angle of the fresnel biprism x0 (float): central position of fresnel biprism radius (float): radius of the fresnel biprism, if mask is True mask (bool): if True radius is applied """ k = 2 * np.pi / self.wavelength # distance from generatriz to cone axis xp = self.x > x0 xn = self.x <= x0 # heigth h = np.zeros_like(self.x) h[xp] = -np.sin(angle) * (self.x[xp] - x0) h[xn] = np.sin(angle) * (self.x[xn] - x0) u = np.exp(1.j * (k * h + np.pi)) t = np.ones_like(self.x) if radius == 0: t = 1 else: ipasa = np.abs(self.x - x0) > radius t[ipasa] = 0. remove_phase_out = np.angle(u) remove_phase_out[ipasa] = 0 u = np.abs(u) * np.exp(1j * remove_phase_out) self.u = u * t
[docs] def biprism_fresnel_nh(self, x0, width, height, n): """Fresnel biprism, uses height and refraction index. Parameters: x0 (float): vertex of biprism width (float): size of biprism height (float): height of biprism n (float): refractive_index """ k = 2 * np.pi / self.wavelength xp = self.x > 0 xn = self.x <= 0 # heigth h = np.zeros_like(self.x) h[xp] = -2 * height / width * (self.x[xp] - x0) + 2 * height h[xn] = 2 * height / width * (self.x[xn] - x0) + 2 * height # No existencia de heights negativas iremove = h < 0 h[iremove] = 0 # Region de transmitancia u = np.zeros_like(self.x) ipasa = np.abs(self.x - x0) < width u[ipasa] = 1 self.u = u * np.exp(1.j * k * (n - 1) * h) return h
[docs] def lens(self, x0, focal, radius=0): """Paraxial lens. Parameters: x0 (float): center of lens focal (float): focal length of lens """ k = 2 * np.pi / self.wavelength # Definicion de la amplitude y la phase if radius == 0: t = 1 else: t = np.zeros_like(self.x) ix = (self.x < x0 + radius) & (self.x > x0 - radius) t[ix] = 1 h = (self.x - x0)**2 / (2 * focal) self.u = t * np.exp(-1.j * ( k * h+np.pi)) h = h - h.min() h = h / h.max() return h
[docs] def lens_spherical(self, x0, radius, focal, refractive_index=1.5): """Spherical lens, without paraxial approximation. The focal distance and the refraction index are used for the definition. When the refraction index decreases, the radius of curvature decrases and less paraxial. Parameters: r0 (float, float): (x0,y0) - center of lens radius (float, float) or (float): radius of lens mask focal (float, float) or (float): focal length of lens refraction index (float): refraction index of the lens """ k = 2 * np.pi / self.wavelength R = (refractive_index - self.n_background) * focal if radius == 0: t = 1 else: t = np.zeros_like(self.x, dtype=int) ix = (self.x < x0 + radius) & (self.x > x0 - radius) t[ix] = 1 h = (np.sqrt(R**2 - self.x**2) - R) h[(R**2 - self.x**2) < 0] = 0 self.u = t * np.exp(1j * k * (refractive_index - 1) * h) self.u[t == 0] = 0 return h
[docs] def aspheric(self, x0, c, k, a, n0, n1, radius): """Asferic surface. $z = \frac{c r^2}{1+\sqrt{1-(1+k) c^2 r^2 }}+\sum{a_i r^{2i}}$ Parameters: x0 (float): position of center c (float): base curvature at vertex, inverse of radius k (float): conic constant a (list): order aspheric coefficients: A4, A6, A8, ... n0 (float): refraction index of first medium n1 (float): refraction index of second medium radius (float): radius of aspheric surface Conic Constant Surface Type k = 0 spherical k = -1 Paraboloid k < -1 Hyperboloid -1 < k < 0 Ellipsoid k > 0 Oblate eliposid References: https://www.edmundoptics.com/knowledge-center/application-notes/optics/all-about-aspheric-lenses/ """ s2 = (self.x - x0)**2 t1 = c * s2 / (1 + np.sqrt(1 - (1 + k) * c**2 * s2)) t2 = 0 if a is not None: for i, ai in enumerate(a): t2 = t2 + ai * s2**(2 + i) t = t1 + t2 if radius > 0: m1 = np.zeros_like(self.x, dtype=int) ix = (self.x < x0 + radius) & (self.x > x0 - radius) m1[ix] = 1 else: m1 = 1 self.u = m1 * np.exp(1j * 2 * np.pi * (n1 - n0) * t / self.wavelength) self.u[m1 == 0] = 0 return t
[docs] def fresnel_lens(self, x0, focal, kind='phase', binary=False, phase=np.pi, radius=0 * um): """Fresnel lens. Amplitude phase, continuous or binary. Parameters: x0 (float): center of lens focal (float): focal length of lens kind (str): 'amplitude' or phase binary (bool): binary or profile phase (float): if kind=='phase' -> maximum phase mask (bool): if True, mask with size radius radius (float): radius of lens mask Returns: h (np.array): heights [0,1] of lens. """ # Vector de onda k = 2 * np.pi / self.wavelength # Definicion de la amplitude y la phase if radius > 0: t1 = np.zeros_like(self.x) ix = (self.x < x0 + radius) & (self.x > x0 - radius) t1[ix] = 1 else: t1 = 1 h =k*(self.x - x0)**2 / (2 * focal) h = -h%(2*np.pi) if kind == 'amplitude': u_fresnel = np.cos(h) if binary is True: u_fresnel[u_fresnel > 0] = 1 u_fresnel[u_fresnel <= 0] = 0 h = u_fresnel else: u_fresnel = h/(2*np.pi) elif kind == 'phase': u_fresnel = np.exp(1j*(h+np.pi)) if binary is True: print(h.max(), h.min()) u_fresnel[h > np.pi] = np.exp(1j*phase) u_fresnel[h <= np.pi] = 1 h=np.angle(u_fresnel)*phase/np.pi h = h - h.min() self.u = u_fresnel * t1 h = t1 * h return h
[docs] def roughness(self, t=50 * um, s=1 * um): """Rough surface, phase According to movile average (Ogilvy p.224). very good in time for long arrays Parameters: t (float): correlation lens s (float): std of roughness Returns: numpy.array: topography maps in microns """ h_corr = roughness_1D(self.x, t, s) k = 2 * np.pi / self.wavelength u = np.exp(-1.j * k * 2 * h_corr) u = u[0:len(self.x)] h_corr = h_corr[0:len(self.x)] self.u = u return h_corr
[docs] def dust_different_sizes(self, percentage, size, std=0): """Mask with dust particles of different sizes. Parameters: percentage (float): percentage of area afected by noise size (float): mean size of dust std (float): std for size of dust Returns: numpy.array: positions - positions of dust numpy.array: sizes - size of dust float: percentage_real - real percentage of dust """ total_length = self.x[-1] - self.x[0] num_particles = int(percentage * total_length / size) if percentage > 0.5: num_particles = int(num_particles * (1 + np.sqrt(percentage))) sizes = size + std * np.random.randn(num_particles) sizes[sizes < 0] = size positions = self.x[0] + total_length * np.random.rand(num_particles) dust = Scalar_mask_X(self.x, self.wavelength, 'dust') dust.u = np.ones_like(self.x) tmp = Scalar_mask_X(self.x, self.wavelength, 'dust') for i in range(num_particles): tmp.slit(x0=positions[i], size=sizes[i]) dust.u = dust.u * (1 - tmp.u) # dust.u[dust.u > value] = value # dust.u = 1 - dust.u # dust.u[dust.u < 1] = value self.u = dust.u # can be used to increase dust_particles, when there is overlapping percentage_real = 1 - self.u.sum() / len(self.x) return positions, sizes, percentage_real
[docs] def dust(self, percentage, size=0): """ Mask with dust particles of equal sizes. Parameters: percentage (float): percentage of area afected by noise size (float): size of dust value (float): value included when there is noise Returns: numpy.array: positions - positions of dust numpy.array: sizes - size of dust float: percentage_real - real percentage of dust """ total_length = self.x[-1] - self.x[0] dx = self.x[1] - self.x[0] i_center = int(len(self.x) / 2) num_particles = int(percentage * total_length / size) if percentage > 0.5: num_particles = int(num_particles * (1 + np.sqrt(percentage))) # habria que quitar algo por los solapamientos positions = self.x[0] + total_length * np.random.rand(num_particles) dust = np.zeros_like(self.x) i_positions, _, _ = nearest2(self.x, positions) dust[i_positions] = 1 filtro = np.zeros_like(self.x) num_pixels_2 = int(size / (2 * dx)) filtro[i_center - num_pixels_2:i_center + num_pixels_2] = 1 dust = fft_convolution1d(dust, filtro) dust[dust > 1] = 1 self.u = 1 - dust percentage_real = self.u.sum() / len(self.x) return positions, percentage_real
[docs] def sine_grating(self, x0, period, amp_min=0, amp_max=1): """Sinusoidal grating Parameters: x0 (float): shift of grating period (float): period of the grating amp_min (float): minimum amplitude amp_max (float): maximum amplitude """ # Definicion de la sinusoidal self.u = amp_min + (amp_max - amp_min) * (1 + np.cos(2 * np.pi * (self.x - x0) / period)) / 2 return self.u
[docs] def ronchi_grating(self, x0, period, fill_factor=0.5): """Amplitude binary grating, fill-factor can be defined. It is obtained as a sine_grating that after is binarized. Fill factor is determined as y0=cos(pi*fill_factor) Parameters: x0 (float): shift of the grating period (float): period of the grating fill_factor (float): (0,1) - fill factor of grating """ t = Scalar_mask_X(self.x, self.wavelength) y0 = np.cos(np.pi * fill_factor) t.sine_grating(period=period, amp_min=-1, amp_max=1, x0=x0) t.u[t.u > y0] = 1 t.u[t.u <= y0] = 0 self.u = t.u return t.u
[docs] def binary_grating(self, x0, period, fill_factor, amin, amax, phase): """binary grating amplitude and/or phase Parameters: x0 (float): shift of the grating period (float): period of the grating fill_factor (float): (0,1) - fill factor of grating amin (float): minimum amplitude amax (float): maximum amplitude phase (float): phase shift (radians) """ t = Scalar_mask_X(self.x, self.wavelength) t.ronchi_grating(period=period, x0=x0, fill_factor=fill_factor) self.u = amin + (amax - amin) * t.u self.u = self.u * np.exp(1j * phase * t.u) return t.u
[docs] def blazed_grating(self, x0, period, phase_max): """Phase, blazed grating. The phase shift is determined by heigth and refraction index. Parameters: x0 (float): shift of the grating period (float): period of the grating phase_max (float): maximum_phase_differences returns: phase (np.array): phase for each position """ k = 2 * np.pi / self.wavelength # Slope computation num_periods = (self.x[-1] - self.x[0]) / period # Height computation phase = (self.x - x0) * phase_max * num_periods / (self.x[-1] - self.x[0]) # normalization between 0 and 2pi phase = np.remainder(phase, phase_max) self.u = np.exp(1j * phase) return phase
[docs] def chirped_grating_p(self, kind, p0, p1, amp_min, amp_max, phase_max, delta_x=0, x0=None, length=0, x_center=0): """Chirped grating with linear p(x) variation. Parameters: kind (str): 'amplitude', 'phase', 'amplitude_binary', 'phase_binary' p0 (float): initial period of the grating p1 (float): final period of the grating amp_min (float): minimum transmittance amp_max (float): maximum transmittance phase_max (float): maximum modulation for phase gratings delta_x (float): x shifting for movement of grating x0 (float): - length (float): length of the grating. 0: length is equal to size of x l=(x[-1]-x[0]), <l: it can be shorter than l x_center (float): x-position of center of grating Returns: numpy.array: px """ mask = Scalar_mask_X(self.x, self.wavelength) if length == 0 or length == self.x[-1] - self.x[0]: size = self.x[-1] - self.x[0] mask.u = np.ones_like(self.x) x0 = self.x[0] - delta_x elif length < self.x[-1] - self.x[0]: """ es sencillo. se hace una red del tamaño l nueva (como si fuera 0) y luego se añade a la que hay """ size = length x0 = self.x[0] - delta_x x1 = np.linspace(0, length, len(self.x)) red1 = Scalar_mask_X(x1, self.wavelength) conds = { 'kind': kind, 'p0': p0, 'p1': p1, 'amp_min': amp_min, 'amp_max': amp_max, 'delta_x': delta_x, 'phase_max': phase_max, 'length': 0, 'x_center': 0, } px = red1.chirped_grating_p(**conds) px = np.zeros_like(px, dtype=float) # sale mal en este formato self.insert_mask(red1, x_center, kind_position='center') return px else: size = self.x[-1] - self.x[0] mask.u = np.ones_like(self.x) print("possible error in chriped_grating_q: length > x[-1]-x[0]") x0 = self.x[0] - delta_x pa = (p1 - p0) / size px = 2. * np.pi * np.log(p0 + pa * (self.x - x0)) / pa t = amp_min + (amp_max - amp_min) * (1 + np.cos(px)) / 2 if kind == 'amplitude_binary' or kind == 'phase_binary': levels = [0, 1] bin_level = 0.5 t_binaria = np.zeros_like(t, dtype='float') t_binaria[t <= bin_level] = levels[0] t_binaria[t > bin_level] = levels[1] t = t_binaria if kind == 'amplitude': self.u = t elif kind == 'phase': self.u = np.exp(1.j * phase_max * t) print(np.angle(self.u)) elif kind == 'amplitude_binary': self.u = t_binaria elif kind == 'phase_binary': self.u = np.exp(1.j * phase_max * t_binaria) else: print("kind of chirped_grating_q not well defined") amplitud = self.u * mask.u fase = np.angle(self.u) * (1 - mask.u) self.u = amplitud * np.exp(1j * fase) px = (p0 + pa * (self.x - x0)) * mask.u return px, t
[docs] def chirped_grating_q(self, kind, p0, p1, amp_min, amp_max, phase_max, delta_x=0, length=0, x_center=0): """Chirped grating with linear q(x) variation. The transmitance is: t = np.cos(np.pi*q*(x-x0) + np.pi*q0*(x-x0)) Parameters: kind (str): 'amplitude', 'phase', 'amplitude_binary', 'phase_binary' p0 (float): initial period of the grating p1 (float): final period of the grating amp_min (float): minimum transmittance amp_max (float): maximum transmittance phase_max (float): maximum modulation for phase gratings delta_x (float): x shifting for movement of grating length (float): length of the grating, 0: length is equal to size of x l=(x[-1]-x[0]). <l: it can be shorter than l x_center (float): x-position of center of grating Returns: numpy.array: qx """ mascara = Scalar_mask_X(self.x, self.wavelength) if length == 0 or length == self.x[-1] - self.x[0]: size = self.x[-1] - self.x[0] mascara.u = np.ones_like(self.x) x0 = self.x[0] - delta_x elif length < self.x[-1] - self.x[0]: size = length x0 = self.x[0] - delta_x x1 = np.linspace(0, length, len(self.x)) red1 = Scalar_mask_X(x1, self.wavelength) conds = { 'kind': kind, 'p0': p0, 'p1': p1, 'amp_min': amp_min, 'amp_max': amp_max, 'delta_x': delta_x, 'phase_max': phase_max, 'length': 0, 'x_center': 0, } qx = red1.chirped_grating_q(**conds) qx = np.zeros_like(qx, dtype=float) # sale mal en este formato self.insert_mask(red1, x_center, kind_position='center') return qx else: size = self.x[-1] - self.x[0] mascara.u = np.ones_like(self.x) print("possible error in chriped_grating_q: length > x[-1]-x[0]") x0 = self.x[0] - delta_x q0 = 2 * np.pi / p0 q1 = 2 * np.pi / p1 qa = (q1 - q0) / size qx = q0 + 0.5 * qa * (self.x - x0) t = amp_min + (amp_max - amp_min) * (1 + np.cos(qx * (self.x - x0))) / 2 if kind == 'amplitude_binary' or kind == 'phase_binary': levels = [0, 1] bin_level = 0.5 t_binaria = np.zeros_like(t, dtype='float') t_binaria[t <= bin_level] = levels[0] t_binaria[t > bin_level] = levels[1] t = t_binaria if kind == 'amplitude': self.u = t elif kind == 'phase': self.u = np.exp(1.j * phase_max * t) print(np.angle(self.u)) elif kind == 'amplitude_binary': self.u = t_binaria elif kind == 'phase_binary': self.u = np.exp(1.j * phase_max * t_binaria) else: print("kind of chirped_grating_q not well defined") amplitud = self.u * mascara.u fase = np.angle(self.u) * (1 - mascara.u) self.u = amplitud * np.exp(1j * fase) qx = (q0 + qa * (self.x - x0)) * mascara.u return qx, t
[docs] def chirped_grating(self, kind, p_x, x0, amp_min, amp_max, phase_max, delta_x, length=0): """General chirped grating with variation given by function p(x). Parameters: kind (str): 'amplitude', 'phase', 'amplitude_binary', 'phase_binary' p_x (str): function with variation of periods amp_min (float): minimum transmittance amp_max (float): maximum transmittance phase_max (float): maximum modulation for phase gratings delta_x (float): x shifting for movement of grating length (float): length of the grating. 0: length is equal to size of x l=(x[-1]-x[0]). <l: it can be shorter than l Returns: numpy.array: p(x) """ if length == 0 or length == []: length = self.x[-1] - self.x[0] period = eval(p_x) q_x = 2 * np.pi / period t = amp_min + (amp_max - amp_min) * (1 + np.cos(q_x * (self.x - delta_x))) / 2 # plt.figure() # plt.plot(t) if kind == 'amplitude_binary' or kind == 'phase_binary': levels = [0, 1] bin_level = 0.5 t_binaria = np.zeros_like(t, dtype='float') t_binaria[t <= bin_level] = levels[0] t_binaria[t > bin_level] = levels[1] t = t_binaria if kind == 'amplitude': self.u = t elif kind == 'phase': self.u = np.exp(1.j * phase_max * t) elif kind == 'amplitude_binary': self.u = t_binaria elif kind == 'phase_binary': self.u = np.exp(1.j * phase_max * t_binaria) self.u = cut_function(self.x, self.u, length, '') return t
[docs] def binary_code_positions(self, x_transitions, start='down', has_draw=True): """ Genenerates a binary code, using the positions given in x_transitions Parameters: x_transitions (numpy.array): positions where transitions are placed start (str): How the binary code starts:'down' (starts in 0) or 'up' (starts in 1) has_draw (bool): If True, draws the code """ x_transitions = np.sort(x_transitions) x_transitions = np.hstack((self.x[0], x_transitions, self.x[-1])) x_transitions = np.unique(x_transitions) t = np.ones_like(self.x) i_transitions, _, _ = nearest2(self.x, x_transitions) i_transitions = i_transitions.astype(int) for i in range(0, len(i_transitions) - 1, 2): i0 = i_transitions[i] i1 = i_transitions[i + 1] t[i0:i1] = 0 if start == 'up': t = 1 - t self.u = t if has_draw: plt.figure(figsize=(18, 5)) plt.plot(self.x, t) plt.plot(x_transitions, np.ones_like(x_transitions), 'ko') plt.xlim(self.x[0], self.x[-1]) return t
[docs] def binary_code(self, x0=0 * um, kind='standard', code=[1, 1, 0, 0, 1, 0, 1], bit_width=20 * um): """Binary code in form of 1's and 0's. Parameters: kind (str): there are serveral types of codes 'standard' - normal 'abs_fag' - used in some abs encoders code (numpy.array): array with values of code bit_width (float): size of each data of code x0 (float): Initial position """ if kind == 'abs_fag': i0_ones = np.ones_like(code) i0_zeros = np.zeros_like(code) code = np.vstack((i0_zeros, i0_ones, code, i0_ones)).reshape( (-1, ), order='F') bit_width = bit_width / 2 t = Scalar_mask_X(self.x, self.wavelength) t2 = Scalar_mask_X(self.x, self.wavelength) t.u = np.zeros(self.x.shape) for i0j, j in zip(code, list(range(len(code)))): t2.slit(x0 + (j + 0.5) * bit_width, bit_width) t.u = t.u + i0j * t2.u self.u[-1] = self.u[-2] self.u = t.u return t.u