plot.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. import scipy.constants
  4. try:
  5. from numpy.fft import rfftfreq
  6. except ImportError:
  7. # This is a backport of the rfftfreq function present as of 2012 but not
  8. # included in Ubuntu 12.04.
  9. #
  10. # Licensed under BSD-new.
  11. def rfftfreq(n, d=1.0):
  12. """
  13. Return the Discrete Fourier Transform sample frequencies
  14. (for usage with rfft, irfft).
  15. The returned float array `f` contains the frequency bin centers in cycles
  16. per unit of the sample spacing (with zero at the start). For instance, if
  17. the sample spacing is in seconds, then the frequency unit is cycles/second.
  18. Given a window length `n` and a sample spacing `d`::
  19. f = [0, 1, ..., n/2-1, n/2] / (d*n) if n is even
  20. f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) if n is odd
  21. Unlike `fftfreq` (but like `scipy.fftpack.rfftfreq`)
  22. the Nyquist frequency component is considered to be positive.
  23. Parameters
  24. ----------
  25. n : int
  26. Window length.
  27. d : scalar, optional
  28. Sample spacing (inverse of the sampling rate). Defaults to 1.
  29. Returns
  30. -------
  31. f : ndarray
  32. Array of length ``n//2 + 1`` containing the sample frequencies.
  33. Examples
  34. --------
  35. >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4], dtype=float)
  36. >>> fourier = np.fft.rfft(signal)
  37. >>> n = signal.size
  38. >>> sample_rate = 100
  39. >>> freq = np.fft.fftfreq(n, d=1./sample_rate)
  40. >>> freq
  41. array([ 0., 10., 20., 30., 40., -50., -40., -30., -20., -10.])
  42. >>> freq = np.fft.rfftfreq(n, d=1./sample_rate)
  43. >>> freq
  44. array([ 0., 10., 20., 30., 40., 50.])
  45. """
  46. val = 1.0/(n*d)
  47. N = n//2 + 1
  48. results = np.arange(0, N, dtype=int)
  49. return results * val
  50. H = 184
  51. FREV = scipy.constants.c / 110.4 # lightspeed divided by circumference
  52. TREV = 1 / FREV
  53. # This is a backport of the polyval function present as of 2011 but not
  54. # included in Ubuntu 12.04.
  55. #
  56. # Licensed under BSD-new.
  57. def polyval(x, c, tensor=True):
  58. """
  59. Evaluate a polynomial at points x.
  60. If `c` is of length `n + 1`, this function returns the value
  61. .. math:: p(x) = c_0 + c_1 * x + ... + c_n * x^n
  62. The parameter `x` is converted to an array only if it is a tuple or a
  63. list, otherwise it is treated as a scalar. In either case, either `x`
  64. or its elements must support multiplication and addition both with
  65. themselves and with the elements of `c`.
  66. If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If
  67. `c` is multidimensional, then the shape of the result depends on the
  68. value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
  69. x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
  70. scalars have shape (,).
  71. Trailing zeros in the coefficients will be used in the evaluation, so
  72. they should be avoided if efficiency is a concern.
  73. Parameters
  74. ----------
  75. x : array_like, compatible object
  76. If `x` is a list or tuple, it is converted to an ndarray, otherwise
  77. it is left unchanged and treated as a scalar. In either case, `x`
  78. or its elements must support addition and multiplication with
  79. with themselves and with the elements of `c`.
  80. c : array_like
  81. Array of coefficients ordered so that the coefficients for terms of
  82. degree n are contained in c[n]. If `c` is multidimensional the
  83. remaining indices enumerate multiple polynomials. In the two
  84. dimensional case the coefficients may be thought of as stored in
  85. the columns of `c`.
  86. tensor : boolean, optional
  87. If True, the shape of the coefficient array is extended with ones
  88. on the right, one for each dimension of `x`. Scalars have dimension 0
  89. for this action. The result is that every column of coefficients in
  90. `c` is evaluated for every element of `x`. If False, `x` is broadcast
  91. over the columns of `c` for the evaluation. This keyword is useful
  92. when `c` is multidimensional. The default value is True.
  93. .. versionadded:: 1.7.0
  94. Returns
  95. -------
  96. values : ndarray, compatible object
  97. The shape of the returned array is described above.
  98. See Also
  99. --------
  100. polyval2d, polygrid2d, polyval3d, polygrid3d
  101. Notes
  102. -----
  103. The evaluation uses Horner's method.
  104. Examples
  105. --------
  106. >>> from numpy.polynomial.polynomial import polyval
  107. >>> polyval(1, [1,2,3])
  108. 6.0
  109. >>> a = np.arange(4).reshape(2,2)
  110. >>> a
  111. array([[0, 1],
  112. [2, 3]])
  113. >>> polyval(a, [1,2,3])
  114. array([[ 1., 6.],
  115. [ 17., 34.]])
  116. >>> coef = np.arange(4).reshape(2,2) # multidimensional coefficients
  117. >>> coef
  118. array([[0, 1],
  119. [2, 3]])
  120. >>> polyval([1,2], coef, tensor=True)
  121. array([[ 2., 4.],
  122. [ 4., 7.]])
  123. >>> polyval([1,2], coef, tensor=False)
  124. array([ 2., 7.])
  125. """
  126. c = np.array(c, ndmin=1, copy=0)
  127. if c.dtype.char in '?bBhHiIlLqQpP':
  128. # astype fails with NA
  129. c = c + 0.0
  130. if isinstance(x, (tuple, list)):
  131. x = np.asarray(x)
  132. if isinstance(x, np.ndarray) and tensor:
  133. c = c.reshape(c.shape + (1,)*x.ndim)
  134. c0 = c[-1] + x*0
  135. for i in range(2, len(c) + 1) :
  136. c0 = c[-i] + c0*x
  137. return c0
  138. def bunch(data, number, adc=None, frm=0, to=-1, **kwargs):
  139. bdata = data.bunch(number)[frm:to,1:]
  140. xs = np.arange(frm, max(to, bdata.shape[0]))
  141. if adc is None:
  142. plt.plot(xs, np.mean(bdata, axis=1),
  143. label='Averaged ADC count, bunch {}'.format(number),
  144. **kwargs)
  145. else:
  146. plt.plot(xs, bdata[:,adc-1],
  147. label='ADC {}, bunch {}'.format(adc, number),
  148. **kwargs)
  149. def train(data, axis, adc=None, frm=0, to=-1, **kwargs):
  150. pdata = data.array[frm:to, :-1]
  151. if adc is None:
  152. axis.plot(np.mean(pdata, axis=1), **kwargs)
  153. else:
  154. axis.plot(pdata[:,adc-1], **kwargs)
  155. axis.set_xlabel('Sample point')
  156. if adc:
  157. axis.set_title('ADC {}'.format(adc))
  158. def combined(data, axis, adcs, frm=0, to=-1, show_reconstructed=True):
  159. array = data.array[frm:to, :]
  160. N_s = 16
  161. N_p = array.shape[0]
  162. # Remove bunch number and flatten array
  163. array = array[:,:4].reshape((-1, 1))
  164. # plot original data
  165. orig_xs = np.arange(0, array.shape[0])
  166. axis.plot(orig_xs, array, '.')
  167. # 4 rows for each ADC
  168. ys = array.reshape((4, -1), order='F')
  169. # multi-fit for each column of 4 ADCs, unfortunately, xs' are always the
  170. # same, so we have to offset them later when computing the value
  171. xs = [1, 2, 3, 4]
  172. c = np.polynomial.polynomial.polyfit(xs, ys, 6)
  173. smooth_xs = np.linspace(1, 4, N_s)
  174. fitted_ys = polyval(smooth_xs, c, tensor=True)
  175. if True:
  176. # Output maxima
  177. ys = np.max(fitted_ys, axis=1)
  178. xs = 4 * ((np.argmax(fitted_ys, axis=1) + 1) / float(N_s)) + orig_xs[::4] - .5
  179. axis.plot(xs, ys, '.', color="red")
  180. if True:
  181. # Debug output
  182. ys = fitted_ys.reshape((-1, 1))
  183. xs = np.repeat(np.arange(0, 4 * N_p, 4), N_s) + np.tile(np.linspace(0, 3, N_s), N_p)
  184. axis.plot(xs, ys, '.', alpha=0.3)
  185. def heatmap(heatmap, axis):
  186. image = axis.imshow(heatmap, interpolation='nearest', aspect='auto')
  187. axis.invert_yaxis()
  188. axis.set_xlabel('Turn')
  189. axis.set_ylabel('Bunch position')
  190. return image
  191. def fft(data, axis, adc, frm=0, to=-1, skipped=0):
  192. transform = data.fft(adc, frm=frm, to=to)
  193. freqs = rfftfreq(transform.shape[1], TREV * (skipped + 1))
  194. transform = transform[:, 1:] # Throw away column 1
  195. # Due to the nature of the signal being divided into 'buckets', frequency '1' has an excessively large value and
  196. # skews the proportions for the other signals. It does not hold any useful information either...
  197. # Therefore, we remove it from the results.
  198. magnitude = np.log(np.abs(transform))
  199. image = axis.imshow(magnitude,
  200. interpolation='none',
  201. aspect='auto',
  202. extent=[freqs[1], freqs[-1], 0, H], # Start from freq[1] since we removed freq[0] from the data
  203. origin='lower')
  204. axis.set_xlabel('Frequency')
  205. axis.set_ylabel('Bunch position')
  206. return image