Esempio n. 1
0
def shaper(shape,
           order,
           peaktime,
           dt=1E-9,
           pz=0.0,
           normalize=True,
           return_zpk=False,
           bipolar=False):
    if shape == 'gaussian':
        f = gaussian_shaper
    elif shape == 'crrc':
        f = crrc_shaper
    else:
        raise ValueError('specified shaper shape not supported')
    dzpk, azpk = f(order, peaktime, dt=dt, pz=pz)
    zeros, poles, gain = dzpk
    if bipolar:
        zeros = np.append(zeros, [1])

    if normalize:
        sos = signal.zpk2sos(zeros, poles, 1)
        t = np.arange(-1 * peaktime, 2 * peaktime, dt)
        tail = np.zeros_like(t)
        tail[t > 0] = np.exp(-t[t > 0] * pz)
        ytail = signal.sosfilt(sos, tail)
        gain = 1. / np.max(ytail)
        sos = signal.zpk2sos(zeros, poles, gain)
        dzpk = zeros, poles, gain
    else:
        sos = signal.zpk2sos(*dzpk)

    if return_zpk:
        return sos, dzpk, azpk
    else:
        return sos
Esempio n. 2
0
 def bandpass(self, data):
     # raise for some bad scenarios
     if self.high - 1.0 > -1e-6:
         msg = ("Selected high corner frequency ({}) of bandpass is at or "
                "above Nyquist ({}). Applying a high-pass instead.").format(
                    self.freqmax, self.fe)
         logger.warning(msg)
         #warnings.warn(msg)
         return highpass(data,
                         freq=self.freqmin,
                         df=self.sampling_rate,
                         corners=self.corners,
                         zerophase=self.zerophase)
     if self.low > 1:
         msg = "Selected low corner frequency is above Nyquist."
         raise ValueError(msg)
     if self.zi is None:
         z, p, k = iirfilter(self.corners, [self.low, self.high],
                             btype='bandpass',
                             ftype='butter',
                             output='zpk')
         self.sos = zpk2sos(z, p, k)
         self.zi = sosfilt_zi(self.sos)
     data, self.zi = sosfilt(self.sos, data, zi=self.zi)
     return data
Esempio n. 3
0
 def _butter_bandpass(self, lowcut, highcut, fs, order):
     nyq = 0.5 * fs
     low = lowcut / nyq
     high = highcut / nyq
     z, p, k = butter(order, [low, high], btype='bandpass', output='zpk')
     sos = zpk2sos(z, p, k)
     return sos
Esempio n. 4
0
def cheby_bandpass(data, cutoff, fs, Rs = 100):
    """
    cheby_bandpass(data, flow, fhigh, fs, , Rs = 100)

    Parameters
    ----------
    data :  1d ndarray, signal 
    cutoff : List [lowcut = Float, low bound frequency limit,  highcut = Float, upper bound frequency limit]
    fs : Int, sampling rate
    Rs: Int, stopband attenuation in Db, Optional, Default value = 100.

    Returns
    -------
    y : 1d ndarray, filtered signal 

    """
    flow = cutoff[0]; fhigh = cutoff[1]  
    Fn = fs/2                                          # Nyquist Frequency (Hz)
    Wp = [flow/Fn,   fhigh/Fn]                         # Passband Frequency (Normalised)
    Ws = [(flow-1)/Fn,   (fhigh+1)/Fn]                 # Stopband Frequency (Normalised)
    Rp = 1                                             # Passband Ripple (dB)
    Rs = 100     
    
    # Get Filter Order
    n, Ws = cheb2ord(Wp,Ws,Rp,Rs);
    
    # Design Filter
    z,p,k = cheby2(n,Rs,Ws,btype = 'bandpass', analog=False, output='zpk')
    
    # Convert to second order sections
    sos = zpk2sos(z,p,k); 
    
    # filter data
    y = sosfiltfilt(sos,data)
    return y    
Esempio n. 5
0
def generate_noise(fs=1024, f1=15, f2=100, amplify=1):
    bg_raw = np.random.randn(1000)

    # f1 and f2 is a bandpass
    sosBP1 = sig.butter(8, [f1 / (fs / 2), f2 / (fs / 2)],
                        btype='bandpass',
                        output='sos')

    # invertable band pass
    fz = [4, 400]
    fp = [15, 20, 150]

    _, z0, _ = sig.butter(10, fz[0] / (fs / 2), btype='lowpass', output='zpk')
    _, p0, _ = sig.butter(8, fp[0] / (fs / 2), btype='lowpass', output='zpk')
    _, p1, _ = sig.butter(1, fp[1] / (fs / 2), btype='lowpass', output='zpk')
    _, p2, _ = sig.butter(3, fp[1] / (fs / 2), btype='lowpass', output='zpk')
    _, z1, _ = sig.butter(2, fz[1] / (fs / 2), btype='lowpass', output='zpk')

    zs = np.concatenate((z0, z1))
    ps = np.concatenate((p0, p1))
    BP = sig.zpk2sos(zs, ps, 1, pairing='keep_odd')
    sosBP = np.concatenate([sosBP1, BP], axis=0)

    # filter the data using many second-order-sections
    bg = sig.sosfilt(sosBP, bg_raw) * amplify
    return bg
Esempio n. 6
0
def butter_highpass(data, cutoff, fs, order = 5):
    """
    butter_highpass(data, cutoff, fs, order = 5)

    Parameters
    ----------
    data : 1d ndarray, signal 
    cutoff : Float, cutoff frequency
    fs : Int, sampling rate
    order : Int, filter order. The default is 5.

    Returns
    -------
    y : 1d ndarray, filtered signal 

    """
    nyq = 0.5 * fs               # Nyquist Frequency (Hz)
    normal_cutoff = cutoff[0] / nyq # Low-bound Frequency (Normalised)
    
    # Design filter
    z,p,k = butter(order, normal_cutoff, btype='high', analog=False, output ='zpk') 
    
    sos = zpk2sos(z,p,k)         # Convert to second order sections
    y = sosfiltfilt(sos, data)   # Filter data
    return y
