Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #9
0
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)
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
    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
Beispiel #15
0
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}
Beispiel #16
0
def RMSE(p1, p2):
    return _sqrt(MSE(p1, p2))
Beispiel #17
0
    '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'],