Beispiel #1
0
    def cwt_diff(signal, wv_width, order=1, method='auto'):
        """
        Take a numerical derivative using a Haar wavelet (noise-supression)
        
        Parameters
        ----------
        signal : ndarray (1D)
            Signal data
        
        wv_width : int
            Width of wavelet to use (balance noise suppression and distortion)
            
        order : int, optional (default=1)
            Order of derivative (e.g., 1st-order derivative)

        method : str {'auto' (default), 'fft', 'direct'}
            
        Returns
        -------
        deriv : ndarray (1D)
            Derivative of input signal
        """
        deriv = _copy.deepcopy(signal)
        for count in range(order):
            try:
                deriv = _convolve(deriv, PeakFinder.haar(wv_width), mode='same', 
                                  method=method)
            except:
                print('peakfind.py | cwt_diff: Likely using an old version of SciPy (no convolve method parameter)')
                deriv = _convolve(deriv, PeakFinder.haar(wv_width), mode='same')
        return deriv
Beispiel #2
0
    def cwt_diff(signal, wv_width, order=1, method='auto'):
        """
        Take a numerical derivative using a Haar wavelet (noise-supression)
        
        Parameters
        ----------
        signal : ndarray (1D)
            Signal data
        
        wv_width : int
            Width of wavelet to use (balance noise suppression and distortion)
            
        order : int, optional (default=1)
            Order of derivative (e.g., 1st-order derivative)

        method : str {'auto' (default), 'fft', 'direct'}
            
        Returns
        -------
        deriv : ndarray (1D)
            Derivative of input signal
        """
        deriv = _copy.deepcopy(signal)
        for count in range(order):
            deriv = _convolve(deriv,
                              PeakFinder.haar(wv_width),
                              mode='same',
                              method=method)
        return deriv
Beispiel #3
0
def max_patch(im, filt_size):
    """Return the patch of maximum response (highest intensity)
    in the image. Might be used on an image containing fixation densities
    to determine where to crop the real image to have "maximum saliency".

    Args:
        im (2D matrix): the image to find the max response.

        filt_size (scalar): the filter size in pixels. Only set up
            for square filter regions, currently.

    Returns:
        max_im: a 2D array of size (filt_size, filt_size) containing
            the maximum response.
        max_x: a scalar containing the left-hand x coord.
        max_y: the top y coord of the max_im box.
    """

    filter_kernel = _np.ones((filt_size, filt_size))
    filter_responses = _convolve(im, filter_kernel, mode='valid')
    position_of_maxium = _np.unravel_index(filter_responses.argmax(),
                                           filter_responses.shape)
    max_y, max_x = position_of_maxium
    max_im = im[max_y:max_y+filt_size, max_x:max_x+filt_size]
    return(max_im, max_x, max_y)
Beispiel #4
0
def convolve_overlap_add(signal,
                         impulse_responses,
                         nhop,
                         ntaps,
                         initial_values=None):
    """Convolve iterable `signal` with time-variant `impulse_responses`.

    :param signal: Signal in blocks of size `nblock`.
    :param impulse_responses: Impulse responses of length `ntaps`.
    :param nhop: Impulse responses is updated every `nhop` samples. This should correspond to the blocksize of `signal`.
    :param ntaps: Length of impulse responses.
    :param initial_values. Value to use before convolution kicks in.
    :returns: Convolution.

    This function implements the overlap-add method. Time-variant `impulse_responses is supported.
    Each item (`block`) in `signal` corresponds to an impulse response (`ir`) in `impulse_responses`.

    This implementation of overlap-add buffers only one segment. Therefore, only `nblock>=ntaps` is supported.

    .. warning:: This function cannot be used when `ntaps > nblock`.

    .. seealso:: :func:`convolve_overlap_save`

    """
    nblock = nhop

    if not nblock >= ntaps:
        raise ValueError(
            "Amount of samples in block should be the same or more than the amount of filter taps."
        )

    if initial_values is None:
        tail_previous_block = np.zeros(ntaps - 1)
    else:
        tail_previous_block = initial_values

    for block, ir in zip(signal, impulse_responses):
        # The result of the convolution consists of a head, a body and a tail
        # - the head and tail have length `taps-1`
        # - the body has length `signal-taps+1`??
        try:
            convolved = _convolve(block, ir, mode='full')
        except ValueError:
            raise GeneratorExit

        # The final block consists of
        # - the head and body of the current convolution
        # - and the tail of the previous convolution.
        resulting_block = convolved[:-ntaps + 1]
        #print(resulting_block)
        #resulting_block[:ntaps-1] += tail_previous_block
        resulting_block[:ntaps -
                        1] = resulting_block[:ntaps -
                                             1] + tail_previous_block  # Because of possibly different dtypes
        # We store the tail for the  next cycle
        tail_previous_block = convolved[-ntaps + 1:]
        #print(tail_previous_block)

        # Yield the result of this step
        yield resulting_block
