コード例 #1
0
def soft_pileup_corr(w_in, n_in, tau_in, w_out):
    """
    Fit the baseline to an exponential with the provided time
    constant and then subtract the best-fit function from the
    entire waveform.
    
    Parameters
    ----------
    w_in  : array-like
            The input waveform
    n_in  : int
            The number of samples at the beginning of the waveform
            to fit to an exponential
    tau_in: float
            The fixed, exponential time constant
    w_out : array-like
            The output waveform with the exponential subtracted
    
    Processing Chain Example
    ------------------------
    "wf_bl": {
        "function": "soft_pileup_corr",
        "module": "pygama.dsp.processors",
        "args": ["waveform", "1000", "500*us", "wf_bl"],
        "unit": "ADC",
        "prereqs": ["waveform"]
    }
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any() or np.isnan(n_in) or np.isnan(tau_in):
        return

    if not np.floor(n_in) == n_in:
        raise DSPFatal('The number of samples is not an integer')

    if n_in < 2:
        raise DSPFatal('The number of samples is not enough for a fit')

    if n_in > len(w_in):
        raise DSPFatal(
            'The number of samples is more than the waveform length')

    s1 = 0.0
    s2 = 0.0
    s3 = 0.0
    s4 = 0.0
    s5 = 0.0
    for i in range(0, n_in, 1):
        s1 += 1.0
        s2 += np.exp(-1.0 * i / tau_in)
        s3 += np.exp(-2.0 * i / tau_in)
        s4 += np.exp(-1.0 * i / tau_in) * w_in[i]
        s5 += w_in[i]
    B = (s5 - s2 * (s4 * s1 - s2 * s5) / (s3 * s1 - s2 * s2)) / s1
    A = (s4 - B * s2) / s3
    for i in range(0, len(w_in), 1):
        w_out[i] = w_in[i] - (A * np.exp(-1.0 * i / tau_in) + B)
コード例 #2
0
ファイル: convolutions.py プロジェクト: patgo25/pygama
def t0_filter(rise, fall):
    """
    Apply a modified, asymmetric trapezoidal filter to the waveform.  Note
    that it is composed of a factory function that is called using the init_args
    argument and that the function the waveforms are passed to using args.

    Initialization Parameters
    -------------------------
    rise: int
          The length of the rise section.  This is the linearly increasing
          section of the filter that performs a weighted average.
    fall: int
          The length of the fall section.  This is the simple averaging part
          of the filter.

    Parameters
    ----------
    w_in : array-like
           The input waveform
    w_out: array-like
           The filtered waveform

    Processing Chain Example
    ------------------------
    "wf_t0_filter": {
        "function": "t0_filter",
        "module": "pygama.dsp.processors",
        "args": ["wf_pz", "wf_t0_filter(3748,f)"],
        "unit": "ADC",
        "prereqs": ["wf_pz"],
        "init_args": ["128*ns", "2*us"]
    }
    """
    if rise < 0:
        raise DSPFatal('The length of the rise section must be positive')

    if fall < 0:
        raise DSPFatal('The length of the fall section must be positive')

    t0_kern = np.arange(2 / float(rise), 0, -2 / (float(rise)**2))
    t0_kern = np.append(t0_kern, np.zeros(int(fall)) - (1 / float(fall)))

    @guvectorize(
        ["void(float32[:], float32[:])", "void(float64[:], float64[:])"],
        "(n),(m)",
        forceobj=True)
    def t0_filter_out(w_in, w_out):
        w_out[:] = np.nan

        if np.isnan(w_in).any():
            return

        if len(t0_kern) > len(w_in):
            raise DSPFatal('The filter is longer than the input waveform')

        w_out[:] = np.convolve(w_in, t0_kern)[:len(w_in)]

    return t0_filter_out
コード例 #3
0
def moving_window_multi(w_in, length, num_mw, w_out):
    """
    Apply a series of moving-average windows to the waveform, alternating
    its application between the left and the right.

    Parameters
    ----------
    w_in  : array-like
            The input waveform
    length: int
            The length of the moving window
    num_mw: int
            The number of moving windows
    w_out : array-like
            The windowed waveform

    Processing Chain Example
    ------------------------
    "curr_av": {
        "function": "moving_window_multi",
        "module": "pygama.dsp.processors",
        "args": ["curr", "96*ns", "3", "curr_av"],
        "unit": "ADC/sample",
        "prereqs": ["curr"]
    }
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any():
        return

    if np.floor(length) != length:
        raise DSPFatal('The length of the moving window must be an integer')

    if np.floor(num_mw) != num_mw:
        raise DSPFatal('The number of moving windows must be an integer')

    if int(length) < 0 or int(length) >= len(w_in):
        raise DSPFatal('The length of the moving window is out of range')

    if int(num_mw) < 0:
        raise DSPFatal('The number of moving windows much be positive')

    wf_buf = w_in.copy()
    for i in range(0, int(num_mw), 1):
        if i % 2 == 1:
            w_out[-1] = w_in[-1]
            for i in range(len(w_in) - 2, len(w_in) - int(length) - 1, -1):
                w_out[i] = w_out[i+1] + (w_in[i] - w_out[-1]) / length
            for i in range(len(wf_buf) - int(length) - 1, -1, -1):
                w_out[i] = w_out[i+1] + (wf_buf[i] - wf_buf[i+int(length)]) / length
        else:
            w_out[0] = wf_buf[0] / length
            for i in range(1, int(length), 1):
                w_out[i] = w_out[i-1] + wf_buf[i] / length
            for i in range(int(length), len(w_in), 1):
                w_out[i] = w_out[i-1] + (wf_buf[i] - wf_buf[i-int(length)]) / length
        wf_buf[:] = w_out[:]