Esempio n. 7
0
    def add_antialias(self,Fs,freq,maxorder=8):
        # From obspy
        nyquist = Fs * 0.5
        
        # rp - maximum ripple of passband, rs - attenuation of stopband
        rp, rs, order = 1, 96, 1e99
        ws = freq / nyquist  # stop band frequency
        wp = ws  # pass band frequency
        # raise for some bad scenarios
        if ws > 1:
            ws = 1.0
            msg = "** Selected corner frequency is above Nyquist. " + \
                  "** Setting Nyquist as high corner."
            warnings.warn(msg)
        while True:
            if order <= maxorder:
                break
            wp = wp * 0.99
            order, wn = cheb2ord(wp, ws, rp, rs, analog=0)
        
        z, p, k = cheby2(order, rs, wn, 
            btype='low', analog=0, output='zpk')

        self.anti_alias = zpk2sos(z,p,k)
        return()
Esempio n. 8
0
def lowpass(freq, df, corners=4):
    """
    Butterworth-Lowpass Filter.

    Filter data removing data over certain frequency ``freq`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freq: Filter corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the number of corners but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    f = freq / fe
    # raise for some bad scenarios
    if f > 1:
        f = 1.0
        msg = "Selected corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    z, p, k = iirfilter(corners, f, btype='lowpass', ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    return sos
Esempio n. 9
0
def bandpass_in_time_domain_sos(data,
                                freqmin=0.01,
                                freqmax=1.0,
                                sample_rate=0.5,
                                order=2,
                                axis=-1,
                                taper=None,
                                zerophase=True,
                                **kwargs):
    fe = 0.5 * sample_rate
    low = freqmin / fe
    high = freqmax / fe
    # raise for some bad scenarios
    if high - 1.0 > -1e-6:
        print("freqmax ({}) of bandpass is at or above Nyquist ({}). Ignoring."
              ).format(freqmax, fe)
        return data

    if low > 1:
        print(
            "Selected freqmin ({}) is above Nyquist. Ignoring".format(freqmin))
        return data
    z, p, k = iirfilter(order, [low, high],
                        btype='band',
                        ftype='butter',
                        output='zpk')  #,fs=sample_rate)
    sos = zpk2sos(z, p, k)
    if zerophase:
        result = sosfilt(sos, data)
        return np.flip(sosfilt(sos, np.flip(result, axis=axis)), axis=axis)
    else:
        return sosfilt(sos, data, axis=axis)
Esempio n. 10
0
def lowpass(freq, df, corners=4):
    """
    Butterworth-Lowpass Filter.

    Filter data removing data over certain frequency ``freq`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freq: Filter corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the number of corners but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    f = freq / fe
    # raise for some bad scenarios
    if f > 1:
        f = 1.0
        msg = "Selected corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    z, p, k = iirfilter(corners,
                        f,
                        btype='lowpass',
                        ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    return sos
def low_pass_filter(source, sr, cutoff_freq, order):
    """Function that takes an 1D array as an argument and returns the filtered 
    signal following the application of a low pass filter with a cutoff frequency = cutoff_freq and
    order = order
    
    Args :      source (np.array) = The signal to be filtered
                sr (int) = The sampling rate of the signal
                cutoff_freq (int) = the cutoff frequency of the lowpass filter
                order (int) = the order of the lowpass filter
                
    
    Returns :   sink (np.array) = The centered moving average of the input signal
    """
    
    for name, arg in zip(("sr", "cutoff_freq", "order"), (sr, cutoff_freq, order)):
        
        if not isinstance(arg, int):
            raise RuntimeError("The argument {0} is of incorrect type. Input : {1}, Requiered : int"
                               .format(name, type(arg)))
    
    source = np.array(source)
    
    if len(source.shape) == 1:
        nyq = sr / 2  # The nyquist frequency
        normalized_cutoff = cutoff_freq / nyq
        
        z, p, k = signal.butter(order, normalized_cutoff, output="zpk")
        lesos = signal.zpk2sos(z, p, k)
        filtered = signal.sosfilt(lesos, source)
        sink = np.array(filtered)
        
        return sink
    else:
        raise RuntimeError("The input array has too many dimensions. Input : {0}D, Requiered : 1D"
                           .format(len(source.shape)))
Esempio n. 12
0
def bandstop(data, freqmin, freqmax, df, corners=4, zerophase=False):
    """
    Butterworth-Bandstop Filter.

    Filter data removing data between frequencies ``freqmin`` and ``freqmax``
    using ``corners`` corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    Parameters
    ----------
    data : array
        Data to filter.

    freqmin : float 
        Stop band low corner frequency.
    
    freqmax : float
        Stop band high corner frequency.
    
    df : float
        Sampling rate in Hz.
    
    corners : int
        Filter corners / order.
        **Default:** ``4``

    zerophase : bool
        If True, apply filter once forwards and once backwards. This results in twice the filter order but zero phase shift in the resulting filtered trace.
        **Default:** ``False``

    Returns
    -------
    data : array
        Filtered data.
        
    """

    fe = 0.5 * df
    low = freqmin / fe
    high = freqmax / fe
    # raise for some bad scenarios
    if high > 1:
        high = 1.0
        msg = "Selected high corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    if low > 1:
        msg = "Selected low corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, [low, high],
                        btype='bandstop',
                        ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 13
0
def butter_bandpass(data, cutoff, fs, order = 10):
    """
    butter_bandpass(data, cutoff, fs, order = 10)

    Parameters
    ----------
    data : 1d ndarray, signal 
    cutoff : List [lowcut = Float, low bound frequency limit,  highcut = Float, upper bound frequency limit]
    fs : Int, sampling rate
    order : Int, filter order. The default is 5.

    Returns
    -------
    y : 1d ndarray, filtered signal 

    """
    nyq = 0.5 * fs                      # Nyquist Frequency (Hz)
    low = cutoff[0] / nyq                  # Low-bound Frequency (Normalised)
    high = cutoff[1] / nyq                # Upper-bound Frequency (Normalised)
    
    # Design filter
    z,p,k = butter(order, [low, high], btype='band', analog=False, output ='zpk')
    
    # Convert to second order sections
    sos = zpk2sos(z,p,k) 
    
    # Filter data
    y = sosfiltfilt(sos, data)
    return y
Esempio n. 14
0
def highpass(data, freq, df, corners=4, zerophase=False):
    """
    Butterworth-Highpass Filter.

    Filter data removing data below certain frequency ``freq`` using
    ``corners`` corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freq: Filter corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the number of corners but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    f = freq / fe
    # raise for some bad scenarios
    if f > 1:
        msg = "Selected corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, f, btype='highpass', ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 15
0
def _design_iir(wp,
                ws,
                sample_rate,
                gpass,
                gstop,
                analog=False,
                ftype='cheby1',
                output='zpk'):
    nyq = sample_rate / 2.
    wp = atleast_1d(wp)
    ws = atleast_1d(ws)
    if analog:
        wp *= TWO_PI
        ws *= TWO_PI
    else:
        wp /= nyq
        ws /= nyq
    z, p, k = signal.iirdesign(wp,
                               ws,
                               gpass,
                               gstop,
                               analog=analog,
                               ftype=ftype,
                               output='zpk')
    if analog:
        z /= -TWO_PI
        p /= -TWO_PI
    if output == 'zpk':
        return z, p, k
    elif output == 'ba':
        return signal.zpk2tf(z, p, k)
    elif output == 'sos':
        return signal.zpk2sos(z, p, k)
    else:
        raise ValueError("'%s' is not a valid output form." % output)
Esempio n. 16
0
def bandpass(data, freq_min, freq_max, sample_frequency, corners=4):
    """
    Zero-Phase Butterworth-Bandpass Filter.

    Filter data from ``freqmin`` to ``freqmax`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freqmin: Pass band low corner frequency.
    :param freqmax: Pass band high corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :return: Filtered data.
    """
    nyquist = 0.5 * sample_frequency
    low = freq_min / nyquist
    high = freq_max / nyquist

    zeroes, poles, gain = iirfilter(corners, [low, high],
                                    btype='band',
                                    ftype='butter',
                                    output='zpk')
    sos = zpk2sos(zeroes, poles, gain)

    firstpass = sosfilt(sos, data)
    return sosfilt(sos, firstpass[::-1])[::-1]
Esempio n. 17
0
def band_stop(ite_data,
              freqmin,
              freqmax,
              samp_freq,
              corners=4,
              zerophase=True):
    fe = samp_freq / 2.0
    low = freqmin / fe
    high = freqmax / fe
    # raise error for illegal input
    if high - 1.0 > -1e-6:
        msg = (
            "Selected high corner frequency ({}) of bandpass is at or above Nyquist ({}). Applying a high-pass instead."
        ).format(freqmax, fe)
        return False
    if low > 1:
        msg = "selected low corner requency is above Nyquist"
        return False

    z, p, k = signal.iirfilter(corners, [low, high],
                               btype='bandstop',
                               ftype='butter',
                               output='zpk')
    sos = zpk2sos(z, p, k)
    ite_data = sosfilt(sos, ite_data)
    if zerophase:
        ite_data = sosfilt(sos, ite_data[::-1])[::-1]
    return ite_data
Esempio n. 18
0
def highpass(data, freq, df, corners=4, zerophase=False):
    """
    Butterworth-Highpass Filter.

    Filter data removing data below certain frequency ``freq`` using
    ``corners`` corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freq: Filter corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the number of corners but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    f = freq / fe
    # raise for some bad scenarios
    if f > 1:
        msg = "Selected corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, f, btype='highpass', ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 19
