Beispiel #1
0
 def __default_mtm_kwargs(self, n):
     kw = dict()
     kw['NW'] = self.NW
     kw['adaptive_weights'] = self.adaptive
     kw['fs'] = self.parent.x_scale**-1.0
     kw['nfft'] = nextpow2(n) if self.pow2 else n
     kw['jackknife'] = False
     return kw
Beispiel #2
0
def lowpass_envelope(x: 'ElectrodeDataSource', n: int, lowpass: float, design_kws=None, filt_kws=None):
    """
    Compute the lowpass envelope of the timeseries rows in array x in blockwise fashion.

    x : ndarray, n_chans x n_points

    n : int
        block size over which to compute Hilbert transform

    lowpass : float, 0 < lowpass < 1
        the corner frequency of the lowpass filter in unit frequency

    design_kws : dict
        any extra filter design arguments (sampling rate will be forced to 1)

    filt_kws : dict
        any extra filter processing arguments (e.g. "filtfilt" : {T/F} )

    """
    return_ndarray = False
    if isinstance(x, np.ndarray):
        return_ndarray = True
        from ecogdata.datasource import PlainArraySource
        x = PlainArraySource(x)
    if filt_kws is None:
        filt_kws = dict()
    n = nextpow2(n)
    # do a little bit of overlap to avoid hilbert transform edge effects
    overlap = int(0.1 * n)
    for block, sl in x.iter_blocks(block_length=n, overlap=overlap, return_slice=True, partial_block=True):
        chan_slice, time_slice = sl
        start = time_slice.start
        stop = time_slice.stop
        new_sl = (chan_slice, slice(start + overlap, stop - overlap))
        sl_length = stop - start - 2 * overlap
        block_a = signal.hilbert(block, N=n)
        x[new_sl] = np.abs(block_a[..., overlap:overlap + sl_length])

    if lowpass == 1:
        return x

    if design_kws is None:
        design_kws = dict()
    if filt_kws is None:
        filt_kws = dict()
    filt_kws.setdefault('filtfilt', True)

    # hope for the best
    design_kws['Fs'] = 1.0
    design_kws['hi'] = lowpass
    design_kws.setdefault('ord', 5)
    x = x.filter_array(inplace=True, design_kwargs=design_kws, filt_kwargs=filt_kws)
    return x.data_buffer if return_ndarray else x
Beispiel #3
0
 def __default_mtm_kwargs(self, strip):
     kw = dict()
     kw['NW'] = self.NW
     kw['adaptive_weights'] = self.adaptive
     Fs = self.parent.x_scale**-1.0
     kw['Fs'] = Fs
     kw['jackknife'] = False
     kw['detrend'] = 'linear' if self.detrend else ''
     lag = int(Fs * self.lag / 1000.)
     if strip is None:
         strip = int(Fs * self.strip / 1000.)
     kw['nfft'] = nextpow2(strip)
     kw['pl'] = 1.0 - float(lag) / strip
     if self.high_res:
         kw['samp_factor'] = self.over_samp
         kw['low_bias'] = 0.95
     return kw, strip
Beispiel #4
0
def hilbert_envelope_filter(x, y):
    itr = block_itr_factory(x, axis=1, out=y)
    for xc in tqdm(itr,
                   desc='Hilbert Transform',
                   leave=True,
                   total=itr.n_blocks):
        # xc = x[sl]
        n = xc.shape[1]
        nfft = nextpow2(n)

        # if n is closer to the previous power of 2, then split this block into two computations
        if (nfft - n) > (n - nfft / 2):
            n1 = int(n / 2)
            nfft = int(nfft / 2)
            y1 = hilbert(xc[..., :n1], N=nfft)[..., :n1]
            y2 = hilbert(xc[..., n1:], N=nfft)[..., :n - n1]
            # y[sl] = np.hstack((np.abs(y1), np.abs(y2)))
            itr.write_out(np.hstack((np.abs(y1), np.abs(y2))))
        else:
            y1 = hilbert(xc, N=nfft)[..., :n]
            # y[sl] = np.abs(y1)
            itr.write_out(np.abs(y1))