Beispiel #5
0
def convolve_overlap_add(signal, impulse_responses, nhop, ntaps, initial_values=None):
    """Convolve iterable `signal` with time-variant `impulse_responses`.

    :param signal: Signal in blocks of size `nblock`.
    :param impulse_responses: Impulse responses of length `ntaps`.
    :param nhop: Impulse responses is updated every `nhop` samples. This should correspond to the blocksize of `signal`.
    :param ntaps: Length of impulse responses.
    :param initial_values. Value to use before convolution kicks in.
    :returns: Convolution.

    This function implements the overlap-add method. Time-variant `impulse_responses is supported.
    Each item (`block`) in `signal` corresponds to an impulse response (`ir`) in `impulse_responses`.

    This implementation of overlap-add buffers only one segment. Therefore, only `nblock>=ntaps` is supported.

    .. warning:: This function cannot be used when `ntaps > nblock`.

    .. seealso:: :func:`convolve_overlap_save`

    """
    nblock = nhop

    if not nblock >= ntaps:
        raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")

    if initial_values is None:
        tail_previous_block = np.zeros(ntaps - 1)
    else:
        tail_previous_block = initial_values

    for block, ir in zip(signal, impulse_responses):
        # The result of the convolution consists of a head, a body and a tail
        # - the head and tail have length `taps-1`
        # - the body has length `signal-taps+1`??
        try:
            convolved = _convolve(block, ir, mode="full")
        except ValueError:
            raise GeneratorExit

        # The final block consists of
        # - the head and body of the current convolution
        # - and the tail of the previous convolution.
        resulting_block = convolved[: -ntaps + 1]
        # print(resulting_block)
        # resulting_block[:ntaps-1] += tail_previous_block
        resulting_block[: ntaps - 1] = (
            resulting_block[: ntaps - 1] + tail_previous_block
        )  # Because of possibly different dtypes
        # We store the tail for the  next cycle
        tail_previous_block = convolved[-ntaps + 1 :]
        # print(tail_previous_block)

        # Yield the result of this step
        yield resulting_block
Beispiel #6
0
def _convolve_crossfade(block, ir1, ir2, fading1):
    """Convolve block with two impulse responses and crossfade the result.

    :param block: Block.
    :param ir1: Impulse response 1.
    :param ir2: Impulse response 2.
    :param fading1: Fading.
    :returns: Crossfaded convolutions of block and impulse responses.

    We switch from `ir1` to `ir2`.

    A more efficient method is presented in *Efficient time-varying FIR filtering using
    crossfading implemented in the DFT domain* by Frank Wefers.

    """
    # Convolve segment with both impulse responses.
    convolved1 = _convolve(block, ir1, mode="full")
    convolved2 = _convolve(block, ir2, mode="full")
    # Fading windows
    fading2 = 1.0 - fading1
    # Crossfaded convolutions
    convolved = convolved1 * fading1 + convolved2 * fading2
    return convolved