0
def stream_filter_bessel(stream,
                         center_freq,
                         gamma=0.5,
                         corners=4,
                         zerophase=False):
    filtered_stream = obspy.Stream()
    for tr in stream.copy():
        fe = 0.5 * tr.stats.sampling_rate

        freqmin = center_freq - (gamma * center_freq)
        freqmax = center_freq + (gamma * center_freq)

        low = freqmin / fe
        high = freqmax / fe
        z, p, k = signal.iirfilter(corners, [low, high],
                                   btype='bandpass',
                                   ftype='bessel',
                                   output='zpk')
        sos = signal.zpk2sos(z, p, k)

        if zerophase:
            first_pass = signal.sosfilt(sos, tr.data)
            second_pass = signal.sosfilt(sos, first_pass[::-1])[::-1]
            tr.data = second_pass
            filtered_stream += tr
        else:
            filtered_data = signal.sosfilt(sos, tr.data)
            tr.data = filtered_data
            filtered_stream += tr

    return filtered_stream
Esempio n. 20
0
def _design_iir(wp, ws, sample_rate, gpass, gstop,
                analog=False, ftype='cheby1', output='zpk'):
    # pylint: disable=invalid-name
    nyq = sample_rate / 2.
    wp = numpy.atleast_1d(wp)
    ws = numpy.atleast_1d(ws)
    if analog:  # convert Hz to rad/s
        wp *= TWO_PI
        ws *= TWO_PI
    else:  # convert Hz to half-cycles / sample
        wp /= nyq
        ws /= nyq
    z, p, k = signal.iirdesign(wp, ws, gpass, gstop, analog=analog,
                               ftype=ftype, output='zpk')
    if analog:  # convert back to Hz
        z /= -TWO_PI
        p /= -TWO_PI
        k *= TWO_PI ** z.size / -TWO_PI ** p.size
    if output == 'zpk':
        return z, p, k
    elif output == 'ba':
        return signal.zpk2tf(z, p, k)
    elif output == 'sos':
        return signal.zpk2sos(z, p, k)
    else:
        raise ValueError("'%s' is not a valid output form." % output)
Esempio n. 21
0
def bandpass(data, fs, fl, fh, order=None, axis=-1):
    """ Apply Butterworth bandpass filter using scipy.signal.sosfiltfilt method
    Parameters
    ----------
    data: array
    fs: sampling frequency
    fl, fh: low and high frequency for bandpass
    axis: axis to apply the filter on 
    
    Returns:
    --------
    data_filt: filtered array 
    """
    if order is None:
        order = 8
        
    # Make filter
    nyq = fs/2.
    low, high = fl/nyq, fh/nyq  # normalize frequency
    z, p, k = sig.butter(order, [low, high], btype='bandpass', output='zpk')
    sos = sig.zpk2sos(z, p, k)

    # Apply filter and return output
    data_filt = sig.sosfiltfilt(sos, data, axis=axis)
    return data_filt