コード例 #4
0
def multi_a_filter(w_in, va_arbitrary_in, a_delta_in, va_max_out):
    """
    Finds the maximums in a waveform and returns the amplitude of the wave at those points
    
    Parameters
    ----------
    w_in : array-like
        The array of data within which amplitudes of extrema will be found 
    va_arbitrary_in : array-like
        An array of fixed length that tells numba to return the list of amplitudes of the same length
    a_delta_in : scalar
        The absolute level by which data must vary (in one direction) about an
        extremum in order for it to be tagged
        
    Returns
    -------
    va_max_out: array-like
        An array of the amplitudes of the maximums of the waveform
    """

    # Initialize output parameters

    va_max_out[:] = np.nan

    # Check inputs

    if (np.isnan(w_in).any() or np.isnan(a_delta_in)):
        return

    if not a_delta_in >= 0:
        raise DSPFatal('Error Message: a_delta_in must be positive')

    if len(va_arbitrary_in) != len(va_max_out):
        raise DSPFatal(
            'Error Message: Output arrays must be the same length as the arbitary input array'
        )

    if (not len(va_arbitrary_in) < len(w_in)):
        raise DSPFatal(
            'The length of your return array must be smaller than the length of your waveform'
        )

    # Use get_multi_local_extrema to find vt_max_out for a waveform

    vt_max_out = np.full_like(va_arbitrary_in, np.nan, dtype=np.float32)
    vt_min_out = np.full_like(va_arbitrary_in, np.nan, dtype=np.float32)
    n_max_out = np.array([np.nan], dtype=np.float32)
    n_min_out = np.array([np.nan], dtype=np.float32)
    flag_out = np.array([np.nan], dtype=np.float32)
    get_multi_local_extrema(w_in, a_delta_in, va_arbitrary_in, vt_max_out,
                            vt_min_out, n_max_out, n_min_out, flag_out)

    # Feed vt_max_out into fixed_time_pickoff to get va_max_out

    fixed_time_pickoff(w_in, vt_max_out, va_max_out)