Beispiel #7
0
def _convolve_crossfade(block, ir1, ir2, fading1):
    """Convolve block with two impulse responses and crossfade the result.

    :param block: Block.
    :param ir1: Impulse response 1.
    :param ir2: Impulse response 2.
    :param fading1: Fading.
    :returns: Crossfaded convolutions of block and impulse responses.

    We switch from `ir1` to `ir2`.

    A more efficient method is presented in *Efficient time-varying FIR filtering using
    crossfading implemented in the DFT domain* by Frank Wefers.

    """
    # Convolve segment with both impulse responses.
    convolved1 = _convolve(block, ir1, mode='full')
    convolved2 = _convolve(block, ir2, mode='full')
    # Fading windows
    fading2 = 1. - fading1
    # Crossfaded convolutions
    convolved = convolved1 * fading1 + convolved2 * fading2
    return convolved
Beispiel #8
0
    def algorithm(cls, signal, params):
        fsamp = signal.get_sampling_freq()
        fp, fs, loss, att, wtype = params["fp"], params["fs"], params[
            "loss"], params["att"], params["wtype"]

        if isinstance(signal, _UnevenlySignal):
            cls.warn(
                'Filtering Unevenly signal is undefined. Returning original signal.'
            )
            return signal

        fp = _np.array(fp)
        fs = _np.array(fs)

        if att > 0:
            att = -att
        d1 = 10**(loss / 10)
        d2 = 10**(att / 10)
        Dsamp = _np.min(abs(fs - fp)) / fsamp

        # from https://dsp.stackexchange.com/questions/31066/how-many-taps-does-an-fir-filter-need
        N = int(2 / 3 * _np.log10(1 / (10 * d1 * d2)) * fsamp / Dsamp)

        pass_zero = True

        if isinstance(fp, Sequence):
            if fp[0] > fs[0]:
                pass_zero = False
        else:
            if fp > fs:
                pass_zero = False

        nyq = 0.5 * fsamp
        fp = _np.array(fp)
        wp = fp / nyq

        if N % 2 == 0:
            N += 1
        b = _firwin(N, wp, width=Dsamp, window=wtype, pass_zero=pass_zero)
        sig_filtered = signal.clone_properties(
            _convolve(signal.get_values(), b, mode='same'))

        if _np.isnan(sig_filtered[0]):
            cls.warn(
                'Filter parameters allow no solution. Returning original signal.'
            )
            return signal
        else:
            return sig_filtered
Beispiel #9
0
    def algorithm(cls, signal, params):
        fsamp = signal.get_sampling_freq()
        fp, fs, loss, att, wtype = params["fp"], params["fs"], params["loss"], params["att"], params["wtype"]

        if isinstance(signal, _UnevenlySignal):
            cls.warn('Filtering Unevenly signal is undefined. Returning original signal.')
            return signal

        fp = _np.array(fp)
        fs = _np.array(fs)
        
        if att>0:
            att = -att
        d1 = 10**(loss/10)
        d2 = 10**(att/10)
        Dsamp = _np.min(abs(fs-fp))/fsamp
        

        # from https://dsp.stackexchange.com/questions/31066/how-many-taps-does-an-fir-filter-need
        N = int(2/3*_np.log10(1/(10*d1*d2))*fsamp/Dsamp)
                
        pass_zero=True
                  
        if isinstance(fp, Sequence):
            if fp[0]>fs[0]:
                pass_zero=False
        else:    
            if fp>fs:
                pass_zero=False
        
            
        
        nyq = 0.5 * fsamp
        fp = _np.array(fp)
        wp = fp / nyq
        print(N)
        b = _firwin(N, wp, width=Dsamp, window=wtype, pass_zero=pass_zero)
        sig_filtered = signal.clone_properties(_convolve(signal.get_values(), b, mode='same'))

        if _np.isnan(sig_filtered[0]):
            cls.warn('Filter parameters allow no solution. Returning original signal.')
            return signal
        else:
            return sig_filtered