Esempio n. 22
0
def highpass(rawData, samplFreq, highpassCutOff):
    #This function high passes the data with sampling frequency samplFreq with a highpass
    # cut off of highpassCutOff
    #
    # Usage: [highPassedData] = highpass(rawData, samplFreq, highpassCutOff)
    #
    # rawData : raw time series Data
    # samplFreq: sampling Frequency of Data
    # highpassCutOff: The high pass frequency cut off.
    #
    numberOfChannels = len(rawData)
    dataLength = len(rawData[0])
    duration = dataLength / samplFreq

    halfDataLength = dataLength / 2 + 1

    for channelNumber in xrange(numberOfChannels):
        if (len(rawData[channelNumber]) != dataLength):
            sys.exit('Data length not consistent\n')

    nyquistFrequency = samplFreq / 2.0

    lpefOrder = 0

    if (highpassCutOff > 0):
        hpfOrder = 12
        hpfZeros, hpfPoles, hpfGain = sig.butter(hpfOrder,
                                                 highpassCutOff /
                                                 nyquistFrequency,
                                                 btype='highpass',
                                                 output='zpk')
        hpfSOS = sig.zpk2sos(hpfZeros, hpfPoles, hpfGain)

        #magnitude response of high pass filter
        minimumFrequencyStep = 1.0 / duration
        frequencies = np.arange(0, nyquistFrequency, minimumFrequencyStep)
        hpfArgument = np.power((frequencies / highpassCutOff), 2 * hpfOrder)
        hpfResponse = hpfArgument / (1 + hpfArgument)

        highPassCutOffIndex = np.ceil(highpassCutOff / minimumFrequencyStep)

    highPassedData = []
    for channelNumber in xrange(numberOfChannels):
        if (highpassCutOff > 0):
            x = sig.sosfilt(hpfSOS, rawData[channelNumber])
            x = np.flipud(x)
            x = sig.sosfilt(hpfSOS, x)
            x = np.flipud(x)
        else:
            x = rawData[channelNumber]

        x[0:lpefOrder] = np.zeros(lpefOrder)
        x[dataLength - lpefOrder:dataLength - 1] = np.zeros(lpefOrder)

        highPassedData.append(x)

    highPassedData = np.asarray(highPassedData)

    return highPassedData
Esempio n. 23
0
def chebyBandpassFilter(data, cutoff, gstop=40, gpass=1, fs=2048.):
    """
    Design a filter with scipy functions avoiding unstable results (when using
    ab output and filtfilt(), lfilter()...).
    Cf. ()[]

    Parameters
    ----------
    data : instance of numpy.array | instance of pandas.core.DataFrame
        Data to be filtered. Each column will be filtered if data is a
        dataframe.
    cutoff : array-like of float
        Pass and stop frequencies in order:
            - the first element is the stop limit in the lower bound
            - the second element is the lower bound of the pass-band
            - the third element is the upper bound of the pass-band
            - the fourth element is the stop limit in the upper bound
        For instance, [0.9, 1, 45, 48] will create a band-pass filter between
        1 Hz and 45 Hz.
    gstop : int
        The minimum attenuation in the stopband (dB).
    gpass : int
        The maximum loss in the passband (dB).

    Returns:

    zpk :

    filteredData : instance of numpy.array | instance of pandas.core.DataFrame
        The filtered data.
    """

    wp = [cutoff[1] / (fs / 2), cutoff[2] / (fs / 2)]
    ws = [cutoff[0] / (fs / 2), cutoff[3] / (fs / 2)]

    z, p, k = iirdesign(wp=wp,
                        ws=ws,
                        gstop=gstop,
                        gpass=gpass,
                        ftype='cheby2',
                        output='zpk')
    zpk = [z, p, k]
    sos = zpk2sos(z, p, k)

    order, Wn = cheb2ord(wp=wp, ws=ws, gstop=gstop, gpass=gpass, analog=False)
    print 'Creating cheby filter of order %d...' % order

    if (data.ndim == 2):
        print 'Data contain multiple columns. Apply filter on each columns.'
        filteredData = np.zeros(data.shape)
        for electrode in range(data.shape[1]):
            # print 'Filtering electrode %s...' % electrode
            filteredData[:, electrode] = sosfiltfilt(sos, data[:, electrode])
    else:
        # Use sosfiltfilt instead of filtfilt fixed the artifacts at the beggining
        # of the signal
        filteredData = sosfiltfilt(sos, data)
    return zpk, filteredData
Esempio n. 24
0
    def test_filter(self, losc):
        zpk = [], [], 1
        fts = losc.filter(zpk, analog=True)
        utils.assert_quantity_sub_equal(losc, fts)

        # check SOS filters can be used directly
        zpk = filter_design.highpass(50, sample_rate=losc.sample_rate)
        sos = signal.zpk2sos(*zpk)
        utils.assert_quantity_almost_equal(losc.filter(zpk), losc.filter(sos))
Esempio n. 25
0
def highpass(rawData, samplFreq, highpassCutOff):
  #This function high passes the data with sampling frequency samplFreq with a highpass
  # cut off of highpassCutOff
  #
  # Usage: [highPassedData] = highpass(rawData, samplFreq, highpassCutOff)
  # 
  # rawData : raw time series Data
  # samplFreq: sampling Frequency of Data
  # highpassCutOff: The high pass frequency cut off.
  #
  numberOfChannels = len(rawData)
  dataLength = len(rawData[0])
  duration = dataLength/samplFreq
  
  
  halfDataLength = dataLength/2 + 1
  
  for channelNumber in xrange(numberOfChannels):
    if(len(rawData[channelNumber]) != dataLength):
      sys.exit('Data length not consistent\n')
  
  nyquistFrequency = samplFreq/2.0
  
  lpefOrder  = 0
  
  if(highpassCutOff>0):
    hpfOrder = 12
    hpfZeros, hpfPoles, hpfGain = sig.butter(hpfOrder, highpassCutOff/nyquistFrequency, btype = 'highpass', output = 'zpk' )
    hpfSOS = sig.zpk2sos(hpfZeros, hpfPoles, hpfGain)
    
    #magnitude response of high pass filter
    minimumFrequencyStep = 1.0/duration
    frequencies = np.arange(0, nyquistFrequency, minimumFrequencyStep)
    hpfArgument = np.power((frequencies / highpassCutOff), 2*hpfOrder)
    hpfResponse = hpfArgument/(1 + hpfArgument)
    
    highPassCutOffIndex = np.ceil(highpassCutOff/minimumFrequencyStep)
  
  highPassedData = []
  for channelNumber in xrange(numberOfChannels):
    if(highpassCutOff>0):
      x = sig.sosfilt(hpfSOS, rawData[channelNumber])
      x = np.flipud(x)
      x = sig.sosfilt(hpfSOS, x)
      x = np.flipud(x)
    else:
      x = rawData[channelNumber]
    
    x[0:lpefOrder] = np.zeros(lpefOrder)
    x[dataLength - lpefOrder:dataLength-1] = np.zeros(lpefOrder)
    
    highPassedData.append(x)
  
  highPassedData = np.asarray(highPassedData)
  
  return highPassedData
