def fromCsv(cls, fname, skiprows=0, delimiter=',', wavelength_multiplier=1): '''A constructor that allows the loading of a csv datafile.''' material = cls() data = _np.loadtxt(fname, skiprows=skiprows, delimiter=delimiter) data[:, 0] *= wavelength_multiplier if (data < 0).any(): raise ValueError( 'Refractive index and extinction coefficient must \ be positive, as well as wavelength.') print('Loaded', fname) print('Dataset range:', data[0, 0], 'um -', data[-1, 0], 'um') if len(data.shape) != 2: raise ValueError('Loaded data was misshapen.') if data.shape[1] > 3: print( '\33[33mWarning:\33[0m Extraneous columns detected. These were \ skipped') if data.shape[1] == 2: print('2 columns detected. Assuming lossless material.') material.getEc = lambda l: 0 material.getRealN = _interp1d(data[:, 0], data[:, 1]) else: material.getRealN = _interp1d(data[:, 0], data[:, 1]) material.getEc = _interp1d(data[:, 0], data[:, 2]) return material
def fromArray(cls, wavelength, realN, Ec=0): '''Constructor that allows the creation of a theoretical material with complex refractive index realN(lambda) + 1j*Ec(lambda). RealN and Ec are data for n and Ec at wavelength. Ec and realN can be a single number''' material = cls() realN = _np.array(realN, ndmin=1) Ec = _np.array(Ec, ndmin=1) wavelength = _np.array(wavelength, ndmin=1) if (len(wavelength) != len(realN) and len(realN) != 1): raise ValueError('Wavelength and real refractive index must be \ the same size, or refractive index must be scalar.') if (len(wavelength) != len(Ec) and len(Ec) != 1): raise ValueError('Wavelength and extinction coefficient must be \ the same size, or refractive index must be scalar.') if (realN < 0).any() or (Ec < 0).any(): raise ValueError( 'Refractive index and extinction coefficient must \ be positive.') if (len(Ec) == 1): material.getRealN = lambda l: realN[0] else: material.getRealN = _interp1d(wavelengths, realN) if (len(Ec) == 1): material.getEc = lambda l: Ec[0] else: material.getEc = _interp1d(wavelengths, Ec) return material
def _resample_with_constant_dx(x_data, y_data): f = _interp1d(x_data, y_data) x = _linspace(x_data[0], x_data[-1], len(x_data)) y = f(x) return x, y
def fromYml(cls, fname): '''Loads a yml file with the same structure as the ones contained in the refractiveindex.info database.''' table = cls() #initialise an empty MaterialTable named table with open(fname) as file: table.datafile = _yml.full_load(file) print('Loaded yml datafile:', fname) dataK_found = False dataN_found = False # Find k and n data and load them for datatable in table.datafile['DATA']: if datatable['type'] == 'tabulated nk': # If both found in same dataset no extra data is needed data = _np.loadtxt(_io.StringIO(datatable['data'])) print('Loaded tabulated nk data.') print('Range:', data[0, 0], 'um -', data[-1, 0], 'um') if not dataN_found: table.getRealN = _interp1d(data[:, 0], data[:, 1]) else: print('\33[33mWarning:\33[0m Duplicate n data. Skipped') if not dataK_found: table.getEc = _interp1d(data[:, 0], data[:, 2]) else: print('\33[33mWarning:\33[0m Duplicate k data. Skipped') dataN_found = True dataK_found = True elif datatable['type'] == 'tabulated n': if dataN_found: print( '\33[33mWarning:\33[0m Found duplicate n data. Skipped' ) continue data = _np.loadtxt(_io.StringIO(datatable['data'])) print('Loaded tabulated n data') print('Range:', data[0, 0], 'um -', data[-1, 0], 'um') dataN_found = True table.getRealN = _interp1d(data[:, 0], data[:, 1]) elif datatable['type'] == 'tabulated k': if dataK_found: print( '\33[33mWarning:\33[0m Found duplicate k data. Skipped' ) continue data = _np.loadtxt(_io.StringIO(datatable['data'])) print('Loaded tabulated k data') print('Range:', data[0, 0], 'um -', data[-1, 0], 'um') dataK_found = True table.getEc = _interp1d(data[:, 0], data[:, 1]) elif 'formula' in datatable['type']: if dataN_found: print( '\33[33mWarning:\33[0m Found duplicate n data. Skipped' ) continue ID = int( _re.search('(?<=formula\ )[0-9]', datatable['type']).group(0)) - 1 if (ID >= len(MaterialTable.formulae)): raise KeyError('Unknown formula:', datatable['type']) print('Loaded', datatable['type'], 'data') range = _np.loadtxt(_io.StringIO( datatable['wavelength_range'])) coeffs = _np.loadtxt(_io.StringIO(datatable['coefficients'])) print('Range:', range[0], 'um -', range[1], 'um') table.getRealN = MaterialTable.formulae[ID](coeffs, range) dataN_found = True else: raise ValueError('Unknown type of datatable:', datatable['type']) if dataN_found and dataK_found: # Check if we are at the end of the dataset if datatable != table.datafile['DATA'][-1]: print('\33[33mWarning:\33[0m Some datatables were skipped \ as sufficient data was found before end of file.') break # End loop if all parameters are loaded if not dataK_found: print('No k data found. Assuming lossless material') table.getEc = lambda l: 0 return table
def parseDataset(self,database,lmin=None,lmax=None,allow_interpolation=True,\ require_k=False): '''This method is responsible for checking and loading the dataset once the material database was found in findMaterial, or otherwise. lmin and lmax are the optional bounds of wavelength we are interested in the material in units of um. allow_interpolation decides whether interpolation is acceptable for the refractive index data. require_k is a parameter specifying, whether data for k is also desired. Datasets with k specified as well are always preffered, and if found will be used regardless of require_k. k is the extinction coefficient in this context.''' if (lmin == None and lmax != None): # Sanitising the input lmin = lmax elif (lmin != None and lmax == None): lmax = lmin elif (lmin == None and lmax == None): lmin = _np.inf lmax = -_np.inf # This makes the check below always return True elif (lmin > lmax): raise ValueError('lmin must be strictly smaller than lmax') goodDatasets = [] for dataset in database: with open('./database/data/' + database[dataset]['data']) as file: datafile = _yml.full_load(file) for data in datafile['DATA']: # Filtering out not n data if not (('tabulated n' in data['type'] and allow_interpolation) \ or 'formula' in data['type']): continue # If formula is in the data type, the range is specified if 'formula' in data['type']: range = _np.loadtxt(_io.StringIO(data['wavelength_range'])) else: tabulated = _np.loadtxt(_io.StringIO(data['data'])) range = _np.array([tabulated[0, 0], tabulated[-1, 0]]) if (range[0] < lmin and range[1] > lmax): # Append data for the good datasets. The structure is: # [dataset, N-index,range-N, datafile, K-index,range-K] # as k is not tested yet, it is None as well as its range goodDatasets.append([ dataset, datafile['DATA'].index(data), range, datafile, None, None ]) # Check for k data contains_k = [] for d in goodDatasets: datafile = d[3] for data in datafile['DATA']: if not ('tabulated k' in data['type'] or 'tabulated nk' in data['type']): continue tabulated = _np.loadtxt(_io.StringIO(data['data'])) range = _np.array([tabulated[0, 0], tabulated[-1, 0]]) if (range[0] < lmin and range[1] > lmax): contains_k.append(d) contains_k[-1][4] = datafile['DATA'].index(data) contains_k[-1][5] = range if len(goodDatasets) == 0: raise KeyError('No datasets satisfying requirements found') print('Found', len(goodDatasets), 'datasets, which satisfied requirements') if len(contains_k) != 0: goodDatasets = contains_k elif require_k: raise KeyError('No k data was found') print('Out of which', len(contains_k), 'datasets contain k data') print('Using ' + goodDatasets[0][0]) print('Name:', database[goodDatasets[0][0]]['name']) if 'division' in database[goodDatasets[0][0]].keys(): print('Division:', database[goodDatasets[0][0]]['division']) print('Location: ./database/data/' + database[goodDatasets[0][0]]['data']) print('Datatable type:', goodDatasets[0][3]['DATA'][goodDatasets[0][1]]['type']) print('Datatable range:', goodDatasets[0][2][0], 'um -', goodDatasets[0][2][1], 'um') if (contains_k == goodDatasets): if (goodDatasets[0][1] != goodDatasets[0][4]): print('Datatable type:', goodDatasets[0][3]['DATA'][goodDatasets[0][4]]['type']) print('Datatable range:', goodDatasets[0][5][0], 'um -', goodDatasets[0][5][1], 'um') dataN = goodDatasets[0][1] dataK = goodDatasets[0][4] self.datafile = goodDatasets[0][3] # If k dataset is not found error is raised if getK is called if dataK == None: self.getEc = lambda l: 0 # Check for the different types of data k and n might be contained in elif 'tabulated k' in self.datafile['DATA'][dataK]['type']: tabulated = _np.loadtxt( _io.StringIO(self.datafile['DATA'][dataK]['data'])) self.getEc = _interp1d(tabulated[:, 0], tabulated[:, 1]) if 'tabulated nk' in self.datafile['DATA'][dataN]['type']: tabulated = _np.loadtxt( _io.StringIO(self.datafile['DATA'][dataN]['data'])) self.getRealN = _interp1d(tabulated[:, 0], tabulated[:, 1]) self.getEc = _interp1d(tabulated[:, 0], tabulated[:, 2]) elif 'tabulated n' in self.datafile['DATA'][dataN]['type']: tabulated = _np.loadtxt( _io.StringIO(self.datafile['DATA'][dataN]['data'])) self.getRealN = _interp1d(tabulated[:, 0], tabulated[:, 1]) else: formulaN = int( _re.search('(?<=formula\ )[0-9]', self.datafile['DATA'][dataN]['type']).group(0)) coefficients = _np.loadtxt( _io.StringIO(self.datafile['DATA'][dataN]['coefficients'])) self.getRealN = MaterialTable.formulae[formulaN - 1]( coefficients, goodDatasets[0][2])
def grid_count(y, window_size, offset=0, size=None, fuzz=True, bounds=None): """ Parameters ---------- `y` is the 1-d array of signal samples. `window_size` is the number of samples to show horizontally in the eye diagram. Typically this is twice the number of samples in a "symbol" (i.e. in a data bit). `offset` is the number of initial samples to skip before computing the eye diagram. This allows the overall phase of the diagram to be adjusted. `size` must be a tuple of two integers. It sets the size of the array of counts, (height, width). The default is (800, 640). `fuzz`: If True, the values in `y` are reinterpolated with a random "fuzz factor" before plotting in the eye diagram. This reduces an aliasing-like effect that arises with the use of Bresenham's algorithm. `bounds` must be a tuple of two floating point values, (ymin, ymax). These set the y range of the returned array. If not given, the bounds are `(y.min() - 0.05*A, y.max() + 0.05*A)`, where `A` is `y.max() - y.min()`. Return Value ------------ Returns a numpy array of integers. """ if size is None: size = (800, 640) height, width = size dt = width / window_size counts = _np.zeros((width, height), dtype=_np.int32) if bounds is None: ymin = y.min() ymax = y.max() yamp = ymax - ymin ymin = ymin - 0.05*yamp ymax = ymax + 0.05*yamp else: ymin, ymax = bounds start = offset while start + window_size < len(y): end = start + window_size yy = y[start:end+1] k = _np.arange(len(yy)) xx = dt*k if fuzz: f = _interp1d(xx, yy, kind='cubic') jiggle = dt*(_np.random.beta(a=3, b=3, size=len(xx)-2) - 0.5) xx[1:-1] += jiggle yd = f(xx) else: yd = yy iyd = (height * (yd - ymin)/(ymax - ymin)).astype(_np.int32) _bres_curve_count(xx.astype(_np.int32), iyd, counts) start = end return counts