Beispiel #10
0
def convolve_overlap_save(signal, impulse_responses, nhop, ntaps):
    """Convolve signal with linear time-invariant `impulse_response` using overlap-discard method.

    :param signal: Signal. Consists of samples.
    :param impulse_responses: Linear time-variant impulses response of filter.
    :param nhop: Impulse response is renewed every `nhop` samples.
    :returns: Convolution of `signal` with `impulse_responses`.
    :rtype: Generator consisting of arrays.

    .. note:: The *overlap-discard* method is more commonly known as *overlap-save*.

    """
    nwindow = nhop + ntaps - 1
    noverlap = ntaps - 1
    windows = blocks(signal, nwindow, noverlap)
    # Convolve function to use
    _convolve_func = lambda x, y: _convolve(x, y, mode="valid")
    # Convolved blocks
    convolved = map(_convolve_func, windows, impulse_responses)
    yield from convolved
Beispiel #11
0
def convolve_overlap_save(signal, impulse_responses, nhop, ntaps):
    """Convolve signal with linear time-invariant `impulse_response` using overlap-discard method.

    :param signal: Signal. Consists of samples.
    :param impulse_responses: Linear time-variant impulses response of filter.
    :param nhop: Impulse response is renewed every `nhop` samples.
    :returns: Convolution of `signal` with `impulse_responses`.
    :rtype: Generator consisting of arrays.

    .. note:: The *overlap-discard* method is more commonly known as *overlap-save*.

    """
    nwindow = nhop + ntaps - 1
    noverlap = ntaps - 1
    windows = blocks(signal, nwindow, noverlap)
    # Convolve function to use
    _convolve_func = lambda x, y: _convolve(x, y, mode='valid')
    # Convolved blocks
    convolved = map(_convolve_func, windows, impulse_responses)
    yield from convolved
Beispiel #12
0
def convolve_overlap_discard(signal, impulse_response, nblock_in=None, nblock_out=None):
    """Convolve signal with linear time-invariant `impulse_response` using overlap-discard method.

    :param signal: Signal. Can either consists of blocks or samples. `nblock_in` should be set to the block size of the signal.
    :param impulse_response: Linear time-invariant impulse response of filter.
    :param nblock_in: Actual input blocksize of signal. Should be set to `None` is `signal` is sample-based.
    :param nblock_out: Desired output blocksize.
    :returns: Convolution of `signal` with `impulse_response`.
    :rtype: Generator consisting of arrays.

    Setting the input blocksize can be useful because this gives control over the delay of the process.
    Setting the output blocksize is convenient because you know on beforehand the output blocksize.
    Setting neither will result in blocksize of one, or individual samples. This will be slow.
    Setting both is not possible.


    .. note:: The *overlap-discard* method is more commonly known as *overlap-save*.

    """
    # Amount of filter taps
    ntaps = len(impulse_response)
    # Amount of overlap that is needed
    noverlap = ntaps - 1

    # In the following block we create overlapping windows.

    # Both are set.
    if nblock_in is not None and nblock_out is not None:
        raise ValueError("Set block size of either input or output.")

    # Only output blocksize is explicitly mentioned
    elif nblock_out is not None:
        nblock_in = nblock_out + ntaps - 1
    # Only input blocksize is explicitly mentioned
    elif nblock_in is not None:
        if not nblock_in >= ntaps:
            raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")
        nblock_out = nblock_in - ntaps + 1
    else:
        nblock_in = ntaps
        nblock_out = nblock_in - ntaps + 1

    windows = blocks(signal, nblock_in, noverlap)

    ## We have sample-based signal and we want blocks with specified size out.
    # if nblock_in is None and nblock_out is not None:
    # nblock_in = nblock_out + ntaps -1
    # windows = blocks(signal, nblock_in, noverlap)
    ## We have sample-based signal and we want samples out (actually blocks of size 1).
    # elif nblock_in is None and nblock_out is None:
    # nblock_in = ntaps
    # windows = blocks(signal, nblock_in, noverlap)
    ## We have block-based signal and we don't mind output block size
    # elif nblock_in is not None and nblock_out is None:
    # if not nblock_in >= ntaps:
    # raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")
    # nblock_out = nblock_in - ntaps + 1
    # windows = change_blocks(signal, nblock_in, 0, nblock_in, noverlap)
    ## We have block-based signal and we have specified an output block. We need to change the block size.
    # elif nblock_in is not None and nblock_out is not None:
    # if not nblock_in >= ntaps:
    # raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")
    # nblock_in_new = nblock_out + ntaps -1
    # windows = change_blocks(signal, nblock_in, 0, nblock_in_new, noverlap, )
    # nblock_in = nblock_in_new

    # Convolve function to use
    _convolve_func = lambda x: _convolve(x, impulse_response, mode="valid")

    # Convolved blocks
    convolved = map(_convolve_func, windows)

    return convolved, nblock_out