Esempio n. 26
0
def butter_bandstop_filter(lowcut, highcut, fs, order):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq

    z, p, k = butter(order, [low, high], btype='bandstop', output='zpk')
    assert np.all(np.abs(p) < 1), 'unstable filter'
    sos = zpk2sos(z, p, k)
    #     sos = iirdesign([low-0.01, high+0.01], [low+0.01, high-0.01], 3, 40, output='sos')
    return sos
Esempio n. 27
0
def iir_band_filter(ite_data,
                    fs,
                    btype,
                    ftype,
                    order=None,
                    Quality=None,
                    window=None,
                    lowcut=None,
                    highcut=None,
                    zerophase=None,
                    rps=None):
    fe = fs / 2.0
    if not lowcut == '' and not highcut == '':
        wn = [lowcut / fe, highcut / fe]
    elif not lowcut == '':
        wn = lowcut / fe
    elif not highcut == '':
        wn = highcut / fe

    if rps[0] == '':
        rps[0] = 10
    if rps[1] == '':
        rps[1] = 10

    if btype in ["butter", "bessel", "cheby1", "cheby2", "ellip"]:
        z, p, k = signal.iirfilter(order,
                                   wn,
                                   btype=ftype,
                                   ftype=btype,
                                   output="zpk",
                                   rp=rps[0],
                                   rs=rps[1])
        try:
            sos = signal.zpk2sos(z, p, k)
            ite_data = signal.sosfilt(sos, ite_data)
            if zerophase:
                ite_data = signal.sosfilt(sos, ite_data[::-1])[::-1]
        except:
            print('A filter had an issue: ', 'btype', btype, 'ftype', ftype,
                  'order', order, 'Quality', Quality, 'window', window,
                  'lowcut', lowcut, 'highcut', highcut, 'rps', rps)
    elif btype == "iirnotch":
        b, a = signal.iirnotch(lowcut, Quality, fs)
        y = signal.filtfilt(b, a, ite_data)
    elif btype == "Moving average":
        z2 = np.cumsum(np.pad(ite_data, ((window, 0)),
                              'constant',
                              constant_values=0),
                       axis=0)
        z1 = np.cumsum(np.pad(ite_data, ((0, window)),
                              'constant',
                              constant_values=ite_data[-1]),
                       axis=0)
        ite_data = (z1 - z2)[(window - 1):-1] / window
    return ite_data
Esempio n. 28
0
def preprocessEEG(eeg,
                  fs,
                  eogChannels=None,
                  badChannels=None,
                  hpCutoff=0.5,
                  stdThresh=4):
    """

    Preprocess EEG data and return data that has been filtered with bad channels removed.

    Input:
       eeg          - ndarray of samples x channels (TxD)
       fs           - sampling rate in Hz
       eogChannels  - list/tuple of which channels in EEG are EOG (Default = None)
       badChannels  - list/tuple of channels in EEG to remove (Default = None)
       hpCutoff     - cutoff of the high-pass filter in Hz (Default = 0.5 Hz)
       stdThresh    - # of standard deviations to tolerate before marking sample outlier (Default = 4)

    """

    z, p, k = sig.butter(5, hpCutoff / fs * 2, 'highpass', output='zpk')

    sos = sig.zpk2sos(z, p, k)

    T, D = eeg.shape

    eeg = eeg - np.concatenate([eeg[[0], :]
                                for i in range(T)])  # remove starting offset

    eeg = sig.sosfilt(sos, eeg)  # apply high-pass filtering

    if eogChannels is not None:
        eeg = eeg - np.dot(eeg[:, eogChannels],
                           lin.lstsq(eeg[:, eogChannels],
                                     eeg)[0])  # regress out EOG data
        eeg = np.delete(eeg, eogChannels, axis=1)

    # detect outliers > stdThresh
    stdThresh = stdThresh * np.std(eeg, 0)
    stdThresh = np.stack([stdThresh for _ in range(T)], axis=0)

    eeg[np.nonzero(np.abs(eeg) > stdThresh)] = 0  # remove outliers

    h = np.zeros(int(np.around(fs * 0.04)))

    h[0] = 1

    eeg = sig.lfilter(h, 1, np.flipud(sig.lfilter(h, 1, np.flipud(eeg))))

    eeg[np.isnan(eeg)] = 0.0

    if badChannels is not None:
        eeg[:, badChannels] = 0  # zero out bad channels

    return eeg
Esempio n. 29
0
def filter_from_npz(filename, fs):
    with np.load(filename) as data:
        z = data['z']
        p = data['p']
        k = data['k']

    #sos conversion
    zd, pd, kd = zpk_bilinear(z, p, k, fs)
    sys_disc = sig.ZerosPolesGain(zd, pd, kd, dt=1 / fs)
    sos = sig.zpk2sos(sys_disc.zeros, sys_disc.poles, sys_disc.gain)
    return sos
Esempio n. 30
0
def lowpass(data, freq, df, corners=4, zerophase=False):
    """
    Butterworth-Lowpass Filter.

    Filter data removing data over certain frequency ``freq`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    Parameters
    ----------
    data : array
        Data to filter.

    freq : float 
        Filter corner frequency.
    
    df : float
        Sampling rate in Hz.
    
    corners : int
        Filter corners / order.
        **Default:** ``4``

    zerophase : bool
        If True, apply filter once forwards and once backwards. This results in twice the filter order but zero phase shift in the resulting filtered trace.
        **Default:** ``False``

    Returns
    -------
    data : array
        Filtered data.

    """

    fe = 0.5 * df
    f = freq / fe
    # raise for some bad scenarios
    if f > 1:
        f = 1.0
        msg = "Selected corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    z, p, k = iirfilter(corners,
                        f,
                        btype='lowpass',
                        ftype='butter',
                        output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 31
0
def lowpass_filter(data, SRD, freq, order):
    sampling_rate = SRD
    nyq = sampling_rate / 2
    cutoff = freq
    normalized_cutoff = cutoff / nyq

    z, p, k = signal.butter(order, normalized_cutoff, output="zpk")
    lesos = signal.zpk2sos(z, p, k)
    filtered = signal.sosfilt(lesos, data)
    filtered = np.array(filtered)

    return filtered
