latools/processes/signal_id.py
def autorange_components(t, sig, transform='log', gwin=7, swin=None,
                         win=30, on_mult=(1.5, 1.), off_mult=(1., 1.5),
                         thresh=None):
    """
    Returns the components underlying the autorange algorithm.

    Returns
    -------
    t : array-like
        Time axis (independent variable)
    sig : array-like
        Raw signal (dependent variable)
    sigs : array-like
        Smoothed signal (swin)
    tsig : array-like
        Transformed raw signal (transform)
    tsigs : array-like
        Transformed smoothed signal (transform, swin)
    kde_x : array-like
        kernel density estimate of smoothed signal.
    yd : array-like
        bins of kernel density estimator.
    g : array-like
        gradient of smoothed signal (swin, gwin)
    trans : dict
        per-transition data.
    thresh : float
        threshold identified from kernel density plot
    """
    failed = []
    # smooth signal
    if swin is not None:
        sigs = fastsmooth(sig, swin)
    else:
        sigs = sig

    # transform signal
    if transform == 'log':
        tsigs = np.log10(sigs)
        tsig = np.log10(sig)
    else:
        tsigs = sigs
        tsig = sig

    if thresh is None:
        bins = 50
        kde_x = np.linspace(tsigs.min(), tsigs.max(), bins)

        kde = gaussian_kde(tsigs)
        yd = kde.pdf(kde_x)
        mins = findmins(kde_x, yd)  # find minima in kde

        if len(mins) > 0:
            bkg = tsigs < (mins[0])  # set background as lowest distribution
            thresh = mins[0]
        else:
            bkg = np.ones(tsigs.size, dtype=bool)
    else:
        bkg = tsigs < thresh

    # assign rough background and signal regions based on kde minima
    fbkg = bkg
    fsig = ~bkg

    # remove transitions by fitting a gaussian to the gradients of
    # each transition

    # 1. determine the approximate index of each transition
    zeros = bool_2_indices(fsig)

    # 2. calculate the absolute gradient of the target trace.
    g = abs(fastgrad(sigs, gwin))  # gradient of untransformed data.

    if zeros is not None:
        zeros = zeros.flatten()
        trans = dict(zeros=zeros.flatten(),
                     lohi=[],
                     pgs=[],
                     excl=[],
                     tps=[],
                     failed=[],
                     xs=[],
                     ys=[])

        for z in zeros:  # for each approximate transition
            # isolate the data around the transition
            if z - win < 0:
                lo = gwin // 2
                hi = int(z + win)
            elif z + win > (len(sig) - gwin // 2):
                lo = int(z - win)
                hi = len(sig) - gwin // 2
            else:
                lo = int(z - win)
                hi = int(z + win)

            xs = t[lo:hi]
            ys = g[lo:hi]

            trans['xs'].append(xs)
            trans['ys'].append(ys)

            trans['lohi'].append([lo, hi])

            # determine type of transition (on/off)
            mid = (hi + lo) // 2
            tp = sigs[mid + 3] > sigs[mid - 3]  # True if 'on' transition.
            trans['tps'].append(tp)

            c = t[z]  # center of transition
            width = (t[1] - t[0]) * 2  # initial width guess
            try:
                pg, _ = curve_fit(gauss, xs, ys,
                                  p0=(np.nanmax(ys),
                                      c,
                                      width),
                                  sigma=(xs - c)**2 + .01)
                trans['pgs'].append(pg)
                fwhm = abs(2 * pg[-1] * np.sqrt(2 * np.log(2)))
                # apply on_mult or off_mult, as appropriate.
                if tp:
                    lim = np.array([-fwhm, fwhm]) * on_mult + pg[1]
                else:
                    lim = np.array([-fwhm, fwhm]) * off_mult + pg[1]
                trans['excl'].append(lim)

                fbkg[(t > lim[0]) & (t < lim[1])] = False
                fsig[(t > lim[0]) & (t < lim[1])] = False
                failed.append(False)
            except RuntimeError:
                failed.append(True)
                trans['lohi'].append([np.nan, np.nan])
                trans['pgs'].append([np.nan, np.nan, np.nan])
                trans['excl'].append([np.nan, np.nan])
                trans['tps'].append(tp)
                pass
    else:
        zeros = []
    
    return t, sig, sigs, tsig, tsigs, kde_x, yd, g, trans, thresh
def autorange_components(t, sig, transform='log', gwin=7, swin=None,
                         win=30, on_mult=(1.5, 1.), off_mult=(1., 1.5),
                         thresh=None):
    """
    Returns the components underlying the autorange algorithm.

    Returns
    -------
    t : array-like
        Time axis (independent variable)
    sig : array-like
        Raw signal (dependent variable)
    sigs : array-like
        Smoothed signal (swin)
    tsig : array-like
        Transformed raw signal (transform)
    tsigs : array-like
        Transformed smoothed signal (transform, swin)
    kde_x : array-like
        kernel density estimate of smoothed signal.
    yd : array-like
        bins of kernel density estimator.
    g : array-like
        gradient of smoothed signal (swin, gwin)
    trans : dict
        per-transition data.
    thresh : float
        threshold identified from kernel density plot
    """
    failed = []
    # smooth signal
    if swin is not None:
        sigs = fastsmooth(sig, swin)
    else:
        sigs = sig

    # transform signal
    if transform == 'log':
        tsigs = np.log10(sigs)
        tsig = np.log10(sig)
    else:
        tsigs = sigs
        tsig = sig

    if thresh is None:
        bins = 50
        kde_x = np.linspace(tsigs.min(), tsigs.max(), bins)

        kde = gaussian_kde(tsigs)
        yd = kde.pdf(kde_x)
        mins = findmins(kde_x, yd)  # find minima in kde

        if len(mins) > 0:
            bkg = tsigs < (mins[0])  # set background as lowest distribution
            thresh = mins[0]
        else:
            bkg = np.ones(tsigs.size, dtype=bool)
    else:
        bkg = tsigs < thresh

    # assign rough background and signal regions based on kde minima
    fbkg = bkg
    fsig = ~bkg

    # remove transitions by fitting a gaussian to the gradients of
    # each transition

    # 1. determine the approximate index of each transition
    zeros = bool_2_indices(fsig)

    # 2. calculate the absolute gradient of the target trace.
    g = abs(fastgrad(sigs, gwin))  # gradient of untransformed data.

    if zeros is not None:
        zeros = zeros.flatten()
        trans = dict(zeros=zeros.flatten(),
                     lohi=[],
                     pgs=[],
                     excl=[],
                     tps=[],
                     failed=[],
                     xs=[],
                     ys=[])

        for z in zeros:  # for each approximate transition
            # isolate the data around the transition
            if z - win < 0:
                lo = gwin // 2
                hi = int(z + win)
            elif z + win > (len(sig) - gwin // 2):
                lo = int(z - win)
                hi = len(sig) - gwin // 2
            else:
                lo = int(z - win)
                hi = int(z + win)

            xs = t[lo:hi]
            ys = g[lo:hi]

            trans['xs'].append(xs)
            trans['ys'].append(ys)

            trans['lohi'].append([lo, hi])

            # determine type of transition (on/off)
            mid = (hi + lo) // 2
            tp = sigs[mid + 3] > sigs[mid - 3]  # True if 'on' transition.
            trans['tps'].append(tp)

            c = t[z]  # center of transition
            width = (t[1] - t[0]) * 2  # initial width guess
            try:
                pg, _ = curve_fit(gauss, xs, ys,
                                  p0=(np.nanmax(ys),
                                      c,
                                      width),
                                  sigma=(xs - c)**2 + .01)
                trans['pgs'].append(pg)
                fwhm = abs(2 * pg[-1] * np.sqrt(2 * np.log(2)))
                # apply on_mult or off_mult, as appropriate.
                if tp:
                    lim = np.array([-fwhm, fwhm]) * on_mult + pg[1]
                else:
                    lim = np.array([-fwhm, fwhm]) * off_mult + pg[1]
                trans['excl'].append(lim)

                fbkg[(t > lim[0]) & (t < lim[1])] = False
                fsig[(t > lim[0]) & (t < lim[1])] = False
                failed.append(False)
            except RuntimeError:
                failed.append(True)
                trans['lohi'].append([np.nan, np.nan])
                trans['pgs'].append([np.nan, np.nan, np.nan])
                trans['excl'].append([np.nan, np.nan])
                trans['tps'].append(tp)
                pass
    else:
        zeros = []
    
    return t, sig, sigs, tsig, tsigs, kde_x, yd, g, trans, thresh
Returns the components underlying the autorange algorithm.

    Returns
    -------
    t : array-like
        Time axis (independent variable)
    sig : array-like
        Raw signal (dependent variable)
    sigs : array-like
        Smoothed signal (swin)
    tsig : array-like
        Transformed raw signal (transform)
    tsigs : array-like
        Transformed smoothed signal (transform, swin)
    kde_x : array-like
        kernel density estimate of smoothed signal.
    yd : array-like
        bins of kernel density estimator.
    g : array-like
        gradient of smoothed signal (swin, gwin)
    trans : dict
        per-transition data.
    thresh : float
        threshold identified from kernel density plot