コード例 #5
0
ファイル: time_point_thresh.py プロジェクト: patgo25/pygama
def time_point_thresh(w_in, a_threshold, t_start, walk_forward, t_out):
    """
    Find the index where the waveform value crosses the threshold,
    walking either forward or backward from the starting index.

    Parameters
    ----------
    w_in        : array-like
                  The input waveform
    a_threshold : float
                  The threshold value
    t_start     : int
                  The starting index
    walk_forward: int
                  The backward (0) or forward (1) search direction
    t_out       : float
                  The index where the waveform value crosses the threshold

    Processing Chain Example
    ------------------------
    "tp_0": {
        "function": "time_point_thresh",
        "module": "pygama.dsp.processors",
        "args": ["wf_atrap", "bl_std", "tp_start", 0, "tp_0"],
        "unit": "ns",
        "prereqs": ["wf_atrap", "bl_std", "tp_start"]
    }
    """
    t_out[0] = np.nan

    if np.isnan(w_in).any() or np.isnan(a_threshold) or np.isnan(t_start) or np.isnan(walk_forward):
        return
    
    if np.floor(t_start) != t_start:
        raise DSPFatal('The starting index must be an integer')

    if np.floor(walk_forward) != walk_forward:
        raise DSPFatal('The search direction must be an integer')

    if int(t_start) < 0 or int(t_start) >= len(w_in):
        raise DSPFatal('The starting index is out of range')

    if int(walk_forward) == 1:
        for i in range(int(t_start), len(w_in) - 1, 1):
            if w_in[i] <= a_threshold < w_in[i+1]:
                t_out[0] = i
                return
    else:
        for i in range(int(t_start), 1, -1):
            if w_in[i-1] < a_threshold <= w_in[i]:
                t_out[0] = i
                return
コード例 #6
0
def optimize_1pz(w_in, a_baseline_in, t_beg_in, t_end_in, p0_in, val0_out):
    """
    Find the optimal, single pole-zero cancellation's parameter
    by minimizing the slope in the waveform's specified time range.
    
    Parameters
    ----------
    w_in         : array-like
                   The input waveform
    a_baseline_in: float
                   The resting baseline
    t_beg_in     : int
                   The lower bound's index for the time range over
                   which to optimize the pole-zero cancellation
    t_end_in     : int
                   The upper bound's index for the time range over
                   which to optimize the pole-zero cancellation
    p0_in        : float
                   The initial guess of the optimal time constant
    val0_out     : float
                   The output value of the best-fit time constant
              
    Processing Chain Example
    ------------------------
    "tau0": {
        "function": "optimize_1pz",
        "module": "pygama.dsp.processors",
        "args": ["waveform", "baseline", "0", "20*us", "500*us", "tau0"],
        "prereqs": ["waveform", "baseline"],
        "unit": "us"
    }
    """
    val0_out[0] = np.nan

    if np.isnan(w_in).any() or np.isnan(a_baseline_in) or np.isnan(t_beg_in) or np.isnan(t_end_in) or\
       np.isnan(p0_in):
        return

    if not np.floor(t_beg_in) == t_beg_in or\
       not np.floor(t_end_in) == t_end_in:
        raise DSPFatal('The waveform index is not an integer')

    if int(t_beg_in) < 0 or int(t_beg_in) > len(w_in) or\
       int(t_end_in) < 0 or int(t_end_in) > len(w_in):
        raise DSPFatal('The waveform index is out of range')

    m = Minuit(Model(pole_zero, w_in, a_baseline_in, int(t_beg_in), int(t_end_in)), [p0_in])
    m.print_level = -1
    m.strategy = 1
    m.errordef = Minuit.LEAST_SQUARES
    m.migrad()
    val0_out[0] = m.values[0]
コード例 #7
0
ファイル: multi_a_filter.py プロジェクト: legend-exp/pygama
def multi_a_filter(w_in, vt_maxs_in, va_max_out): 
    """
    Finds the maximums in a waveform and returns the amplitude of the wave at those points
    
    Parameters
    ----------
    w_in : array-like
        The array of data within which amplitudes of extrema will be found 
    vt_maxs_in : array-like
        The array of max positions for each wf
    Returns
    -------
    va_max_out: array-like
        An array of the amplitudes of the maximums of the waveform
    """
    
    # Initialize output parameters 
    
    va_max_out[:] = np.nan
    
    # Check inputs 
    
    if (np.isnan(w_in).any()):
        return
        
    if (not len(vt_maxs_in)<len(w_in)):
        raise DSPFatal('The length of your return array must be smaller than the length of your waveform')
    
    fixed_time_pickoff(w_in, vt_maxs_in, va_max_out)