Esempio n. 32
0
def band_pass_filter(data, minfreq = 0.5, maxfreq = 0.8, df = 4, corners = 4):

    fe = 0.5 * df
    low = minfreq / fe
    high = maxfreq / fe

    z, p, k = sig.iirfilter(corners, [low, high], btype='band',
                        ftype='butter', output='zpk')
    sos = sig.zpk2sos(z, p, k)


    return sig.sosfilt(sos, data)
Esempio n. 33
0
def cost_filter(fs, zeros, poles, zero_order, pole_order):
    s_zeros = []
    s_poles = []

    if sum(zero_order) != sum(pole_order):
        raise ValueError('Bandpass not invertible!')

    for ii, fz in enumerate(zeros):
        _, sz, _ = sig.butter(zero_order[ii], fz / (fs / 2), output='zpk')
        s_zeros.append(sz)

    for ii, fp in enumerate(poles):
        _, sp, _ = sig.butter(pole_order[ii], fp / (fs / 2), output='zpk')
        s_poles.append(sp)

    s_zeros = np.concatenate(s_zeros)
    s_poles = np.concatenate(s_poles)
    BP = sig.zpk2sos(s_zeros, s_poles, 1, pairing='keep_odd')
    invBP = sig.zpk2sos(s_poles, s_zeros, 1, pairing='keep_odd')

    return BP, invBP
Esempio n. 34
0
 def test_equivalence(self):
     x = np.random.RandomState(0).randn(1000)
     for order in range(1, 6):
         zpk = signal.butter(order, 0.35, output="zpk")
         b, a = signal.zpk2tf(*zpk)
         sos = signal.zpk2sos(*zpk)
         y = signal.filtfilt(b, a, x)
         y_sos = sosfiltfilt(sos, x)
         np.testing.assert_allclose(y,
                                    y_sos,
                                    atol=1e-12,
                                    err_msg=f"order={order}")
Esempio n. 35
0
def zpk2sos_quant(discrete_system, Qformat):
    sos = signal.zpk2sos(*discrete_system, pairing='nearest')
    
    # Trick for higher accuracy on small numerator coefficients
    non_zeros = sos[0,:3] > 0
    b_factor = np.prod(sos[0,:3][non_zeros]) ** (1/non_zeros.sum())
    sos[0,:3] /= b_factor
    sos[:,:3] *= b_factor ** (1/sos.shape[0])

    sos_quant = quantizer_real(sos, Qformat)

    return sos, sos_quant
Esempio n. 36
0
    def test_filter(self, losc):
        zpk = [], [], 1
        fts = losc.filter(zpk, analog=True)
        utils.assert_quantity_sub_equal(losc, fts)

        # check SOS filters can be used directly
        zpk = filter_design.highpass(50, sample_rate=losc.sample_rate)
        try:
            sos = signal.zpk2sos(*zpk)
        except AttributeError:  # scipy < 0.16
            pass
        else:
            utils.assert_quantity_almost_equal(losc.filter(zpk),
                                               losc.filter(sos))
Esempio n. 37
0
def A_weighting(fs, output='ba'):
    """
    Design of a digital A-weighting filter.

    Designs a digital A-weighting filter for
    sampling frequency `fs`.
    Warning: fs should normally be higher than 20 kHz. For example,
    fs = 48000 yields a class 1-compliant filter.

    Parameters
    ----------
    fs : float
        Sampling frequency
    output : {'ba', 'zpk', 'sos'}, optional
        Type of output:  numerator/denominator ('ba'), pole-zero ('zpk'), or
        second-order sections ('sos'). Default is 'ba'.

    Examples
    --------
    Plot frequency response

    >>> from scipy.signal import freqz
    >>> import matplotlib.pyplot as plt
    >>> fs = 200000
    >>> b, a = A_weighting(fs)
    >>> f = np.logspace(np.log10(10), np.log10(fs/2), 1000)
    >>> w = 2*pi * f / fs
    >>> w, h = freqz(b, a, w)
    >>> plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h)))
    >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
    >>> plt.axis([10, 100e3, -50, 20])

    Since this uses the bilinear transform, frequency response around fs/2 will
    be inaccurate at lower sampling rates.
    """
    z, p, k = ABC_weighting('A')

    # Use the bilinear transformation to get the digital filter.
    z_d, p_d, k_d = _zpkbilinear(z, p, k, fs)

    if output == 'zpk':
        return z_d, p_d, k_d
    elif output in {'ba', 'tf'}:
        return zpk2tf(z_d, p_d, k_d)
    elif output == 'sos':
        return zpk2sos(z_d, p_d, k_d)
    else:
        raise ValueError("'%s' is not a valid output form." % output)
Esempio n. 38
0
def lowpass_cheby_2(data, freq, df, maxorder=12, ba=False,
                    freq_passband=False):
    """
    Cheby2-Lowpass Filter

    Filter data by passing data only below a certain frequency.
    The main purpose of this cheby2 filter is downsampling.
    #318 shows some plots of this filter design itself.

    This method will iteratively design a filter, whose pass
    band frequency is determined dynamically, such that the
    values above the stop band frequency are lower than -96dB.

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freq: The frequency above which signals are attenuated
        with 95 dB
    :param df: Sampling rate in Hz.
    :param maxorder: Maximal order of the designed cheby2 filter
    :param ba: If True return only the filter coefficients (b, a) instead
        of filtering
    :param freq_passband: If True return additionally to the filtered data,
        the iteratively determined pass band frequency
    :return: Filtered data.
    """
    nyquist = df * 0.5
    # rp - maximum ripple of passband, rs - attenuation of stopband
    rp, rs, order = 1, 96, 1e99
    ws = freq / nyquist  # stop band frequency
    wp = ws  # pass band frequency
    # raise for some bad scenarios
    if ws > 1:
        ws = 1.0
        msg = "Selected corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    while True:
        if order <= maxorder:
            break
        wp = wp * 0.99
        order, wn = cheb2ord(wp, ws, rp, rs, analog=0)
    if ba:
        return cheby2(order, rs, wn, btype='low', analog=0, output='ba')
    z, p, k = cheby2(order, rs, wn, btype='low', analog=0, output='zpk')
    sos = zpk2sos(z, p, k)
    if freq_passband:
        return sosfilt(sos, data), wp * nyquist
    return sosfilt(sos, data)
