peng/wave_functions.py
def find(wave, dep_var, der=None, inst=1, indep_min=None, indep_max=None):
    r"""
    Return the independent variable point associated with a dependent variable point.

    If the dependent variable point is not in the dependent variable vector the
    independent variable vector point is obtained by linear interpolation

    :param wave: Waveform
    :type  wave: :py:class:`peng.eng.Waveform`

    :param dep_var: Dependent vector value to search for
    :type  dep_var: integer, float or complex

    :param der: Dependent vector derivative filter. If +1 only independent
                vector points that have positive derivatives when crossing
                the requested dependent vector point are returned; if -1 only
                independent vector points that have negative derivatives when
                crossing the requested dependent vector point are returned;
                if 0 only independent vector points that have null derivatives
                when crossing the requested dependent vector point are
                returned; otherwise if None all independent vector points are
                returned regardless of the dependent vector derivative. The
                derivative of the first and last point of the waveform is
                assumed to be null
    :type  der: integer, float or complex

    :param inst: Instance number filter. If, for example, **inst** equals 3,
                 then the independent variable vector point at which the
                 dependent variable vector equals the requested value for the
                 third time is returned
    :type  inst: positive integer

    :param indep_min: Independent vector start point of computation
    :type  indep_min: integer or float

    :param indep_max: Independent vector stop point of computation
    :type  indep_max: integer or float

    :rtype: integer, float or None if the dependent variable point is not found

    .. [[[cog cog.out(exobj_eng.get_sphinx_autodoc(raised=True)) ]]]
    .. Auto-generated exceptions documentation for
    .. peng.wave_functions.find

    :raises:
     * RuntimeError (Argument \`dep_var\` is not valid)

     * RuntimeError (Argument \`der\` is not valid)

     * RuntimeError (Argument \`indep_max\` is not valid)

     * RuntimeError (Argument \`indep_min\` is not valid)

     * RuntimeError (Argument \`inst\` is not valid)

     * RuntimeError (Argument \`wave\` is not valid)

     * RuntimeError (Incongruent \`indep_min\` and \`indep_max\`
       arguments)

    .. [[[end]]]
    """
    # pylint: disable=C0325,R0914,W0613
    ret = copy.copy(wave)
    _bound_waveform(ret, indep_min, indep_max)
    close_min = np.isclose(min(ret._dep_vector), dep_var, FP_RTOL, FP_ATOL)
    close_max = np.isclose(max(ret._dep_vector), dep_var, FP_RTOL, FP_ATOL)
    if ((np.amin(ret._dep_vector) > dep_var) and (not close_min)) or (
        (np.amax(ret._dep_vector) < dep_var) and (not close_max)
    ):
        return None
    cross_wave = ret._dep_vector - dep_var
    sign_wave = np.sign(cross_wave)
    exact_idx = np.where(np.isclose(ret._dep_vector, dep_var, FP_RTOL, FP_ATOL))[0]
    # Locations where dep_vector crosses dep_var or it is equal to it
    left_idx = np.where(np.diff(sign_wave))[0]
    # Remove elements to the left of exact matches
    left_idx = np.setdiff1d(left_idx, exact_idx)
    left_idx = np.setdiff1d(left_idx, exact_idx - 1)
    right_idx = left_idx + 1 if left_idx.size else np.array([])
    indep_var = ret._indep_vector[exact_idx] if exact_idx.size else np.array([])
    dvector = np.zeros(exact_idx.size).astype(int) if exact_idx.size else np.array([])
    if left_idx.size and (ret.interp == "STAIRCASE"):
        idvector = (
            2.0 * (ret._dep_vector[right_idx] > ret._dep_vector[left_idx]).astype(int)
            - 1
        )
        if indep_var.size:
            indep_var = np.concatenate((indep_var, ret._indep_vector[right_idx]))
            dvector = np.concatenate((dvector, idvector))
            sidx = np.argsort(indep_var)
            indep_var = indep_var[sidx]
            dvector = dvector[sidx]
        else:
            indep_var = ret._indep_vector[right_idx]
            dvector = idvector
    elif left_idx.size:
        y_left = ret._dep_vector[left_idx]
        y_right = ret._dep_vector[right_idx]
        x_left = ret._indep_vector[left_idx]
        x_right = ret._indep_vector[right_idx]
        slope = ((y_left - y_right) / (x_left - x_right)).astype(float)
        # y = y0+slope*(x-x0) => x0+(y-y0)/slope
        if indep_var.size:
            indep_var = np.concatenate(
                (indep_var, x_left + ((dep_var - y_left) / slope))
            )
            dvector = np.concatenate((dvector, np.where(slope > 0, 1, -1)))
            sidx = np.argsort(indep_var)
            indep_var = indep_var[sidx]
            dvector = dvector[sidx]
        else:
            indep_var = x_left + ((dep_var - y_left) / slope)
            dvector = np.where(slope > 0, +1, -1)
    if der is not None:
        indep_var = np.extract(dvector == der, indep_var)
    return indep_var[inst - 1] if inst <= indep_var.size else None
