def rcosfir(beta, sps, span=None): """Generates a raised cosine FIR filter. :param beta: shape of the raised cosine filter (0-1) :param sps: number of samples per symbol :param span: length of the filter in symbols (None => automatic selection) >>> import arlpy >>> rc = arlpy.comms.rcosfir(0.25, 6) >>> bb = arlpy.comms.modulate(arlpy.comms.random_data(100), arlpy.comms.psk()) >>> pb = arlpy.comms.upconvert(bb, 6, 27000, 18000, rc) """ if beta < 0 or beta > 1: raise ValueError('Beta must be between 0 and 1') if span is None: # from http://www.commsys.isy.liu.se/TSKS04/lectures/3/MichaelZoltowski_SquareRootRaisedCosine.pdf # since this recommendation is for root raised cosine filter, it is conservative for a raised cosine filter span = 33 - int(44 * beta) if beta < 0.68 else 4 delay = int(span * sps / 2) t = _np.arange(-delay, delay + 1, dtype=_np.float) / sps denom = 1 - (2 * beta * t)**2 eps = _np.finfo(float).eps idx1 = _np.nonzero(_np.abs(denom) > _sqrt(eps)) b = _np.full_like(t, beta * _sin(_pi / (2 * beta)) / (2 * sps)) b[idx1] = _np.sinc(t[idx1]) * _cos( _pi * beta * t[idx1]) / denom[idx1] / sps b /= _sqrt(_np.sum(b**2)) return b
def imfp_TPP2M(energy_k, rho, molar_mass, n_valence, energy_bg, units='angstroms'): """The TPP-2M is the modified TPP-2 equation for estimating inelastic mean free paths (IMFP) [1] Parameters ---------- energy_k : float Kinetic energy [eV] rho : float Density (g/cm**3) molar_mass : float Atomic or molar mass n_valence : float Valence electrons energy_bg : float Bandgap energy [eV] units : str 'angstroms' or 'si' (the default is 'angstroms') Returns ------- float Inelastic mean free path (IMFP) References -------- .. [1] S. Tanuma, C. J. Powell, D. R. Penn: Surf. Interf. Anal.,Vol. 21, 165 (1994) """ # NOTE gamma, betaM, u, c, d are fitting parameters as in ref. u = n_valence * rho / molar_mass c = 1.97 - 0.91 * u d = 53.4 - 20.8 * u energy_plasmon = _sqrt(829.4 * u) gamma = 0.191 * rho**-0.50 betaM = -0.10 + 0.944 / _sqrt(energy_plasmon**2 + energy_bg**2) betaM += 0.069 * rho**0.1 imfp = energy_k imfp /= (energy_plasmon**2 * (betaM * _log(gamma * energy_k) - c / energy_k + d / energy_k**2)) if units.lower() == 'si': # Convert to meters return imfp * 1E-10 # Leave units unmodified in Angstroms return imfp
def langevin(alpha, mass1, mass2): """ :param alpha: alpha: polarizability of neutral reactant (A^3) :param mass1: mass of first particle (amu) :param mass2: mass of second particle (amu) :return: ion-neutral interaction rate constant (cm^3/s) """ mu = reduced_mass(mass1, mass2) * 1.660538782e-24 alpha = alpha * 1e-24 top = 2 * _pi * _e * _sqrt(alpha) bot = _sqrt(mu) output = top / bot return output
def upconvert(x, sps, fc, fs=2.0, g=None): """Upconvert a complex baseband signal with pulse shaping. This function supports upconversion by an integer factor. For a more general passband conversion (but without pulse shaping), see :func:`arlpy.signal.bb2pb`. If the carrier frequency is 0, the upsampled (at passband sampling rate) and pulse shaped complex baseband data is returned. If the pulse shape is None, a rectangular pulse shape is assumed. The upconversion process introduces a group delay depending on the pulse shaping filter. It is usually (len(g)-1)/2 passband samples. When g is None, the group delay is (sps-1)/2 passband samples. :param x: complex baseband data :param sps: number of passband samples per baseband symbol :param fc: carrier frequency in Hz :param fs: passband sampling rate :param g: pulse shaping filter >>> import arlpy >>> rrc = arlpy.comms.rrcosfir(0.25, 6) >>> bb = arlpy.comms.modulate(arlpy.comms.random_data(100), arlpy.comms.psk()) >>> pb = arlpy.comms.upconvert(bb, 6, 27000, 108000, rrc) """ x = _np.asarray(x, dtype=_np.complex) if g is None: y = _np.repeat(x, sps) / _np.sqrt(sps) else: y = _sp.upfirdn(g, x, up=sps) if fc != 0: y *= _sqrt(2) * _np.exp(2j * _pi * fc * _time(y, fs)) y = y.real return y
def awgn(x, snr, measured=False, complex=None): """Add Gaussian noise to signal. :param x: real passband or complex baseband signal :param snr: SNR in dB :param measured: True to measure signal strength, False to assume unit strength signal :param complex: True for complex noise, False for real noise, None to automatically decide >>> import arlpy >>> d1 = arlpy.comms.random_data(100, 4) >>> qpsk = arlpy.comms.psk(4) >>> x = arlpy.comms.modulate(d1, qpsk) >>> y = arlpy.comms.awgn(x, 6) >>> d2 = arlpy.comms.demodulate(y, qpsk) >>> arlpy.comms.ser(d1, d2) 0.02 """ signal = _np.std(x) if measured else 1.0 noise = signal * _np.power(10, -snr / 20.0) if complex is None: complex = (x.dtype == _np.complex) if complex: noise /= _sqrt(2) y = x + _np.random.normal( 0, noise, _np.shape(x)) + 1j * _np.random.normal(0, noise, _np.shape(x)) else: y = x + _np.random.normal(0, noise, _np.shape(x)) return y
def qam(m=16, gray=True): """Generate a QAM constellation with m signal points. The constellation represents the baseband values for symbols 0 through m-1 respectively. The constellation is scaled for unit average energy per sample, assuming the symbols are randomly distributed. :param m: symbol alphabet size (must be a square of an integer) :param gray: True to use Gray coding, False otherwise >>> import arlpy >>> arlpy.comms.iqplot(arlpy.comms.qam(16)) """ n = int(_sqrt(m)) if n * n != m: raise ValueError('m must be an integer squared') x = _np.empty((n, n), dtype=_np.complex) for r in range(n): for i in range(n): x[r, i] = r + 1j * i x -= _np.mean(x) x /= _np.std(x) x = _np.ravel(x) if gray: ndx = _np.reshape(gray_code(m), (n, n)) for i in range(1, n, 2): ndx[i] = _np.flipud(ndx[i]) ndx = invert_map(_np.ravel(ndx)) x = x[ndx] return x
def pam(m=2, gray=True, centered=True): """Generate a PAM constellation with m signal points. The constellation represents the baseband values for symbols 0 through m-1 respectively. The constellation is scaled for unit average energy per sample, assuming the symbols are randomly distributed. :param m: symbol alphabet size :param gray: True to use Gray coding, False otherwise :param centered: True to center constellation around 0, False otherwise >>> import arlpy >>> arlpy.comms.pam() array([-1, 1]) >>> arlpy.comms.pam(m=4, gray=False, centered=False) array([0, 0.535, 1.069, 1.604]) """ if gray and 2**int(_np.log2(m)) != m: raise ValueError('m must be a power of 2 if Gray coding is desired') x = _np.arange(m, dtype=_np.float) if centered: x -= _np.mean(x) x /= _sqrt(_np.mean(x**2)) if gray: x = x[invert_map(gray_code(m))] return x
def dipole(temperature, mass1, mass2, mu_d, c): """ Calculates ion-dipole interaction component to rate constant :param temperature: collision temperature (K) :param mass1: mass of first particle (amu) :param mass2: mass of second particle (amu) :param mu_d: dipole moment of neutral reactant (D) :param c: unitless factor parameterized by mu_d and alpha :return: ion-dipole interaction rate constant (cm^3/s) """ mu = reduced_mass(mass1, mass2) * 1.660538782e-24 mu_d = mu_d * 1e-18 top = 2 * _sqrt(2) * _pi * _e * c * mu_d bot = _sqrt(mu * _pi * _kb * temperature) output = top / bot return output
def ook(): """Generate an on-off keying constellation. The constellation represents the baseband values for bits 0 and 1 respectively. The constellation is scaled for unit average energy per bit, assuming the bits are randomly distributed. >>> import arlpy >>> arlpy.comms.ook() array([0, 1.414]) """ return _np.array([0, _sqrt(2)], dtype=_np.float)
def mb_mean_velocity(temperature, mass): """ Calculates the mean velocity of a Maxwell Boltzmann distribution :param temperature: temperature of distribution :param mass: mass of gas particle :return: velocity """ top = 8 * _u.k * temperature bot = mass * _pi output = _sqrt(top / bot) return output
def max_supersonic_velocity(temperature, mu, gamma): """ Maximum velocity of a supersonic beam :param temperature: temperature of initial gas sample :param mu: reduced mass of gas particles :param gamma: heat capacity ratio (1+1/f) where f is the number of degrees of freedom :return: velocity """ top = 2 * _u.k * temperature * gamma bot = mu * (gamma - 1) output = _sqrt(top / bot) return output
def rrcosfir(beta, sps, span=None): """Generates a root raised cosine FIR filter. :param beta: shape of the root raised cosine filter (0-1) :param sps: number of samples per symbol :param span: length of the filter in symbols (None => automatic selection) >>> import arlpy >>> rrc = arlpy.comms.rrcosfir(0.25, 6) >>> bb = arlpy.comms.modulate(arlpy.comms.random_data(100), arlpy.comms.psk()) >>> pb = arlpy.comms.upconvert(bb, 6, 27000, 18000, rrc) """ if beta < 0 or beta > 1: raise ValueError('Beta must be between 0 and 1') if span is None: # from http://www.commsys.isy.liu.se/TSKS04/lectures/3/MichaelZoltowski_SquareRootRaisedCosine.pdf span = 33 - int(44 * beta) if beta < 0.68 else 4 delay = int(span * sps / 2) t = _np.arange(-delay, delay + 1, dtype=_np.float) / sps b = _np.empty_like(t) b[delay] = -1 / (_pi * sps) * (_pi * (beta - 1) - 4 * beta) eps = _np.finfo(float).eps idx2 = _np.nonzero(_np.abs(_np.abs(4 * beta * t) - 1) < _sqrt(eps)) if len(idx2) > 0: b[idx2] = (_pi * (beta + 1) * _sin(_pi * (beta + 1) / (4 * beta)) - 4 * beta * _sin(_pi * (beta - 1) / (4 * beta)) + _pi * (beta - 1) * _cos(_pi * (beta - 1) / (4 * beta))) / (2 * _pi * sps) ind = _np.arange(len(t)) ind = _np.delete(ind, _np.append(idx2, delay)) nind = t[ind] b[ind] = -4 * beta / sps * (_cos((1 + beta) * _pi * nind) + _sin( (1 - beta) * _pi * nind) / (4 * beta * nind)) / (_pi * ( (4 * beta * nind)**2 - 1)) b /= _sqrt(_np.sum(b**2)) return b
def downconvert(x, sps, fc, fs=2.0, g=None): """Downconvert a passband signal with a matched pulse shaping filter. This function supports downconversion by an integer factor. For a more general baseband conversion (but without matched filtering), see :func:`arlpy.signal.pb2bb`. If the carrier frequency is 0, the input is assumed to be complex baseband, and only undergoes matched filtering and downsampling. If the pulse shape is None, a rectangular pulse shape is assumed. The downconversion process introduces a group delay depending on the matched filter. It is usually (len(g)-1)/2 passband samples. :param x: real passband data (or complex baseband data at passband sampling rate, if fc=0) :param sps: number of passband samples per baseband symbol :param fc: carrier frequency in Hz :param fs: passband sampling rate :param g: pulse shaping filter (for matched filtering) >>> import arlpy >>> d1 = arlpy.comms.random_data(100, 4) >>> qpsk = arlpy.comms.psk(4) >>> bb1 = arlpy.comms.modulate(d1, qpsk) >>> rrc = arlpy.comms.rrcosfir(0.25, 6) >>> pb = arlpy.comms.upconvert(bb1, 6, 27000, 108000, rrc) >>> bb2 = arlpy.comms.downconvert(pb, 6, 27000, 108000, rrc) >>> delay = (len(rrc)-1)/2 # compute passband group delay of rrc FIR filter >>> delay = 2*delay/6 # compute baseband group delay after filtering twice >>> d2 = arlpy.comms.demodulate(bb2[delay:-delay], qpsk) >>> arlpy.comms.ser(d1, d2) 0.0 """ if fc == 0: y = _np.asarray(x, dtype=_np.complex) else: y = _sp.hilbert(x) / 2 y *= _sqrt(2) * _np.exp(-2j * _pi * fc * _time(y, fs)) if g is None: y = _np.sum(_np.reshape(y, (sps, -1), order='F'), axis=0) / _np.sqrt(sps) else: y = _sp.upfirdn(g, y, down=sps) return y
def _update_ps(self, es): """update path with isotropic delta mean, possibly clipped. From input argument `es`, the attributes isotropic_mean_shift, opts['CSA_clip_length_value'], and N are used. opts['CSA_clip_length_value'] can be a single value, the upper bound parameter, such that:: max_len = sqrt(N) + opts['CSA_clip_length_value'] * N / (N+2) or a list with lower and upper bound parameters. """ if not self.is_initialized: self.initialize(es) if self._ps_updated_iteration == es.countiter: return z = es.isotropic_mean_shift if es.opts['CSA_clip_length_value'] is not None: vals = es.opts['CSA_clip_length_value'] try: len(vals) except TypeError: vals = [-np.inf, vals] if vals[0] > 0 or vals[1] < 0: raise ValueError( """value(s) for option 'CSA_clip_length_value' = %s not allowed""" % str(es.opts['CSA_clip_length_value'])) min_len = es.N**0.5 + vals[0] * es.N / (es.N + 2) max_len = es.N**0.5 + vals[1] * es.N / (es.N + 2) act_len = _norm(z) new_len = Mh.minmax(act_len, min_len, max_len) if new_len != act_len: z *= new_len / act_len # z *= (es.N / sum(z**2))**0.5 # ==> sum(z**2) == es.N # z *= es.const.chiN / sum(z**2)**0.5 self.ps = (1 - self.cs) * self.ps + _sqrt(self.cs * (2 - self.cs)) * z self._ps_updated_iteration = es.countiter
def ball_and_stick_2D(target, pore_area='pore.area', throat_area='throat.area', pore_diameter='pore.diameter', throat_diameter='throat.diameter', conduit_lengths='throat.conduit_lengths'): r""" Calculate conduit shape factors for throat conductance associated with diffusion-like physics (ex. thermal/diffusive/electrical conductance), assuming pores and throats are circles (balls) and rectangles (sticks). Parameters ---------- target : OpenPNM Object The object which this model is associated with. This controls the length of the calculated array, and also provides access to other necessary properties. pore_area : string Dictionary key of the pore area values throat_area : string Dictionary key of the throat area values pore_diameter : string Dictionary key of the pore diameter values throat_diameter : string Dictionary key of the throat diameter values conduit_lengths : string Dictionary key of the conduit lengths' values Returns ------- SF : dictionary Dictionary containing conduit shape factors to be used in conductance models associated with diffusion-like physics. Shape factors are accessible via the keys: 'pore1', 'pore2' and 'throat'. Notes ----- (1) This model accounts for the variable cross-section area in circles. (2) WARNING: This model could break if `conduit_lengths` does not correspond to an actual ball and stick! Example: pore length is greater than pore radius --> :( """ _np.warnings.filterwarnings('ignore', category=RuntimeWarning) network = target.project.network throats = network.map_throats(throats=target.Ts, origin=target) cn = network['throat.conns'][throats] # Get pore diameter D1 = network[pore_diameter][cn[:, 0]] D2 = network[pore_diameter][cn[:, 1]] # Get conduit lengths L1 = network[conduit_lengths + '.pore1'][throats] L2 = network[conduit_lengths + '.pore2'][throats] Lt = network[conduit_lengths + '.throat'][throats] # Get pore/throat baseline areas (the one used in generic conductance) A1 = network[pore_area][cn[:, 0]] A2 = network[pore_area][cn[:, 1]] At = network[throat_area][throats] # Preallocating F, SF # F is INTEGRAL(1/A) dx , x : 0 --> L F1, F2, Ft = _np.zeros((3, len(Lt))) SF1, SF2, SFt = _np.ones((3, len(Lt))) # Setting SF to 1 when Li = 0 (ex. boundary pores) # INFO: This is needed since area could also be zero, which confuses NumPy m1, m2, mt = [Li != 0 for Li in [L1, L2, Lt]] SF1[~m1] = SF2[~m2] = SFt[~mt] = 1 F1[m1] = (0.5 * _atanh(2 * L1 / _sqrt(D1**2 - 4 * L1**2)))[m1] F2[m2] = (0.5 * _atanh(2 * L2 / _sqrt(D2**2 - 4 * L2**2)))[m2] Ft[mt] = (Lt / At)[mt] # Calculate conduit shape factors SF1[m1] = (L1 / (A1 * F1))[m1] SF2[m2] = (L2 / (A2 * F2))[m2] SFt[mt] = (Lt / (At * Ft))[mt] _np.warnings.filterwarnings('default', category=RuntimeWarning) return {'pore1': SF1, 'throat': SFt, 'pore2': SF2}
def RMSE(p1, p2): return _sqrt(MSE(p1, p2))
'value': 0.11, 'units': None, 'symbol': symbols(r'\alpha_s', positive=True) } αem = { 'value': 1.0 / 137.0, 'units': None, 'symbol': symbols(r'\alpha_{e}', positive=True) } cW = { 'value': mW['value'] / mZ['value'], 'units': 'GeV', 'symbol': symbols('c_W', real=True) } sW = { 'value': _sqrt(1 - cW['value']**2), 'units': 'GeV', 'symbol': symbols('s_W', real=True) } g = { 'value': 2 * (mW['value'] / SMvev['value']), 'unit': None, 'symbol': symbols('g', real=True) } ge = { 'value': _sqrt(4 * _pi * αem['value']), 'unit': None, 'symbol': symbols('g_e', real=True) } gw = { 'value': ge['value'] / sW['value'],