コード例 #1
0
def get_sampling_w(t: npt.ArrayLike,
                   oversampling: Optional[int] = 8,
                   max_freq: Optional[int] = 1) -> npt.ArrayLike:
    '''
    Get sampling frequency of time-series

    Args:
        t: Sampling times
        oversampling: Oversampling factor
        max_freq: Maximum frequency scaling factor. Any value over 1 will
            ignore Nyquists frequency limit

    Returns:
        Sampling frequencies spaced by 1/(T * oversampling) where T
        is the interval spanned by t
    '''

    T = (t.max() - t.min())
    N = t.shape[0]

    return np.arange(1 / (T * oversampling), max_freq * N / (2 * T),
                     1 / (T * oversampling))
コード例 #2
0
ファイル: _geometric_slerp.py プロジェクト: yacth/scipy
def geometric_slerp(
    start: npt.ArrayLike,
    end: npt.ArrayLike,
    t: npt.ArrayLike,
    tol: float = 1e-7,
) -> np.ndarray:
    """
    Geometric spherical linear interpolation.

    The interpolation occurs along a unit-radius
    great circle arc in arbitrary dimensional space.

    Parameters
    ----------
    start : (n_dimensions, ) array-like
        Single n-dimensional input coordinate in a 1-D array-like
        object. `n` must be greater than 1.
    end : (n_dimensions, ) array-like
        Single n-dimensional input coordinate in a 1-D array-like
        object. `n` must be greater than 1.
    t: float or (n_points,) array-like
        A float or array-like of doubles representing interpolation
        parameters, with values required in the inclusive interval
        between 0 and 1. A common approach is to generate the array
        with ``np.linspace(0, 1, n_pts)`` for linearly spaced points.
        Ascending, descending, and scrambled orders are permitted.
    tol: float
        The absolute tolerance for determining if the start and end
        coordinates are antipodes.

    Returns
    -------
    result : (t.size, D)
        An array of doubles containing the interpolated
        spherical path and including start and
        end when 0 and 1 t are used. The
        interpolated values should correspond to the
        same sort order provided in the t array. The result
        may be 1-dimensional if ``t`` is a float.

    Raises
    ------
    ValueError
        If ``start`` and ``end`` are antipodes, not on the
        unit n-sphere, or for a variety of degenerate conditions.

    Notes
    -----
    The implementation is based on the mathematical formula provided in [1]_,
    and the first known presentation of this algorithm, derived from study of
    4-D geometry, is credited to Glenn Davis in a footnote of the original
    quaternion Slerp publication by Ken Shoemake [2]_.

    .. versionadded:: 1.5.0

    References
    ----------
    .. [1] https://en.wikipedia.org/wiki/Slerp#Geometric_Slerp
    .. [2] Ken Shoemake (1985) Animating rotation with quaternion curves.
           ACM SIGGRAPH Computer Graphics, 19(3): 245-254.

    See Also
    --------
    scipy.spatial.transform.Slerp : 3-D Slerp that works with quaternions

    Examples
    --------
    Interpolate four linearly-spaced values on the circumference of
    a circle spanning 90 degrees:

    >>> from scipy.spatial import geometric_slerp
    >>> import matplotlib.pyplot as plt
    >>> fig = plt.figure()
    >>> ax = fig.add_subplot(111)
    >>> start = np.array([1, 0])
    >>> end = np.array([0, 1])
    >>> t_vals = np.linspace(0, 1, 4)
    >>> result = geometric_slerp(start,
    ...                          end,
    ...                          t_vals)

    The interpolated results should be at 30 degree intervals
    recognizable on the unit circle:

    >>> ax.scatter(result[...,0], result[...,1], c='k')
    >>> circle = plt.Circle((0, 0), 1, color='grey')
    >>> ax.add_artist(circle)
    >>> ax.set_aspect('equal')
    >>> plt.show()

    Attempting to interpolate between antipodes on a circle is
    ambiguous because there are two possible paths, and on a
    sphere there are infinite possible paths on the geodesic surface.
    Nonetheless, one of the ambiguous paths is returned along
    with a warning:

    >>> opposite_pole = np.array([-1, 0])
    >>> with np.testing.suppress_warnings() as sup:
    ...     sup.filter(UserWarning)
    ...     geometric_slerp(start,
    ...                     opposite_pole,
    ...                     t_vals)
    array([[ 1.00000000e+00,  0.00000000e+00],
           [ 5.00000000e-01,  8.66025404e-01],
           [-5.00000000e-01,  8.66025404e-01],
           [-1.00000000e+00,  1.22464680e-16]])

    Extend the original example to a sphere and plot interpolation
    points in 3D:

    >>> from mpl_toolkits.mplot3d import proj3d
    >>> fig = plt.figure()
    >>> ax = fig.add_subplot(111, projection='3d')

    Plot the unit sphere for reference (optional):

    >>> u = np.linspace(0, 2 * np.pi, 100)
    >>> v = np.linspace(0, np.pi, 100)
    >>> x = np.outer(np.cos(u), np.sin(v))
    >>> y = np.outer(np.sin(u), np.sin(v))
    >>> z = np.outer(np.ones(np.size(u)), np.cos(v))
    >>> ax.plot_surface(x, y, z, color='y', alpha=0.1)

    Interpolating over a larger number of points
    may provide the appearance of a smooth curve on
    the surface of the sphere, which is also useful
    for discretized integration calculations on a
    sphere surface:

    >>> start = np.array([1, 0, 0])
    >>> end = np.array([0, 0, 1])
    >>> t_vals = np.linspace(0, 1, 200)
    >>> result = geometric_slerp(start,
    ...                          end,
    ...                          t_vals)
    >>> ax.plot(result[...,0],
    ...         result[...,1],
    ...         result[...,2],
    ...         c='k')
    >>> plt.show()
    """

    start = np.asarray(start, dtype=np.float64)
    end = np.asarray(end, dtype=np.float64)

    if start.ndim != 1 or end.ndim != 1:
        raise ValueError("Start and end coordinates "
                         "must be one-dimensional")

    if start.size != end.size:
        raise ValueError("The dimensions of start and "
                         "end must match (have same size)")

    if start.size < 2 or end.size < 2:
        raise ValueError("The start and end coordinates must "
                         "both be in at least two-dimensional "
                         "space")

    if np.array_equal(start, end):
        return np.linspace(start, start, np.asarray(t).size)

    # for points that violate equation for n-sphere
    for coord in [start, end]:
        if not np.allclose(np.linalg.norm(coord), 1.0, rtol=1e-9, atol=0):
            raise ValueError("start and end are not" " on a unit n-sphere")

    if not isinstance(tol, float):
        raise ValueError("tol must be a float")
    else:
        tol = np.fabs(tol)

    coord_dist = euclidean(start, end)

    # diameter of 2 within tolerance means antipodes, which is a problem
    # for all unit n-spheres (even the 0-sphere would have an ambiguous path)
    if np.allclose(coord_dist, 2.0, rtol=0, atol=tol):
        warnings.warn("start and end are antipodes"
                      " using the specified tolerance;"
                      " this may cause ambiguous slerp paths")

    t = np.asarray(t, dtype=np.float64)

    if t.size == 0:
        return np.empty((0, start.size))

    if t.min() < 0 or t.max() > 1:
        raise ValueError("interpolation parameter must be in [0, 1]")

    if t.ndim == 0:
        return _geometric_slerp(start, end, np.atleast_1d(t)).ravel()
    else:
        return _geometric_slerp(start, end, t)
