| from functools import update_wrapper, lru_cache |
| import inspect |
|
|
| from ._pocketfft import helper as _helper |
|
|
| import numpy as np |
| from scipy._lib._array_api import array_namespace |
|
|
|
|
| def next_fast_len(target, real=False): |
| """Find the next fast size of input data to ``fft``, for zero-padding, etc. |
| |
| SciPy's FFT algorithms gain their speed by a recursive divide and conquer |
| strategy. This relies on efficient functions for small prime factors of the |
| input length. Thus, the transforms are fastest when using composites of the |
| prime factors handled by the fft implementation. If there are efficient |
| functions for all radices <= `n`, then the result will be a number `x` |
| >= ``target`` with only prime factors < `n`. (Also known as `n`-smooth |
| numbers) |
| |
| Parameters |
| ---------- |
| target : int |
| Length to start searching from. Must be a positive integer. |
| real : bool, optional |
| True if the FFT involves real input or output (e.g., `rfft` or `hfft` |
| but not `fft`). Defaults to False. |
| |
| Returns |
| ------- |
| out : int |
| The smallest fast length greater than or equal to ``target``. |
| |
| Notes |
| ----- |
| The result of this function may change in future as performance |
| considerations change, for example, if new prime factors are added. |
| |
| Calling `fft` or `ifft` with real input data performs an ``'R2C'`` |
| transform internally. |
| |
| Examples |
| -------- |
| On a particular machine, an FFT of prime length takes 11.4 ms: |
| |
| >>> from scipy import fft |
| >>> import numpy as np |
| >>> rng = np.random.default_rng() |
| >>> min_len = 93059 # prime length is worst case for speed |
| >>> a = rng.standard_normal(min_len) |
| >>> b = fft.fft(a) |
| |
| Zero-padding to the next regular length reduces computation time to |
| 1.6 ms, a speedup of 7.3 times: |
| |
| >>> fft.next_fast_len(min_len, real=True) |
| 93312 |
| >>> b = fft.fft(a, 93312) |
| |
| Rounding up to the next power of 2 is not optimal, taking 3.0 ms to |
| compute; 1.9 times longer than the size given by ``next_fast_len``: |
| |
| >>> b = fft.fft(a, 131072) |
| |
| """ |
| pass |
|
|
|
|
| |
| |
| _sig = inspect.signature(next_fast_len) |
| next_fast_len = update_wrapper(lru_cache(_helper.good_size), next_fast_len) |
| next_fast_len.__wrapped__ = _helper.good_size |
| next_fast_len.__signature__ = _sig |
|
|
|
|
| def prev_fast_len(target, real=False): |
| """Find the previous fast size of input data to ``fft``. |
| Useful for discarding a minimal number of samples before FFT. |
| |
| SciPy's FFT algorithms gain their speed by a recursive divide and conquer |
| strategy. This relies on efficient functions for small prime factors of the |
| input length. Thus, the transforms are fastest when using composites of the |
| prime factors handled by the fft implementation. If there are efficient |
| functions for all radices <= `n`, then the result will be a number `x` |
| <= ``target`` with only prime factors <= `n`. (Also known as `n`-smooth |
| numbers) |
| |
| Parameters |
| ---------- |
| target : int |
| Maximum length to search until. Must be a positive integer. |
| real : bool, optional |
| True if the FFT involves real input or output (e.g., `rfft` or `hfft` |
| but not `fft`). Defaults to False. |
| |
| Returns |
| ------- |
| out : int |
| The largest fast length less than or equal to ``target``. |
| |
| Notes |
| ----- |
| The result of this function may change in future as performance |
| considerations change, for example, if new prime factors are added. |
| |
| Calling `fft` or `ifft` with real input data performs an ``'R2C'`` |
| transform internally. |
| |
| In the current implementation, prev_fast_len assumes radices of |
| 2,3,5,7,11 for complex FFT and 2,3,5 for real FFT. |
| |
| Examples |
| -------- |
| On a particular machine, an FFT of prime length takes 16.2 ms: |
| |
| >>> from scipy import fft |
| >>> import numpy as np |
| >>> rng = np.random.default_rng() |
| >>> max_len = 93059 # prime length is worst case for speed |
| >>> a = rng.standard_normal(max_len) |
| >>> b = fft.fft(a) |
| |
| Performing FFT on the maximum fast length less than max_len |
| reduces the computation time to 1.5 ms, a speedup of 10.5 times: |
| |
| >>> fft.prev_fast_len(max_len, real=True) |
| 92160 |
| >>> c = fft.fft(a[:92160]) # discard last 899 samples |
| |
| """ |
| pass |
|
|
|
|
| |
| |
| _sig_prev_fast_len = inspect.signature(prev_fast_len) |
| prev_fast_len = update_wrapper(lru_cache()(_helper.prev_good_size), prev_fast_len) |
| prev_fast_len.__wrapped__ = _helper.prev_good_size |
| prev_fast_len.__signature__ = _sig_prev_fast_len |
|
|
|
|
| def _init_nd_shape_and_axes(x, shape, axes): |
| """Handle shape and axes arguments for N-D transforms. |
| |
| Returns the shape and axes in a standard form, taking into account negative |
| values and checking for various potential errors. |
| |
| Parameters |
| ---------- |
| x : array_like |
| The input array. |
| shape : int or array_like of ints or None |
| The shape of the result. If both `shape` and `axes` (see below) are |
| None, `shape` is ``x.shape``; if `shape` is None but `axes` is |
| not None, then `shape` is ``numpy.take(x.shape, axes, axis=0)``. |
| If `shape` is -1, the size of the corresponding dimension of `x` is |
| used. |
| axes : int or array_like of ints or None |
| Axes along which the calculation is computed. |
| The default is over all axes. |
| Negative indices are automatically converted to their positive |
| counterparts. |
| |
| Returns |
| ------- |
| shape : tuple |
| The shape of the result as a tuple of integers. |
| axes : list |
| Axes along which the calculation is computed, as a list of integers. |
| |
| """ |
| x = np.asarray(x) |
| return _helper._init_nd_shape_and_axes(x, shape, axes) |
|
|
|
|
| def fftfreq(n, d=1.0, *, xp=None, device=None): |
| """Return the Discrete Fourier Transform sample frequencies. |
| |
| The returned float array `f` contains the frequency bin centers in cycles |
| per unit of the sample spacing (with zero at the start). For instance, if |
| the sample spacing is in seconds, then the frequency unit is cycles/second. |
| |
| Given a window length `n` and a sample spacing `d`:: |
| |
| f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even |
| f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd |
| |
| Parameters |
| ---------- |
| n : int |
| Window length. |
| d : scalar, optional |
| Sample spacing (inverse of the sampling rate). Defaults to 1. |
| xp : array_namespace, optional |
| The namespace for the return array. Default is None, where NumPy is used. |
| device : device, optional |
| The device for the return array. |
| Only valid when `xp.fft.fftfreq` implements the device parameter. |
| |
| Returns |
| ------- |
| f : ndarray |
| Array of length `n` containing the sample frequencies. |
| |
| Examples |
| -------- |
| >>> import numpy as np |
| >>> import scipy.fft |
| >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5], dtype=float) |
| >>> fourier = scipy.fft.fft(signal) |
| >>> n = signal.size |
| >>> timestep = 0.1 |
| >>> freq = scipy.fft.fftfreq(n, d=timestep) |
| >>> freq |
| array([ 0. , 1.25, 2.5 , ..., -3.75, -2.5 , -1.25]) |
| |
| """ |
| xp = np if xp is None else xp |
| |
| |
| if hasattr(xp, 'fft') and xp.__name__ != 'numpy': |
| return xp.fft.fftfreq(n, d=d, device=device) |
| if device is not None: |
| raise ValueError('device parameter is not supported for input array type') |
| return np.fft.fftfreq(n, d=d) |
|
|
|
|
| def rfftfreq(n, d=1.0, *, xp=None, device=None): |
| """Return the Discrete Fourier Transform sample frequencies |
| (for usage with rfft, irfft). |
| |
| The returned float array `f` contains the frequency bin centers in cycles |
| per unit of the sample spacing (with zero at the start). For instance, if |
| the sample spacing is in seconds, then the frequency unit is cycles/second. |
| |
| Given a window length `n` and a sample spacing `d`:: |
| |
| f = [0, 1, ..., n/2-1, n/2] / (d*n) if n is even |
| f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) if n is odd |
| |
| Unlike `fftfreq` (but like `scipy.fftpack.rfftfreq`) |
| the Nyquist frequency component is considered to be positive. |
| |
| Parameters |
| ---------- |
| n : int |
| Window length. |
| d : scalar, optional |
| Sample spacing (inverse of the sampling rate). Defaults to 1. |
| xp : array_namespace, optional |
| The namespace for the return array. Default is None, where NumPy is used. |
| device : device, optional |
| The device for the return array. |
| Only valid when `xp.fft.rfftfreq` implements the device parameter. |
| |
| Returns |
| ------- |
| f : ndarray |
| Array of length ``n//2 + 1`` containing the sample frequencies. |
| |
| Examples |
| -------- |
| >>> import numpy as np |
| >>> import scipy.fft |
| >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4], dtype=float) |
| >>> fourier = scipy.fft.rfft(signal) |
| >>> n = signal.size |
| >>> sample_rate = 100 |
| >>> freq = scipy.fft.fftfreq(n, d=1./sample_rate) |
| >>> freq |
| array([ 0., 10., 20., ..., -30., -20., -10.]) |
| >>> freq = scipy.fft.rfftfreq(n, d=1./sample_rate) |
| >>> freq |
| array([ 0., 10., 20., 30., 40., 50.]) |
| |
| """ |
| xp = np if xp is None else xp |
| |
| |
| if hasattr(xp, 'fft') and xp.__name__ != 'numpy': |
| return xp.fft.rfftfreq(n, d=d, device=device) |
| if device is not None: |
| raise ValueError('device parameter is not supported for input array type') |
| return np.fft.rfftfreq(n, d=d) |
|
|
|
|
| def fftshift(x, axes=None): |
| """Shift the zero-frequency component to the center of the spectrum. |
| |
| This function swaps half-spaces for all axes listed (defaults to all). |
| Note that ``y[0]`` is the Nyquist component only if ``len(x)`` is even. |
| |
| Parameters |
| ---------- |
| x : array_like |
| Input array. |
| axes : int or shape tuple, optional |
| Axes over which to shift. Default is None, which shifts all axes. |
| |
| Returns |
| ------- |
| y : ndarray |
| The shifted array. |
| |
| See Also |
| -------- |
| ifftshift : The inverse of `fftshift`. |
| |
| Examples |
| -------- |
| >>> import numpy as np |
| >>> freqs = np.fft.fftfreq(10, 0.1) |
| >>> freqs |
| array([ 0., 1., 2., ..., -3., -2., -1.]) |
| >>> np.fft.fftshift(freqs) |
| array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.]) |
| |
| Shift the zero-frequency component only along the second axis: |
| |
| >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3) |
| >>> freqs |
| array([[ 0., 1., 2.], |
| [ 3., 4., -4.], |
| [-3., -2., -1.]]) |
| >>> np.fft.fftshift(freqs, axes=(1,)) |
| array([[ 2., 0., 1.], |
| [-4., 3., 4.], |
| [-1., -3., -2.]]) |
| |
| """ |
| xp = array_namespace(x) |
| if hasattr(xp, 'fft'): |
| return xp.fft.fftshift(x, axes=axes) |
| x = np.asarray(x) |
| y = np.fft.fftshift(x, axes=axes) |
| return xp.asarray(y) |
|
|
|
|
| def ifftshift(x, axes=None): |
| """The inverse of `fftshift`. Although identical for even-length `x`, the |
| functions differ by one sample for odd-length `x`. |
| |
| Parameters |
| ---------- |
| x : array_like |
| Input array. |
| axes : int or shape tuple, optional |
| Axes over which to calculate. Defaults to None, which shifts all axes. |
| |
| Returns |
| ------- |
| y : ndarray |
| The shifted array. |
| |
| See Also |
| -------- |
| fftshift : Shift zero-frequency component to the center of the spectrum. |
| |
| Examples |
| -------- |
| >>> import numpy as np |
| >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3) |
| >>> freqs |
| array([[ 0., 1., 2.], |
| [ 3., 4., -4.], |
| [-3., -2., -1.]]) |
| >>> np.fft.ifftshift(np.fft.fftshift(freqs)) |
| array([[ 0., 1., 2.], |
| [ 3., 4., -4.], |
| [-3., -2., -1.]]) |
| |
| """ |
| xp = array_namespace(x) |
| if hasattr(xp, 'fft'): |
| return xp.fft.ifftshift(x, axes=axes) |
| x = np.asarray(x) |
| y = np.fft.ifftshift(x, axes=axes) |
| return xp.asarray(y) |
|
|