AnalysisWaveform.cc
1 #include "AnalysisWaveform.h"
2 #include "FFTtools.h"
3 #include "TAxis.h"
4 #include "RFInterpolate.h"
5 #include "TDirectory.h"
6 #include <stdlib.h>
7 #include "TMutex.h"
8 #include <assert.h>
9 #include "TH1.h"
10 
11 #define ALIGNMENT 32
12 
13 #ifdef ENABLE_VECTORIZE
14 #include "vectorclass.h"
15 #define VEC_T double
16 #define VEC_N 4
17 #define VEC Vec4d
18 #define IVEC Vec4i
19 static VEC INDEX(0,1,2,3);
20 #endif
21 
24 
25 
26 /* Branch prediction help macros. Not sure if these work with clang */
27 #define likely(x) __builtin_expect((!!x),1)
28 #define unlikely(x) __builtin_expect((!!x),0)
29 
30 const int minPointsForGslInterp = 6;
31 
32 #ifdef ANITA_ANALYSIS_DEBUG
33 static bool DEBUGON = false;
34 void AnalysisWaveform::enableDebug(bool debug) { DEBUGON = debug; }
35 #else
36 void AnalysisWaveform::enableDebug(bool debug) { fprintf(stderr, "enableDebug(%d) ineffective without ANITA_ANALYSIS_DEBUG defined\n", debug); }
37 #endif
38 
39 
40 static bool ALLOW_EVEN_TO_UNEVEN = false;
41 void AnalysisWaveform::allowEvenToUnevenConversion( bool allow) { ALLOW_EVEN_TO_UNEVEN = allow; }
42 
43 
44 static __thread bool nag_if_not_zero_padded = false;
45 
46 
48 volatile static unsigned counter = 0;
49 
50 
51 static void fillEven(int N, double * x, double dt, double t0)
52 {
53 #ifdef ENABLE_VECTORIZE
54 
55  int leftover = N % VEC_N;
56  int nit = N / VEC_N + (leftover ? 1 : 0);
57  VEC vt0(t0);
58  VEC vdt(dt);
59 
60  for (int i = 0; i < nit; i++)
61  {
62  VEC index(i * VEC_N);
63  index += INDEX;
64  VEC vx = mul_add(index,vdt,vt0);
65 
66  if (i == nit-1 && leftover > 0)
67  {
68  vx.store_partial(leftover, &x[i*VEC_N]);
69  }
70  else
71  {
72  vx.store(&x[i * VEC_N]);
73  }
74  }
75 #else
76  for (int i = 0; i < N; i++)
77  {
78  x[i] = i * dt + t0;
79  }
80 #endif
81 }
82 
83 
84 static void setNewSize(TGraphAligned * g, int size )
85 {
86  int old_size = g->GetN();
87  g->Set(size);
88  double dt = g->GetX()[1] - g->GetX()[0];
89  if (size > old_size)
90  {
91  fillEven(size-old_size, g->GetX() + old_size, dt, g->GetX()[old_size-1] + dt);
92  }
93 }
94 
95 
96 static int complaints = 0;
97 
98 AnalysisWaveform::AnalysisWaveform(int N, const double *x, const double * y, double nominal_dt,
99  InterpolationType interp_type, InterpolationOptions *opt)
100  : g_uneven(N,x,y), dt(nominal_dt), fft(0), theEvenAkimaInterpolator(0,ROOT::Math::Interpolation::kAKIMA),
101  interpolation_type(interp_type), must_update_uneven(false), must_update_freq(true), must_update_even(true),
102  uneven_equals_even(false), hilbert_transform(0), force_even_size(0)
103 {
104 
105  if (opt) interpolation_options = *opt;
106  power_dirty = true;
107  hilbert_dirty = true;
108  even_akima_interpolator_dirty = true;
109  power_db_dirty = true;
110  hilbert_envelope_dirty = true;
111  phase_dirty = true;
112  group_delay_dirty = true;
113  just_padded = false;
114  fft_len = 0;
115 
116  uid = __sync_fetch_and_add(&counter,1);
117  nameGraphs();
118 
119  //HACK HACK HACK
120  //check for zero's at the end
121  for (int i = 1; i < g_uneven.GetN(); i++)
122  {
123  if (g_uneven.GetX()[i] < g_uneven.GetX()[i-1])
124  {
125  if (complaints++ < 100)
126  {
127  fprintf(stderr,"WARNING: truncating graph to %d points to make monotonic\n",i);
128  if (complaints == 100)
129  {
130  fprintf(stderr," shutting up about truncating graphs after 100 complaints... I think I've made my point clear!\n");
131  }
132  }
133  g_uneven.Set(i);
134  break;
135  }
136  }
137 
138  //should prevent interpolation error from too few points
139  while (g_uneven.GetN() < minPointsForGslInterp) {
140  g_uneven.SetPoint(g_uneven.GetN(), g_uneven.GetX()[g_uneven.GetN()-1] + 1, 0);
141  }
142 
143 
144 }
145 
146 AnalysisWaveform::AnalysisWaveform(int N, const double * y, double dt, double t0)
147  : g_even(N), dt(dt), fft(0), theEvenAkimaInterpolator(0,ROOT::Math::Interpolation::kAKIMA),
148  interpolation_type(AKIMA), must_update_uneven(false), must_update_freq(true), must_update_even(false),
149  uneven_equals_even(true), hilbert_transform(0), force_even_size(0)
150 {
151  fillEven(N,g_even.GetX(),dt,t0);
152  memcpy(g_even.GetY(), y, sizeof(double) * N);
153  fft_len = N/2 +1;
154  df = 1./(N * dt);
155  power_dirty = true;
156  hilbert_dirty = true;
157  power_db_dirty = true;
158  hilbert_envelope_dirty = true;
159  even_akima_interpolator_dirty = true;
160  phase_dirty = true;
161  group_delay_dirty = true;
162  just_padded = false;
163  uid = __sync_fetch_and_add(&counter,1);
164  nameGraphs();
165 }
166 
167 
168 AnalysisWaveform::AnalysisWaveform(int N, double dt, double t0)
169  : g_even(N), dt(dt), fft(0), theEvenAkimaInterpolator(0,ROOT::Math::Interpolation::kAKIMA),
170  interpolation_type(AKIMA), must_update_uneven(false), must_update_freq(true),
171  must_update_even(false), uneven_equals_even(true), hilbert_transform(0), force_even_size(0)
172 {
173 
174  fillEven(N,g_even.GetX(),dt,t0);
175  memset(g_even.GetY(),0, sizeof(double) * N);
176  fft_len = N/2 +1;
177  df = 1./(N * dt);
178  power_dirty = true;
179  hilbert_dirty = true;
180  power_db_dirty = true;
181  phase_dirty = true;
182  group_delay_dirty = true;
183  hilbert_envelope_dirty = true;
184  even_akima_interpolator_dirty = true;
185  uid = __sync_fetch_and_add(&counter,1);
186  nameGraphs();
187  just_padded = false;
188 
189 }
190 
191 AnalysisWaveform::AnalysisWaveform(int N, const FFTWComplex * f, double df, double t0)
192  : g_even(N), df(df), theEvenAkimaInterpolator(0,ROOT::Math::Interpolation::kAKIMA), interpolation_type(AKIMA),
193  must_update_uneven(false), must_update_freq(false), must_update_even(true), uneven_equals_even(true),
194  hilbert_transform(0), force_even_size(0)
195 {
196  fft_len = N/2 +1;
197  int ret = posix_memalign( (void**) &fft, ALIGNMENT, sizeof(FFTWComplex) * fft_len);
198  assert (!ret);
199 
200  memcpy(fft, f, fft_len * sizeof(FFTWComplex));
201  dt = 1./ (N*df);
202 
203  fillEven(N,g_even.GetX(),dt,t0);
204  memset(g_even.GetY(),0, sizeof(double) * N);
205 
206  even_akima_interpolator_dirty = true;
207  power_dirty = true;
208  hilbert_dirty = true;
209  hilbert_envelope_dirty = true;
210  power_db_dirty = true;
211  phase_dirty = true;
212  group_delay_dirty = true;
213  uid = __sync_fetch_and_add(&counter,1);
214  just_padded = false;
215  even_akima_interpolator_dirty = true;
216 }
217 
218 
219 
221 {
222 
223  if (uneven_equals_even) return even();
224 
225  return &g_uneven;
226 }
227 
229 {
230 
231 #ifdef ANITA_ANALYSIS_DEBUG
232  if (DEBUGON) printf("Called even()!\n");
233  if (DEBUGON) printf ("[%p]: \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n", this, must_update_even, must_update_freq, must_update_uneven);
234  //kaboom
235 #endif
236  assert (!(must_update_even && must_update_freq && must_update_uneven));
237 
238  if ((must_update_even && must_update_freq))
239  {
240  calculateEvenFromUneven();
241  }
242  else if ((must_update_even))
243  {
244  calculateEvenFromFreq();
245  }
246 
247  return &g_even;
248 }
249 
251 {
252 
253 
254 #ifdef ANITA_ANALYSIS_DEBUG
255  if (DEBUGON) printf("Called freq()!\n");
256  if (DEBUGON) printf ("[%p] \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n", this, must_update_even, must_update_freq, must_update_uneven);
257 #endif
258 
259  if (must_update_freq)
260  {
261  calculateFreqFromEven();
262  }
263 
264  return fft;
265 }
266 
267 
268 
269 
270 void AnalysisWaveform::updateEven(const TGraph * replace)
271 {
272 
273 #ifdef ANITA_ANALYSIS_DEBUG
274  if (DEBUGON) printf("Called updateEven(replace)!\n");
275  if (DEBUGON) printf ("[%p] \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n", this, must_update_even, must_update_freq, must_update_uneven);
276 #endif
277 
278  g_even.Set(replace->GetN());
279  memcpy(g_even.GetX(), replace->GetX(), replace->GetN() * sizeof(double));
280  memcpy(g_even.GetY(), replace->GetY(), replace->GetN() * sizeof(double));
281  if (!ALLOW_EVEN_TO_UNEVEN) uneven_equals_even = true;
282  must_update_uneven = !uneven_equals_even;
283  must_update_freq = true;
284  must_update_even = false;
285  even_akima_interpolator_dirty = true;
286  just_padded = false;
287  hilbert_dirty = true;
288  hilbert_envelope_dirty = true;
289  dt = replace->GetX()[1]-replace->GetX()[0];
290  df = 1./(Neven() * dt);
291 }
292 
293 
295 {
296 
297 #ifdef ANITA_ANALYSIS_DEBUG
298  if (DEBUGON) printf("Called updateEven()!\n");
299  if (DEBUGON) printf ("\tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n", must_update_even, must_update_freq, must_update_uneven);
300 #endif
301 
302  TGraphAligned * ev = (TGraphAligned *) even();
303  if (!ALLOW_EVEN_TO_UNEVEN) uneven_equals_even = true;
304  must_update_uneven = !uneven_equals_even;
305  must_update_freq = true;
306  even_akima_interpolator_dirty = true;
307  just_padded = false;
308  hilbert_envelope_dirty = true;
309  hilbert_dirty = true;
310  return ev;
311 }
312 
314 {
315 #ifdef ANITA_ANALYSIS_DEBUG
316  if (DEBUGON) printf("Called updateUneven()!\n");
317  if (DEBUGON) printf ("[%p]: \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n",this, must_update_even, must_update_freq, must_update_uneven);
318 #endif
319  TGraphAligned * g = (TGraphAligned*) uneven();
320  uneven_equals_even = false;
321  must_update_even = true;
322  must_update_freq = true;
323  just_padded = false;
324  even_akima_interpolator_dirty = true;
325  hilbert_dirty = true;
326  hilbert_envelope_dirty = true;
327 
328  return g;
329 }
330 
332 {
333 #ifdef ANITA_ANALYSIS_DEBUG
334  if (DEBUGON) printf("Called updateFreq()!\n");
335  if (DEBUGON) printf ("[%p]: \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n",this, must_update_even, must_update_freq, must_update_uneven);
336 #endif
337  FFTWComplex * fr = (FFTWComplex*) freq();
338 
339  power_dirty = true;
340  power_db_dirty = true;
341  hilbert_dirty = true;
342  hilbert_envelope_dirty = true;
343  phase_dirty = true;
344  group_delay_dirty = true;
345  just_padded = false;
346 
347  even_akima_interpolator_dirty = true;
348  must_update_even = true;
349  if (!ALLOW_EVEN_TO_UNEVEN) uneven_equals_even = true;
350  must_update_uneven = !uneven_equals_even;
351 
352  return fr;
353 }
354 
355 
356 #define DO_FOR_ALL(THING) g_uneven.THING; g_hilbert_envelope.THING; g_even.THING; g_power.THING; g_power_db.THING; g_phase.THING; g_group_delay.THING;
357 #define DO_FOR_TIME(THING) g_uneven.THING; g_hilbert_envelope.THING; g_even.THING;
358 #define DO_FOR_FREQ(THING) g_power.THING; g_power_db.THING; g_phase.THING; g_group_delay.THING;
359 
360 void AnalysisWaveform::setColor(int c)
361 {
362  DO_FOR_ALL(SetLineColor(c));
363  DO_FOR_ALL(SetMarkerColor(c));
364 }
365 
366 void AnalysisWaveform::setTitle(const char * title)
367 {
368  DO_FOR_ALL(SetTitle(title));
369 }
370 
371 void AnalysisWaveform::setFreqDisplayRange(double l, double h)
372 {
373  DO_FOR_FREQ(GetXaxis()->SetRangeUser(l,h));
374 }
375 
376 void AnalysisWaveform::setTimeDisplayRange(double l, double h)
377 {
378  DO_FOR_TIME(GetXaxis()->SetRangeUser(l,h));
379 }
380 
381 void AnalysisWaveform::setWidth(int w)
382 {
383  DO_FOR_ALL(SetLineWidth(w));
384 
385 }
386 
387 
388 
389 
390 void AnalysisWaveform::updateUneven(const TGraph * replace)
391 {
392 
393 #ifdef ANITA_ANALYSIS_DEBUG
394  if (DEBUGON) printf("Called updateUneven(replace)!\n");
395  if (DEBUGON) printf ("[%p]: \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n",this, must_update_even, must_update_freq, must_update_uneven);
396 #endif
397 
398 
399  g_uneven.Set(replace->GetN());
400  memcpy(g_uneven.GetX(), replace->GetX(), replace->GetN() * sizeof(double));
401  memcpy(g_uneven.GetY(), replace->GetY(), replace->GetN() * sizeof(double));
402 
403  uneven_equals_even = false;
404  just_padded = false;
405  must_update_even = true;
406  must_update_uneven = false;
407  must_update_freq = true;
408  even_akima_interpolator_dirty = true;
409 }
410 
411 void AnalysisWaveform::calculateUnevenFromEven() const
412 {
413  const TGraphAligned * g = even();
414 
415 
416  if (interpolation_type == AKIMA)
417  {
418 
419 
420  const ROOT::Math::Interpolator * irp = evenAkimaInterpolator();
421  for (int i = 0; i < g_uneven.GetN(); i++)
422  {
423  if (g_uneven.GetX()[i] < g->GetX()[g->GetN()-1])
424  g_uneven.GetY()[i] = irp->Eval(g_uneven.GetX()[i]);
425  }
426  }
427  else
428  {
429 
430  FFTtools::getInterpolatedGraphSparseInvert(g, &g_uneven, interpolation_options.max_distance, 0, 0,
431  interpolation_type == SPARSE_YEN ? 0 : interpolation_options.mu,
432  interpolation_options.regularization_order);
433 
434 
435  }
436 
437  must_update_uneven = false;
438 }
439 
440 const ROOT::Math::Interpolator * AnalysisWaveform::evenAkimaInterpolator() const
441 {
442 
443  if (even_akima_interpolator_dirty)
444  {
445  const TGraphAligned * g = even();
446  if(g->GetN() >= minPointsForGslInterp){
447  theEvenAkimaInterpolator.SetData(g->GetN(),g->GetX(),g->GetY());
448  even_akima_interpolator_dirty= false;
449  }
450  else{
451  // perhaps this needs better handling, but for now...
452  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ": Insufficient points for Akima interpolation." << std::endl;
453  }
454  }
455  return &theEvenAkimaInterpolator;
456 }
457 
458 void AnalysisWaveform::calculateEvenFromUneven() const
459 {
460 
461 
462  const TGraphAligned * g = uneven();
463  int npoints = (g->GetX()[g->GetN()-1] - g->GetX()[0]) / dt;
464  g_even.Set(force_even_size ? force_even_size : npoints);
465 
466  // this has been applied so we can forget about it now
467  force_even_size = 0;
468 
469  double t0 = g->GetX()[0];
470  for (int i = 0; i < g_even.GetN(); i++)
471  {
472  double x = t0 + i * dt;
473  g_even.GetX()[i] = x;
474 
475  }
476 
477  if (interpolation_type == AKIMA)
478  {
479  ROOT::Math::Interpolator irp(g->GetN(), ROOT::Math::Interpolation::kAKIMA);
480  if(g->GetN() >= minPointsForGslInterp){
481  irp.SetData(g->GetN(),g->GetX(),g->GetY());
482  }
483  else{
484  // perhaps this needs better handling, but for now...
485  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ": Insufficient points for Akima interpolation." << std::endl;
486  }
487 
488  // irp.SetData(g->GetN(), g->GetX(), g->GetY());
489 
490  for (int i = 0; i < g_even.GetN(); i++)
491  {
492  if (g_even.GetX()[i] > g->GetX()[g->GetN()-1])
493  {
494  memset(g_even.GetY()+i, 0, (g_even.GetN() - i )*sizeof(double));
495  break ;
496 
497 // g_even.GetY()[i] = 0;
498  }
499 
500  else
501  {
502  g_even.GetY()[i] = irp.Eval(g_even.GetX()[i]);
503  }
504 
505 // printf("%d %f\n", i, g_even.GetY()[i]);
506  }
507  }
508  else
509  {
510  FFTtools::getInterpolatedGraphSparseInvert(g, &g_even, interpolation_options.max_distance, 0, 0,
511  interpolation_type == SPARSE_YEN ? 0 : interpolation_options.mu,
512  interpolation_options.regularization_order);
513 
514  }
515  hilbert_envelope_dirty = true;
516 
517  must_update_even = false;
518 }
519 
520 void AnalysisWaveform::calculateEvenFromFreq() const
521 {
522  FFTtools::doInvFFTNoClobber(g_even.GetN(), fft, g_even.GetY());
523 
524  double t0 = g_even.GetX()[0];
525 
526  if (force_even_size)
527  {
528  setNewSize(&g_even, force_even_size);
529  force_even_size = 0; //applied so we can forget about it now.
530  }
531  if (g_even.GetX()[1] - t0 != dt)
532  {
533  fillEven(g_even.GetN(), g_even.GetX(), dt,t0);
534  }
535 
536  hilbert_envelope_dirty = true;
537 
538  must_update_even = false;
539 }
540 
541 void AnalysisWaveform::calculateFreqFromEven() const
542 {
543 
544  const TGraphAligned * g = even(); // in case it must be converted from uneven
545 
546  assert(g->GetN() > 0);
547  dt = g->GetX()[1] - g->GetX()[0];
548  int old_fft_len = fft_len;
549  fft_len = g->GetN()/2+1;
550  df = 1./ (g->GetN() * dt);
551 
552 
553  if (fft && old_fft_len != fft_len)
554  {
555  free(fft);
556  fft = 0;
557  }
558 
559  if (!fft)
560  {
561 
562  int ret = posix_memalign( (void**) &fft, ALIGNMENT, sizeof(FFTWComplex) * fft_len);
563  assert(!ret);
564  }
565 
566  FFTtools::doFFT(g->GetN(), g->GetY(),fft);
567 
568  must_update_freq = false;
569  power_dirty = true;
570  hilbert_dirty = true;
571  hilbert_envelope_dirty = true;
572  power_db_dirty = true;
573  phase_dirty = true;
574  group_delay_dirty = true;
575 }
576 
577 
578 
579 void AnalysisWaveform::updateFreq(int new_N, const FFTWComplex * new_fft, double new_df )
580 {
581 
582 #ifdef ANITA_ANALYSIS_DEBUG
583  if (DEBUGON) printf("Called updateFreq(replace)!\n");
584  if (DEBUGON) printf ("[%p]: \tmust_update_even=%d, must_update_freq=%d, must_update_uneven=%d\n",this, must_update_even, must_update_freq, must_update_uneven);
585 #endif
586 
587  if (new_N && new_N != g_even.GetN())
588  {
589  free(fft);
590  fft = 0;
591  fft_len = new_N/2 + 1;
592  int ret = posix_memalign( (void**) &fft, ALIGNMENT, sizeof(FFTWComplex) * fft_len);
593  assert(!ret);
594  g_even.Set(new_N);
595  }
596 
597  memcpy(fft, new_fft, fft_len * sizeof(FFTWComplex));
598  if (new_df)
599  {
600  df = new_df;
601  }
602  dt = 1./ (g_even.GetN() * df);
603 
604  must_update_freq = false;
605  must_update_even = true;
606  if (!ALLOW_EVEN_TO_UNEVEN) uneven_equals_even = true;
607  must_update_uneven = !uneven_equals_even;
608  hilbert_dirty = true;
609  hilbert_envelope_dirty = true;
610  power_dirty = true;
611  power_db_dirty = true;
612  phase_dirty = true;
613  group_delay_dirty = true;
614  just_padded = false;
615 }
616 
618 {
619  const FFTWComplex * the_fft = freq(); //will update if necessary
620  if (phase_dirty)
621  {
622 
623  g_phase.Set(fft_len);
624  for (int i = 0; i < fft_len; i++)
625  {
626  g_phase.SetPoint(i, i * df, the_fft[i].getPhase());
627  }
628 
629  phase_dirty = false;
630  }
631 
632  return &g_phase;
633 }
634 
636 {
637  if (group_delay_dirty)
638  {
639 
640  g_group_delay.adopt(phase());
641 
642  FFTtools::unwrap( g_group_delay.GetN(), g_group_delay.GetY(), 2 * TMath::Pi());
643 
644  double last = g_group_delay.GetY()[0];
645  double dw = df * 2 * TMath::Pi();
646  for (int i = 1; i < fft_len; i++)
647  {
648  double current = g_group_delay.GetY()[i] ;
649  g_group_delay.GetY()[i-1] = (last - current) /dw;
650  last = current;
651  }
652 
653  g_group_delay.GetY()[g_group_delay.GetN()-1] = 0;
654  group_delay_dirty = false;
655  }
656 
657  return &g_group_delay;
658 }
659 
661 {
662  const TGraphAligned * the_power = power(); //will update if necessary
663  if (power_db_dirty)
664  {
665 
666  g_power_db.adopt(the_power);
667  g_power_db.dBize();
668  power_db_dirty = false;
669  }
670 
671  return &g_power_db;
672 }
673 
674 
676 {
677 
678  (void) freq();
679 
680  if (hilbert_dirty)
681  {
682  if (hilbert_transform) delete hilbert_transform;
683  hilbert_transform = new AnalysisWaveform(*this);
684 
685  FFTWComplex * hilbert = hilbert_transform->updateFreq();
686  for (int i = 0; i < fft_len; i++)
687  {//todo: check if this gets vectorized
688  double temp_im = hilbert[i].im;
689  hilbert[i].im = hilbert[i].re;
690  hilbert[i].re = - temp_im;
691  }
692 
693  hilbert_dirty = false;
694  }
695 
696 
697  return hilbert_transform;
698 }
699 
701 {
702  const TGraphAligned * the_even = even();
703 
704  if (hilbert_envelope_dirty)
705  {
706  g_hilbert_envelope.adopt(the_even);
707  const AnalysisWaveform * hilbert = hilbertTransform();
708 
709  double * y = g_hilbert_envelope.GetY();
710  const double * H = hilbert->even()->GetY();
711  for (int i = 0; i < g_hilbert_envelope.GetN(); i++)
712  {
713  y[i] = sqrt(y[i] * y[i] + H[i]*H[i]);
714  }
715 
716  hilbert_envelope_dirty = false;
717 
718  }
719 
720  return &g_hilbert_envelope;
721 }
722 
724 {
725 
726  if (power_dirty)
727  {
728 
729  if (power_options.method == PowerCalculationOptions::FFT)
730  {
731  const FFTWComplex * the_fft = freq(); //will update if necessary
732  g_power.Set(fft_len);
733  for (int i = 0; i < fft_len; i++)
734  {
735  if (i == 0 || i == fft_len -1)
736  {
737  g_power.SetPoint(i, i * df, the_fft[i].getAbsSq()/fft_len/50/1000);
738  }
739  else
740  {
741  g_power.SetPoint(i, i * df, the_fft[i].getAbsSq()*2/fft_len/50/1000);
742  }
743  }
744  }
745  else
746  {
747  const TGraphAligned * g = even();
748 
749  if (power_options.method == PowerCalculationOptions::BARTLETT)
750  {
751  FFTtools::welchPeriodogram(g, power_options.window_size, 0, &FFTtools::RECTANGULAR_WINDOW, true,&g_power);
752  }
753  else
754  {
755  FFTtools::welchPeriodogram(g, power_options.window_size, 0.5, power_options.type,true,&g_power);
756  }
757  }
758 
759  power_dirty = false;
760  }
761 
762  return &g_power;
763 }
764 
765 AnalysisWaveform::~AnalysisWaveform()
766 {
767  if (fft)
768  {
769  free(fft);
770  }
771 
772  if (hilbert_transform)
773  delete hilbert_transform;
774 
775 }
776 
778 {
779  if (must_update_even) //defer
780  {
781  force_even_size = size;
782  return;
783  }
784  setNewSize(&g_even, size);
785 
786 }
787 
788 void AnalysisWaveform::evalEven(int N, const double * __restrict t, double * __restrict v, EvenEvaluationType type) const
789 {
790 
791  if (type == EVAL_LINEAR)
792  {
793  const TGraphAligned * g = even();
794  int Ng = g->GetN();
795  if (Ng < 1) return;
796  const double *y = g->GetY();
797  // __builtin_prefetch(y);
798  // __builtin_prefetch(t);
799  // __builtin_prefetch(v,1);
800 
801  double t0 = g->GetX()[0];
802 
803 
804 
805 #ifndef ENABLE_VECTORIZE
806  for (int i = 0; i < N; i++)
807  {
808  double xval = (t[i]-t0) / dt;
809  int bin_low = int(xval);
810 
811  int branchless_too_low = bin_low < 0;
812  int branchless_too_high = bin_low >= Ng;
813  int branchless_on_edge = bin_low == Ng-1;
814 
815  int bin_high = bin_low+1;
816  bin_low *= (1-branchless_too_high) * (1-branchless_too_low);
817  bin_high *= (1-branchless_too_high) * (1-branchless_too_low) * (1-branchless_on_edge);
818  double val_low = y[bin_low];
819  double val_high = y[bin_high];
820  double frac = xval - bin_low;
821  double val = val_low + frac * (val_high - val_low);
822 
823  v[i] = val * (1-branchless_too_low) * (1-branchless_too_high) * (1-branchless_on_edge) + branchless_on_edge * y[Ng-1];
824  }
825 #else
826 
827  int leftover = N % VEC_N;
828  int nit = N / VEC_N + (leftover ? 1 : 0);
829 
830  VEC v_t;
831  VEC v_t0(t0);
832  VEC inv_dt(1./dt);
833  IVEC dont_get_out_of_bounds;
834 
835  for (int i = 0; i < VEC_N; i++)
836  {
837  dont_get_out_of_bounds.insert(i, i >= leftover ? 1 : 0 );
838  }
839 
840  for (int i = 0; i < nit; i++)
841  {
842  if (i < nit -1 || !leftover)
843  {
844  v_t.load(t + i * VEC_N);
845  }
846  else
847  {
848  v_t.load_partial(leftover, t+i*VEC_N) ;
849  }
850 
851  VEC xval = (v_t - v_t0) * inv_dt;
852  VEC truncated_xval = truncate(xval);
853  VEC frac = xval - truncated_xval;
854  IVEC bin_low = truncate_to_int(truncated_xval);
855 
856  IVEC branchless_too_low = bin_low < IVEC(0);
857  IVEC branchless_too_high = bin_low >= IVEC(Ng);
858  IVEC branchless_on_edge = bin_low== IVEC(Ng-1);
859 
860  int scalar_out_of_bounds = int(i == nit-1 && leftover > 0);
861  IVEC out_of_bounds = scalar_out_of_bounds * dont_get_out_of_bounds;
862 
863  IVEC bin_high = bin_low+1;
864 
865  //Optimistically grab it. Hopefully it's not out of bounds.
866  __builtin_prefetch(y+bin_low[0]);
867 
868  IVEC too_low_or_too_high = (1-branchless_too_low) * (1-branchless_too_high) * (1-out_of_bounds);
869  IVEC kill_it = too_low_or_too_high * ( 1- branchless_on_edge);
870 
871  bin_low *= too_low_or_too_high;
872  bin_high *= kill_it;
873 
874  double lowv[VEC_N];
875  double highv[VEC_N];
876  for (int j = 0; j < VEC_N; j++)
877  {
878  lowv[j] = y[bin_low[j]];
879  highv[j] = y[bin_high[j]];
880  }
881 
882  VEC val_low; val_low.load(lowv);
883  VEC val_high; val_high.load(highv);
884 
885  VEC val = mul_add(frac , (val_high - val_low), val_low);
886 
887  if (scalar_out_of_bounds)
888  {
889  val.store_partial(leftover, v + i * VEC_N);
890  }
891  else
892  {
893  val.store(v + i * VEC_N);
894  }
895  }
896 
897 #endif
898 
899  }
900 
901  else if (type == EVAL_AKIMA)
902  {
903  const ROOT::Math::Interpolator * irp = evenAkimaInterpolator();
904 
905  /*TODO this is probably very slow */
906  for (int i = 0; i < N; i++)
907  {
908  v[i] = irp->Eval(t[i]);
909  }
910  }
911  else
912  {
913  fprintf(stderr,"Bad even evaluation type\n");
914  }
915 
916 }
917 
919 {
920  if (typ == EVAL_AKIMA)
921  {
922  return evenAkimaInterpolator()->Eval(t);
923  }
924  else if (typ == EVAL_LINEAR)
925  {
926  const TGraphAligned * g = even();
927  double t0 = g->GetX()[0];
928  double xval = (t-t0) / dt;
929 
930  int bin_low = int (xval);
931 
932  if (bin_low < 0) return 0;
933  if (bin_low >= g->GetN()) return 0;
934  if (bin_low == g->GetN()-1) return g->GetY()[g->GetN()-1];
935 
936  int bin_high = bin_low + 1;
937  double val_low = g->GetY()[bin_low];
938  double val_high = g->GetY()[bin_high];
939 
940  double frac = xval - bin_low;
941 
942  return val_low + frac*(val_high-val_low);
943  }
944 
945  fprintf(stderr, "Bad EvenEvaluationType\n");
946 
947  return 0;
948 }
949 
950 AnalysisWaveform & AnalysisWaveform::operator=(const AnalysisWaveform & other)
951 {
952  if (this != &other)
953  {
954  g_uneven.adopt(&other.g_uneven);
955  g_even.adopt(&other.g_even);
956 
957  dt = other.dt;
958  df = other.df;
959  interpolation_type = other.interpolation_type;
960  interpolation_options = other.interpolation_options;
961 
962  uneven_equals_even = other.uneven_equals_even;
963  must_update_even = other.must_update_even;
964  must_update_freq = other.must_update_freq;
965  must_update_uneven = other.must_update_uneven;
966  just_padded = other.just_padded;
967  force_even_size = other.force_even_size;
968  // printf("%d\n", force_even_size);
969 
970 
971  //don't bother copying these, they can be regenerated if needed
972  power_dirty = true;
973  power_db_dirty = true;
974  phase_dirty = true;
975  group_delay_dirty = true;
976  hilbert_dirty = true;
977  hilbert_envelope_dirty = true;
978  hilbert_transform = 0;
979 
980 
981  fft_len = g_even.GetN()/2+1;
982 
983  if (!must_update_freq)
984  {
985  int ret = posix_memalign( (void**) &fft, ALIGNMENT, sizeof(FFTWComplex) * fft_len);
986  assert(!ret);
987  memcpy(fft, other.fft, fft_len * sizeof(FFTWComplex));
988  }
989  else
990  {
991  fft = 0;
992  }
993  }
994 
995  return *this;
996 }
997 
999  :
1000  g_uneven(other.uneven_equals_even ? 0 : other.g_uneven.GetN()),
1001  g_even(other.Neven())
1002 {
1003 
1004 
1005  //first copy over scalars
1006 
1007  dt = other.dt;
1008  df = other.df;
1009 
1010  interpolation_type = other.interpolation_type;
1011  interpolation_options = other.interpolation_options;
1012 
1013  uneven_equals_even = other.uneven_equals_even;
1014  must_update_even = other.must_update_even;
1015  must_update_freq = other.must_update_freq;
1016  must_update_uneven = other.must_update_uneven;
1017  just_padded = other.just_padded;
1018  force_even_size = other.force_even_size;
1019 // printf("%d\n", force_even_size);
1020 
1021 
1022  //don't bother copying these, they can be regenerated if needed
1023  power_dirty = true;
1024  power_db_dirty = true;
1025  phase_dirty = true;
1026  group_delay_dirty = true;
1027  hilbert_dirty = true;
1028  hilbert_envelope_dirty = true;
1029  hilbert_transform = 0;
1030 
1031 
1032 
1033  // we must copy x from g_uneven if it's not equal to even
1034  if (!uneven_equals_even)
1035  {
1036  memcpy(g_uneven.GetX(), other.g_uneven.GetX(), g_uneven.GetN() * sizeof(double));
1037 
1038  if (!must_update_uneven)
1039  {
1040  memcpy(g_uneven.GetY(), other.g_uneven.GetY(), g_uneven.GetN() * sizeof(double));
1041  }
1042  }
1043 
1044 
1045  if (!must_update_even)
1046  {
1047  memcpy(g_even.GetY(), other.g_even.GetY(), g_even.GetN() * sizeof(double));
1048  memcpy(g_even.GetX(), other.g_even.GetX(), g_even.GetN() * sizeof(double));
1049  }
1050 
1051  fft_len = g_even.GetN()/2+1;
1052 
1053  if (!must_update_freq)
1054  {
1055  int ret = posix_memalign( (void**) &fft, ALIGNMENT, sizeof(FFTWComplex) * fft_len);
1056  assert(!ret);
1057  memcpy(fft, other.fft, fft_len * sizeof(FFTWComplex));
1058  }
1059  else
1060  {
1061  fft = 0;
1062  }
1063 
1064 }
1065 
1066 
1067 AnalysisWaveform * AnalysisWaveform::convolution(const AnalysisWaveform *A, const AnalysisWaveform *B, int npad, double scale)
1068 {
1069  if (A->Nfreq() != B->Nfreq())
1070  {
1071  fprintf(stderr,"convolution does not handle the case where A and B are of different lengths (%d vs. %d)!\n", A->Nfreq(), B->Nfreq());
1072  return 0;
1073  }
1074 
1075  double offset = A->even()->GetX()[0] - B->even()->GetX()[0];
1076 
1077  AnalysisWaveform * answer = new AnalysisWaveform(A->Neven(), A->freq(),
1078  A->deltaF(), A->even()->GetX()[0]);
1079 
1080  int N = answer->even()->GetN();
1081  FFTWComplex * update = answer->updateFreq();
1082 
1083  const FFTWComplex * Bfreq = B->freq();
1084 // double inv = 1./(N*scale);
1085 
1086  //TODO this can be vectorized
1087  for (int i = 0; i < B->Nfreq(); i++)
1088  {
1089  FFTWComplex vA = update[i];
1090  FFTWComplex vB = Bfreq[i];
1091  update[i] = vA * vB;
1092  }
1093 
1094  answer->padFreq(npad);
1095 
1096  N = answer->even()->GetN();
1097  TGraphAligned g(N);
1098 
1099  double dt = answer->deltaT();
1100  memcpy(g.GetY(), answer->even()->GetY() + N/2, N/2 * sizeof(double));
1101  memcpy(g.GetY()+ N/2, answer->even()->GetY(), N/2 * sizeof(double));
1102 
1103  for (int i = 0; i < N; i++)
1104  {
1105  g.GetX()[i] =(i - N/2) * dt + offset;
1106  }
1107 
1108 
1109  answer->updateEven(&g);
1110 
1111 
1112  return answer;
1113 }
1114 
1115 
1116 AnalysisWaveform * AnalysisWaveform::correlation(const AnalysisWaveform *A, const AnalysisWaveform *B, int npad, double scale, int window_normalize)
1117 {
1118  if (A->Nfreq() != B->Nfreq())
1119  {
1120  fprintf(stderr,"correlation does not handle the case where A and B are of different lengths (%d vs. %d)!\n", A->Nfreq(), B->Nfreq());
1121  return 0;
1122  }
1123 
1124 
1125  if(nag_if_not_zero_padded && (!A->checkIfPaddedInTime() || !B->checkIfPaddedInTime()))
1126  {
1127 
1128  fprintf(stderr,"warning: waveforms don't appear to be padded in time, will be computing circular correlation!\n");
1129  }
1130  double offset = A->even()->GetX()[0] - B->even()->GetX()[0];
1131 
1132  AnalysisWaveform * answer = new AnalysisWaveform(A->Neven(), A->freq(),
1133  A->deltaF(), A->even()->GetX()[0]);
1134 
1135  int N = answer->even()->GetN();
1136  FFTWComplex * update = answer->updateFreq();
1137 
1138  const FFTWComplex * Bfreq = B->freq();
1139  double inv = 1./(N*scale);
1140 
1141  //TODO this can be vectorized
1142  for (int i = 0; i < B->Nfreq(); i++)
1143  {
1144  FFTWComplex vA = update[i];
1145  FFTWComplex vB = Bfreq[i];
1146  update[i].re = (vA.re * vB.re + vA.im * vB.im) *inv;
1147  update[i].im = (vA.im * vB.re - vA.re * vB.im) *inv;
1148 // printf("%f %f\n", update[i].re, update[i].im);
1149  }
1150 
1151  answer->padFreq(npad);
1152 
1153  N = answer->even()->GetN();
1154  TGraphAligned g(N);
1155 
1156  double dt = answer->deltaT();
1157  memcpy(g.GetY(), answer->even()->GetY() + N/2, N/2 * sizeof(double));
1158  memcpy(g.GetY()+ N/2, answer->even()->GetY(), N/2 * sizeof(double));
1159 
1160 
1161  // we need to calculate the integral sumv2 of the inputs
1162  if (window_normalize)
1163  {
1164 
1165  std::vector <double> sum2A(A->Neven());
1166  std::vector <double> sum2B(B->Neven());
1167 
1168  const double * Ay = A->even()->GetY();
1169  const double * By = B->even()->GetY();
1170 
1171  for (int i = 0; i < A->Neven(); i++)
1172  {
1173  sum2A[i] = (i == 0 ? 0 : sum2A[i-1]) + Ay[i]*Ay[i];
1174  }
1175 
1176  for (int i = B->Neven()-1; i >= 0; i--)
1177  {
1178  sum2B[i] = (i == B->Neven()-1 ? 0 : sum2B[i+1]) + By[i]*By[i];
1179  }
1180 
1181 
1182  //find first and last non-zero sample
1183  int start = 0;
1184  int end = g.GetN()-1;
1185 
1186  while(!g.GetY()[start]) start++;
1187  while(!g.GetY()[end]) end--;
1188 
1189  for (int i = start+window_normalize; i <= end-window_normalize+1; i++)
1190  {
1191  double this_norm = sqrt (sum2A[i] * sum2B[i])/(i-start);
1192  if (this_norm > 0)
1193  {
1194  g.GetY()[i]/=this_norm;
1195  if ( i == window_normalize + start)
1196  {
1197  for (int ii = start; ii < i; ii++) g.GetY()[ii]/=this_norm;
1198  }
1199 
1200  if (i == end-window_normalize + 1)
1201  {
1202  for (int ii = end-window_normalize+2; ii <= end; ii++) g.GetY()[ii]/=this_norm;
1203  }
1204  }
1205  }
1206  }
1207 
1208  for (int i = 0; i < N; i++)
1209  {
1210  g.GetX()[i] =(i - N/2) * dt + offset;
1211  }
1212 
1213 
1214  answer->updateEven(&g);
1215 
1216 
1217  return answer;
1218 }
1219 
1221 {
1222  if (npad < 1) return;
1223 
1224 
1225 
1226  //new even size
1227  if (g_even.GetN() ==0) (void) even(); //may need to calculate even if it never has been
1228  int new_N = g_even.GetN() * (1+npad);
1229 
1230  FFTWComplex * new_fft =0;
1231  int ret = posix_memalign( (void**) &new_fft, ALIGNMENT, sizeof(FFTWComplex) * (new_N/2+1));
1232  assert(!ret);
1233 
1234  const FFTWComplex * old_freq = freq();
1235  //printf("%d\n", fft_len);
1236 
1237  //copy old
1238  memcpy(new_fft, old_freq, TMath::Min(new_N/2+1,fft_len) * sizeof(FFTWComplex));
1239 
1240  //scale
1241  double scale = (1 + npad);
1242  for (int i =0; i < Nfreq(); i++) { new_fft[i].re *= scale; new_fft[i].im *= scale; }
1243 
1244 
1245  // zero rest
1246  memset(new_fft + fft_len, 0, (new_N/2 + 1 - fft_len) * sizeof(FFTWComplex));
1247 
1248  //set new lengths and dt
1249  fft_len = new_N/2 + 1;
1250  g_even.Set(new_N);
1251  dt = 1./ (g_even.GetN() * df);
1252 
1253 
1254  //swap in new fft
1255  free(fft);
1256  fft = new_fft;
1257 
1258  //others need to update now!
1259  must_update_even = true;
1260  must_update_uneven = !uneven_equals_even;
1261  must_update_freq = false;
1262  power_dirty = true;
1263  power_db_dirty = true;
1264  phase_dirty = true;
1265  group_delay_dirty = true;
1266  hilbert_dirty = true;
1267  hilbert_envelope_dirty = true;
1268  just_padded = false;
1269 }
1270 
1271 
1272 
1274 {
1275  if (npad < 1) return;
1276 
1277 
1278 
1279  //new even size
1280  if (g_even.GetN() ==0) (void) even(); //may need to calculate even if it never has been
1281  int old_N = g_even.GetN();
1282  int new_N = g_even.GetN() + npad;
1283 
1284  FFTWComplex * new_fft =0;
1285  int ret = posix_memalign( (void**) &new_fft, ALIGNMENT, sizeof(FFTWComplex) * (new_N/2+1));
1286  assert(!ret);
1287 
1288  const FFTWComplex * old_freq = freq();
1289  //printf("%d\n", fft_len);
1290 
1291  //copy old
1292  memcpy(new_fft, old_freq, TMath::Min(new_N/2+1,fft_len) * sizeof(FFTWComplex));
1293 
1294  //scale
1295  double scale = (double(new_N) / old_N);
1296  for (int i =0; i < Nfreq(); i++) {
1297  new_fft[i].re *= scale;
1298  new_fft[i].im *= scale; }
1299 
1300 
1301  // zero rest
1302  memset(new_fft + fft_len, 0, (new_N/2 + 1 - fft_len) * sizeof(FFTWComplex));
1303 
1304  //set new lengths and dt
1305  fft_len = new_N/2 + 1;
1306  g_even.Set(new_N);
1307  dt = 1./ (g_even.GetN() * df);
1308 
1309 
1310  //swap in new fft
1311  free(fft);
1312  fft = new_fft;
1313 
1314  //others need to update now!
1315  must_update_even = true;
1316  must_update_uneven = !uneven_equals_even;
1317  must_update_freq = false;
1318  power_dirty = true;
1319  power_db_dirty = true;
1320  phase_dirty = true;
1321  group_delay_dirty = true;
1322  hilbert_dirty = true;
1323  hilbert_envelope_dirty = true;
1324  just_padded = false;
1325 
1326 }
1327 
1328 
1330 {
1331  power_options = opt;
1332  power_dirty = true;
1333  power_db_dirty = true;
1334 }
1335 
1336 void AnalysisWaveform::padEven(int npad, int where)
1337 {
1338  if (npad < 1) return;
1339  TGraphAligned * g = updateEven();
1340  int old_n = g->GetN();
1341  g->Set(g->GetN() *(1+npad));
1342  df /= (1+npad);
1343 
1344 
1345 
1346  if (where > 0)
1347  {
1348  for (int i = old_n; i < g->GetN(); i++)
1349  {
1350  g->GetX()[i] = g->GetX()[i-1] + dt;
1351  g->GetY()[i] = 0;
1352  }
1353  }
1354  else if (where < 0)
1355  {
1356  memcpy(g->GetY() + old_n, g->GetY(), old_n * sizeof(double));
1357  memcpy(g->GetX() + old_n, g->GetX(), old_n * sizeof(double));
1358  for (int i = old_n-1; i >= 0; i--)
1359  {
1360  g->GetX()[i] = g->GetX()[i+1] - dt;
1361  g->GetY()[i] = 0;
1362  }
1363  }
1364 
1365  else if (where == 0)
1366  {
1367  memmove(g->GetY() + old_n/2, g->GetY(), old_n * sizeof(double));
1368  memmove(g->GetX() + old_n/2, g->GetX(), old_n * sizeof(double));
1369 
1370  for (int i = old_n/2-1; i >= 0; i--)
1371  {
1372  g->GetX()[i] = g->GetX()[i+1] - dt;
1373  g->GetY()[i] = 0;
1374  }
1375  for (int i = old_n + old_n/2; i < g->GetN(); i++)
1376  {
1377  g->GetX()[i] = g->GetX()[i-1] + dt;
1378  g->GetY()[i] = 0;
1379  }
1380  }
1381 
1382 
1383  if (npad >= 1) just_padded = true;
1384 }
1385 
1387 {
1388  if (just_padded) return true;
1389 
1390  const TGraphAligned *g = even();
1391 
1392  for (int i = g->GetN()/2; i <g->GetN(); i++)
1393  {
1394  if (g->GetY()[i] !=0) return false;
1395  }
1396  just_padded = true;
1397  return true;
1398 }
1399 
1400 static void doDraw(const TGraphAligned * cg,const char * opt, int color)
1401 {
1402  TGraphAligned * g = (TGraphAligned*) cg;
1403 
1404  if (color >= 0)
1405  {
1406  g->SetLineColor(color);
1407  g->SetMarkerColor(color);
1408  }
1409  g->Draw(opt);
1410 }
1411 
1412 
1413 void AnalysisWaveform::drawEven(const char * opt, int color) const{ doDraw(even(),opt,color); }
1414 void AnalysisWaveform::drawUneven(const char * opt, int color) const{ doDraw(uneven(),opt,color); }
1415 void AnalysisWaveform::drawPower(const char * opt, int color)const { doDraw(power(),opt,color); }
1416 void AnalysisWaveform::drawPowerdB(const char * opt, int color)const { doDraw(powerdB(),opt,color); }
1417 void AnalysisWaveform::drawPhase(const char * opt, int color) const{ doDraw(phase(),opt,color); }
1418 void AnalysisWaveform::drawHilbertEnvelope(const char * opt, int color) const{ doDraw(hilbertEnvelope(),opt,color); }
1419 
1420 
1422 {
1423  (void) freq();
1424  return fft_len;
1425 }
1426 
1427 
1429  AnalysisWaveform * __restrict y) {
1430 
1431 
1432 
1433  int N = TMath::Min(x->Neven(), y->Neven());
1434 
1435  //is this right? who knows
1436  const TGraphAligned * g_yh = y->hilbertTransform()->even();
1437  const TGraphAligned * g_y = y->even();
1438  const TGraphAligned * g_xh = x->hilbertTransform()->even();
1439  const TGraphAligned * g_x = x->even();
1440 
1441  const double one_over_sqrt2 = 1./sqrt(2);
1442 
1443  double new_x[N] __attribute__((aligned));
1444  double new_y[N] __attribute__((aligned));
1445 
1446  for (int i = 0; i < N; i++)
1447  {
1448  new_x[i] = one_over_sqrt2 * ( g_xh->GetY()[i] + g_y->GetY()[i]);
1449  new_y[i] = one_over_sqrt2 * ( g_x->GetY()[i] + g_yh->GetY()[i]);
1450  }
1451 
1452 
1453  memcpy(x->updateEven()->GetY(), new_x, N * sizeof(double));
1454  memcpy(y->updateEven()->GetY(), new_y, N * sizeof(double));
1455 
1456  x->forceEvenSize(N);
1457  y->forceEvenSize(N);
1458 
1459 }
1460 
1462 {
1463  int N = TMath::Min(x->Neven(), y->Neven());
1464 
1465  //is this right? who knows
1466  const TGraphAligned * g_x = x->even();
1467  const TGraphAligned * g_y = y->even();
1468 
1469  double new_x[N] __attribute__((aligned));
1470  double new_y[N] __attribute__((aligned));
1471 
1472  for (int i = 0; i < N; i++)
1473  {
1474  new_x[i] = 0.5 * ( g_x->GetY()[i] + g_y->GetY()[i] );
1475  new_y[i] = 0.5 * ( g_x->GetY()[i] - g_y->GetY()[i] );
1476  }
1477 
1478 
1479  memcpy(x->updateEven()->GetY(), new_x, N * sizeof(double));
1480  memcpy(y->updateEven()->GetY(), new_y, N * sizeof(double));
1481 
1482  x->forceEvenSize(N);
1483  y->forceEvenSize(N);
1484 }
1485 
1486 
1487 AnalysisWaveform * AnalysisWaveform::autoCorrelation(int npadtime, int npadfreq, double scale)
1488 {
1489 
1490  if (npadtime)
1491  {
1492  AnalysisWaveform copy(*this);
1493  copy.padEven(1);
1494  return correlation(&copy,&copy,npadfreq,scale);
1495  }
1496 
1497  return correlation(this,this,npadfreq,scale);
1498 }
1499 
1501 {
1502  TGraphAligned * g = updateEven();
1503 
1504  double mean = g->GetMean(2);
1505  for (int i = 0; i <g->GetN(); i++)
1506  {
1507  g->GetY()[i]-=mean;
1508  }
1509 }
1510 
1511 void AnalysisWaveform::setCorrelationNag(bool nag)
1512 {
1513 
1514  nag_if_not_zero_padded = nag;
1515 }
1516 
1517 void AnalysisWaveform::nameGraphs()
1518 {
1519 #ifdef USE_OMP
1520 #pragma omp critical
1521 #endif
1522  {
1523  TDirectory * old_dir = gDirectory;
1524  gDirectory = 0; // this is supposed to be thread local if open mp is enabled?
1525 
1526  DO_FOR_TIME(GetXaxis()->SetTitle("ns"));
1527  DO_FOR_FREQ(GetXaxis()->SetTitle("Ghz"));
1528 
1529  g_uneven.SetName(TString::Format("wf_uneven_%d", uid));
1530 
1531  g_even.SetName(TString::Format("wf_even_%d", uid));
1532 
1533  g_hilbert_envelope.SetName(TString::Format("wf_hilbert_env_%d", uid));
1534  g_hilbert_envelope.GetYaxis()->SetTitle("Analytic Envelope");
1535 
1536  g_power.SetName(TString::Format("wf_power_%d", uid));
1537  g_power.GetYaxis()->SetTitle("Power (arb) ");
1538 
1539  g_power_db.SetName(TString::Format("wf_power_db_%d", uid));
1540  g_power_db.GetYaxis()->SetTitle("Power (dbSomething) ");
1541 
1542  g_phase.SetName(TString::Format("wf_phase_%d", uid));
1543  g_phase.GetYaxis()->SetTitle("Phase");
1544 
1545  g_group_delay.SetName(TString::Format("wf_group_delay_%d", uid));
1546  g_group_delay.GetYaxis()->SetTitle("Group Delay (ns)");
1547  gDirectory = old_dir;
1548  }
1549 }
1550 
1551 
1552 double AnalysisWaveform::getRMS() const
1553 {
1554  // do it with the even waveform if we can!
1555 
1556  if (!must_update_even)
1557  {
1558  double mean,rms;
1559  even()->getMeanAndRMS(&mean,&rms);
1560  return rms;
1561  }
1562 
1563  if(!must_update_uneven && !uneven_equals_even)
1564  {
1565 
1566  double mean,rms;
1567  uneven()->getMeanAndRMS(&mean,&rms);
1568  return rms;
1569  }
1570 
1571  //otherwise do this in the frequency domain...
1572 
1573  int N = Nfreq();
1574 
1575  double sum2 = 0;
1576  const FFTWComplex * f = freq();
1577  for (int i = 1; i < N; i++)
1578  {
1579  sum2+= f[i].getAbsSq();
1580  }
1581 
1582  return sqrt(sum2/2)/(N-1);
1583 }
1584 
1585 AnalysisWaveform * AnalysisWaveform::makeWf(const TGraph * g, bool even, AnalysisWaveform *wf)
1586 {
1587 
1588  double dt0 = g->GetX()[1]-g->GetX()[0];
1589 
1590  //see if it's actually even
1591  if (!even)
1592  {
1593  even = true; //start by assuming it is
1594  for (int i = 2; i < g->GetN(); i++)
1595  {
1596  if (g->GetX()[i]-g->GetX()[i-1] != dt0)
1597  {
1598  even = false;
1599  break;
1600  }
1601  }
1602  }
1603 
1604  //find mean dt
1605  if (!even)
1606  {
1607  double sumdt = 0;
1608  for (int i = 1; i < g->GetN(); i++)
1609  {
1610  sumdt += g->GetX()[i] - g->GetX()[i-1];
1611  }
1612  dt0 = sumdt / (g->GetN()-1.);
1613  }
1614  if (wf)
1615  {
1616  wf->~AnalysisWaveform();
1617  }
1618  else
1619  {
1620  wf = (AnalysisWaveform*) malloc(sizeof(AnalysisWaveform));
1621  }
1622 
1623  if (even) return new (wf) AnalysisWaveform(g->GetN(), g->GetY(), dt0, g->GetX()[0]);
1624  return new (wf) AnalysisWaveform(g->GetN(), g->GetX(), g->GetY(), dt0);
1625 
1626 
1627 }
1628 
1629 
1630 
double evalEven(double t, EvenEvaluationType=EVAL_LINEAR) const
const TGraphAligned * power() const
struct __attribute__((packed))
Debugging use only TURF scaler data.
const AnalysisWaveform * hilbertTransform() const
void drawHilbertEnvelope(const char *opt="", int color=-1) const
void forceEvenSize(int size)
double im
The imaginary part.
Definition: FFTWComplex.h:18
const TGraphAligned * powerdB() const
const TGraphAligned * phase() const
FFTWComplex * doFFT(int length, const double *theInput)
Computes an FFT of an array of real numbers.
Definition: FFTtools.cxx:436
bool checkIfPaddedInTime() const
static AnalysisWaveform * makeWf(const TGraph *g, bool even=true, AnalysisWaveform *replace=0)
TGraphAligned * updateEven()
void drawPowerdB(const char *opt="", int color=-1) const
static void basisChange(AnalysisWaveform *__restrict hpol_or_lcp, AnalysisWaveform *__restrict vpol_or_rcp)
static void enableDebug(bool enable)
static InterpolationType defaultInterpolationType
void doInvFFTNoClobber(int length, const FFTWComplex *properly_aligned_input, double *properly_aligned_output)
Definition: FFTtools.cxx:372
const FFTWComplex * freq() const
const TGraphAligned * uneven() const
AnalysisWaveform(int Nt, const double *x, const double *y, double nominal_dt=1./2.6, InterpolationType type=defaultInterpolationType, InterpolationOptions *opt=&defaultInterpolationOptions)
void drawPower(const char *opt="", int color=-1) const
This is a wrapper class for a complex number.
Definition: FFTWComplex.h:12
void drawEven(const char *opt="", int color=-1) const
void padEven(int factor, int where=1)
void padFreq(int factor)
double deltaT() const
double re
Destructor.
Definition: FFTWComplex.h:15
TGraph * welchPeriodogram(const TGraph *gin, int segment_size, double overlap_fraction=0.5, const FFTWindowType *window=&GAUSSIAN_WINDOW, bool truncate_extra=true, TGraph *gout=0)
static InterpolationOptions defaultInterpolationOptions
const TGraphAligned * groupDelay() const
double deltaF() const
const TGraphAligned * hilbertEnvelope() const
static void allowEvenToUnevenConversion(bool allow)
TGraphAligned * updateUneven()
void drawPhase(const char *opt="", int color=-1) const
void setPowerCalculationOptions(PowerCalculationOptions &opt)
static void sumDifference(AnalysisWaveform *__restrict a, AnalysisWaveform *__restrict b)
static AnalysisWaveform * correlation(const AnalysisWaveform *A, const AnalysisWaveform *B, int npadfreq=0, double scale=1, int window_normalize=0)
void unwrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2857
const TGraphAligned * even() const
FFTWComplex * updateFreq()
void padFreqAdd(int npad)
This class is intended to be the main storage vessel for ANITA waveforms. It is similar in principle ...
AnalysisWaveform * autoCorrelation(int npadtime=1, int npadfreq=0, double scale=1)
void drawUneven(const char *opt="", int color=-1) const