Exemplo n.º 1
0
def besselord(omega_p, omega_s, alfa_max, alfa_min, omega_d, max_pc_delay):

    min_order = 0

    # partimos de suponer que al menos será el orden de un Butter o más grande
    start_order, _ = sig.buttord(omega_p,
                                 omega_s,
                                 alfa_max,
                                 alfa_min + alfa_max,
                                 analog=True)

    # de forma iterativa, intentamos cumplimentar la plantilla
    for ii in range(start_order, 20):

        z, p, k = sig.besselap(ii, norm='delay')

        this_lti = sig.ZerosPolesGain(z, p, k).to_tf()

        _, mm, pp = sig.bode(this_lti,
                             w=[0, 0.0001, omega_p, omega_d, omega_d + 0.0001])

        # attenuation in omega_p, i.e. bandpass end
        this_ripple = -mm[2]

        # relative delay
        this_delay = 1 - np.abs((pp[4] - pp[3]) / (pp[1] - pp[0]))

        if this_ripple <= alfa_max and this_delay <= max_pc_delay:
            break

    min_order = ii

    return min_order
Exemplo n.º 2
0
 def __init__(self,f,order,f0,Z0=50.):
     """Constructor
     @param f list of float frequencies
     @param order int filter order
     @param f0 float cutoff frequency (Hz)
     @note This device requires installation of the scipy package
     """
     try:
         from scipy.signal import besselap
     except: raise SignalIntegrityExceptionSParameters('Bessel filters require the scipy package to be installed') # pragma: no cover
     (z,p,k)=besselap(order,'mag')
     # this filter has -3 dB point at w=1 radian
     ClassicalFilter.__init__(self,f,z,p,k,f0,Z0)
Exemplo n.º 3
0
def plane_25d(x0, r0, npw, fs, max_order=None, c=None, s2z=matchedz_zpk):
    r"""Virtual plane wave by 2.5-dimensional NFC-HOA.

    .. math::

        D(\phi_0, s) =
        2\e{\frac{s}{c}r_0}
        \sum_{m=-M}^{M}
        (-1)^m
        \Big(\frac{s}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu
        \prod_{l=1}^{\nu}
        \frac{s^2}{(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}
        \e{\i m(\phi_0 - \phi_\text{pw})}

    The driving function is represented in the Laplace domain,
    from which the recursive filters are designed.
    :math:`\sigma_l + \i\omega_l` denotes the complex roots of
    the reverse Bessel polynomial.
    The number of second-order sections is
    :math:`\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor`,
    whereas the number of first-order section :math:`\mu` is either 0 or 1
    for even and odd :math:`|m|`, respectively.

    Parameters
    ----------
    x0 : (N, 3) array_like
        Sequence of secondary source positions.
    r0 : float
        Radius of the circular secondary source distribution.
    npw : (3,) array_like
        Unit vector (propagation direction) of plane wave.
    fs : int
        Sampling frequency in Hertz.
    max_order : int, optional
        Ambisonics order.
    c : float, optional
        Speed of sound in m/s.
    s2z : callable, optional
        Function transforming s-domain poles and zeros into z-domain,
        e.g. :func:`matchedz_zpk`, :func:`scipy.signal.bilinear_zpk`.

    Returns
    -------
    delay : float
        Overall delay in seconds.
    weight : float
        Overall weight.
    sos : list of numpy.ndarray
        Second-order section filters :func:`scipy.signal.sosfilt`.
    phaseshift : (N,) numpy.ndarray
        Phase shift in radians.
    selection : (N,) numpy.ndarray
        Boolean array containing only ``True`` indicating that
        all secondary source are "active" for NFC-HOA.
    secondary_source_function : callable
        A function that can be used to create the sound field of a
        single secondary source.  See `sfs.td.synthesize()`.

    Examples
    --------
    .. plot::
        :context: close-figs

        delay, weight, sos, phaseshift, selection, secondary_source = \
            sfs.td.nfchoa.plane_25d(array.x, R, npw, fs)
        d = sfs.td.nfchoa.driving_signals_25d(
                delay, weight, sos, phaseshift, signal)
        plot(d, selection, secondary_source)

    """
    if max_order is None:
        max_order = _util.max_order_circular_harmonics(len(x0))
    if c is None:
        c = _default.c

    x0 = _util.asarray_of_rows(x0)
    npw = _util.asarray_1d(npw)
    phi0, _, _ = _util.cart2sph(*x0.T)
    phipw, _, _ = _util.cart2sph(*npw)
    phaseshift = phi0 - phipw + _np.pi

    delay = -r0 / c
    weight = 2
    sos = []
    for m in range(max_order + 1):
        _, p, _ = _sig.besselap(m, norm='delay')
        s_zeros = _np.zeros(m)
        s_poles = c / r0 * p
        s_gain = 1
        z_zeros, z_poles, z_gain = s2z(s_zeros, s_poles, s_gain, fs)
        sos.append(_sig.zpk2sos(z_zeros, z_poles, z_gain, pairing='nearest'))
    selection = _util.source_selection_all(len(x0))
    return (delay, weight, sos, phaseshift, selection,
            _secondary_source_point(c))