Esempio n. 39
0
def bandpass(data, freqmin, freqmax, df, corners=4, zerophase=False):
    """
    Butterworth-Bandpass Filter.

    Filter data from ``freqmin`` to ``freqmax`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freqmin: Pass band low corner frequency.
    :param freqmax: Pass band high corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the filter order but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    low = freqmin / fe
    high = freqmax / fe
    # raise for some bad scenarios
    if high - 1.0 > -1e-6:
        msg = ("Selected high corner frequency ({}) of bandpass is at or "
               "above Nyquist ({}). Applying a high-pass instead.").format(
            freqmax, fe)
        warnings.warn(msg)
        return highpass(data, freq=freqmin, df=df, corners=corners,
                        zerophase=zerophase)
    if low > 1:
        msg = "Selected low corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, [low, high], btype='band',
                        ftype='butter', output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 40
0
def bandstop(data, freqmin, freqmax, df, corners=4, zerophase=False):
    """
    Butterworth-Bandstop Filter.

    Filter data removing data between frequencies ``freqmin`` and ``freqmax``
    using ``corners`` corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freqmin: Stop band low corner frequency.
    :param freqmax: Stop band high corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the number of corners but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    low = freqmin / fe
    high = freqmax / fe
    # raise for some bad scenarios
    if high > 1:
        high = 1.0
        msg = "Selected high corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    if low > 1:
        msg = "Selected low corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, [low, high],
                        btype='bandstop', ftype='butter', output='zpk')
    sos = zpk2sos(z, p, k)
    if zerophase:
        firstpass = sosfilt(sos, data)
        return sosfilt(sos, firstpass[::-1])[::-1]
    else:
        return sosfilt(sos, data)
Esempio n. 41
0
def bandpass(freqmin, freqmax, df, corners=4):
    """
    From obspy with modification.

    Butterworth-Bandpass Filter.

    Filter data from ``freqmin`` to ``freqmax`` using ``corners``
    corners.
    The filter uses :func:`scipy.signal.iirfilter` (for design)
    and :func:`scipy.signal.sosfilt` (for applying the filter).

    :type data: numpy.ndarray
    :param data: Data to filter.
    :param freqmin: Pass band low corner frequency.
    :param freqmax: Pass band high corner frequency.
    :param df: Sampling rate in Hz.
    :param corners: Filter corners / order.
    :param zerophase: If True, apply filter once forwards and once backwards.
        This results in twice the filter order but zero phase shift in
        the resulting filtered trace.
    :return: Filtered data.
    """
    fe = 0.5 * df
    low = freqmin / fe
    high = freqmax / fe
    # raise for some bad scenarios
    if high > 1:
        high = 1.0
        msg = "Selected high corner frequency is above Nyquist. " + \
              "Setting Nyquist as high corner."
        warnings.warn(msg)
    if low > 1:
        msg = "Selected low corner frequency is above Nyquist."
        raise ValueError(msg)
    z, p, k = iirfilter(corners, [low, high], btype='band',
                        ftype='butter', output='zpk')
    sos = zpk2sos(z, p, k)
    return sos
def ITU_R_468_weighting(fs, output='ba'):
    """
    Return ITU-R 468 digital weighting filter transfer function

    Parameters
    ----------
    fs : float
        Sampling frequency

    Examples
    --------

    >>> from scipy.signal import freqz
    >>> import matplotlib.pyplot as plt
    >>> fs = 200000
    >>> b, a = ITU_R_468_weighting(fs)
    >>> f = np.logspace(np.log10(10), np.log10(fs/2), 1000)
    >>> w = 2*pi * f / fs
    >>> w, h = freqz(b, a, w)
    >>> plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h)))
    >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
    >>> plt.axis([10, 100e3, -50, 20])
    """

    z, p, k = ITU_R_468_weighting_analog()

    # Use the bilinear transformation to get the digital filter.
    zz, pz, kz = _zpkbilinear(z, p, k, fs)

    if output == 'zpk':
        return zz, pz, kz
    elif output in {'ba', 'tf'}:
        return zpk2tf(zz, pz, kz)
    elif output == 'sos':
        return zpk2sos(zz, pz, kz)
    else:
        raise ValueError("'%s' is not a valid output form." % output)
Esempio n. 43
0
def _design_iir(wp, ws, sample_rate, gpass, gstop,
                analog=False, ftype='cheby1', output='zpk'):
    nyq = sample_rate / 2.
    wp = atleast_1d(wp)
    ws = atleast_1d(ws)
    if analog:
        wp *= TWO_PI
        ws *= TWO_PI
    else:
        wp /= nyq
        ws /= nyq
    z, p, k = signal.iirdesign(wp, ws, gpass, gstop, analog=analog,
                               ftype=ftype, output='zpk')
    if analog:
        z /= -TWO_PI
        p /= -TWO_PI
    if output == 'zpk':
        return z, p, k
    elif output == 'ba':
        return signal.zpk2tf(z, p, k)
    elif output == 'sos':
        return signal.zpk2sos(z, p, k)
    else:
        raise ValueError("'%s' is not a valid output form." % output)
Esempio n. 44
0
File: IIR.py Progetto: maxmouchet/tb
# Frequence de coupure dans la bande attenuee
fa = 4000
ws = fa/(fe/2)

# Taux d'ondulation dans la bande passante (dB)
delta1 = 3

# Taux d'ondulation dans la bande attenuee (dB)
delta2 = 30

# Determination de l'ordre et de la frequence de coupure
N, Wn = signal.buttord(wp, ws, delta1, delta2)

# Determination des coefficients
a, b = signal.butter(N, Wn)

# Determination de la reponse frequentielle
w, h = signal.freqz(b, a, whole=True)

# Plot
f, (ax1, ax2) = plt.subplots(2)

ax1.plot(w, 20 * np.log10(abs(h)))
ax2.plot(w, np.unwrap(np.angle(h)))

plt.show()