Beispiel #13
0
def convolve_overlap_discard(signal,
                             impulse_response,
                             nblock_in=None,
                             nblock_out=None):
    """Convolve signal with linear time-invariant `impulse_response` using overlap-discard method.

    :param signal: Signal. Can either consists of blocks or samples. `nblock_in` should be set to the block size of the signal.
    :param impulse_response: Linear time-invariant impulse response of filter.
    :param nblock_in: Actual input blocksize of signal. Should be set to `None` is `signal` is sample-based.
    :param nblock_out: Desired output blocksize.
    :returns: Convolution of `signal` with `impulse_response`.
    :rtype: Generator consisting of arrays.

    Setting the input blocksize can be useful because this gives control over the delay of the process.
    Setting the output blocksize is convenient because you know on beforehand the output blocksize.
    Setting neither will result in blocksize of one, or individual samples. This will be slow.
    Setting both is not possible.


    .. note:: The *overlap-discard* method is more commonly known as *overlap-save*.

    """
    # Amount of filter taps
    ntaps = len(impulse_response)
    # Amount of overlap that is needed
    noverlap = ntaps - 1

    # In the following block we create overlapping windows.

    # Both are set.
    if nblock_in is not None and nblock_out is not None:
        raise ValueError("Set block size of either input or output.")

    # Only output blocksize is explicitly mentioned
    elif nblock_out is not None:
        nblock_in = nblock_out + ntaps - 1
    # Only input blocksize is explicitly mentioned
    elif nblock_in is not None:
        if not nblock_in >= ntaps:
            raise ValueError(
                "Amount of samples in block should be the same or more than the amount of filter taps."
            )
        nblock_out = nblock_in - ntaps + 1
    else:
        nblock_in = ntaps
        nblock_out = nblock_in - ntaps + 1

    windows = blocks(signal, nblock_in, noverlap)

    ## We have sample-based signal and we want blocks with specified size out.
    #if nblock_in is None and nblock_out is not None:
    #nblock_in = nblock_out + ntaps -1
    #windows = blocks(signal, nblock_in, noverlap)
    ## We have sample-based signal and we want samples out (actually blocks of size 1).
    #elif nblock_in is None and nblock_out is None:
    #nblock_in = ntaps
    #windows = blocks(signal, nblock_in, noverlap)
    ## We have block-based signal and we don't mind output block size
    #elif nblock_in is not None and nblock_out is None:
    #if not nblock_in >= ntaps:
    #raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")
    #nblock_out = nblock_in - ntaps + 1
    #windows = change_blocks(signal, nblock_in, 0, nblock_in, noverlap)
    ## We have block-based signal and we have specified an output block. We need to change the block size.
    #elif nblock_in is not None and nblock_out is not None:
    #if not nblock_in >= ntaps:
    #raise ValueError("Amount of samples in block should be the same or more than the amount of filter taps.")
    #nblock_in_new = nblock_out + ntaps -1
    #windows = change_blocks(signal, nblock_in, 0, nblock_in_new, noverlap, )
    #nblock_in = nblock_in_new

    # Convolve function to use
    _convolve_func = lambda x: _convolve(x, impulse_response, mode='valid')

    # Convolved blocks
    convolved = map(_convolve_func, windows)

    return convolved, nblock_out