Exemplo n.º 4
0
def point_3d(x0, r0, xs, fs, max_order=None, c=None, s2z=matchedz_zpk):
    r"""Virtual point source by 3-dimensional NFC-HOA.

    .. math::

        D(\phi_0, s) =
        \frac{\e{\frac{s}{c}(r_0-r_\text{s})}}{4 \pi r_0 r_\text{s}}
        \sum_{n=0}^{N}
        (2n+1) P_{n}(\cos\Theta)
        \Big(\frac{s-\frac{c}{r_\text{s}}\sigma_0}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu
        \prod_{l=1}^{\nu}
        \frac{(s-\frac{c}{r_\text{s}}\sigma_l)^2-(\frac{c}{r_\text{s}}\omega_l)^2}
        {(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}

    The driving function is represented in the Laplace domain,
    from which the recursive filters are designed.
    :math:`\sigma_l + \i\omega_l` denotes the complex roots of
    the reverse Bessel polynomial.
    The number of second-order sections is
    :math:`\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor`,
    whereas the number of first-order section :math:`\mu` is either 0 or 1
    for even and odd :math:`|m|`, respectively.
    :math:`P_{n}(\cdot)` denotes the Legendre polynomial of degree :math:`n`,
    and :math:`\Theta` the angle between :math:`(\theta, \phi)`
    and :math:`(\theta_\text{s}, \phi_\text{s})`.

    Parameters
    ----------
    x0 : (N, 3) array_like
        Sequence of secondary source positions.
    r0 : float
        Radius of the spherial secondary source distribution.
    xs : (3,) array_like
        Virtual source position.
    fs : int
        Sampling frequency in Hertz.
    max_order : int, optional
        Ambisonics order.
    c : float, optional
        Speed of sound in m/s.
    s2z : callable, optional
        Function transforming s-domain poles and zeros into z-domain,
        e.g. :func:`matchedz_zpk`, :func:`scipy.signal.bilinear_zpk`.

    Returns
    -------
    delay : float
        Overall delay in seconds.
    weight : float
        Overall weight.
    sos : list of numpy.ndarray
        Second-order section filters :func:`scipy.signal.sosfilt`.
    phaseshift : (N,) numpy.ndarray
        Phase shift in radians.
    selection : (N,) numpy.ndarray
        Boolean array containing only ``True`` indicating that
        all secondary source are "active" for NFC-HOA.
    secondary_source_function : callable
        A function that can be used to create the sound field of a
        single secondary source.  See `sfs.td.synthesize()`.

    """
    if max_order is None:
        max_order = _util.max_order_spherical_harmonics(len(x0))
    if c is None:
        c = _default.c

    x0 = _util.asarray_of_rows(x0)
    xs = _util.asarray_1d(xs)
    phi0, theta0, _ = _util.cart2sph(*x0.T)
    phis, thetas, rs = _util.cart2sph(*xs)
    phaseshift = _np.arccos(_np.dot(x0 / r0, xs / rs))

    delay = (rs - r0) / c
    weight = 1 / r0 / rs
    sos = []
    for m in range(max_order + 1):
        _, p, _ = _sig.besselap(m, norm='delay')
        s_zeros = c / rs * p
        s_poles = c / r0 * p
        s_gain = 1
        z_zeros, z_poles, z_gain = s2z(s_zeros, s_poles, s_gain, fs)
        sos.append(_sig.zpk2sos(z_zeros, z_poles, z_gain, pairing='nearest'))
    selection = _util.source_selection_all(len(x0))
    return (delay, weight, sos, phaseshift, selection,
            _secondary_source_point(c))