def find(wave, dep_var, der=None, inst=1, indep_min=None, indep_max=None):
    r"""
    Return the independent variable point associated with a dependent variable point.

    If the dependent variable point is not in the dependent variable vector the
    independent variable vector point is obtained by linear interpolation

    :param wave: Waveform
    :type  wave: :py:class:`peng.eng.Waveform`

    :param dep_var: Dependent vector value to search for
    :type  dep_var: integer, float or complex

    :param der: Dependent vector derivative filter. If +1 only independent
                vector points that have positive derivatives when crossing
                the requested dependent vector point are returned; if -1 only
                independent vector points that have negative derivatives when
                crossing the requested dependent vector point are returned;
                if 0 only independent vector points that have null derivatives
                when crossing the requested dependent vector point are
                returned; otherwise if None all independent vector points are
                returned regardless of the dependent vector derivative. The
                derivative of the first and last point of the waveform is
                assumed to be null
    :type  der: integer, float or complex

    :param inst: Instance number filter. If, for example, **inst** equals 3,
                 then the independent variable vector point at which the
                 dependent variable vector equals the requested value for the
                 third time is returned
    :type  inst: positive integer

    :param indep_min: Independent vector start point of computation
    :type  indep_min: integer or float

    :param indep_max: Independent vector stop point of computation
    :type  indep_max: integer or float

    :rtype: integer, float or None if the dependent variable point is not found

    .. [[[cog cog.out(exobj_eng.get_sphinx_autodoc(raised=True)) ]]]
    .. Auto-generated exceptions documentation for
    .. peng.wave_functions.find

    :raises:
     * RuntimeError (Argument \`dep_var\` is not valid)

     * RuntimeError (Argument \`der\` is not valid)

     * RuntimeError (Argument \`indep_max\` is not valid)

     * RuntimeError (Argument \`indep_min\` is not valid)

     * RuntimeError (Argument \`inst\` is not valid)

     * RuntimeError (Argument \`wave\` is not valid)

     * RuntimeError (Incongruent \`indep_min\` and \`indep_max\`
       arguments)

    .. [[[end]]]
    """
    # pylint: disable=C0325,R0914,W0613
    ret = copy.copy(wave)
    _bound_waveform(ret, indep_min, indep_max)
    close_min = np.isclose(min(ret._dep_vector), dep_var, FP_RTOL, FP_ATOL)
    close_max = np.isclose(max(ret._dep_vector), dep_var, FP_RTOL, FP_ATOL)
    if ((np.amin(ret._dep_vector) > dep_var) and (not close_min)) or (
        (np.amax(ret._dep_vector) < dep_var) and (not close_max)
    ):
        return None
    cross_wave = ret._dep_vector - dep_var
    sign_wave = np.sign(cross_wave)
    exact_idx = np.where(np.isclose(ret._dep_vector, dep_var, FP_RTOL, FP_ATOL))[0]
    # Locations where dep_vector crosses dep_var or it is equal to it
    left_idx = np.where(np.diff(sign_wave))[0]
    # Remove elements to the left of exact matches
    left_idx = np.setdiff1d(left_idx, exact_idx)
    left_idx = np.setdiff1d(left_idx, exact_idx - 1)
    right_idx = left_idx + 1 if left_idx.size else np.array([])
    indep_var = ret._indep_vector[exact_idx] if exact_idx.size else np.array([])
    dvector = np.zeros(exact_idx.size).astype(int) if exact_idx.size else np.array([])
    if left_idx.size and (ret.interp == "STAIRCASE"):
        idvector = (
            2.0 * (ret._dep_vector[right_idx] > ret._dep_vector[left_idx]).astype(int)
            - 1
        )
        if indep_var.size:
            indep_var = np.concatenate((indep_var, ret._indep_vector[right_idx]))
            dvector = np.concatenate((dvector, idvector))
            sidx = np.argsort(indep_var)
            indep_var = indep_var[sidx]
            dvector = dvector[sidx]
        else:
            indep_var = ret._indep_vector[right_idx]
            dvector = idvector
    elif left_idx.size:
        y_left = ret._dep_vector[left_idx]
        y_right = ret._dep_vector[right_idx]
        x_left = ret._indep_vector[left_idx]
        x_right = ret._indep_vector[right_idx]
        slope = ((y_left - y_right) / (x_left - x_right)).astype(float)
        # y = y0+slope*(x-x0) => x0+(y-y0)/slope
        if indep_var.size:
            indep_var = np.concatenate(
                (indep_var, x_left + ((dep_var - y_left) / slope))
            )
            dvector = np.concatenate((dvector, np.where(slope > 0, 1, -1)))
            sidx = np.argsort(indep_var)
            indep_var = indep_var[sidx]
            dvector = dvector[sidx]
        else:
            indep_var = x_left + ((dep_var - y_left) / slope)
            dvector = np.where(slope > 0, +1, -1)
    if der is not None:
        indep_var = np.extract(dvector == der, indep_var)
    return indep_var[inst - 1] if inst <= indep_var.size else None