# Decomposition en cellules du 1er et du 2eme ordre
Z = signal.zpk2sos(np.roots(a), np.roots(b), a[0])
print(Z)
Esempio n. 45
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))
Esempio n. 46
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))
Esempio n. 47
0
    def filter(self, *filt):
        """Apply the given filter to this `TimeSeries`.

        All recognised filter arguments are converted either into cascading
        second-order sections (if scipy >= 0.16 is installed), or into the
        ``(numerator, denominator)`` representation before being applied
        to this `TimeSeries`.

        .. note::

           All filters are presumed to be digital (Z-domain), if you have
           an analog ZPK (in Hertz or in rad/s) you should be using
           `TimeSeries.zpk` instead.

        .. note::

           When using `scipy` < 0.16 some higher-order filters may be
           unstable. With `scipy` >= 0.16 higher-order filters are
           decomposed into second-order-sections, and so are much more stable.

        Parameters
        ----------
        *filt
            one of:

            - :class:`scipy.signal.lti`
            - `MxN` `numpy.ndarray` of second-order-sections
              (`scipy` >= 0.16 only)
            - ``(numerator, denominator)`` polynomials
            - ``(zeros, poles, gain)``
            - ``(A, B, C, D)`` 'state-space' representation

        Returns
        -------
        result : `TimeSeries`
            the filtered version of the input `TimeSeries`

        See also
        --------
        TimeSeries.zpk
            for instructions on how to filter using a ZPK with frequencies
            in Hertz
        scipy.signal.sosfilter
            for details on the second-order section filtering method
            (`scipy` >= 0.16 only)
        scipy.signal.lfilter
            for details on the filtering method

        Raises
        ------
        ValueError
            If ``filt`` arguments cannot be interpreted properly
        """
        sos = None
        # single argument given
        if len(filt) == 1:
            filt = filt[0]
            # detect LTI
            if isinstance(filt, signal.lti):
                filt = filt
                a = filt.den
                b = filt.num
            # detect SOS
            elif isinstance(filt, numpy.ndarray) and filt.ndim == 2:
                sos = filt
            # detect taps
            else:
                b = filt
                a = [1]
        # detect TF
        elif len(filt) == 2:
            b, a = filt
        elif len(filt) == 3:
            try:
                sos = signal.zpk2sos(*filt)
            except AttributeError:
                b, a = signal.zpk2tf(*filt)
        elif len(filt) == 4:
            try:
                zpk = signal.ss2zpk(*filt)
                sos = signal.zpk2sos(zpk)
            except AttributeError:
                b, a = signal.ss2tf(*filt)
        else:
            raise ValueError("Cannot interpret filter arguments. Please "
                             "give either a signal.lti object, or a "
                             "tuple in zpk or ba format. See "
                             "scipy.signal docs for details.")
        if sos is not None:
            new = signal.sosfilt(sos, self, axis=0).view(self.__class__)
        else:
            new = signal.lfilter(b, a, self, axis=0).view(self.__class__)
        new.__dict__ = self.copy_metadata()
        return new
Esempio n. 48
0
#dt = np.sum(np.abs(examp_time[:-1])) / (ntimesteps-1)
dt = duration / ntimesteps
dt_test = abs(examp_time[-1]-examp_time[0]) / ntimesteps

if dt_test != dt and rank == 0:
    msg = 'Small discrepancy between inferred and prescribed sampling rate:' 
    warn(msg)
    print(dt)
    print(dt_test)
    
# Determine the sampling rate
fs_old = 1./dt

# Get filter coeff
z, p, k = cheby2_lowpass(fs_old,freq)
sos = zpk2sos(z, p, k)

# Determine which channels to save...
if channel is not 'all':
    cha_incr = 3
    if channel == 'MXN':
        cha_offset = 0
    elif channel == 'MXE':
        cha_offset = 1
    elif channel == 'MXZ':
        cha_offset = 2
else:
    cha_incr = 1
    cha_offset = 0        

counter = 0
Esempio n. 49
0
def filter_zpk(timeseries, z, p, k):
    """Return a new timeseries that was filtered with a zero-pole-gain filter.
    The transfer function in the s-domain looks like:
    .. math::
    \\frac{H(s) = (s - s_1) * (s - s_3) * ... * (s - s_n)}{(s - s_2) * (s - s_4) * ... * (s - s_m)}, m >= n

    The zeroes, and poles entered in Hz are converted to angular frequency,
    along the imaginary axis in the s-domain s=i*omega.  Then the zeroes, and
    poles are bilinearly transformed via:
    .. math::
    z(s) = \\frac{(1 + s*T/2)}{(1 - s*T/2)}

    Where z is the z-domain value, s is the s-domain value, and T is the
    sampling period.  After the poles and zeroes have been bilinearly
    transformed, then the second-order sections are found and filter the data
    using scipy.

    Parameters
    ----------
    timeseries: TimeSeries
        The TimeSeries instance to be filtered.
    z: array
        Array of zeros to include in zero-pole-gain filter design.
        In units of Hz.
    p: array
        Array of poles to include in zero-pole-gain filter design.
        In units of Hz.
    k: float
        Gain to include in zero-pole-gain filter design. This gain is a
        constant multiplied to the transfer function.

    Returns
    -------
    Time Series: TimeSeries
        A  new TimeSeries that has been filtered.

    Examples
    --------
    To apply a 5 zeroes at 100Hz, 5 poles at 1Hz, and a gain of 1e-10 filter
    to a TimeSeries instance, do:
    >>> filtered_data = zpk_filter(timeseries, [100]*5, [1]*5, 1e-10)
    """

    # sanity check type
    if not isinstance(timeseries, TimeSeries):
        raise TypeError("Can only filter TimeSeries instances.")

    # sanity check casual filter
    degree = len(p) - len(z)
    if degree < 0:
        raise TypeError("May not have more zeroes than poles. \
                         Filter is not casual.")

    # cast zeroes and poles as arrays and gain as a float
    z = np.array(z)
    p = np.array(p)
    k = float(k)

    # put zeroes and poles in the s-domain
    # convert from frequency to angular frequency
    z *= -2 * np.pi
    p *= -2 * np.pi

    # get denominator of bilinear transform
    fs = 2.0 * timeseries.sample_rate

    # zeroes in the z-domain
    z_zd = (1 + z/fs) / (1 - z/fs)

    # any zeros that were at infinity are moved to the Nyquist frequency
    z_zd = z_zd[np.isfinite(z_zd)]
    z_zd = np.append(z_zd, -np.ones(degree))

    # poles in the z-domain
    p_zd = (1 + p/fs) / (1 - p/fs)

    # gain change in z-domain
    k_zd = k * np.prod(fs - z) / np.prod(fs - p)

    # get second-order sections
    sos = zpk2sos(z_zd, p_zd, k_zd)

    # filter
    filtered_data = sosfilt(sos, timeseries.numpy())

    return TimeSeries(filtered_data, delta_t = timeseries.delta_t,
                      dtype=timeseries.dtype,
                      epoch=timeseries._epoch)