コード例 #3
0
ファイル: date_time_helpers.py プロジェクト: ericspod/ExeTera
def get_days(
    date_field: ArrayLike,
    date_filter: ArrayLike = None,
    start_date: Optional[np.float64] = None,
    end_date: Optional[np.float64] = None
) -> Tuple[ArrayLike, Optional[ArrayLike]]:
    """
    This converts a field of timestamps into a field of relative elapsed days.
    The precise behaviour depends on the optional parameters but essentially, the lowest
    valid day is taken as day 0, and all other timestamps are converted to whole numbers
    of days elapsed since this timestamp:
    
    * If ``start_date`` is set, the start_date is used as the zero-date
    * If ``start_date`` is not set:
    
      * If ``date_filter`` is not set, the lowest timestamp is used as the zero-date
      * If ``date_filter`` is set, the lowest unfiltered timestamp is used as the zero-date

    As well as returning the elapsed days, this method can also return a filter for which
    elapsed dates are valid. This is determined as follows:
    
    * If ``date_filter``, ``start_date`` and ``end_date`` are None, None is returned
    * otherwise:
    
      * If ``date_filter`` is not provided, the filter represents all dates that are out
        of range with respect to the start_date and end_date parameters
      * If ``date_filter`` is provided, the filter is all dates out of range with respect to
        the start_date and end_date parameters unioned with the date_filter that was
        passed in

    """
    if not isinstance(date_field,
                      np.ndarray) or date_field.dtype != np.float64:
        raise ValueError(
            "'date_field' must be a numpy array of type np.float64")
    if date_filter is not None:
        if not isinstance(date_filter,
                          np.ndarray) or date_filter.dtype not in (bool,
                                                                   np.int8):
            raise ValueError(
                "'date_filter' must be a numpy array of type bool or np.int8")

    if start_date is None and end_date is None and date_filter is None:
        min_date = date_field.min()
        days = np.floor(
            (date_field - min_date) / SECONDS_PER_DAY).astype(np.int32)
        return days, None
    else:
        in_range = np.ones(len(date_field),
                           dtype=bool) if date_filter is None else date_filter
        if start_date is not None:
            min_date = start_date
            in_range = in_range & (date_field >= start_date)
        else:
            min_date = np.min(
                date_field if date_filter is None else date_field[date_filter])
        if end_date is not None:
            in_range = in_range & (date_field < end_date)
        days = np.floor(
            (date_field - min_date) / SECONDS_PER_DAY).astype(np.int32)
        return days, in_range