r"""
    Return the independent variable point associated with a dependent variable point.

    If the dependent variable point is not in the dependent variable vector the
    independent variable vector point is obtained by linear interpolation

    :param wave: Waveform
    :type  wave: :py:class:`peng.eng.Waveform`

    :param dep_var: Dependent vector value to search for
    :type  dep_var: integer, float or complex

    :param der: Dependent vector derivative filter. If +1 only independent
                vector points that have positive derivatives when crossing
                the requested dependent vector point are returned; if -1 only
                independent vector points that have negative derivatives when
                crossing the requested dependent vector point are returned;
                if 0 only independent vector points that have null derivatives
                when crossing the requested dependent vector point are
                returned; otherwise if None all independent vector points are
                returned regardless of the dependent vector derivative. The
                derivative of the first and last point of the waveform is
                assumed to be null
    :type  der: integer, float or complex

    :param inst: Instance number filter. If, for example, **inst** equals 3,
                 then the independent variable vector point at which the
                 dependent variable vector equals the requested value for the
                 third time is returned
    :type  inst: positive integer

    :param indep_min: Independent vector start point of computation
    :type  indep_min: integer or float

    :param indep_max: Independent vector stop point of computation
    :type  indep_max: integer or float

    :rtype: integer, float or None if the dependent variable point is not found

    .. [[[cog cog.out(exobj_eng.get_sphinx_autodoc(raised=True)) ]]]
    .. Auto-generated exceptions documentation for
    .. peng.wave_functions.find

    :raises:
     * RuntimeError (Argument \`dep_var\` is not valid)

     * RuntimeError (Argument \`der\` is not valid)

     * RuntimeError (Argument \`indep_max\` is not valid)

     * RuntimeError (Argument \`indep_min\` is not valid)

     * RuntimeError (Argument \`inst\` is not valid)

     * RuntimeError (Argument \`wave\` is not valid)

     * RuntimeError (Incongruent \`indep_min\` and \`indep_max\`
       arguments)

    .. [[[end]]]