33 Find the tune using the fast fourier transform technique
35 Apply a small displacement to the reference trajectory and track through a
36 lattice; use the displaced trajectory
39 def __init__(self, u_data = None, peak_finder = None,
40 use_hanning_filter =
False):
42 Initialise the tune finder
44 - u_data: position data, for use in Fourier Transform calculation
45 - peak_finder: peak finder object, object used to find peaks in the tune
46 diagram. If peak_finder is None, uses a WindowPeakFinder with a
48 - use_hanning_filer: experimental hanning filter (probably doesnt work)
63 Find the fractional tune for a given tracking object
65 - tune_tolerance: tolerance with which the tune finder will attempt to
66 calculate the tune. If set to None, FTTuneFinder will use
69 Displaces the reference hit by an amount delta, tracks this hit using
70 the tracking object and runs a one dimensional FFT against the axis
71 variable. Number of samples used in the FFT is determined by the
72 tracking object (and hence accuracy of the tune calculation).
74 Note that u_data must be of odd length for this algorithm; FFTTuneFinder
75 will discard the last element if this is not the case.
77 Returns the principle Fourier frequency that is not 0.
80 raise ValueError(
"No data set for Fourier Transform")
81 if len(self.
u) % 2 == 0:
83 if tune_tolerance ==
None:
84 tune_tolerance = 1./len(self.
u)/100.
90 if tune_tolerance < 1./len(self.
k_mag_x):
95 index = self.k_mag_x.index(new_peak_x)
98 sys.excepthook(*sys.exc_info())
102 def run_tracking(self, axis, delta, reference_hit, tracking, use_hits=None):
104 Set position data from tracking output
106 - reference_hit: Hit on the closed orbit (for a ring).
107 - axis: string, variable from Hit.get_variables() over which the tune
109 - delta: float, displacement from the reference_hit.
110 - tracking: xboa.tracking.TrackingBase, tracking object to propagate
111 particles through the lattice.
112 - use_hits: list of integers, only consider hits returned by tracking
113 with an index in use_hits. If set to None, consider all hits.
115 hit = reference_hit.deepcopy()
117 hits_out = tracking.track_one(hit)
119 hits_out = [hit
for i, hit
in enumerate(hits_out)
if i
in use_hits]
120 self.
u = [hit[axis]
for hit
in hits_out]
125 Plot the FFT frequency spectrum
126 - title, string used as a title in FFT plots
127 Returns tuple of TCanvas, TH2, TGraph
129 canvas = common.make_root_canvas(title)
130 x_list = range(len(self.
u))
131 hist, graph = common.make_root_graph(title,
132 x_list,
'count', self.
u,
'signal')
137 return canvas, hist, graph
139 def plot_fft(self, title, ymin=None, ymax=None):
141 Plot the FFT frequency spectrum
142 - title, string used as a title in FFT plots
143 Returns tuple of TCanvas, TH2, TGraph
147 canvas = common.make_root_canvas(title)
149 ymin = max([1e-5, min(self.
k_mag_y)])
150 hist, graph = common.make_root_graph(title,
153 ymin=ymin, ymax=ymax)
159 return canvas, hist, graph
162 fit_lower_index, fit_upper_index, fit =
None):
164 Draw the FFT spectrum and fit within a window
165 - title, string title for the plot
166 - peak_k_index, integer corresponding to element from self.k_mag which
167 makes the seed for the position of the hit
168 - fit_lower_bound, integer corresponding to the element from self.k_mag
169 which makes the lower edge of the fit window
170 - fit_lower_bound, integer corresponding to the element from self.k_mag
171 which makes the upper edge of the fit window
172 - fit, ROOT.TF1 used for fitting. If set to None, a Gaussian will be
173 used with reasonable parameters. Note that user has responsibility to
174 set the fit window in fit
176 Uses the ROOT library to do the fit; this means drawing the data onto a
177 ROOT Canvas using self.plot_fft. Fits with a Gaussian; in the presence
178 of noisy/low statistics data, this can improve the estimate of tune.
180 Returns a tuple of TCanvas, TH2, TGraph, TF1. Hint:- to get the
181 fractional tune, use TF1::GetParameter(0); to get the estimated error,
182 use TF1::GetParError(0).
184 canvas, hist, graph = self.
plot_fft(title)
185 fit_height = self.
k_mag_y[peak_k_index]
186 fit_centre = self.
k_mag_x[peak_k_index]
187 fit_low = self.
k_mag_x[fit_lower_index]
188 fit_hi = self.
k_mag_x[fit_upper_index]
190 fit_function =
"[1]*exp(-((x-[0])*[2])**2)"
191 fit = ROOT.TF1(title+
" fit", fit_function, fit_low, fit_hi)
192 fit.SetParameter(0, fit_centre)
193 fit.SetParameter(1, fit_height)
194 fit.SetParameter(2, fit_height)
198 print "Got peak at", fit.GetParameter(0),
"with error", fit.GetParError(0)
200 return canvas, hist, graph, fit
204 Find the maximum peak in self.peak_index_list
206 peak_index_list = [self.k_mag_x.index(k_x)
for k_x
in self.
peak_x_list]
207 peak_values = [self.
k_mag_y[i]
for i
in peak_index_list]
208 if len(peak_values) == 0:
209 raise ValueError(
"Can't get max peak - found no peaks at all")
210 peak_max = max(peak_values)
211 peak_index = self.k_mag_y.index(peak_max)
217 Perform a slow Fourier Transform and find any peaks
219 n_items = int(1./interval/2.)
220 self.
k_mag_x = [i*interval
for i
in range(n_items)]
226 Perform the Fast Fourier Transform and find any peaks
228 fft = numpy.fft.rfft(numpy.array(self.
u))
229 k_list = [[float(numpy.real(z)), float(numpy.imag(z))]
for z
in fft]
230 self.
k_mag_y = [(z[0]**2+z[1]**2)**0.5
for z
in k_list]
231 self.
k_mag_x = [i/2./float(len(k_list))
for i, z
in enumerate(k_list)]
238 peak_index_list = sorted(self._peak_finder.find_peaks(self.
k_mag_y))
239 if len(peak_index_list) == 0:
241 if peak_index_list[0] == 0:
242 peak_index_list.pop(0)
248 Use slow fourier transforms in the region of a peak to recursively
249 improve the peak estimate to some tolerance.
251 On each iteration, the new k_mag values are appended to k_mag_x/y.
253 Stop recursing if the new value is < the neighbouring value; we assume
254 this is numerical precision noise and the recursion has converged
255 (implicit that the seed peak was closer than any troughs).
257 Returns the new peak_index
259 peak_index = self.k_mag_x.index(k_x)
260 if peak_index+1 == len(self.
k_mag_y):
262 y_values = [self.
k_mag_y[peak_index-1],
265 if y_values[2] > y_values[0]:
267 x_values = [self.
k_mag_x[peak_index],
269 index_right = peak_index+1
272 x_values = [self.
k_mag_x[peak_index-1],
274 index_right = peak_index
275 new_x = (x_values[0] + x_values[1])/2.
276 new_y = self.
_sft(new_x)
277 if abs(x_values[1] - x_values[0]) < x_tolerance:
278 return self.
k_mag_x[peak_index]
279 self.k_mag_x.insert(index_right, new_x)
280 self.k_mag_y.insert(index_right, new_y)
283 if new_y > y_values[0]
and new_y > y_values[1]:
284 new_peak_index = index_right
287 elif y_values[0] > new_y
and y_values[1] > new_y:
288 new_peak_index = self.k_mag_y.index(y_values[0])
290 new_peak_index = self.k_mag_y.index(y_values[1])
292 elif y_values[0] > y_values[1]:
293 new_peak_index = peak_index
296 new_peak_index = peak_index + 1
301 Calculate "Slow" Fourier Transform at k_x
303 - k_x, float, position at which the sft is found
304 - hanning filter, bool, set to True to apply a hanning filter
306 "Slow" Fourier transform means using Sum(A_i cos(...) + A_i sin(...)) to
307 get the FT at a given k value
309 y_point, z_point = 0., 0.
310 n = float(len(self.
u))
312 for m, a_m
in enumerate(self.
u):
314 hanning = 2.*math.sin(math.pi*m/n)**2.
315 f = 2.*math.pi*m*k_x*(n+1)/n
316 dy = hanning*a_m*math.cos(f)
317 dz = hanning*a_m*math.sin(f)
320 k_y = (y_point**2+z_point**2)**0.5
def _fft_find_peaks
Perform the Fast Fourier Transform and find any peaks.
def plot_fft
Plot the FFT frequency spectrum.
def _sft_find_peaks
Perform a slow Fourier Transform and find any peaks.
def _get_max_peak
Find the maximum peak in self.peak_index_list.
def _recursive_refine_peak
Use slow fourier transforms in the region of a peak to recursively improve the peak estimate to some ...
def run_tracking
Set position data from tracking output.
Find the tune using the fast fourier transform technique.
def plot_fft_fit
Draw the FFT spectrum and fit within a window.
def _find_peaks
Run the peak finder.
def __init__
Initialise the tune finder.
def _sft
Calculate "Slow" Fourier Transform at k_x.
Deprecated accessor to xboa.common module.
def get_tune
Find the fractional tune for a given tracking object.
Algorithms to find peaks in potentially noisy data.
def plot_signal
Plot the FFT frequency spectrum.