Exemplo n.º 5
0
        z, p, k = sig.buttap(this_order)

        eps = np.sqrt(10**(this_ripple / 10) - 1)
        num, den = sig.zpk2tf(z, p, k)
        num, den = sig.lp2lp(num, den, eps**(-1 / this_order))

        z, p, k = sig.tf2zpk(num, den)

    elif aprox_name == 'Chebyshev1':

        z, p, k = sig.cheb1ap(this_order, this_ripple)

    elif aprox_name == 'Chebyshev2':

        z, p, k = sig.cheb2ap(this_order, this_ripple)

    elif aprox_name == 'Bessel':

        z, p, k = sig.besselap(this_order, norm='mag')

    elif aprox_name == 'Cauer':

        z, p, k = sig.ellipap(this_order, this_ripple, this_att)

    num, den = sig.zpk2tf(z, p, k)

    all_sys.append(sig.TransferFunction(num, den))
    filter_names.append(aprox_name + '_ord_' + str(this_order) + '_rip_' +
                        str(this_ripple) + '_att_' + str(this_att))

analyze_sys(all_sys, filter_names)
Exemplo n.º 6
0
if aprox_name == 'Butterworth':

    z, p, k = sig.buttap(order2analyze)

elif aprox_name == 'Chebyshev1':

    z, p, k = sig.cheb1ap(order2analyze, ripple)

elif aprox_name == 'Chebyshev2':

    z, p, k = sig.cheb2ap(order2analyze, ripple)

elif aprox_name == 'Bessel':

    z, p, k = sig.besselap(order2analyze, norm='mag')

elif aprox_name == 'Cauer':

    z, p, k = sig.ellipap(order2analyze, ripple, attenuation)

num, den = sig.zpk2tf(z, p, k)

# Desnormalizamos para wc
num, den = sig.lp2lp(num, den, 2 * np.pi * fc)

my_analog_filter = sig.TransferFunction(num, den)
my_analog_filter_desc = aprox_name + '_ord_' + str(order2analyze) + '_analog'

all_sys.append(my_analog_filter)
filter_names.append(my_analog_filter_desc)
Exemplo n.º 7
0
# Obtengo la Transferencia Normalizada
my_tf_ch = tfunction(NUM2, DEN2)
print('\n', my_tf_ch)

#pretty_print_lti(my_tf_ch)

print('\nDenominador Factorizado de la Transferencia Normalizada:',
      convert2SOS(my_tf_ch))

# ----------------------------------------------------------------------------

print('\n\nFiltro Bessel de Orden 5:\n')

# Filtro de Bessel: Uso de los Métodos dentro del Paquete signal de Scipy.
z3, p3, k3 = sig.besselap(orden_filtro, 'mag')

# Obtengo los Coeficientes de mi Transferencia.
NUM3, DEN3 = sig.zpk2tf(z3, p3, k3)

# Obtengo la Transferencia Normalizada
my_tf_be = tfunction(NUM3, DEN3)
print('\n', my_tf_be)

#pretty_print_lti(my_tf_be)

print('Denominador Factorizado de la Transferencia Normalizada:',
      convert2SOS(my_tf_be))

# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
Exemplo n.º 8
0
@author: mariano
"""

import scipy.signal as sig
import numpy as np
from splane import tfadd, tfcascade, analyze_sys, pzmap, grpDelay, bodePlot, pretty_print_lti


nn = 2 # orden
ripple = 3 # dB


eps = np.sqrt(10**(ripple/10)-1)

z,p,k = sig.besselap(nn, norm='delay')
# z,p,k = sig.buttap(nn)


num_lp, den_lp = sig.zpk2tf(z,p,k)
num_lp, den_lp = sig.lp2lp(num_lp, den_lp, eps**(-1/nn) )

num_hp, den_hp = sig.lp2hp(num_lp,den_lp)
lp_sys = sig.TransferFunction(num_lp,den_lp)
hp_sys = sig.TransferFunction(num_hp,den_hp)
xover = tfadd(lp_sys, hp_sys)
bandpass = tfcascade(lp_sys, hp_sys)

pretty_print_lti(lp_sys)
pretty_print_lti(hp_sys)
pretty_print_lti(xover)
Exemplo n.º 9
0
    if aprox_name == 'Butterworth':
    
        z,p,k = sig.buttap(ii)
    
    elif aprox_name == 'Chebyshev1':
    
        z,p,k = sig.cheb1ap(ii, ripple)
        
    elif aprox_name == 'Chebyshev2':
    
        z,p,k = sig.cheb2ap(ii, ripple)
        
    elif aprox_name == 'Bessel':
        
        z,p,k = sig.besselap(ii, norm='mag')
        
    elif aprox_name == 'Cauer':
       
        z,p,k = sig.ellipap(ii, ripple, attenuation)


    num, den = sig.zpk2tf(z,p,k)
    
    all_sys.append(sig.TransferFunction(num,den))
    filter_names.append(aprox_name + '_ord_' + str(ii))


analyze_sys( all_sys, filter_names )

Exemplo n.º 10
0
def plane_25d(x0, r0, npw, fs, max_order=None, c=None, s2z=matchedz_zpk):
    r"""Virtual plane wave by 2.5-dimensional NFC-HOA.

    .. math::

        D(\phi_0, s) =
        2\e{\frac{s}{c}r_0}
        \sum_{m=-M}^{M}
        (-1)^m
        \Big(\frac{s}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu
        \prod_{l=1}^{\nu}
        \frac{s^2}{(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}
        \e{\i m(\phi_0 - \phi_\text{pw})}

    The driving function is represented in the Laplace domain,
    from which the recursive filters are designed.
    :math:`\sigma_l + \i\omega_l` denotes the complex roots of
    the reverse Bessel polynomial.
    The number of second-order sections is
    :math:`\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor`,
    whereas the number of first-order section :math:`\mu` is either 0 or 1
    for even and odd :math:`|m|`, respectively.

    Parameters
    ----------
    x0 : (N, 3) array_like
        Sequence of secondary source positions.
    r0 : float
        Radius of the circular secondary source distribution.
    npw : (3,) array_like
        Unit vector (propagation direction) of plane wave.
    fs : int
        Sampling frequency in Hertz.
    max_order : int, optional
        Ambisonics order.
    c : float, optional
        Speed of sound in m/s.
    s2z : callable, optional
        Function transforming s-domain poles and zeros into z-domain,
        e.g. :func:`matchedz_zpk`, :func:`scipy.signal.bilinear_zpk`.

    Returns
    -------
    delay : float
        Overall delay in seconds.
    weight : float
        Overall weight.
    sos : list of numpy.ndarray
        Second-order section filters :func:`scipy.signal.sosfilt`.
    phaseshift : (N,) numpy.ndarray
        Phase shift in radians.
    selection : (N,) numpy.ndarray
        Boolean array containing only ``True`` indicating that
        all secondary source are "active" for NFC-HOA.
    secondary_source_function : callable
        A function that can be used to create the sound field of a
        single secondary source.  See `sfs.td.synthesize()`.

    Examples
    --------
    .. plot::
        :context: close-figs

        delay, weight, sos, phaseshift, selection, secondary_source = \
            sfs.td.nfchoa.plane_25d(array.x, R, npw, fs)
        d = sfs.td.nfchoa.driving_signals_25d(
                delay, weight, sos, phaseshift, signal)
        plot(d, selection, secondary_source)

    """
    if max_order is None:
        max_order = _util.max_order_circular_harmonics(len(x0))
    if c is None:
        c = _default.c

    x0 = _util.asarray_of_rows(x0)
    npw = _util.asarray_1d(npw)
    phi0, _, _ = _util.cart2sph(*x0.T)
    phipw, _, _ = _util.cart2sph(*npw)
    phaseshift = phi0 - phipw + _np.pi

    delay = -r0 / c
    weight = 2
    sos = []
    for m in range(max_order + 1):
        _, p, _ = _sig.besselap(m, norm='delay')
        s_zeros = _np.zeros(m)
        s_poles = c / r0 * p
        s_gain = 1
        z_zeros, z_poles, z_gain = s2z(s_zeros, s_poles, s_gain, fs)
        sos.append(_sig.zpk2sos(z_zeros, z_poles, z_gain, pairing='nearest'))
    selection = _util.source_selection_all(len(x0))
    return (delay, weight, sos, phaseshift, selection,
            _secondary_source_point(c))
Exemplo n.º 11
0
def point_3d(x0, r0, xs, fs, max_order=None, c=None, s2z=matchedz_zpk):
    r"""Virtual point source by 3-dimensional NFC-HOA.

    .. math::

        D(\phi_0, s) =
        \frac{\e{\frac{s}{c}(r_0-r_\text{s})}}{4 \pi r_0 r_\text{s}}
        \sum_{n=0}^{N}
        (2n+1) P_{n}(\cos\Theta)
        \Big(\frac{s-\frac{c}{r_\text{s}}\sigma_0}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu
        \prod_{l=1}^{\nu}
        \frac{(s-\frac{c}{r_\text{s}}\sigma_l)^2-(\frac{c}{r_\text{s}}\omega_l)^2}
        {(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}

    The driving function is represented in the Laplace domain,
    from which the recursive filters are designed.
    :math:`\sigma_l + \i\omega_l` denotes the complex roots of
    the reverse Bessel polynomial.
    The number of second-order sections is
    :math:`\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor`,
    whereas the number of first-order section :math:`\mu` is either 0 or 1
    for even and odd :math:`|m|`, respectively.
    :math:`P_{n}(\cdot)` denotes the Legendre polynomial of degree :math:`n`,
    and :math:`\Theta` the angle between :math:`(\theta, \phi)`
    and :math:`(\theta_\text{s}, \phi_\text{s})`.

    Parameters
    ----------
    x0 : (N, 3) array_like
        Sequence of secondary source positions.
    r0 : float
        Radius of the spherial secondary source distribution.
    xs : (3,) array_like
        Virtual source position.
    fs : int
        Sampling frequency in Hertz.
    max_order : int, optional
        Ambisonics order.
    c : float, optional
        Speed of sound in m/s.
    s2z : callable, optional
        Function transforming s-domain poles and zeros into z-domain,
        e.g. :func:`matchedz_zpk`, :func:`scipy.signal.bilinear_zpk`.

    Returns
    -------
    delay : float
        Overall delay in seconds.
    weight : float
        Overall weight.
    sos : list of numpy.ndarray
        Second-order section filters :func:`scipy.signal.sosfilt`.
    phaseshift : (N,) numpy.ndarray
        Phase shift in radians.
    selection : (N,) numpy.ndarray
        Boolean array containing only ``True`` indicating that
        all secondary source are "active" for NFC-HOA.
    secondary_source_function : callable
        A function that can be used to create the sound field of a
        single secondary source.  See `sfs.td.synthesize()`.

    """
    if max_order is None:
        max_order = _util.max_order_spherical_harmonics(len(x0))
    if c is None:
        c = _default.c

    x0 = _util.asarray_of_rows(x0)
    xs = _util.asarray_1d(xs)
    phi0, theta0, _ = _util.cart2sph(*x0.T)
    phis, thetas, rs = _util.cart2sph(*xs)
    phaseshift = _np.arccos(_np.dot(x0 / r0, xs / rs))

    delay = (rs - r0) / c
    weight = 1 / r0 / rs
    sos = []
    for m in range(max_order + 1):
        _, p, _ = _sig.besselap(m, norm='delay')
        s_zeros = c / rs * p
        s_poles = c / r0 * p
        s_gain = 1
        z_zeros, z_poles, z_gain = s2z(s_zeros, s_poles, s_gain, fs)
        sos.append(_sig.zpk2sos(z_zeros, z_poles, z_gain, pairing='nearest'))
    selection = _util.source_selection_all(len(x0))
    return (delay, weight, sos, phaseshift, selection,
            _secondary_source_point(c))
Exemplo n.º 12
0
#!/usr/bin/env python3
from scipy.signal import besselap

for n in range(1, 26):
    [zs, ps, k] = besselap(n)
    if (n == 1):
        print("    if (n == 1)\n    {")
    else:
        print("    }\n    else if (n == %d)\n    {" % (n))
    i = 0
    for p in ps:
        #print "        p[%d] = %.16f + %.16f*_Complex_I;"%(i,p.real,p.imag)
        print("        poles[%d] = std::complex<double> (%.18f, %.18f);" %
              (i, p.real, p.imag))
        i = i + 1
print("    }")
Exemplo n.º 13
0
filter_names.append('Butter_ord_' + str(order2analyze))

# Chebyshev

z, p, k = sig.cheb1ap(order2analyze, ripple)

num, den = sig.zpk2tf(z, p, k)

all_sys.append(sig.TransferFunction(num, den))

filter_names.append('Cheby_ord_' + str(order2analyze))

# Bessel

z, p, k = sig.besselap(order2analyze, norm='delay')

num, den = sig.zpk2tf(z, p, k)

all_sys.append(sig.TransferFunction(num, den))

filter_names.append('Bessel_ord_' + str(order2analyze))

# Cauer

# z,p,k = sig.ellipap(order2analyze, ripple, attenuation)

# num, den = sig.zpk2tf(z,p,k)

# all_sys.append(sig.TransferFunction(num,den))
    
    NUM, DEN = sig.zpk2tf (z, p, k)
    NUM, DEN = sig.lp2lp ( NUM, DEN, wb )
    
    z, p, k = sig.tf2zpk ( NUM, DEN ) 
    
    
elif (aprox_name == 'Chebyshev1'):
    
    # Le paso Orden y ripple (alfa_máx)
    z, p, k = sig.cheb1ap (order_filter, ripple_) 
    
    
elif (aprox_name == 'Bessel'):
    
    z, p, k = sig.besselap ( order_filter, norm = 'mag' )
    
    
else:
    
    sys.exit(' No Existe esa Aproximación o Está mal Escrita.')
    

# Genero el Numerador y Denominador de mi Transferencia
NUM, DEN = sig.zpk2tf(z, p, k)

my_tf = tf ( NUM, DEN ) # Genero mi Transferencia


# Ploteo.
bodePlot (my_tf)
Exemplo n.º 15
0
    if force_order <= 0:
        print_console_alert(aprox_name + ': parameters calculated')
        print(
            'Chebyshev type 2 (equiripple in band-stop) order n = {:d}'.format(
                this_order))

elif aprox_name == 'Bessel':

    if force_order > 0:
        this_order = force_order
    else:
        this_order = besselord(omega_p, omega_s, alfa_max, alfa_min, omega_d,
                               max_pc_delay)

    z, p, k = sig.besselap(this_order, norm='delay')

    if force_order <= 0:
        print_console_alert(aprox_name + ': parameters calculated')
        print('order n = {:d}'.format(this_order))

elif aprox_name == 'Cauer':

    if force_order > 0:
        this_order = force_order
    else:
        this_order, _ = sig.ellipord(omega_p,
                                     omega_s,
                                     alfa_max,
                                     alfa_min,
                                     analog=True)