コード例 #8
0
def saturation(w_in, bit_depth_in, n_lo_out, n_hi_out):
    """
    Count the number of samples in the waveform that are
    saturated at the minimum and maximum possible values based
    on the bit depth.
    
    Parameters
    ----------
    w_in        : array-like
                  The input waveform
    bit_depth_in: int
                  The bit depth of the analog-to-digital converter
    n_lo_out    : int
                  The output number of samples at the minimum
    n_hi_out    : int
                  The output number of samples at the maximum
    
    Processing Chain Example
    ------------------------
    "sat_lo, sat_hi": {
        "function": "saturation",
        "module": "pygama.dsp.processors",
        "args": ["waveform", "16", "sat_lo", "sat_hi"],
        "unit": "ADC",
        "prereqs": ["waveform"]
    }
    """
    n_lo_out[0] = np.nan
    n_hi_out[0] = np.nan

    if np.isnan(w_in).any() or np.isnan(bit_depth_in):
        return

    if not np.floor(bit_depth_in) == bit_depth_in:
        raise DSPFatal('The bit depth is not an integer')

    if bit_depth_in <= 0:
        raise DSPFatal('The bit depth is not positive')

    n_lo_out[0] = 0
    n_hi_out[0] = 0
    for i in range(0, len(w_in), 1):
        if w_in[i] == 0:
            n_lo_out[0] += 1
        elif w_in[i] == np.power(2, int(bit_depth_in)):
            n_hi_out[0] += 1
コード例 #9
0
ファイル: convolutions.py プロジェクト: patgo25/pygama
    def cusp_out(w_in, w_out):
        w_out[:] = np.nan

        if np.isnan(w_in).any():
            return

        if len(cuspd) > len(w_in):
            raise DSPFatal('The filter is longer than the input waveform')

        w_out[:] = np.convolve(w_in, cuspd, 'valid')
コード例 #10
0
ファイル: convolutions.py プロジェクト: patgo25/pygama
    def t0_filter_out(w_in, w_out):
        w_out[:] = np.nan

        if np.isnan(w_in).any():
            return

        if len(t0_kern) > len(w_in):
            raise DSPFatal('The filter is longer than the input waveform')

        w_out[:] = np.convolve(w_in, t0_kern)[:len(w_in)]
コード例 #11
0
def windower(w_in, t0_in, w_out):
    """
    Return a shorter sample of the waveform, starting at the
    specified index.  Note that the length of the output waveform
    is determined by the length of "w_out" rather than an input
    parameter.  If the the length of "w_out" plus "t0_in" extends
    past the end of "w_in" or if "t0_in" is negative, remaining
    values are padded with NaN.
    
    Parameters
    ----------
    w_in : array-like
           The input waveform
    t0_in: int
           The starting index of the window
    w_out: array-like
           The windowed waveform
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any() or np.isnan(t0_in):
        return

    if np.floor(t0_in) != t0_in:
        raise DSPFatal('The starting index must be an integer')

    if len(w_out) >= len(w_in):
        raise DSPFatal(
            'The windowed waveform must be smaller than the input waveform')

    beg = min(int(t0_in), len(w_in))
    end = max(beg + len(w_out), 0)
    if beg < 0:
        w_out[:len(w_out) - end] = np.nan
        w_out[len(w_out) - end:] = w_in[:end]
    elif end < len(w_in):
        w_out[:] = w_in[beg:end]
    else:
        w_out[:len(w_in) - beg] = w_in[beg:len(w_in)]
        w_out[len(w_in) - beg:] = np.nan
コード例 #12
0
def moving_window_left(w_in, length, w_out):
    """
    Apply a moving-average window to the waveform from the left.

    Parameters
    ----------
    w_in  : array-like
            The input waveform
    length: int
            The length of the moving window
    w_out : array-like
            The windowed waveform

    Processing Chain Example
    ------------------------
    "wf_mw": {
        "function": "moving_window_left",
        "module": "pygama.dsp.processors",
        "args": ["wf_pz", "96*ns", "wf_mw"],
        "unit": "ADC",
        "prereqs": ["wf_pz"]
    }
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any():
        return

    if np.floor(length) != length:
        raise DSPFatal('The length of the moving window must be an integer')

    if int(length) < 0 or int(length) >= len(w_in):
        raise DSPFatal('The length of the moving window is out of range')

    w_out[0] = w_in[0] / length
    for i in range(1, int(length)):
        w_out[i] = w_out[i-1] + w_in[i] / length
    for i in range(int(length), len(w_in)):
        w_out[i] = w_out[i-1] + (w_in[i] - w_in[i-int(length)]) / length