Beispiel #5
0
def overlap_add(x, w, progress=False):

    M = len(w)
    N = 0
    nfft = nextpow2(M) / 2
    while N < M:
        nfft *= 2
        # segment size > M and long enough not to cause circular convolution
        N = nfft - M + 1


    blocks = BlockedSignal(x, N, axis=-1)
    xf = np.zeros_like(x)
    #blocks_f = BlockedSignal(xf, nfft, overlap=1.0 - float(N)/nfft, axis=-1)
    blocks_f = BlockedSignal(xf, nfft, overlap=M-1, axis=-1)

    nb1 = len(blocks)
    nb2 = len(blocks_f)

    #print M, N, nfft, nb1, nb2

    # centered kernel (does not work!)
    ## pre_z = (nfft-M) // 2
    ## post_z = nfft - M - pre_z
    ## kern = fft( np.r_[ np.zeros(pre_z), w, np.zeros(post_z) ] )

    # not-centered kernel
    kern = fft(np.r_[w, np.zeros(nfft-M)])

    # centered padding (does not work!)
    ## pre_z = (nfft-N) // 2
    ## post_z = nfft - N - pre_z
    ## z1 = np.zeros( x.shape[:-1] + (pre_z,) )
    ## z2 = np.zeros( x.shape[:-1] + (post_z,) )

    # not-centered padding
    z = np.zeros( x.shape[:-1] + (nfft-N,) )

    # if progress:
    #     itr = tqdm(range(nb1))
    # else:
    itr = range(nb1)
    for n in itr:
        
        b = blocks.block(n)
        if b.shape[-1] == N:
            b = fft(np.concatenate( (b, z), axis=-1 ), axis=-1)
            #b = fft(np.concatenate( (z1, b, z2), axis=-1 ), axis=-1)
        else:
            # zero pad final segment
            z_ = np.zeros( b.shape[:-1] + (nfft-b.shape[-1],) )
            b = fft(np.concatenate( (b, z_), axis=-1 ), axis=-1)
        b = ifft(b * kern).real
        if n < nb2:
            bf = blocks_f.block(n)
            b_sl = [slice(None)] * bf.ndim
            b_sl[-1] = slice(0, bf.shape[-1])
        else:
            # keep the final filtered block and advance the overlap-index
            # within it
            b_sl = [slice(None)] * bf.ndim
            b_sl[-1] = slice(0, bf.shape[-1])
        bf[:] += b[b_sl]    
        #bf[:] += b[..., :bf.shape[-1]]

    if nb2 > nb1:
        print('more output blocks than input blocks??')
    
    return xf
Beispiel #6
0
def _ep_trigger_avg(x, trig_code, pre=0, post=0, iqr_thresh=-1, envelope=False):
    """
    Average response to 1 or more experimental conditions

    Arguments
    ---------
    x: data (nchan, npts)
    trig_code : sequence-type (2, stim) or StimulatedExperiment
        First row is the trigger indices, second row is a condition
        ID (integer). Condition ID -1 codes for a flagged trial to
        be skipped. If a StimulatedExperiment, then triggers and
        conditions are available from this object.
    pre, post : ints
        Number of pre- and post-stim samples in interval. post + pre > 0
        default: 0 and stim-to-stim interval
    sum_limit : int
        Do partial sum up to this many terms
    iqr_thresh : float
        If set, do simple outlier detection on all groups of repeated
        conditions based on RMS power in the epoch interval. The iqr_thresh
        multiplies the width of the inter-quartile range to determine the
        "inlier" range of RMS power.

    Returns
    -------
    avg
        (nchan, ncond, epoch_length)
    n_avg
        number of triggers found for each condition
    skipped
        (nskip, nchan, epoch_length) epochs that were not averaged

    """
    x.shape = (1,) + x.shape if x.ndim == 1 else x.shape
    #pos_edge = trig_code[0]; conds = trig_code[1]
    pos_edge, conds = trigs_and_conds(trig_code)
    epoch_len = int(np.round(np.median(np.diff(pos_edge))))

    n_cond = len(np.unique(conds))
    n_pt = x.shape[1]

    if not (post or pre):
        post = epoch_len

    # this formula should provide consistent epoch lengths,
    # no matter the offset
    epoch_len = int(round(post + pre))
    pre = int(round(pre))
    post = epoch_len - pre

    # edit trigger list to exclude out-of-bounds epochs
    while pos_edge[0] - pre < 0:
        pos_edge = pos_edge[1:]
        conds = conds[1:]
    while pos_edge[-1] + post >= n_pt:
        pos_edge = pos_edge[:-1]
        conds = conds[:-1]

    avg = np.zeros((x.shape[0], n_cond, epoch_len), x.dtype)
    n_avg = np.zeros((x.shape[0], n_cond), 'i')

    for n, c in enumerate(np.unique(conds)):
        trials = np.where(conds == c)[0]
        if not len(trials):
            continue
        epochs = extract_epochs(x, pos_edge, trials, pre, post)
        if iqr_thresh > 0:
            pwr = np.sqrt(np.sum(epochs**2, axis=-1))
            # analyze outlier trials per channel
            out_mask = ut.fenced_out(
                pwr, thresh=iqr_thresh, axis=1, low=False
            )
            epochs = epochs * out_mask[:, :, None]
            n_avg[:, n] = np.sum(out_mask, axis=1)
        else:
            n_avg[:, n] = len(trials)

        if envelope:
            epochs = signal.hilbert(
                epochs, N=ut.nextpow2(epoch_len), axis=-1
            )
            epochs = np.abs(epochs[..., :epoch_len])**2

        avg[:, c - 1, :] = np.sum(epochs, axis=1) / n_avg[:, c - 1][:, None]

    x.shape = [x for x in x.shape if x > 1]
    if envelope:
        np.sqrt(avg, avg)
    return avg, n_avg
Beispiel #7
0
 def __call__(self, array):
     n = array.shape[1]
     nfft = nextpow2(n)
     xa = hilbert(array, N=nfft, axis=-1)
     return np.abs(xa[:, :n])