helper.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. from __future__ import division, print_function, absolute_import
  2. import operator
  3. from numpy import (arange, array, asarray, atleast_1d, intc, integer,
  4. isscalar, issubdtype, take, unique, where)
  5. from numpy.fft.helper import fftshift, ifftshift, fftfreq
  6. from bisect import bisect_left
  7. __all__ = ['fftshift', 'ifftshift', 'fftfreq', 'rfftfreq', 'next_fast_len']
  8. def rfftfreq(n, d=1.0):
  9. """DFT sample frequencies (for usage with rfft, irfft).
  10. The returned float array contains the frequency bins in
  11. cycles/unit (with zero at the start) given a window length `n` and a
  12. sample spacing `d`::
  13. f = [0,1,1,2,2,...,n/2-1,n/2-1,n/2]/(d*n) if n is even
  14. f = [0,1,1,2,2,...,n/2-1,n/2-1,n/2,n/2]/(d*n) if n is odd
  15. Parameters
  16. ----------
  17. n : int
  18. Window length.
  19. d : scalar, optional
  20. Sample spacing. Default is 1.
  21. Returns
  22. -------
  23. out : ndarray
  24. The array of length `n`, containing the sample frequencies.
  25. Examples
  26. --------
  27. >>> from scipy import fftpack
  28. >>> sig = np.array([-2, 8, 6, 4, 1, 0, 3, 5], dtype=float)
  29. >>> sig_fft = fftpack.rfft(sig)
  30. >>> n = sig_fft.size
  31. >>> timestep = 0.1
  32. >>> freq = fftpack.rfftfreq(n, d=timestep)
  33. >>> freq
  34. array([ 0. , 1.25, 1.25, 2.5 , 2.5 , 3.75, 3.75, 5. ])
  35. """
  36. n = operator.index(n)
  37. if n < 0:
  38. raise ValueError("n = %s is not valid. "
  39. "n must be a nonnegative integer." % n)
  40. return (arange(1, n + 1, dtype=int) // 2) / float(n * d)
  41. def next_fast_len(target):
  42. """
  43. Find the next fast size of input data to `fft`, for zero-padding, etc.
  44. SciPy's FFTPACK has efficient functions for radix {2, 3, 4, 5}, so this
  45. returns the next composite of the prime factors 2, 3, and 5 which is
  46. greater than or equal to `target`. (These are also known as 5-smooth
  47. numbers, regular numbers, or Hamming numbers.)
  48. Parameters
  49. ----------
  50. target : int
  51. Length to start searching from. Must be a positive integer.
  52. Returns
  53. -------
  54. out : int
  55. The first 5-smooth number greater than or equal to `target`.
  56. Notes
  57. -----
  58. .. versionadded:: 0.18.0
  59. Examples
  60. --------
  61. On a particular machine, an FFT of prime length takes 133 ms:
  62. >>> from scipy import fftpack
  63. >>> min_len = 10007 # prime length is worst case for speed
  64. >>> a = np.random.randn(min_len)
  65. >>> b = fftpack.fft(a)
  66. Zero-padding to the next 5-smooth length reduces computation time to
  67. 211 us, a speedup of 630 times:
  68. >>> fftpack.helper.next_fast_len(min_len)
  69. 10125
  70. >>> b = fftpack.fft(a, 10125)
  71. Rounding up to the next power of 2 is not optimal, taking 367 us to
  72. compute, 1.7 times as long as the 5-smooth size:
  73. >>> b = fftpack.fft(a, 16384)
  74. """
  75. hams = (8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48,
  76. 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128,
  77. 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
  78. 256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450,
  79. 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729,
  80. 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125,
  81. 1152, 1200, 1215, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536,
  82. 1600, 1620, 1728, 1800, 1875, 1920, 1944, 2000, 2025, 2048, 2160,
  83. 2187, 2250, 2304, 2400, 2430, 2500, 2560, 2592, 2700, 2880, 2916,
  84. 3000, 3072, 3125, 3200, 3240, 3375, 3456, 3600, 3645, 3750, 3840,
  85. 3888, 4000, 4050, 4096, 4320, 4374, 4500, 4608, 4800, 4860, 5000,
  86. 5120, 5184, 5400, 5625, 5760, 5832, 6000, 6075, 6144, 6250, 6400,
  87. 6480, 6561, 6750, 6912, 7200, 7290, 7500, 7680, 7776, 8000, 8100,
  88. 8192, 8640, 8748, 9000, 9216, 9375, 9600, 9720, 10000)
  89. target = int(target)
  90. if target <= 6:
  91. return target
  92. # Quickly check if it's already a power of 2
  93. if not (target & (target-1)):
  94. return target
  95. # Get result quickly for small sizes, since FFT itself is similarly fast.
  96. if target <= hams[-1]:
  97. return hams[bisect_left(hams, target)]
  98. match = float('inf') # Anything found will be smaller
  99. p5 = 1
  100. while p5 < target:
  101. p35 = p5
  102. while p35 < target:
  103. # Ceiling integer division, avoiding conversion to float
  104. # (quotient = ceil(target / p35))
  105. quotient = -(-target // p35)
  106. # Quickly find next power of 2 >= quotient
  107. p2 = 2**((quotient - 1).bit_length())
  108. N = p2 * p35
  109. if N == target:
  110. return N
  111. elif N < match:
  112. match = N
  113. p35 *= 3
  114. if p35 == target:
  115. return p35
  116. if p35 < match:
  117. match = p35
  118. p5 *= 5
  119. if p5 == target:
  120. return p5
  121. if p5 < match:
  122. match = p5
  123. return match
  124. def _init_nd_shape_and_axes(x, shape, axes):
  125. """Handle shape and axes arguments for n-dimensional transforms.
  126. Returns the shape and axes in a standard form, taking into account negative
  127. values and checking for various potential errors.
  128. Parameters
  129. ----------
  130. x : array_like
  131. The input array.
  132. shape : int or array_like of ints or None
  133. The shape of the result. If both `shape` and `axes` (see below) are
  134. None, `shape` is ``x.shape``; if `shape` is None but `axes` is
  135. not None, then `shape` is ``scipy.take(x.shape, axes, axis=0)``.
  136. If `shape` is -1, the size of the corresponding dimension of `x` is
  137. used.
  138. axes : int or array_like of ints or None
  139. Axes along which the calculation is computed.
  140. The default is over all axes.
  141. Negative indices are automatically converted to their positive
  142. counterpart.
  143. Returns
  144. -------
  145. shape : array
  146. The shape of the result. It is a 1D integer array.
  147. axes : array
  148. The shape of the result. It is a 1D integer array.
  149. """
  150. x = asarray(x)
  151. noshape = shape is None
  152. noaxes = axes is None
  153. if noaxes:
  154. axes = arange(x.ndim, dtype=intc)
  155. else:
  156. axes = atleast_1d(axes)
  157. if axes.size == 0:
  158. axes = axes.astype(intc)
  159. if not axes.ndim == 1:
  160. raise ValueError("when given, axes values must be a scalar or vector")
  161. if not issubdtype(axes.dtype, integer):
  162. raise ValueError("when given, axes values must be integers")
  163. axes = where(axes < 0, axes + x.ndim, axes)
  164. if axes.size != 0 and (axes.max() >= x.ndim or axes.min() < 0):
  165. raise ValueError("axes exceeds dimensionality of input")
  166. if axes.size != 0 and unique(axes).shape != axes.shape:
  167. raise ValueError("all axes must be unique")
  168. if not noshape:
  169. shape = atleast_1d(shape)
  170. elif isscalar(x):
  171. shape = array([], dtype=intc)
  172. elif noaxes:
  173. shape = array(x.shape, dtype=intc)
  174. else:
  175. shape = take(x.shape, axes)
  176. if shape.size == 0:
  177. shape = shape.astype(intc)
  178. if shape.ndim != 1:
  179. raise ValueError("when given, shape values must be a scalar or vector")
  180. if not issubdtype(shape.dtype, integer):
  181. raise ValueError("when given, shape values must be integers")
  182. if axes.shape != shape.shape:
  183. raise ValueError("when given, axes and shape arguments"
  184. " have to be of the same length")
  185. shape = where(shape == -1, array(x.shape)[axes], shape)
  186. if shape.size != 0 and (shape < 1).any():
  187. raise ValueError(
  188. "invalid number of data points ({0}) specified".format(shape))
  189. return shape, axes
  190. def _init_nd_shape_and_axes_sorted(x, shape, axes):
  191. """Handle and sort shape and axes arguments for n-dimensional transforms.
  192. This is identical to `_init_nd_shape_and_axes`, except the axes are
  193. returned in sorted order and the shape is reordered to match.
  194. Parameters
  195. ----------
  196. x : array_like
  197. The input array.
  198. shape : int or array_like of ints or None
  199. The shape of the result. If both `shape` and `axes` (see below) are
  200. None, `shape` is ``x.shape``; if `shape` is None but `axes` is
  201. not None, then `shape` is ``scipy.take(x.shape, axes, axis=0)``.
  202. If `shape` is -1, the size of the corresponding dimension of `x` is
  203. used.
  204. axes : int or array_like of ints or None
  205. Axes along which the calculation is computed.
  206. The default is over all axes.
  207. Negative indices are automatically converted to their positive
  208. counterpart.
  209. Returns
  210. -------
  211. shape : array
  212. The shape of the result. It is a 1D integer array.
  213. axes : array
  214. The shape of the result. It is a 1D integer array.
  215. """
  216. noaxes = axes is None
  217. shape, axes = _init_nd_shape_and_axes(x, shape, axes)
  218. if not noaxes:
  219. shape = shape[axes.argsort()]
  220. axes.sort()
  221. return shape, axes