コード例 #13
0
def the_processor_template(w_in, t_in, a_in, w_out, t_out):

    # 4) Document the algorithm
    #
    """
    Add here a complete description of what the processor does, including the
    meaning of input and output variables
    """

    # 5) Initialize output parameters
    #
    # Notes:
    # - All output parameters should be initializes to a NaN.  If a processor
    #   fails, its output parameters should have the default NaN value
    # - Use np.nan for both variables and arrays
    #
    w_out[:] = np.nan  # use [:] for arrays
    t_out[0] = np.nan  # use [0] for scalar parameters

    # 6) Check inputs
    #
    # There are two kinds of checks:
    # - NaN checks.  A processor might depend on others, i.e., its input
    #   parameters are the output parameters of an other processors.  When a
    #   processor fails, all processors depending on its output should not run.
    #   Thus, skip this processor if a NaN value is detected and return NaN
    #   output parameters to propagate the failure throughout the processing chain.
    # - In-range checks.  Check if indexes are within 0 and len(waveform),
    #   amplitudes are positive, etc.  A failure of this check implies errors in
    #   the DSP JSON config file.  Abort the analysis immediately.
    #
    if np.isnan(w_in).any() or np.isnan(t_in) or np.isnan(a_in):
        return

    if a_in < 0:
        raise DSPFatal('The error message goes here')

    # 7) Algorithm
    #
    # Loop over waveforms by using a "for i in range(.., .., ..)" instruction.
    # Avoid loops based on a while condition which might lead to segfault.  Avoid
    # also enumerate/ndenumerate to keep code as similar as possible among all
    # processors.
    #
    # Example of an algorithm to find the first index above "t_in" in which the
    # signal crossed the value "a_in"
    #
    for i in range(t_in, 1, 1):
        if w_in[i] >= a_in and w_in[i - 1] < a_in:
            t_out[0] = i
            return
コード例 #14
0
def avg_current(w_in, length, w_out):
    """
    Calculate the derivative of the waveform, averaged across the specified
    number of samples.

    Parameters
    ----------
    w_in  : array-like
            The input waveform
    length: int
            The length of the moving window
    w_out : array-like
            The output derivative

    Processing Chain Example
    ------------------------
    "curr": {
        "function": "avg_current",
        "module": "pygama.dsp.processors",
        "args": ["wf_pz", 1, "curr(len(wf_pz)-1, f)"],
        "unit": "ADC/sample",
        "prereqs": ["wf_pz"]
    }
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any():
        return

    if np.floor(length) != length:
        raise DSPFatal('The length of the moving window must be an integer')

    if int(length) < 0 or int(length) >= len(w_in):
        raise DSPFatal('The length of the moving window is out of range')

    w_out[:] = w_in[int(length):] - w_in[:-int(length)]
    w_out /= length
コード例 #15
0
def fixed_time_pickoff(w_in, t_in, a_out):
    """
    Pick off the waveform value at the provided index.  If the
    provided index is out of range, return NaN.

    Parameters
    ----------
    w_in : array-like
           The input waveform
    t_in : int
           The waveform index to pick off
    a_out: float
           The output pick-off value

    Processing Chain Example
    ------------------------
    "trapEftp": {
        "function": "fixed_time_pickoff",
        "module": "pygama.dsp.processors",
        "args": ["wf_trap", "tp_0+10*us", "trapEftp"],
        "unit": "ADC",
        "prereqs": ["wf_trap", "tp_0"]
    }
    """
    a_out[0] = np.nan

    if np.isnan(w_in).any() or np.isnan(t_in):
        return

    if np.floor(t_in) != t_in:
        raise DSPFatal('The pick-off index must be an integer')

    if int(t_in) < 0 or int(t_in) >= len(w_in):
        return
  
    a_out[0] = w_in[int(t_in)]
コード例 #16
0
ファイル: trap_filters.py プロジェクト: patgo25/pygama
def trap_pickoff(w_in, rise, flat, t_pickoff, a_out):
    """
    Pick off the value at the provided index of a symmetric trapezoidal
    filter to the input waveform, normalized by the number of samples averaged
    in the rise and fall sections.
    
    Parameters
    ----------
    w_in     : array-like
               The input waveform
    rise     : int
               The number of samples averaged in the rise and fall sections
    flat     : int
               The delay between the rise and fall sections
    t_pickoff: int
               The waveform index to pick off
    a_out    : float
               The output pick-off value of the filtered waveform
    
    Processing Chain Example
    ------------------------
    "ct_corr": {
        "function": "trap_pickoff",
        "module": "pygama.dsp.processors",
        "args": ["wf_pz", "1.5*us", 0, "tp_0", "ct_corr"],
        "unit": "ADC",
        "prereqs": ["wf_pz", "tp_0"]
    }
    """
    a_out[0] = np.nan

    if np.isnan(w_in).any() or np.isnan(rise) or np.isnan(flat) or np.isnan(
            t_pickoff):
        return

    if np.floor(rise) != rise:
        raise DSPFatal(
            'The number of samples in the rise section must be an integer')

    if np.floor(flat) != flat:
        raise DSPFatal(
            'The number of samples in the flat section must be an integer')

    if np.floor(t_pickoff) != t_pickoff:
        raise DSPFatal('The pick-off index must be an integer')

    if int(rise) < 0:
        raise DSPFatal(
            'The number of samples in the rise section must be positive')

    if int(flat) < 0:
        raise DSPFatal(
            'The number of samples in the flat section must be positive')

    if 2 * int(rise) + int(flat) > len(w_in):
        raise DSPFatal('The trapezoid width is wider than the waveform')

    I_1 = 0.
    I_2 = 0.
    rise_int = int(rise)
    flat_int = int(flat)
    start_time = int(t_pickoff + 1)
    for i in range(start_time - rise_int, start_time, 1):
        I_1 += w_in[i]
    for i in range(start_time - 2 * rise_int - flat_int,
                   start_time - rise_int - flat_int, 1):
        I_2 += w_in[i]
    a_out[0] = (I_1 - I_2) / rise
コード例 #17
0
ファイル: convolutions.py プロジェクト: patgo25/pygama
def cusp_filter(length, sigma, flat, decay):
    """
    Apply a CUSP filter to the waveform.  Note that it is composed of a
    factory function that is called using the init_args argument and that
    the function the waveforms are passed to using args.

    Initialization Parameters
    -------------------------
    length: int
            The length of the filter to be convolved
    sigma : float
            The curvature of the rising and falling part of the kernel
    flat  : int
            The length of the flat section
    decay : int
            The decay constant of the exponential to be convolved

    Parameters
    ----------
    w_in : array-like
           The input waveform
    w_out: array-like
           The filtered waveform

    Processing Chain Example
    ------------------------
    "wf_cusp": {
        "function": "cusp_filter",
        "module": "pygama.dsp.processors",
        "args": ["wf_bl", "wf_cusp(101,f)"],
        "unit": "ADC",
        "prereqs": ["wf_bl"],
        "init_args": ["len(wf_bl)-100", "40*us", "3*us", "45*us"]
    }
    """
    if length <= 0:
        raise DSPFatal('The length of the filter must be positive')

    if sigma < 0:
        raise DSPFatal('The curvature parameter must be positive')

    if flat < 0:
        raise DSPFatal('The length of the flat section must be positive')

    if decay < 0:
        raise DSPFatal('The decay constant must be positive')

    lt = int((length - flat) / 2)
    flat_int = int(flat)
    cusp = np.zeros(length)
    for ind in range(0, lt, 1):
        cusp[ind] = float(np.sinh(ind / sigma) / np.sinh(lt / sigma))
    for ind in range(lt, lt + flat_int + 1, 1):
        cusp[ind] = 1
    for ind in range(lt + flat_int + 1, length, 1):
        cusp[ind] = float(
            np.sinh((length - ind) / sigma) / np.sinh(lt / sigma))

    den = [1, -np.exp(-1 / decay)]
    cuspd = np.convolve(cusp, den, 'same')

    @guvectorize(
        ["void(float32[:], float32[:])", "void(float64[:], float64[:])"],
        "(n),(m)",
        forceobj=True)
    def cusp_out(w_in, w_out):
        w_out[:] = np.nan

        if np.isnan(w_in).any():
            return

        if len(cuspd) > len(w_in):
            raise DSPFatal('The filter is longer than the input waveform')

        w_out[:] = np.convolve(w_in, cuspd, 'valid')

    return cusp_out
コード例 #18
0
ファイル: convolutions.py プロジェクト: patgo25/pygama
def zac_filter(length, sigma, flat, decay):
    """
    Apply a ZAC (Zero Area CUSP) filter to the waveform.  Note that it is
    composed of a factory function that is called using the init_args
    argument and that the function the waveforms are passed to using args.

    Initialization Parameters
    -------------------------
    length: int
            The length of the filter to be convolved
    sigma : float
            The curvature of the rising and falling part of the kernel
    flat  : int
            The length of the flat section
    decay : int
            The decay constant of the exponential to be convolved

    Parameters
    ----------
    w_in : array-like
           The input waveform
    w_out: array-like
           The filtered waveform

    Processing Chain Example
    ------------------------
    "wf_zac": {
        "function": "zac_filter",
        "module": "pygama.dsp.processors",
        "args": ["wf_bl", "wf_zac(101,f)"],
        "unit": "ADC",
        "prereqs": ["wf_bl"],
        "init_args": ["len(wf_bl)-100", "40*us", "3*us", "45*us"],
    }
    """
    if length <= 0:
        raise DSPFatal('The length of the filter must be positive')

    if sigma < 0:
        raise DSPFatal('The curvature parameter must be positive')

    if flat < 0:
        raise DSPFatal('The length of the flat section must be positive')

    if decay < 0:
        raise DSPFatal('The decay constant must be positive')

    lt = int((length - flat) / 2)
    flat_int = int(flat)

    # calculate cusp filter and negative parables
    cusp = np.zeros(length)
    par = np.zeros(length)
    for ind in range(0, lt, 1):
        cusp[ind] = float(np.sinh(ind / sigma) / np.sinh(lt / sigma))
        par[ind] = np.power(ind - lt / 2, 2) - np.power(lt / 2, 2)
    for ind in range(lt, lt + flat_int + 1, 1):
        cusp[ind] = 1
    for ind in range(lt + flat_int + 1, length, 1):
        cusp[ind] = float(
            np.sinh((length - ind) / sigma) / np.sinh(lt / sigma))
        par[ind] = np.power(length - ind - lt / 2, 2) - np.power(lt / 2, 2)

    # calculate area of cusp and parables
    areapar, areacusp = 0, 0
    for i in range(0, length, 1):
        areapar += par[i]
        areacusp += cusp[i]

    # normalize parables area
    par = -par / areapar * areacusp

    # create zac filter
    zac = cusp + par

    # deconvolve zac filter
    den = [1, -np.exp(-1 / decay)]
    zacd = np.convolve(zac, den, 'same')

    @guvectorize(
        ["void(float32[:], float32[:])", "void(float64[:], float64[:])"],
        "(n),(m)",
        forceobj=True)
    def zac_out(w_in, w_out):
        w_out[:] = np.nan

        if np.isnan(w_in).any():
            return

        if len(zacd) > len(w_in):
            raise DSPFatal('The filter is longer than the input waveform')

        w_out[:] = np.convolve(w_in, zacd, 'valid')

    return zac_out
コード例 #19
0
def get_multi_local_extrema(w_in, a_delta_in, vt_max_out, vt_min_out, n_max_out, n_min_out, flag_out):
    """
    Get lists of indices of the local maxima and minima of data
    The "local" extrema are those maxima / minima that have heights / depths of
    at least a_delta_in.
    Converted from MATLAB script at: http://billauer.co.il/peakdet.html
    Parameters
    ----------
    w_in : array-like
        The array of data within which extrema will be found
    a_delta_in : scalar
        The absolute level by which data must vary (in one direction) about an
        extremum in order for it to be tagged
    Returns
    -------
    vt_max_out, vt_min_out : array-like, array-like
        Arrays of fixed length (padded with nans) that hold the indices of
        the identified local maxima and minima
    n_max_out, n_min_out: scalar, scalar 
        The number of maxima and minima found in a waveform
    flag_out: scalar
        Returns 1 if there is only one maximum and it is a simple waveform, 
        Returns 0 if there are no peaks, or multiple peaks in a waveform
        
    """

    # prepare output 
    
    vt_max_out[:]= np.nan
    vt_min_out[:] = np.nan    
    n_max_out[0] = np.nan
    n_min_out[0] = np.nan
    flag_out[0] = np.nan
    
    # initialize internal counters
    
    n_max_counter = 0 
    n_min_counter = 0 
    
    
    # Checks 
    
    if (np.isnan(w_in).any() or np.isnan(a_delta_in)):
        return

    if (not len(vt_max_out)<len(w_in) or not len(vt_min_out)<len(w_in)):
        raise DSPFatal('The length of your return array must be smaller than the length of your waveform')
    if (not a_delta_in >= 0): 
        raise DSPFatal('a_delta_in must be positive')
        
    # now loop over data
    
    imax, imin = 0, 0
    find_max = True
    for i in range(len(w_in)):

        if w_in[i] > w_in[imax]: imax = i
        if w_in[i] < w_in[imin]: imin = i

        if find_max:
            # if the sample is less than the current max by more than a_delta_in,
            # declare the previous one a maximum, then set this as the new "min"
            if w_in[i] < w_in[imax] - a_delta_in and int(n_max_counter) < int(len(vt_max_out)):
                vt_max_out[int(n_max_counter)]=imax
                n_max_counter += 1
                imin = i
                find_max = False
        else:
            # if the sample is more than the current min by more than a_delta_in,
            # declare the previous one a minimum, then set this as the new "max"
            if w_in[i] > w_in[imin] + a_delta_in and int(n_min_counter) < int(len(vt_min_out)):
                vt_min_out[int(n_min_counter)] = imin
                n_min_counter += 1
                imax = i
                find_max = True
                
    # set output
    n_max_out[0] = n_max_counter
    n_min_out[0] = n_min_counter
    
    if n_max_out[0] == 1:
        flag_out[0] = 1
    else:
        flag_out[0] = 0
コード例 #20
0
ファイル: trap_filters.py プロジェクト: patgo25/pygama
def trap_norm(w_in, rise, flat, w_out):
    """
    Apply a symmetric trapezoidal filter to the waveform, normalized
    by the number of samples averaged in the rise and fall sections.

    Parameters
    ----------
    w_in : array-like
           The input waveform
    rise : int
           The number of samples averaged in the rise and fall sections
    flat : int
           The delay between the rise and fall sections
    w_out: array-like
           The normalized, filtered waveform

    Processing Chain Example
    ------------------------
    "wf_tf": {
        "function": "trap_norm",
        "module": "pygama.dsp.processors",
        "args": ["wf_pz", "10*us", "3*us", "wf_tf"],
        "unit": "ADC",
        "prereqs": ["wf_pz"]
    }
    """
    w_out[:] = np.nan

    if np.isnan(w_in).any() or np.isnan(rise) or np.isnan(flat):
        return

    if np.floor(rise) != rise:
        raise DSPFatal(
            'The number of samples in the rise section must be an integer')

    if np.floor(flat) != flat:
        raise DSPFatal(
            'The number of samples in the flat section must be an integer')

    if int(rise) < 0:
        raise DSPFatal(
            'The number of samples in the rise section must be positive')

    if int(flat) < 0:
        raise DSPFatal(
            'The number of samples in the flat section must be positive')

    if 2 * int(rise) + int(flat) > len(w_in):
        raise DSPFatal('The trapezoid width is wider than the waveform')

    rise_int = int(rise)
    flat_int = int(flat)
    w_out[0] = w_in[0] / rise
    for i in range(1, rise_int, 1):
        w_out[i] = w_out[i - 1] + w_in[i] / rise
    for i in range(rise_int, rise_int + flat_int, 1):
        w_out[i] = w_out[i - 1] + (w_in[i] - w_in[i - rise_int]) / rise
    for i in range(rise_int + flat_int, 2 * rise_int + flat_int, 1):
        w_out[i] = w_out[i - 1] + (w_in[i] - w_in[i - rise_int] -
                                   w_in[i - rise_int - flat_int]) / rise
    for i in range(2 * rise_int + flat_int, len(w_in), 1):
        w_out[i] = w_out[i - 1] + (w_in[i] - w_in[i - rise_int] -
                                   w_in[i - rise_int - flat_int] +
                                   w_in[i - 2 * rise_int - flat_int]) / rise