FFTtools.cxx
1 #include "FFTtools.h"
2 
3 #include <fftw3.h>
4 #include "TRandom.h"
5 #include <assert.h>
6 #include "TF1.h"
7 #include <algorithm>
8 
9 #ifndef __APPLE__
10 #define SINCOS sincos
11 #else
12 #define SINCOS __sincos
13 #endif
14 
15 
16 
17 
18 using namespace std;
19 
20 
21 Double_t FFTtools::bartlettWindow(Int_t j, Int_t n)
22 {
23 return 1. - TMath::Abs(Double_t(2*j -n)/n);
24 }
25 
26 
27 Double_t FFTtools::welchWindow(Int_t j, Int_t n)
28 {
29  return 1. -TMath::Power(Double_t(2*j -n)/n,2);
30 }
31 
32 TGraph *FFTtools::getInterpolatedGraph(const TGraph *grIn, Double_t deltaT)
33 {
34  //Will use the ROOT::Math::Interpolator function to do this.
35  std::vector<double> tVec;
36  std::vector<double> vVec;
37 
38  Int_t numIn=grIn->GetN();
39  Double_t tIn,vIn;
40 
41  Double_t startTime=0;
42  Double_t lastTime=0;
43  for (int samp=0;samp<numIn;samp++) {
44  grIn->GetPoint(samp,tIn,vIn);
45  tVec.push_back(tIn);
46  vVec.push_back(vIn);
47  //std::cout << "samp " << samp << " t " << tIn << " v " << vIn << " this-last " << tIn-tVec[tVec.size()-2] << std::endl;
48  if(samp==0)
49  startTime=tIn;
50  lastTime=tIn;
51  }
52  if(tVec.size()<1) {
53  std::cout << "Insufficent points for interpolation\n";
54  return NULL;
55  }
56 
57  //Bastards
58  ROOT::Math::Interpolator chanInterp(tVec,vVec,ROOT::Math::Interpolation::kAKIMA);
59 
60  Int_t roughPoints=Int_t((lastTime-startTime)/deltaT);
61 
62 
63  Double_t *newTimes = new Double_t[roughPoints+100]; //Will change this at some point, but for now
64  Double_t *newVolts = new Double_t[roughPoints+100]; //Will change this at some point, but for now
65  Int_t numPoints=0;
66  for(Double_t time=startTime;time<=lastTime;time+=deltaT) {
67  newTimes[numPoints]=time;
68  newVolts[numPoints]=chanInterp.Eval(time);
69  // std::cout << numPoints << "\t" << newTimes[numPoints]
70  // << "\t" << newVolts[numPoints] << std::endl;
71 
72  numPoints++;
73  }
74 
75  TGraph *grInt = new TGraph(numPoints,newTimes,newVolts);
76  delete [] newTimes;
77  delete [] newVolts;
78  return grInt;
79 
80 }
81 
82 
83 
84 TGraph *FFTtools::getInterpolatedGraphFreqDom(const TGraph *grIn, Double_t deltaT)
85 {
86 
87  Int_t numIn=grIn->GetN();
88  Double_t *tIn=grIn->GetX();
89  Double_t *vIn=grIn->GetY();
90  Double_t oldDt=tIn[1]-tIn[0];
91  if(deltaT>oldDt)
92  return getInterpolatedGraph(grIn,deltaT);
93 
94  FFTWComplex *theFFt = doFFT(numIn,vIn);
95  Int_t fftLength=(numIn/2)+1;
96  Int_t newFFTLength=(oldDt/deltaT)*fftLength;
97  FFTWComplex *thePaddedFft = new FFTWComplex[newFFTLength];
98  Int_t numPoints=(newFFTLength-1)*2;
99  // std::cerr << numIn << "\t" << fftLength << "\t" << newFFTLength << "\n";
100  Double_t scaleFactor=Double_t(numPoints)/Double_t(numIn);
101  for(int i=0;i<newFFTLength;i++) {
102  if(i<fftLength) {
103  thePaddedFft[i]=theFFt[i];
104  thePaddedFft[i]*=FFTWComplex(scaleFactor,0);
105  }
106  else {
107  thePaddedFft[i].re=0;
108  thePaddedFft[i].im=0;
109  }
110  }
111 
112  Double_t *newTimes = new Double_t[numPoints]; //Will change this at some point, but for now
113  Double_t *newVolts = doInvFFT(numPoints,thePaddedFft);
114  for(Int_t i=0;i<numPoints;i++) {
115  newTimes[i]=tIn[0]+deltaT*(i-1);
116  // std::cout << i<< "\t" << newTimes[i]
117  // << "\t" << newVolts[i] << std::endl;
118  }
119 
120  TGraph *grInt = new TGraph(numPoints,newTimes,newVolts);
121  delete [] newTimes;
122  delete [] newVolts;
123  delete [] theFFt;
124  delete [] thePaddedFft;
125  return grInt;
126 
127 }
128 
129 
130 
131 
132  /***** WARNING: You are about to enter a zone that is quite complicated!!!
133  *
134  * The basic idea is this: FFTW3 figures out a super fast way to do a
135  * particular FFT, based on its size (and memory alignment, but in practice
136  * we always want things aligned optimally). This operation (planning) takes
137  * a while, and while FFTW3 will "remember" plans it already figured out, its
138  * hash function for storing them is needlesly slow (it does an md5sum of
139  * some properties of the transform, which is slow, partially, at least on
140  * Linux, because glibc sincos is so slow... but I digress)
141  *
142  * So the solution here is to use a std::map to store the FFtW3 goodies. This
143  * will use a tree structure, ensuring O(logN) lookup.
144  *
145  * But because arrays you pass are not necessarily going to be aligned
146  * properly for SIMD, we allocate memory here and will copy data in and out
147  * of the arrays. This might seem like it's slower, and it might be in some
148  * cases, but this is what we do.
149  *
150  * If FFTTOOLS_ALLOCATE_CONTIGUOUS is true, the input and output arrays will
151  * be (almost) contiguous, which theoretically might improve cache locality,
152  * but I haven't done any rigorous profiling.
153  *
154  * Finally, you might notice a bunch of threading-related crap littering the
155  * code. This is because the FFTW3 planning and the static arrays are not
156  * thread-safe. There are two threading models implemented, both
157  * experimental until such time as someone decides they're not (and
158  * therefore, neither enabled by default).
159  *
160  * The current strategy for thread safety is to lock the planning stage and
161  * then allocate different arrays for each thread. The FFT's are then
162  * executed using the new-array variants of fft_execute. It would be nice to
163  * just use TSD for this and just be able to mark the maps as thread_local,
164  * but that is not well implemented enough in compilers yet (afaik?) and I'm
165  * not sure if it works with OpenMP or not (but maybe it does?).
166  *
167  *
168  * FFTTOOLS_THREAD_SAFE adds the necessary machinery to use ROOT's built-in
169  * threading facilities (i.e. pthreads on Unix, and the Windows thread
170  * thingie on on Windows).
171  *
172  * FFTTOOLS_USE_OMP uses the OpenMP macros, which are somewhat easier to use.
173  *
174  * Trying to use both will crash and burn. don't
175  *
176  *
177  * There is one fairly big drawback to the way things are done; the per-thread arrys
178  * are never deleted. As long as you reuse threads instead of spawning countless
179  * numbers of them, this should be ok. In the future, maybe I'll properly use
180  * thread_local and shit to make it work, but I don't feel like it's right to make
181  * people use a C++11 compiler until at least when people stop using Fortran77
182  *
183  *******************************************************************************/
184 
185 
187 static std::map<int, std::pair<fftw_plan, fftw_plan> > cached_plans; //this caches both plans for a given length
188 
189 
190 
191 /* error if you try to compile with both */
192 #ifdef FFTTOOLS_THREAD_SAFE
193 #ifdef FFTTOOLS_USE_OMP
194  Sorry, you cannot compile using both FFTTOOLS_THREAD_SAFE and FFTTOOLS_USE_OMP.
195 #endif
196 #endif
197 
198 
200 #ifdef FFTTOOLS_THREAD_SAFE
201 #define USE_PER_THREAD_MEMORY
202 #include "TMutex.h"
203 #include "TThread.h"
204 static TMutex plan_mutex;
205 #define GET_TID() TThread::SelfId()
206 #endif
207 
208 
210 #ifdef FFTTOOLS_USE_OMP
211 #define USE_PER_THREAD_MEMORY
212 #include "omp.h"
213 #define GET_TID() omp_get_thread_num()
214 #endif
215 
216 
217 #ifdef USE_PER_THREAD_MEMORY
218 /*define memory for each thread, this will use the thread-id as an index
219  *
220  * For OMP, the thread numbers increase sequentially, so I use a vector to
221  * increase lookup speed. For pthreads, the thread number is an opaque handle,
222  * so I use a map instead
223  * */
224 
225 #ifdef FFTTOOLS_USE_OMP
226 static std::map<int, std::vector<double *> > cached_xs;
227 static std::map<int, std::vector<fftw_complex *> > cached_Xs;
228 #else
229 static std::map<int, std::map<long,double *> > cached_xs;
230 static std::map<int, std::map<long,fftw_complex *> > cached_Xs;
231 #endif
232 
233 #else
234 static std::map<int, double*> cached_xs;
235 static std::map<int, fftw_complex*> cached_Xs;
236 #endif
237 
238 static fftw_plan getPlan(int len, bool forward = true)
239 {
240  /*
241  Function which checks whether we've encountered a request to do an FFT of this length before.
242  If we haven't then we need a new plan!
243  */
244 
245 #ifdef FFTOOLS_THREAD_SAFE
246  plan_mutex.Lock(); //root lock
247 #endif
248 
249 
250 
251  std::map<int,std::pair<fftw_plan, fftw_plan> >::iterator it = cached_plans.find(len);
252 
253 
254  bool must_plan = it == cached_plans.end();
255  bool must_allocate = must_plan;
256 
257 #ifdef USE_PER_THREAD_MEMORY
258  unsigned long tid = GET_TID();
259 
260 #ifdef FFTTOOLS_USE_OMP
261  must_allocate = must_allocate || cached_xs[len].size() <= tid || cached_xs[len][tid] == 0 ;
262 #else
263  must_allocate = must_allocate || cached_xs[len].count(tid) == 0 || cached_xs[len][tid] == 0 ;
264 #endif
265 
266 #endif
267 
268  double * mem_x = 0;
269  fftw_complex * mem_X = 0;
270 
271  if(must_allocate)
272  {
273 #ifdef FFTTOOLS_ALLOCATE_CONTIGUOUS
274  /* Allocate contiguous memory for both the real and complex arrays
275  *
276  * For proper alignment, we ought to pad sizeof(double) * len to whatever the largest SIMD alignment is.
277  * Currently that's sizeof(double) * 4, but in the future it might be sizeof(double) * 8;
278  **/
279 
280  void * mem = fftw_malloc(sizeof(double) * (len + len % 8) + (1 + len/2) * sizeof(fftw_complex));
281  mem_x = (double*) mem; //pointer to real array
282  mem_X = (fftw_complex*) (mem_x + len + (len % 8)); //pointer to complex array
283 
284 // printf ("%lu %lu\n", ((size_t)mem_x) % 32, ((size_t)mem_X) % 32); // check that aligned
285 #else
286  mem_x= fftw_alloc_real(len);
287  mem_X= fftw_alloc_complex(len/2+1);
288 #endif
289 
290 #ifdef USE_PER_THREAD_MEMORY
291 
292 
293 #ifdef FFTTOOLS_USE_OMP
294  if (must_plan)
295  {
296  cached_xs[len] = std::vector<double*>(tid+1,0);
297  cached_Xs[len] = std::vector<fftw_complex*>(tid+1,0);
298  }
299 
300  if (cached_xs[len].size() <= tid)
301  {
302  cached_xs[len].resize(tid+1,0);
303  cached_Xs[len].resize(tid+1,0);
304  }
305 
306 #endif
307 
308  cached_xs[len][tid] = mem_x;
309  cached_Xs[len][tid] = mem_X;
310 
311 // printf("FFTtools:: Allocated memory for thread %lu, length %d\n", tid, len);
312 #else
313  cached_xs[len] = mem_x; //insert into maps
314  cached_Xs[len] = mem_X;
315 #endif
316 
317  }
318 
319 
320  if (must_plan)
321  {
322 
323  //create plans
324  std::pair<fftw_plan,fftw_plan> plans;
325 #ifdef FFTW_USE_PATIENT
326  plans.first = fftw_plan_dft_r2c_1d(len,mem_x, mem_X, FFTW_PATIENT | FFTW_PRESERVE_INPUT);
327  plans.second = fftw_plan_dft_c2r_1d(len,mem_X, mem_x, FFTW_PATIENT);
328 #else
329  plans.first = fftw_plan_dft_r2c_1d(len,mem_x, mem_X, FFTW_MEASURE | FFTW_PRESERVE_INPUT);
330  plans.second = fftw_plan_dft_c2r_1d(len,mem_X, mem_x, FFTW_MEASURE);
331 #endif
332  cached_plans[len] = plans;
333  }
334 
335 #ifdef FFTOOLS_THREAD_SAFE
336  plan_mutex.UnLock();
337 #endif
338 
339  if (!must_plan)
340  {
341  return forward ? (*it).second.first : (*it).second.second;
342  }
343  else
344  {
345  return forward ? cached_plans[len].first : cached_plans[len].second;
346  }
347 
348 }
349 
350 
351 void FFTtools::doFFT(int length, const double * in, FFTWComplex * out)
352 {
353 
354  fftw_plan plan;
355 #ifdef FFTTOOLS_USE_OMP
356 #pragma omp critical (fft_tools)
357  {
358  plan = getPlan(length,true);
359  }
360 #else
361  plan = getPlan(length,true);
362 #endif
363 
364  fftw_execute_dft_r2c(plan, (double*) in, (fftw_complex*) out);
365 }
366 
367 
368 
369 
370 
371 
372 void FFTtools::doInvFFTNoClobber(int length, const FFTWComplex * in, double * out)
373 {
374  fftw_plan plan;
375 #ifdef FFTTOOLS_USE_OMP
376 #pragma omp critical (fft_tools)
377  {
378  plan = getPlan(length,false);
379  }
380 #else
381  plan = getPlan(length,false);
382 #endif
383 
384  fftw_complex new_in[length/2+1] __attribute__((aligned(32)));
385 
386 #if ( __clang__major__ >3 || (__clang_major__==3 && __clang_minor__ >=6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4))
387  FFTWComplex * ain = (FFTWComplex*) __builtin_assume_aligned(in,32);
388 #else
389  FFTWComplex * ain = (FFTWComplex*) in;
390 #endif
391  memcpy(new_in, ain, (length/2+1) * sizeof(FFTWComplex));
392  fftw_execute_dft_c2r(plan,new_in, out);
393 
394 #if ( __clang__major__ >3 || (__clang_major__==3 && __clang_minor__ >=6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4))
395  double * aout = (double*) __builtin_assume_aligned(out,32);
396 #else
397  double * aout = (double*) out;
398 #endif
399 
400 
401  for (int i = 0; i < length; i++)
402  {
403  aout[i] /= length;
404  }
405 }
406 
407 
408 void FFTtools::doInvFFTClobber(int length, FFTWComplex * in, double * out)
409 {
410  fftw_plan plan;
411 #ifdef FFTTOOLS_USE_OMP
412 #pragma omp critical (fft_tools)
413  {
414  plan = getPlan(length,false);
415  }
416 #else
417  plan = getPlan(length,false);
418 #endif
419 
420 
421 #if ( __clang__major__ >3 || (__clang_major__==3 && __clang_minor__ >=6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4))
422  fftw_execute_dft_c2r(plan, (fftw_complex*) in, out);
423 
424  double * aout = (double*) __builtin_assume_aligned(out,32);
425 #else
426  double * aout = (double*) out;
427 #endif
428 
429  for (int i = 0; i < length; i++)
430  {
431  aout[i] /= length;
432  }
433 }
434 
435 
436 FFTWComplex *FFTtools::doFFT(int length, const double *theInput) {
437  //Here is what the sillyFFT program should be doing;
438 
439  const int numFreqs= (length/2)+1;
440 #ifdef FFTTOOLS_USE_OMP
441  fftw_plan plan;
442  fftw_complex * mem_X;
443  double * mem_x;
444  unsigned long tid = GET_TID();
445 #pragma omp critical (fft_tools)
446  {
447  plan = getPlan(length, true);
448  mem_X = cached_Xs[length][tid];
449  mem_x = cached_xs[length][tid];
450  }
451 #else
452  fftw_plan plan = getPlan(length, true);
453 
454 #if FFTTOOLS_THREAD_SAFE
455  unsigned long tid = GET_TID();
456  plan_mutex.Lock();
457  fftw_complex * mem_X = cached_Xs[length][tid];
458  double * mem_x = cached_xs[length][tid];
459  plan_mutex.UnLock();
460 #endif
461 
462 #endif
463 
464  FFTWComplex *myOutput = new FFTWComplex [numFreqs];
465 
466 #ifdef USE_PER_THREAD_MEMORY
467 // printf("%x\n", (size_t) mem_x);
468  memcpy(mem_x, theInput, sizeof(double)*length);
469  fftw_execute_dft_r2c(plan, mem_x, mem_X);
470  memcpy(myOutput, mem_X, sizeof(fftw_complex)*numFreqs);
471 #else
472  memcpy(cached_xs[length], theInput, sizeof(double)*length);
473  fftw_execute(plan);
474  memcpy(myOutput, cached_Xs[length], sizeof(fftw_complex)*numFreqs);
475 #endif
476 
477  return myOutput;
478 }
479 
480 
481 
482 double *FFTtools::doInvFFT(int length, const FFTWComplex *theInput) {
483  // This is what sillyFFT should be doing
484  // //Takes account of normailisation
485  // Although note that fftw_plan_dft_c2r_1d assumes that the frequency array is only the positive half, so it gets scaled by sqrt(2) to account for symmetry
486 
487 
488 #ifdef FFTTOOLS_USE_OMP
489  fftw_complex * mem_X;
490  double * mem_x;
491  fftw_plan plan;
492  unsigned long tid = GET_TID();
493 #pragma omp critical (fft_tools)
494  {
495  plan = getPlan(length, false);
496  mem_X = cached_Xs[length][tid];
497  mem_x = cached_xs[length][tid];
498  }
499 #else
500  fftw_plan plan = getPlan(length, false);
501 
502 #if FFTTOOLS_THREAD_SAFE
503  plan_mutex.Lock();
504  unsigned long tid = GET_TID();
505  fftw_complex * mem_X = cached_Xs[length][tid];
506  double *mem_x = cached_xs[length][tid];
507  plan_mutex.UnLock();
508 #endif
509 
510 #endif
511 
512  double *theOutput = new double [length];
513 
514 #ifdef USE_PER_THREAD_MEMORY
515  memcpy(mem_X, theInput, sizeof(fftw_complex) * (length/2 + 1));
516  fftw_execute_dft_c2r(plan, mem_X, mem_x);
517 #else
518  memcpy (cached_Xs[length], theInput, sizeof(fftw_complex) * (length/2 +1));
519  fftw_execute(plan);
520  double * mem_x = cached_xs[length];
521 #endif
522 
523  /* Normalization needed on the inverse transform */
524  for(int i=0; i<length; i++){
525  mem_x[i]/=length;
526  }
527 
528  // Copy output array
529  memcpy(theOutput, mem_x, sizeof(double)*length);
530  return theOutput;
531 }
532 
533 
534 
535 /* done with complicated code */
536 
537 
538 Double_t *FFTtools::combineValuesUsingFFTs(Int_t numArrays, Double_t **thePtrPtr, Int_t eachLength) {
539  FFTWComplex **theFFTs = new FFTWComplex* [numArrays];
540  for(int i=0;i<numArrays;i++) {
541  theFFTs[i]=doFFT(eachLength,thePtrPtr[i]);
542  }
543 
544  int fftLength=(eachLength/2)+1;
545  FFTWComplex *combinedFFT = new FFTWComplex [fftLength];
546 
547 
548  for(int i=0;i<fftLength;i++) {
549  double tempAbs0=getAbs(theFFTs[0][i]);
550  double tempTotAbs=tempAbs0;
551  for(int arNum=1;arNum<numArrays;arNum++) {
552  tempTotAbs+=getAbs(theFFTs[arNum][i]);
553  }
554 
555  combinedFFT[i].re=theFFTs[0][i].re*(tempTotAbs/(tempAbs0*double(numArrays)));
556  combinedFFT[i].im=theFFTs[0][i].im*(tempTotAbs/(tempAbs0*double(numArrays)));
557  }
558 
559  for(int i=0;i<numArrays;i++) {
560  delete [] theFFTs[i];
561  }
562  delete [] theFFTs;
563  double *newValues=doInvFFT(eachLength,combinedFFT);
564  delete [] combinedFFT;
565  return newValues;
566 
567 }
568 
569 
570 TGraph *FFTtools::combineGraphsUsingFFTs(Int_t numGraphs, TGraph **grPtr, const double *theWeights) {
571 
572  double totalWeight=0;
573  if(theWeights) {
574  for(int i=0;i<numGraphs;i++) {
575  totalWeight+=theWeights[i];
576 // cout << "Weight " << i << "\t" << theWeights[i] << endl;
577  }
578  }
579 
580  FFTWComplex **theFFTs = new FFTWComplex* [numGraphs];
581  for(int i=0;i<numGraphs;i++) {
582  double *oldY=grPtr[i]->GetY();
583  int oldLength=grPtr[i]->GetN();
584  theFFTs[i]=doFFT(oldLength,oldY);
585  }
586 
587  int fftLength=((grPtr[0]->GetN())/2)+1;
588  FFTWComplex *combinedFFT = new FFTWComplex [fftLength];
589 
590  for(int i=0;i<fftLength;i++) {
591  if(theWeights) {
592  double tempAbs0=getAbs(theFFTs[0][i]);
593  double tempTotAbs=tempAbs0*theWeights[0];
594  for(int grNum=1;grNum<numGraphs;grNum++) {
595  tempTotAbs+=getAbs(theFFTs[grNum][i])*theWeights[grNum];
596  }
597 
598  combinedFFT[i].re=theFFTs[0][i].re*(tempTotAbs/(tempAbs0*double(totalWeight)));
599  combinedFFT[i].im=theFFTs[0][i].im*(tempTotAbs/(tempAbs0*double(totalWeight)));
600  }
601  else {
602  double tempAbs0=getAbs(theFFTs[0][i]);
603  double tempTotAbs=tempAbs0;
604  for(int grNum=1;grNum<numGraphs;grNum++) {
605  tempTotAbs+=getAbs(theFFTs[grNum][i]);
606  }
607 
608  combinedFFT[i].re=theFFTs[0][i].re*(tempTotAbs/(tempAbs0*double(numGraphs)));
609  combinedFFT[i].im=theFFTs[0][i].im*(tempTotAbs/(tempAbs0*double(numGraphs)));
610  }
611  }
612 
613  for(int i=0;i<numGraphs;i++) {
614  delete [] theFFTs[i];
615  }
616  delete [] theFFTs;
617 
618  double *newX=grPtr[0]->GetX();
619  int newLength=grPtr[0]->GetN();
620  double *newY=doInvFFT(newLength,combinedFFT);
621  TGraph *grOut = new TGraph(newLength,newX,newY);
622  delete [] combinedFFT;
623  return grOut;
624 
625 }
626 
627 TGraph *FFTtools::getNormalisedCorrelationGraphTimeDomain(const TGraph *gr1, const TGraph *gr2, Int_t *zeroOffset, Int_t useDtRange, Double_t dtMin, Double_t dtMax) {
628  //Will also assume these graphs are zero meaned... may fix this assumption
629  //Now we'll extend this up to a power of 2
630  int length=gr1->GetN();
631  Double_t *y1=gr1->GetY();
632  int length2=gr2->GetN();
633  if(length2<length) length=length2;
634  Double_t *y2=gr2->GetY();
635  Double_t denom=gr1->GetRMS(2)*gr2->GetRMS(2);
636 
637  Double_t *x1=gr1->GetX();
638  Double_t *x2=gr2->GetX();
639 
640  double deltaT=x1[1]-x1[0];
641  double waveOffset=x1[0]-x2[0];
642 
643 
644  int N=2*length-1;
645 
646 
647  if(zeroOffset) {
648  *zeroOffset=N/2;
649  (*zeroOffset)+=Int_t(waveOffset/deltaT);
650  }
651 
652  //Will really assume that N's are equal for now
653  // int firstRealSamp=1+(N-2*length)/2;
654  // int lastRealSamp=firstRealSamp+2*(length-1);
655  int firstRealSamp=0;
656  int lastRealSamp=N-1;
657  int minDtIndex=0;
658  int maxDtIndex=N-1;
659  if(useDtRange) {
660  minDtIndex=TMath::Floor((dtMin-waveOffset)/deltaT)+(N/2);
661  if(minDtIndex<0) minDtIndex=0;
662  maxDtIndex=TMath::Ceil((dtMax-waveOffset)/deltaT)+(N/2);
663  if(maxDtIndex<0) maxDtIndex=0;
664  // std::cout << minDtIndex << "\t" << maxDtIndex << "\t" << waveOffset << "\t" << deltaT << "\t" << dtMin << "\t" << dtMax << "\t" << N << "\t" << TMath::Floor((dtMin-waveOffset)/deltaT) << "\n";
665  }
666 
667 
668 
669 
670  double *xVals = new double [N];
671  double *corVals= new double [N];
672  for(int i=minDtIndex;i<=maxDtIndex;i++) {
673  // if(i<minDtIndex || i>maxDtIndex) continue;
674  int dtIndex=(i-minDtIndex);
675 
676 
677  xVals[dtIndex]=((i-N/2)*deltaT)+waveOffset;
678  corVals[dtIndex]=0;
679  if(i>=firstRealSamp && i<=lastRealSamp) {
680  //if (i-firstRealSamp)==0 only one entry in correlation
681  Int_t firstIndex=(i-firstRealSamp);
682  Int_t secondIndex=length-1;
683  if(firstIndex>length-1) {
684  int offset=firstIndex-(length-1);
685  firstIndex=length-1;
686  secondIndex-=offset;
687  }
688 
689  Int_t numSamples=0;
690  //firstIndex+1;
691  //if(secondIndex<firstIndex)
692  // numSamples=secondIndex+1;
693  for(;firstIndex>=0 && secondIndex>=0;firstIndex--) {
694  // std::cout << i << "\t" << firstIndex << "\t" << secondIndex << "\n";
695  corVals[dtIndex]+=y1[firstIndex]*y2[secondIndex];
696  numSamples++;
697  secondIndex--;
698  }
699  corVals[dtIndex]/=denom*sqrt(numSamples);
700  }
701  }
702 
703  TGraph *grCor = new TGraph((maxDtIndex-minDtIndex)+1,xVals,corVals);
704  delete [] xVals;
705  delete [] corVals;
706  return grCor;
707 }
708 
709 TGraph *FFTtools::getNormalisedCorrelationGraph(const TGraph *gr1,const TGraph *gr2, Int_t *zeroOffset) {
710  //Will also assume these graphs are zero meaned... may fix this assumption
711  //Now we'll extend this up to a power of 2
712  int length=gr1->GetN();
713  Double_t *y1=gr1->GetY();
714  int length2=gr2->GetN();
715  Double_t *y2=gr2->GetY();
716  Double_t denom=gr1->GetRMS(2)*gr2->GetRMS(2);
717 
718  int N=int(TMath::Power(2,int(TMath::Log2(length))+2));
719  if(N<length2)
720  N=int(TMath::Power(2,int(TMath::Log2(length2))+2));
721 
722  //Will really assume that N's are equal for now
723  int firstRealSamp=1+(N-2*length)/2;
724  int lastRealSamp=firstRealSamp+2*(length-1);
725  TGraph *grCor = getCorrelationGraph(gr1,gr2,zeroOffset);
726  Double_t *corVal=grCor->GetY();
727  Double_t norm1=0;
728  Double_t norm2=0;
729 
730  for(int i=0;i<N;i++) {
731  if(i>=firstRealSamp && i<=lastRealSamp) {
732  if(i<=N/2) {
733  norm1+=(y1[i-firstRealSamp]*y1[i-firstRealSamp]);
734  norm2+=(y2[length-1-(i-firstRealSamp)]*y2[length-1-(i-firstRealSamp)]);
735  int effN=1+(i-firstRealSamp);
736  corVal[i]/=(sqrt(effN)*denom);
737  }
738  else if(i<N-1) {
739  norm1-=(y1[i-1-(N/2)]*y1[i-1-(N/2)]);
740  norm2-=(y2[length-(i-(N/2))]*y2[length-(i-(N/2))]);
741  int effN=(1+lastRealSamp-i);
742  corVal[i]/=(sqrt(effN)*denom);
743 
744  }
745  }
746  }
747 
748  return grCor;
749 }
750 
751 
752 
753 
754 TGraph *FFTtools::getCorrelationGraph(const TGraph *gr1, const TGraph *gr2, Int_t *zeroOffset) {
755  //Now we'll extend this up to a power of 2
756  int length=gr1->GetN();
757  int length2=gr2->GetN();
758 
759  int N=int(TMath::Power(2,int(TMath::Log2(length))+2));
760  if(N<length2)
761  N=int(TMath::Power(2,int(TMath::Log2(length2))+2));
762 
763  //Will really assume that N's are equal for now
764  int firstRealSamp=(N-length)/2;
765 
766  double *oldY1 = new double [N];
767  double *oldY2 = new double [N];
768 
769  double x,y;
770  Double_t x2,y2;
771  gr1->GetPoint(1,x2,y2);
772  gr1->GetPoint(0,x,y);
773  double deltaT=x2-x;
774  double firstX=x;
775 
776  gr2->GetPoint(0,x2,y2);
777  double waveOffset=firstX-x2;
778 
779 
780  // gr1->GetPoint(N/2,x2,y2);
781  // double offset=x-x2;
782  // std::cout << length << "\t" << length2 << "\n";
783 
784  for(int i=0;i<N;i++) {
785 
786  if(i<firstRealSamp || i>=firstRealSamp+length)
787  y=0;
788  else {
789  gr1->GetPoint(i-firstRealSamp,x,y);
790  }
791  oldY1[i]=y;
792 
793  if(i<firstRealSamp || i>=firstRealSamp+length2)
794  y=0;
795  else {
796  gr2->GetPoint(i-firstRealSamp,x,y);
797  }
798  oldY2[i]=y;
799 
800  }
801 
802 
803  // offset+=waveOffset;
804  if(zeroOffset) {
805  *zeroOffset=N/2;
806  (*zeroOffset)+=Int_t(waveOffset/deltaT);
807  }
808 
809  double *xVals = new double [N];
810  double *yVals = new double [N];
811  double *corVals=getCorrelation(N,oldY1,oldY2);
812  for(int i=0;i<N;i++) {
813  if(i<N/2) {
814  //Positive
815  xVals[i+(N/2)]=(i*deltaT)+waveOffset;
816  yVals[i+(N/2)]=corVals[i];
817  }
818  else {
819  //Negative
820  xVals[i-(N/2)]=((i-N)*deltaT)+waveOffset;
821  yVals[i-(N/2)]=corVals[i];
822  }
823  }
824 
825 
826  TGraph *grCor = new TGraph(N,xVals,yVals);
827  delete [] oldY1;
828  delete [] oldY2;
829  delete [] xVals;
830  delete [] yVals;
831  delete [] corVals;
832 
833  return grCor;
834 }
835 
836 
837 
838 TGraph *FFTtools::getInterpolatedCorrelationGraph(const TGraph *grIn1, const TGraph *grIn2, Double_t deltaT)
839 {
840  TGraph *gr1 = getInterpolatedGraph(grIn1,deltaT);
841  TGraph *gr2 = getInterpolatedGraph(grIn2,deltaT);
842  // std::cout << gr1 << "\t" << gr2 << "\n";
843  // std::cout << gr1->GetN() << "\t" << gr2->GetN() << "\n";
844  TGraph *grCor = getCorrelationGraph(gr1,gr2);
845  // std::cout << grCor << "\n";
847  delete gr1;
848  delete gr2;
849  return grCor;
850 }
851 
852 double *FFTtools::getCorrelation(int length,const float *oldY1, const float *oldY2)
853 {
854  double *newY1 = new double [length];
855  double *newY2 = new double [length];
856  for(int i=0;i<length;i++) {
857  newY1[i]=(double)oldY1[i];
858  newY2[i]=(double)oldY2[i];
859  }
860 
861  double *theCorr=getCorrelation(length,newY1,newY2);
862  delete [] newY1;
863  delete [] newY2;
864  return theCorr;
865 }
866 
867 
868 double *FFTtools::getCorrelation(int length,const double *oldY1, const double *oldY2)
869 {
870 
871 // cout << "Here in getCorrelation" << endl;
872  FFTWComplex *theFFT1=doFFT(length,oldY1);
873  FFTWComplex *theFFT2=doFFT(length,oldY2);
874 
875 
876  int newLength=(length/2)+1;
877 // cout << "newLength " << newLength << endl;
878  FFTWComplex *tempStep = new FFTWComplex [newLength];
879  int no2=length>>1;
880  for(int i=0;i<newLength;i++) {
881  double reFFT1=theFFT1[i].re;
882  double imFFT1=theFFT1[i].im;
883  double reFFT2=theFFT2[i].re;
884  double imFFT2=theFFT2[i].im;
885 
886  //Real part of output
887  tempStep[i].re=(reFFT1*reFFT2+imFFT1*imFFT2)/double(no2/2);
888  //Imaginary part of output
889  tempStep[i].im=(imFFT1*reFFT2-reFFT1*imFFT2)/double(no2/2);
890  }
891 // cout << "finished messing around" << endl;
892  double *theOutput=doInvFFT(length,tempStep);
893 // cout << "got inverse" << endl;
894  delete [] theFFT1;
895  delete [] theFFT2;
896  delete [] tempStep;
897  return theOutput;
898 
899 }
900 
901 
902 double *FFTtools::getCorrelation(const TGraph *gr1,const TGraph *gr2,int firstIndex,int lastIndex) {
903  int tempLength=gr1->GetN();
904  if(firstIndex<0 || lastIndex>tempLength) return 0;
905 
906  int length=lastIndex-firstIndex;
907 // double *x1 = gr1->GetX();
908  double *y1 = gr1->GetY();
909 // double *x2 = gr2->GetX();
910  double *y2 = gr2->GetY();
911 // TGraph newGr1(length,&x1[firstIndex],&y1[firstIndex]);
912 // TGraph newGr2(length,&x2[firstIndex],&y2[firstIndex]);
913 
914 // return getCorrelation(&newGr1,&newGr2);
915  return getCorrelation(length,&y1[firstIndex],&y2[firstIndex]);
916 }
917 
918 
919 TGraph *FFTtools::makeInverseInverseSpectrum(const TGraph *grWave) {
920 
921  double *oldY = grWave->GetY();
922  double *oldX = grWave->GetX();
923 // double deltaT=oldX[1]-oldX[0];
924  int length=grWave->GetN();
925  FFTWComplex *theFFT=doFFT(length,oldY);
926  double *invInvSpectrum = doInvFFT(length,theFFT);
927 
928  TGraph *grInvInv = new TGraph(length,oldX,invInvSpectrum);
929 // for(int i=0;i<length;i++) {
930 // cout << oldX[i] << "\t" << invInvSpectrum[i] << endl;
931 // }
932  return grInvInv;
933 
934 }
935 
936 double* FFTtools::getHilbertTransform(int length, const double * y)
937 {
938 
939  FFTWComplex *theFFT=doFFT(length,y);
940  int newLength=(length/2)+1;
941  for(int i=0;i<newLength;i++) {
942  double tempIm=theFFT[i].im;
943  theFFT[i].im=theFFT[i].re;
944  theFFT[i].re=-1*tempIm;
945  }
946  double *hilbert = doInvFFT(length,theFFT);
947 
948  delete [] theFFT;
949  return hilbert;
950 }
951 TGraph *FFTtools::getHilbertTransform(const TGraph *grWave)
952 {
953  double *oldY = grWave->GetY();
954  double *oldX = grWave->GetX();
955  int length=grWave->GetN();
956  double *hilbert = getHilbertTransform(length, oldY);
957  TGraph *grHilbert = new TGraph(length,oldX,hilbert);
958  delete [] hilbert;
959 
960  return grHilbert;
961 }
962 
963 
964 TGraph *FFTtools::getHilbertEnvelope(const TGraph *grWave)
965 {
966  // cout << "Here" << endl;
967  double *realY = grWave->GetY();
968  double *x = grWave->GetX();
969  TGraph *grHilbert = FFTtools::getHilbertTransform(grWave);
970  double *hilY=grHilbert->GetY();
971  int length=grWave->GetN();
972  Double_t *envY= new Double_t[length];
973  for(int i=0;i<length;i++) {
974 
975  envY[i]=TMath::Sqrt(realY[i]*realY[i] + hilY[i]*hilY[i]);
976  // cout << i << "\t" << envY[i] << endl;
977  }
978  TGraph *grEnvelope = new TGraph(length,x,envY);
979  delete [] envY;
980  delete grHilbert;
981  return grEnvelope;
982 }
983 
984 TGraph *FFTtools::getBoxCar(const TGraph *grWave, Int_t halfWidth)
985 {
986  //Just do this the lazy way for now
987  Double_t *inY = grWave->GetY();
988  Double_t *inX = grWave->GetX();
989  Int_t length=grWave->GetN();
990  Double_t *smoothY = new Double_t[length];
991  for(int i=0;i<length;i++) {
992  smoothY[i]=0;
993  if(i<halfWidth || length-i<=halfWidth) {
994  int countVals=0;
995  for(int j=i-halfWidth;j<=i+halfWidth;j++) {
996  if(j>=0 && j<length) {
997  smoothY[i]+=inY[j];
998  countVals++;
999  }
1000  }
1001  // cout << i << "\t" << countVals << endl;
1002  smoothY[i]/=countVals;
1003  }
1004  else {
1005  for(int j=i-halfWidth;j<=i+halfWidth;j++) {
1006  smoothY[i]+=inY[j];
1007  }
1008  smoothY[i]/=1+2*halfWidth;
1009  }
1010  }
1011  TGraph *grSmooth = new TGraph(length,inX,smoothY);
1012  delete [] smoothY;
1013  return grSmooth;
1014 
1015 }
1016 
1018  Double_t *oldY=grWave->GetY();
1019  Double_t *t = grWave->GetX();
1020  Int_t numPoints = grWave->GetN();
1021  Double_t *newY = new Double_t [numPoints];
1022  for(int i=0;i<numPoints;i++) {
1023  newY[i]=oldY[i]*bartlettWindow(i,numPoints);
1024  }
1025  TGraph *grNew = new TGraph(numPoints,t,newY);
1026  delete [] newY;
1027  return makePowerSpectrumVoltsSeconds(grNew);
1028 }
1029 
1030 
1031 TGraph *FFTtools::makePowerSpectrum(const TGraph *grWave) {
1032 
1033  double *oldY = grWave->GetY();
1034  double *oldX = grWave->GetX();
1035  double deltaT=oldX[1]-oldX[0];
1036  int length=grWave->GetN();
1037  FFTWComplex *theFFT=doFFT(length,oldY);
1038 
1039  int newLength=(length/2)+1;
1040  double *newY = new double [newLength];
1041  double *newX = new double [newLength];
1042 
1043  // double fMax = 1/(2*deltaT); // In GHz
1044  double deltaF=1/(deltaT*length);
1045 
1046  double tempF=0;
1047  for(int i=0;i<newLength;i++) {
1048  float power=pow(getAbs(theFFT[i]),2);
1049  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1050  power/=length;
1051  // if (power>0 ) power=10*TMath::Log10(power);
1052  // else power=-100; //no reason
1053  newX[i]=tempF;
1054  newY[i]=power;
1055  tempF+=deltaF;
1056  }
1057 
1058 
1059 
1060  TGraph *grPower = new TGraph(newLength,newX,newY);
1061  delete [] theFFT;
1062  delete [] newY;
1063  delete [] newX;
1064  return grPower;
1065 
1066 }
1067 
1068 
1069 
1070 TGraph *FFTtools::makePowerSpectrumPeriodogram(const TGraph *grWave) {
1071 
1072  double *oldY = grWave->GetY();
1073  double *oldX = grWave->GetX();
1074  double deltaT=oldX[1]-oldX[0];
1075  int length=grWave->GetN();
1076  FFTWComplex *theFFT=doFFT(length,oldY);
1077 
1078  int newLength=(length/2)+1;
1079 
1080  double *newY = new double [newLength];
1081  double *newX = new double [newLength];
1082 
1083  // double fMax = 1/(2*deltaT); // In Hz
1084  double deltaF=1/(deltaT*length);
1085 
1086  double tempF=0;
1087  for(int i=0;i<newLength;i++) {
1088  float power=pow(getAbs(theFFT[i]),2);
1089  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1090  power/=double(length*length);
1091  // if (power>0 ) power=10*TMath::Log10(power);
1092  // else power=-100; //no reason
1093  newX[i]=tempF;
1094  newY[i]=power;
1095  tempF+=deltaF;
1096  }
1097 
1098  TGraph *grPower = new TGraph(newLength,newX,newY);
1099  delete [] theFFT;
1100  delete [] newY;
1101  delete [] newX;
1102  return grPower;
1103 
1104 }
1105 
1106 TGraph *FFTtools::makePowerSpectrumVoltsSeconds(const TGraph *grWave) {
1107 
1108  double *oldY = grWave->GetY();
1109  double *oldX = grWave->GetX();
1110  double deltaT=oldX[1]-oldX[0];
1111  int length=grWave->GetN();
1112  FFTWComplex *theFFT=doFFT(length,oldY);
1113 
1114  int newLength=(length/2)+1;
1115 
1116  double *newY = new double [newLength];
1117  double *newX = new double [newLength];
1118 
1119  // double fMax = 1/(2*deltaT); // In Hz
1120  double deltaF=1/(deltaT*length); //Hz
1121  deltaF*=1e-6; //MHz
1122 
1123 
1124  double tempF=0;
1125  for(int i=0;i<newLength;i++) {
1126  float power=pow(getAbs(theFFT[i]),2);
1127  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1128  power*=deltaT/(length); //For time-integral squared amplitude
1129  power/=deltaF;//Just to normalise bin-widths
1130  //Ends up the same as dt^2, need to integrate the power (multiply by df)
1131  //to get a meaningful number out.
1132 
1133  newX[i]=tempF;
1134  newY[i]=power;
1135  tempF+=deltaF;
1136  }
1137 
1138 
1139  TGraph *grPower = new TGraph(newLength,newX,newY);
1140  delete [] theFFT;
1141  delete [] newY;
1142  delete [] newX;
1143  return grPower;
1144 
1145 }
1146 
1148 
1149 // double *oldY = grWave->GetY(); //in millivolts
1150 // double *oldX = grWave->GetX(); //in nanoseconds
1151 // int length=grWave->GetN();
1152 
1153 // double milli = 0.001;
1154 // double nano = 0.000000001;
1155 
1156 // double *oldY2 = new double [length];
1157 // double *oldX2 = new double [length];
1158 
1159 // for(int i=0;i<length;i++){
1160 // oldY2[i]=oldY[i]*milli; //in volts
1161 // oldX2[i]=oldX[i]*nano; // in seconds
1162 // }
1163 
1164 // double deltaT=(oldX2[1]-oldX2[0]);
1165 // FFTWComplex *theFFT=doFFT(length,oldY2);
1166 
1167 // int newLength=(length/2)+1;
1168 
1169 // double *newY = new double [newLength];
1170 // double *newX = new double [newLength];
1171 
1172 // // double fMax = 1/(2*deltaT); // In Hz
1173 // double deltaF=1/(deltaT*length); //Hz
1174 // deltaF*=1e-6; //MHz
1175 
1176 
1177 // double tempF=0;
1178 // for(int i=0;i<newLength;i++) {
1179 // float power=pow(getAbs(theFFT[i]),2);
1180 // if(i>0 && i<newLength-1) power*=2; //account for symmetry
1181 // power*=deltaT/(length); //For time-integral squared amplitude
1182 // power/=deltaF;//Just to normalise bin-widths
1183 // //Ends up the same as dt^2, need to integrate the power (multiply by df)
1184 // //to get a meaningful number out.
1185 
1186 // newX[i]=tempF;
1187 // newY[i]=power;
1188 // tempF+=deltaF;
1189 // }
1190 
1191 // TGraph *grPower = new TGraph(newLength,newX,newY);
1192 // delete [] newY;
1193 // delete [] newX;
1194 // delete [] oldY2;
1195 // delete [] oldX2;
1196 // ///////THIS BIT COULD DELETE THE POWERSPEC?????????
1197 // delete [] theFFT;
1198 // return grPower;
1199  double *oldY = grWave->GetY();
1200  double *oldX = grWave->GetX();
1201  double deltaT=oldX[1]-oldX[0];
1202  int length=grWave->GetN();
1203  FFTWComplex *theFFT=doFFT(length,oldY);
1204 
1205  int newLength=(length/2)+1;
1206 
1207  double *newY = new double [newLength];
1208  double *newX = new double [newLength];
1209 
1210  // double fMax = 1/(2*deltaT); // In Hz
1211  double deltaF=1/(deltaT*length); //Hz
1212  deltaF*=1e3; //MHz
1213  // std::cout << fMax << "\t" << deltaF << "\t" << deltaT << "\t" << length << std::endl;
1214 
1215  double tempF=0;
1216  for(int i=0;i<newLength;i++) {
1217  float power=pow(getAbs(theFFT[i]),2);
1218  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1219  power*=deltaT/(length); //For time-integral squared amplitude
1220  // power*=(1e3*1e3)/1e9;
1221  power/=deltaF;//Just to normalise bin-widths
1222  //Ends up the same as dt^2, need to integrate the power (multiply by df)
1223  //to get a meaningful number out.
1224 
1225  //if (power>0 ) power=10*TMath::Log10(power);
1226  //else power=-1000; //no reason
1227  newX[i]=tempF;
1228  newY[i]=power;
1229  tempF+=deltaF;
1230  }
1231 
1232  TGraph *grPower = new TGraph(newLength,newX,newY);
1233  delete [] theFFT;
1234  delete [] newY;
1235  delete [] newX;
1236  return grPower;
1237 
1238 }
1239 
1240 
1241 TGraph *FFTtools::makePowerSpectrumMilliVoltsNanoSecondsdB(const TGraph *grWave)
1242 {
1243  double *oldY = grWave->GetY();
1244  double *oldX = grWave->GetX();
1245  double deltaT=oldX[1]-oldX[0];
1246  int length=grWave->GetN();
1247  FFTWComplex *theFFT=doFFT(length,oldY);
1248 
1249  int newLength=(length/2)+1;
1250 
1251  double *newY = new double [newLength];
1252  double *newX = new double [newLength];
1253 
1254  // double fMax = 1/(2*deltaT); // In Hz
1255  double deltaF=1/(deltaT*length); //Hz
1256  deltaF*=1e3; //MHz
1257  // std::cout << deltaF << "\t" << deltaT << "\t" << length << std::endl;
1258 
1259  double tempF=0;
1260  for(int i=0;i<newLength;i++) {
1261  float power=pow(getAbs(theFFT[i]),2);
1262  if(i>0 && i<newLength-1) power*=2; //Changed form 2 by RJN 29/01/10 //account for symmetry
1263  power*=deltaT/(length); //For time-integral squared amplitude
1264  // power/=(1e3*1e3*1e9); //This bit converts from mv*mv*ns to v*v*s
1265  power/=deltaF;//Just to normalise bin-widths
1266  //Ends up the same as dt^2, need to integrate the power (multiply by df)
1267  //to get a meaningful number out.
1268 
1269  if (power>0 ) power=10*TMath::Log10(power);
1270  else power=-1000; //no reason
1271  newX[i]=tempF;
1272  newY[i]=power;
1273  tempF+=deltaF;
1274  }
1275 
1276 
1277  TGraph *grPower = new TGraph(newLength,newX,newY);
1278  delete [] theFFT;
1279  delete [] newY;
1280  delete [] newX;
1281  return grPower;
1282 
1283 
1284 }
1285 
1286 TGraph *FFTtools::makePowerSpectrumVoltsSecondsdB(const TGraph *grWave) {
1287 
1288  double *oldY = grWave->GetY();
1289  double *oldX = grWave->GetX();
1290  double deltaT=oldX[1]-oldX[0];
1291  int length=grWave->GetN();
1292  FFTWComplex *theFFT=doFFT(length,oldY);
1293 
1294  int newLength=(length/2)+1;
1295 
1296  double *newY = new double [newLength];
1297  double *newX = new double [newLength];
1298 
1299  // double fMax = 1/(2*deltaT); // In Hz
1300  double deltaF=1/(deltaT*length); //Hz
1301  deltaF*=1e-6; //MHz
1302 
1303 
1304  double tempF=0;
1305  for(int i=0;i<newLength;i++) {
1306  double logpower;
1307  double power=pow(getAbs(theFFT[i]),2);
1308  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1309  power*=deltaT/(length); //For time-integral squared amplitude
1310  power/=deltaF;//Just to normalise bin-widths
1311  //Ends up the same as dt^2, need to integrate the power (multiply by df)
1312  //to get a meaningful number out.
1313 
1314  if (power>0 ){
1315  logpower=10*TMath::Log10(power);
1316  }
1317  else{
1318  logpower=-1000; //no reason
1319  }
1320 
1321  newX[i]=tempF;
1322  newY[i]=logpower;
1323  tempF+=deltaF;
1324  }
1325 
1326 
1327  TGraph *grPower = new TGraph(newLength,newX,newY);
1328  delete [] theFFT;
1329  delete [] newY;
1330  delete [] newX;
1331  return grPower;
1332 
1333 
1334 }
1335 
1336 TGraph *FFTtools::makePowerSpectrumVoltsSecondsPadded(const TGraph *grWave, Int_t padFactor) {
1337 
1338  TGraph *grPad=padWave(grWave,padFactor);
1339  TGraph *grPower=makePowerSpectrumVoltsSeconds(grPad);
1340  delete grPad;
1341  return grPower;
1342 
1343 }
1344 
1345 
1346 TGraph *FFTtools::makePowerSpectrumVoltsSecondsPaddeddB(const TGraph *grWave, Int_t padFactor) {
1347  TGraph *grPad=padWave(grWave,padFactor);
1348  TGraph *grPower=makePowerSpectrumVoltsSecondsdB(grPad);
1349  delete grPad;
1350  return grPower;
1351 }
1352 
1353 
1354 TGraph *FFTtools::makeRawPowerSpectrum(const TGraph *grWave) {
1355 
1356  double *oldY = grWave->GetY();
1357  double *oldX = grWave->GetX();
1358  double deltaT=oldX[1]-oldX[0];
1359  int length=grWave->GetN();
1360  FFTWComplex *theFFT=doFFT(length,oldY);
1361 
1362  int newLength=(length/2)+1;
1363  double *newY = new double [newLength];
1364  double *newX = new double [newLength];
1365 
1366  double deltaF=1/(deltaT*length);
1367  // double fMax = 1/(2*deltaT); // In GHz
1368 
1369  double tempF=0;
1370  for(int i=0;i<newLength;i++) {
1371  float power=pow(getAbs(theFFT[i]),2);
1372  if(i>0 && i<newLength-1) power*=2; //account for symmetry
1373  newX[i]=tempF;
1374  newY[i]=power;
1375  tempF+=deltaF;
1376  }
1377 
1378 
1379  TGraph *grPower = new TGraph(newLength,newX,newY);
1380  delete [] theFFT;
1381  delete [] newY;
1382  delete [] newX;
1383  return grPower;
1384 
1385 }
1386 
1387 
1389  return sqrt(theNum.re*theNum.re+theNum.im*theNum.im);
1390 }
1391 
1392 
1393 Double_t FFTtools::sumPower(const TGraph *gr,Int_t firstBin,Int_t lastBin)
1394 {
1395  Double_t integral=0;
1396  Double_t freq,power;
1397  if(firstBin<0) firstBin=0;
1398  if(lastBin<0) lastBin=gr->GetN()-1;
1399  for(int i=firstBin;i<=lastBin;i++) {
1400  gr->GetPoint(i,freq,power);
1401  integral+=power;
1402  }
1403  return integral;
1404 }
1405 
1406 Double_t FFTtools::integratePower(const TGraph *gr,Int_t firstBin,Int_t lastBin)
1407 {
1408  Double_t integral=0;
1409  Double_t freq,power;
1410  gr->GetPoint(1,freq,power);
1411  Double_t df=freq;
1412  gr->GetPoint(0,freq,power);
1413  df-=freq;
1414  if(firstBin<0) firstBin=0;
1415  if(lastBin<0) lastBin=gr->GetN()-1;
1416  for(int i=firstBin;i<=lastBin;i++) {
1417  gr->GetPoint(i,freq,power);
1418  integral+=power*df;
1419  }
1420  return integral;
1421 }
1422 
1423 Double_t FFTtools::sumVoltageSquared(const TGraph *gr,Int_t firstBin,Int_t lastBin)
1424 {
1425  Double_t integral=0;
1426  Double_t time,volts;
1427  if(firstBin<0) firstBin=0;
1428  if(lastBin<0) lastBin=gr->GetN()-1;
1429  for(int i=firstBin;i<=lastBin;i++) {
1430  gr->GetPoint(i,time,volts);
1431  integral+=volts*volts;
1432  }
1433  return integral;
1434 }
1435 
1436 Double_t FFTtools::integrateVoltageSquared(const TGraph *gr,Int_t firstBin,Int_t lastBin)
1437 {
1438  Double_t integral=0;
1439  Double_t this_time=0, next_time=0, this_v=0, next_v=0, dt=0;
1440 
1441  if(firstBin<0) firstBin=0;
1442  if(lastBin<0) lastBin = gr->GetN()-1;
1443  for(int samp=firstBin; samp<lastBin; samp++){
1444  gr->GetPoint(samp, this_time, this_v);
1445  gr->GetPoint(samp+1, next_time, next_v);
1446  dt=next_time-this_time;
1447  integral+=this_v*this_v*dt;
1448  }
1449  //Now account for the last bin -- just use the last dt calculated
1450  integral+=next_v*next_v*dt;
1451 
1452  return integral;
1453 
1454 }
1455 
1456 Int_t FFTtools::getPeakBin(const TGraph *gr)
1457 {
1458  Double_t x,y;
1459  gr->GetPoint(0,x,y);
1460  Double_t peakVal=y;
1461  Int_t peakBin=0;
1462  for(int i=1;i<gr->GetN();i++) {
1463  gr->GetPoint(i,x,y);
1464  if(peakVal<y) {
1465  peakVal=y;
1466  peakBin=i;
1467  }
1468  }
1469  return peakBin;
1470 }
1471 
1472 
1473 Double_t FFTtools::getPeakXvalue(const TGraph *gr)
1474 {
1475  Double_t x,y;
1476  gr->GetPoint(0,x,y);
1477  Double_t peakVal=y;
1478  Double_t peakX=0;
1479  for(int i=1;i<gr->GetN();i++) {
1480  gr->GetPoint(i,x,y);
1481  if(peakVal<y) {
1482  peakVal=y;
1483  peakX=x;
1484  }
1485  }
1486  return peakX;
1487 }
1488 
1489 
1490 Int_t FFTtools::getPeakBin(const TGraph *gr, Int_t firstBin, Int_t lastBin)
1491 {
1492  if(firstBin<0 || lastBin<0 || firstBin>gr->GetN() || lastBin>gr->GetN() ||
1493  (lastBin<firstBin))
1494  return -1;
1495  Double_t x,y;
1496  gr->GetPoint(firstBin,x,y);
1497  Double_t peakVal=y;
1498  Int_t peakBin=0;
1499  for(int i=firstBin;i<lastBin;i++) {
1500  gr->GetPoint(i,x,y);
1501  if(peakVal<y) {
1502  peakVal=y;
1503  peakBin=i;
1504  }
1505  }
1506  return peakBin;
1507 }
1508 
1509 
1510 Double_t FFTtools::getPeakVal(const TGraph *gr, int *index)
1511 {
1512  Double_t x,y;
1513  gr->GetPoint(0,x,y);
1514  Double_t peakVal=y;
1515  Int_t peakBin=0;
1516  Int_t numPoints=gr->GetN();
1517  for(int i=1;i<numPoints;i++) {
1518  gr->GetPoint(i,x,y);
1519  if(peakVal<y) {
1520  peakVal=y;
1521  peakBin=i;
1522  }
1523  }
1524  if(index)
1525  *index=peakBin;
1526  return peakVal;
1527 }
1528 
1529 Double_t FFTtools::getPeakVal(const TGraph *gr, Int_t firstBin, Int_t lastBin, int *index){
1530  if(firstBin<0 || lastBin<0 || firstBin>gr->GetN() || lastBin>gr->GetN() ||
1531  (lastBin<firstBin))
1532  return -1;
1533  Double_t x,y;
1534  gr->GetPoint(firstBin,x,y);
1535  Double_t peakVal=y;
1536  Int_t peakBin=0;
1537  for(int i=firstBin;i<lastBin;i++) {
1538  gr->GetPoint(i,x,y);
1539  if(peakVal<y) {
1540  peakVal=y;
1541  peakBin=i;
1542  }
1543  }
1544  if(index)
1545  *index=peakBin;
1546  return peakVal;
1547 
1548 }
1549 
1550 Double_t FFTtools::getPeakSqVal(const TGraph *gr, int *index)
1551 {
1552  Double_t x,y;
1553  gr->GetPoint(0,x,y);
1554  Double_t peakVal=y*y;
1555  Int_t peakBin=0;
1556  Int_t numPoints=gr->GetN();
1557  for(int i=1;i<numPoints;i++) {
1558  gr->GetPoint(i,x,y);
1559  if(peakVal<y*y) {
1560  peakVal=y*y;
1561  peakBin=i;
1562  }
1563  }
1564  if(index)
1565  *index=peakBin;
1566  return peakVal;
1567 
1568 }
1569 
1570 void FFTtools::getPeakRmsSqVal(const TGraph *gr, Double_t &peak, Double_t &rms, Int_t *index)
1571 {
1572  Int_t numPoints=gr->GetN();
1573  Double_t *y = gr->GetY();
1574  Double_t *ySq = new Double_t [numPoints];
1575  for(int i=0;i<numPoints;i++) {
1576  ySq[i]=y[i]*y[i];
1577  }
1578  Int_t peakInd=TMath::LocMax(numPoints,ySq);
1579  peak=ySq[peakInd];
1580  rms=TMath::RMS(numPoints,ySq);
1581  if(index)
1582  *index=peakInd;
1583  delete [] ySq;
1584 }
1585 
1586 void FFTtools::getPeakRmsRectified(const TGraph *gr, Double_t &peak, Double_t &rms, Int_t *index)
1587 {
1588  TGraph *grRec = rectifyWave(gr);
1589  Int_t numPoints=grRec->GetN();
1590  Double_t *y = grRec->GetY();
1591  Int_t peakInd=TMath::LocMax(numPoints,y);
1592  peak=y[peakInd];
1593  rms=TMath::RMS(numPoints,y);
1594  if(index)
1595  *index=peakInd;
1596  delete grRec;
1597 }
1598 
1599 TGraph *FFTtools::subtractGraphs(const TGraph *grA, const TGraph *grB)
1600 {
1601  Int_t N1=grA->GetN();
1602  Int_t N2=grB->GetN();
1603  if(N1!=N2) return NULL;
1604 
1605  Double_t *newY = new Double_t [N1];
1606  Double_t *xVals=grA->GetX();
1607  Double_t x,yA,yB;
1608  for(int i=0;i<N1;i++) {
1609  grA->GetPoint(i,x,yA);
1610  grB->GetPoint(i,x,yB);
1611  newY[i]=yA-yB;
1612  }
1613  TGraph *grDiff = new TGraph(N1,xVals,newY);
1614  delete [] newY;
1615  return grDiff;
1616 }
1617 
1618 
1619 TGraph *FFTtools::translateGraph(const TGraph *grWave, Double_t deltaT)
1620 {
1621  Int_t N = grWave->GetN();
1622  Double_t *X=grWave->GetX();
1623  Double_t *Y=grWave->GetY();
1624  Double_t *newX = new Double_t[N];
1625  for(int i=0;i<N;i++)
1626  newX[i]=X[i]+deltaT;
1627  TGraph *grOut = new TGraph(N,newX,Y);
1628  delete [] newX;
1629  return grOut;
1630 }
1631 
1632 TGraph *FFTtools::divideGraphs(const TGraph *grA, const TGraph *grB)
1633 {
1634  Int_t N1=grA->GetN();
1635  Int_t N2=grB->GetN();
1636  if(N1!=N2) return NULL;
1637 
1638  Double_t *newY = new Double_t [N1];
1639  Double_t *xVals=grA->GetX();
1640  Double_t x,yA,yB;
1641  for(int i=0;i<N1;i++) {
1642  grA->GetPoint(i,x,yA);
1643  grB->GetPoint(i,x,yB);
1644  newY[i]=yA/yB;
1645  }
1646  TGraph *grRat = new TGraph(N1,xVals,newY);
1647  delete [] newY;
1648  return grRat;
1649 }
1650 
1651 
1652 TGraph *FFTtools::ratioSubtractOneGraphs(const TGraph *grA, const TGraph *grB)
1653 {
1654  Int_t N1=grA->GetN();
1655  Int_t N2=grB->GetN();
1656  // if(N1!=N2) return NULL;
1657 
1658  Int_t newN=N1;
1659  if(N2<N1) {
1660  newN=N2;
1661  //return NULL;
1662  }
1663  Double_t *xVals=grA->GetX();
1664  Double_t *xBVals=grB->GetX();
1665  Double_t deltaF=xVals[1]-xVals[0];
1666  Double_t deltaFB=xBVals[1]-xBVals[0];
1667 
1668  if(TMath::Abs(deltaFB-deltaF)>1) return NULL;
1669  // cout << newN << endl;
1670  Double_t *newY = new Double_t [newN];
1671  Double_t x,yA,yB;
1672  for(int i=0;i<newN;i++) {
1673  grA->GetPoint(i,x,yA);
1674  grB->GetPoint(i,x,yB);
1675  newY[i]=1-yA/yB;
1676  }
1677  TGraph *grRat = new TGraph(newN,xVals,newY);
1678  delete [] newY;
1679  return grRat;
1680 }
1681 
1682 TGraph *FFTtools::dbGraphs(const TGraph *grA, const TGraph *grB)
1683 {
1684  Int_t N1=grA->GetN();
1685  Int_t N2=grB->GetN();
1686  // if(N1!=N2) return NULL;
1687 
1688  Int_t newN=N1;
1689  if(N2<N1) {
1690  newN=N2;
1691  //return NULL;
1692  }
1693  Double_t *xVals=grA->GetX();
1694  Double_t *xBVals=grB->GetX();
1695  Double_t deltaF=xVals[1]-xVals[0];
1696  Double_t deltaFB=xBVals[1]-xBVals[0];
1697  // cout << N1 << "\t" << N2 << "\t" << deltaF << "\t" << deltaFB << "\n";
1698 
1699 
1700  if(TMath::Abs(deltaFB-deltaF)>1) return NULL;
1701  // cout << newN << endl;
1702  Double_t *newY = new Double_t [newN];
1703  Double_t x,yA,yB;
1704  for(int i=0;i<newN;i++) {
1705  grA->GetPoint(i,x,yA);
1706  grB->GetPoint(i,x,yB);
1707  newY[i]=10*TMath::Log10(yA/yB);
1708  }
1709  TGraph *grRat = new TGraph(newN,xVals,newY);
1710  delete [] newY;
1711  return grRat;
1712 }
1713 
1714 
1715 TGraph *FFTtools::smoothFFT(const TGraph *gr,Int_t factor)
1716 {
1717  Int_t N=gr->GetN();
1718  Int_t newN=N/factor;
1719  Double_t *xVals=gr->GetX();
1720  Double_t *yVals=gr->GetY();
1721 
1722  Double_t *newX = new Double_t [newN];
1723  Double_t *newY = new Double_t [newN];
1724  Double_t sumX=0;
1725  Double_t sumY=0;
1726  // cerr << N << "\t" << factor << "\t" << newN << "\n";
1727  for(int i=0;i<N;i++) {
1728  sumX+=xVals[i];
1729  sumY+=yVals[i];
1730  if((i+1)%factor==0) {
1731  // cerr << i << "\t" << sumX << "\t" << sumY << "\n";
1732  //New Point
1733  newX[(i+1)/factor-1]=sumX/factor;
1734  newY[(i+1)/factor-1]=sumY/factor;
1735  sumX=0;
1736  sumY=0;
1737  }
1738  }
1739  TGraph *grSmooth = new TGraph(newN,newX,newY);
1740 // delete [] newX;
1741 // delete [] newY;
1742  return grSmooth;
1743 }
1744 
1745 TGraph *FFTtools::padWave(const TGraph *grWave, Int_t padFactor) {
1746  double *oldY = grWave->GetY();
1747  double *oldX = grWave->GetX();
1748  double deltaT=oldX[1]-oldX[0];
1749  int realLength = grWave->GetN();
1750  int length = grWave->GetN()*padFactor;
1751  double *paddedY = new double [length];
1752  double *paddedX = new double [length];
1753  int newStart=(realLength*(padFactor-1))/2;
1754  for(int i=0;i<length;i++) {
1755  int waveIndex=i-newStart;
1756  paddedY[i]=0;
1757  paddedX[i]=(waveIndex*deltaT)+oldX[0];
1758  if(waveIndex>=0 && waveIndex<realLength) {
1759  paddedY[i]=oldY[waveIndex];
1760  }
1761  }
1762  TGraph *grPadded = new TGraph(length,paddedX,paddedY);
1763  delete [] paddedX;
1764  delete [] paddedY;
1765  return grPadded;
1766 }
1767 
1768 
1769 TGraph *FFTtools::padWaveToLength(const TGraph *grWave, Int_t newLength) {
1770  double *oldY = grWave->GetY();
1771  double *oldX = grWave->GetX();
1772  double deltaT=oldX[1]-oldX[0];
1773  int realLength = grWave->GetN();
1774  if(newLength<realLength) {
1775  std::cerr << "Can't pad waveform of length " << realLength
1776  << " to " << newLength << " you need to crop not pad\n";
1777  return NULL;
1778  }
1779  int length = newLength;
1780  double *paddedY = new double [length];
1781  double *paddedX = new double [length];
1782  int newStart=(newLength-realLength)/2;
1783  for(int i=0;i<length;i++) {
1784  int waveIndex=i-newStart;
1785  paddedY[i]=0;
1786  paddedX[i]=(waveIndex*deltaT)+oldX[0];
1787  if(waveIndex>=0 && waveIndex<realLength) {
1788  paddedY[i]=oldY[waveIndex];
1789  }
1790  }
1791  TGraph *grPadded = new TGraph(length,paddedX,paddedY);
1792  delete [] paddedX;
1793  delete [] paddedY;
1794  return grPadded;
1795 }
1796 
1797 
1798 
1799 TGraph *FFTtools::rectifyWave(const TGraph *gr, Int_t isNeg) {
1800  Int_t sign=1;
1801  if(isNeg)
1802  sign=-1;
1803 
1804  Int_t numPoints = gr->GetN();
1805  Double_t *x = gr->GetX();
1806  Double_t *y = gr->GetY();
1807  Double_t *yRec = new Double_t [numPoints];
1808  for(int i=0;i<numPoints;i++) {
1809  yRec[i]=sign*TMath::Abs(y[i]);
1810  }
1811  TGraph *grRec = new TGraph(numPoints,x,yRec);
1812  delete [] yRec;
1813  return grRec;
1814 }
1815 
1816 
1817 TGraph *FFTtools::getSimplePowerEnvelopeGraph(const TGraph *gr) {
1818  Double_t *ySq = new Double_t [gr->GetN()];
1819  Double_t *xOrig = new Double_t [gr->GetN()];
1820  Double_t *yEnvelope = new Double_t[gr->GetN()];
1821  Double_t *xEnvelope = new Double_t[gr->GetN()];
1822 
1823  Double_t x,y;
1824  Int_t numPoints=0;
1825 
1826  for(int i=0;i<gr->GetN();i++) {
1827  gr->GetPoint(i,x,y);
1828  ySq[i]=y*y;
1829  xOrig[i]=x;
1830  if(i==1) {
1831  if(ySq[0]>ySq[i]) {
1832  yEnvelope[numPoints]=ySq[0];
1833  xEnvelope[numPoints]=xOrig[0];
1834  numPoints++;
1835  }
1836  }
1837  else if(i==gr->GetN()-1 && ySq[i]>ySq[i-1]) {
1838  yEnvelope[numPoints]=ySq[i];
1839  xEnvelope[numPoints]=xOrig[i];
1840  numPoints++;
1841  }
1842  else if(ySq[i-1]>ySq[i-2] && ySq[i-1]>ySq[i]) {
1843  yEnvelope[numPoints]=ySq[i-1];
1844  xEnvelope[numPoints]=xOrig[i-1];
1845  numPoints++;
1846  }
1847  }
1848  TGraph *grEnvelope= new TGraph(numPoints,xEnvelope,yEnvelope);
1849  delete [] ySq;
1850  delete [] xOrig;
1851  delete [] yEnvelope;
1852  delete [] xEnvelope;
1853  return grEnvelope;
1854 }
1855 
1856 TGraph *FFTtools::makePSVSBartlettPaddedOverlap(const TGraph *grWave, Int_t padFactor, Int_t numFreqs)
1857 {
1858  TGraph *grPad=padWave(grWave,padFactor);
1859  Int_t numTot=grPad->GetN();
1860  Double_t *tVals = grPad->GetX();
1861  Double_t *vVals = grPad->GetY();
1862  Int_t m2=numFreqs*2;
1863  Double_t *inTimes = new Double_t[m2];
1864  Double_t *inVolts = new Double_t[m2];
1865  Double_t *outFreqs= new Double_t[m2];
1866  Double_t *outPower= new Double_t[m2];
1867  Int_t numSegs=(numTot-1)/numFreqs;
1868  Double_t delta= numSegs>1 ? Double_t(numTot-m2)/(numSegs-1.) : 0.;
1869  if(numTot < m2) {
1870  cerr << "Not enough data points for this many frequency bins" << endl;
1871  return 0;
1872  }
1873  Int_t numOut=0;
1874  for(int i=0;i<m2;i++) {
1875  outPower[i]=0;
1876  }
1877 
1878  for(int k=0;k<numSegs;k++) {
1879  Int_t noff = (Int_t)(k*delta + 0.5);
1880  for(int i=0;i<m2;i++) {
1881  inTimes[i]=tVals[i+noff];
1882  inVolts[i]=vVals[i+noff]*bartlettWindow(i,m2);
1883  }
1884  TGraph grTemp(m2,inTimes,inVolts);
1885  TGraph *grPowTemp = makePowerSpectrumVoltsSeconds(&grTemp);
1886  Double_t *tempFreq = grPowTemp->GetX();
1887  Double_t *tempPower = grPowTemp->GetY();
1888  numOut=grPowTemp->GetN();
1889  for(int i=0;i<numOut;i++) {
1890  outFreqs[i]=tempFreq[i];
1891  outPower[i]+=tempPower[i]; //To divide by numSegs or not that is the question
1892  }
1893  delete grPowTemp;
1894  }
1895  // std::cout << m2 << "\t" << numOut << "\t" << numSegs << endl;
1896 
1897  TGraph *grRet = new TGraph (numOut,outFreqs,outPower);
1898  delete [] inTimes;
1899  delete [] inVolts;
1900  delete [] outFreqs;
1901  delete [] outPower;
1902  return grRet;
1903 }
1904 
1905 void FFTtools::takeDerivative(Int_t numPoints, const Double_t *inputX, const Double_t *inputY, Double_t *outputX, Double_t *outputY) {
1906  int count=0;
1907  for(int samp=1;samp<numPoints;samp++) {
1908  Double_t deltaT=inputX[samp]-inputX[samp-1];
1909  Double_t deltaV=inputY[samp]-inputY[samp-1];
1910  outputX[count]=inputX[samp];
1911  outputY[count]=deltaV/deltaT;
1912  count++;
1913  }
1914 }
1915 
1916 //Legacy misspelling
1917 TGraph *FFTtools::getDerviative(const TGraph *grIn)
1918 {
1919  return getDerivative(grIn);
1920 }
1921 
1922 TGraph *FFTtools::getDerivative(const TGraph *grIn)
1923 {
1924  Int_t numPoints=grIn->GetN();
1925  if(numPoints<2) return NULL;
1926  Double_t *xVals=grIn->GetX();
1927  Double_t *yVals=grIn->GetY();
1928  Double_t *newX = new Double_t [numPoints];
1929  Double_t *newY = new Double_t [numPoints];
1930  takeDerivative(numPoints,xVals,yVals,newX,newY);
1931  TGraph *grDeriv = new TGraph(numPoints-1,newX,newY);
1932  delete [] newX;
1933  delete [] newY;
1934  return grDeriv;
1935 
1936 }
1937 
1938 TGraph *FFTtools::simplePassBandFilter(const TGraph *grWave, Double_t minFreq, Double_t maxFreq)
1939 {
1940 
1941  double *oldY = grWave->GetY();
1942  double *oldX = grWave->GetX();
1943  double deltaT=oldX[1]-oldX[0];
1944  int length=grWave->GetN();
1945  FFTWComplex *theFFT=doFFT(length,oldY);
1946 
1947  int newLength=(length/2)+1;
1948 
1949  // double fMax = 1/(2*deltaT); // In Hz
1950  double deltaF=1/(deltaT*length); //Hz
1951  deltaF*=1e3; //MHz
1952  // std::cout << fMax << "\t" << deltaF << "\t" << deltaT << "\t" << length << std::endl;
1953 
1954  double tempF=0;
1955  for(int i=0;i<newLength;i++) {
1956  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
1957  if(tempF<minFreq || tempF>maxFreq) {
1958  theFFT[i].re=0;
1959  theFFT[i].im=0;
1960  }
1961  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
1962  tempF+=deltaF;
1963  }
1964 
1965  double *filteredVals = doInvFFT(length,theFFT);
1966 
1967 
1968  TGraph *grFiltered = new TGraph(length,oldX,filteredVals);
1969  delete [] theFFT;
1970  delete [] filteredVals;
1971  return grFiltered;
1972 
1973 }
1974 
1975 TGraph *FFTtools::simpleNotchFilter(const TGraph *grWave, Double_t minFreq, Double_t maxFreq)
1976 {
1977 
1978  double *oldY = grWave->GetY();
1979  double *oldX = grWave->GetX();
1980  double deltaT=oldX[1]-oldX[0];
1981  int length=grWave->GetN();
1982  FFTWComplex *theFFT=doFFT(length,oldY);
1983 
1984  int newLength=(length/2)+1;
1985 
1986  // double fMax = 1/(2*deltaT); // In Hz
1987  double deltaF=1/(deltaT*length); //Hz
1988  deltaF*=1e3; //MHz
1989  // std::cout << fMax << "\t" << deltaF << "\t" << deltaT << "\t" << length << std::endl;
1990 
1991  double tempF=0;
1992  for(int i=0;i<newLength;i++) {
1993  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
1994  if(tempF>minFreq && tempF<maxFreq) {
1995  theFFT[i].re=0;
1996  theFFT[i].im=0;
1997  }
1998  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
1999  tempF+=deltaF;
2000  }
2001 
2002  double *filteredVals = doInvFFT(length,theFFT);
2003 
2004 
2005  TGraph *grFiltered = new TGraph(length,oldX,filteredVals);
2006  delete [] theFFT;
2007  delete [] filteredVals;
2008  return grFiltered;
2009 
2010 }
2011 
2012 TGraph *FFTtools::cropWave(const TGraph *grWave, Double_t minTime, Double_t maxTime)
2013 {
2014  Int_t numPoints=grWave->GetN();
2015  if(numPoints<1) return NULL;
2016  Double_t *xVals=grWave->GetX();
2017  Double_t *yVals=grWave->GetY();
2018 
2019  Double_t *outX = new Double_t[numPoints];
2020  Double_t *outY = new Double_t[numPoints];
2021  Int_t outPoints=0;
2022 
2023  for(int i=0;i<numPoints;i++) {
2024  if(xVals[i]>=minTime && xVals[i]<=maxTime) {
2025  outX[outPoints]=xVals[i];
2026  outY[outPoints]=yVals[i];
2027  outPoints++;
2028  }
2029  }
2030 
2031  TGraph *grCrop = new TGraph(outPoints,outX,outY);
2032  delete [] outX;
2033  delete [] outY;
2034  return grCrop;
2035 }
2036 
2037 
2038 TGraph *FFTtools::multipleSimpleNotchFilters(const TGraph *grWave, Int_t numNotches,const Double_t minFreq[],const Double_t maxFreq[])
2039 {
2040 
2041  double *oldY = grWave->GetY();
2042  double *oldX = grWave->GetX();
2043  double deltaT=oldX[1]-oldX[0];
2044  int length=grWave->GetN();
2045  FFTWComplex *theFFT=doFFT(length,oldY);
2046 
2047  int newLength=(length/2)+1;
2048 
2049  // double fMax = 1/(2*deltaT); // In Hz
2050  double deltaF=1/(deltaT*length); //Hz
2051  deltaF*=1e3; //MHz
2052  // std::cout << fMax << "\t" << deltaF << "\t" << deltaT << "\t" << length << std::endl;
2053 
2054  double tempF=0;
2055  for(int i=0;i<newLength;i++) {
2056  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
2057  for(int notch=0;notch<numNotches;notch++) {
2058  if(tempF>minFreq[notch] && tempF<maxFreq[notch]) {
2059  // std::cout << "notching " << tempF << " notch num " << notch << " min " << minFreq[notch] << " max " << maxFreq[notch] << std::endl;
2060  theFFT[i].re=0;
2061  theFFT[i].im=0;
2062  }
2063  }
2064  // std::cout << tempF << "\t" << theFFT[i].re << "\t" << theFFT[i].im << "\n";
2065  tempF+=deltaF;
2066  }
2067 
2068  double *filteredVals = doInvFFT(length,theFFT);
2069 
2070 
2071  TGraph *grFiltered = new TGraph(length,oldX,filteredVals);
2072  delete [] theFFT;
2073  delete [] filteredVals;
2074  return grFiltered;
2075 
2076 
2077 
2078 }
2079 
2080 //______________________________________________________________
2081 Double_t FFTtools::getWaveformSNR(const TGraph *gr){
2082  Double_t dummyPeak;
2083  Double_t dummyRms;
2084  Double_t snr = getWaveformSNR(gr,dummyPeak,dummyRms);
2085  return snr;
2086 }
2087 
2088 
2089 
2090 
2091 //______________________________________________________________
2092 Double_t FFTtools::getWaveformSNR(const TGraph *gr,Double_t &peakToPeak,Double_t &rms)
2093 {
2094  Int_t nRMS=25;
2095 
2096  Int_t nBins = gr->GetN();
2097  // Double_t *xVals = gr->GetX();
2098  Double_t *yVals = gr->GetY();
2099 
2100  Double_t mean=0.;
2101  Double_t meanSq=0.;
2102 
2103  for(int i=0;i<nRMS;i++){
2104  mean+=yVals[i];
2105  meanSq+=yVals[i]*yVals[i];
2106  }
2107  mean/=static_cast<double>(nRMS);
2108  meanSq/=static_cast<double>(nRMS);
2109 
2110  Int_t trending=3;
2111  Double_t p2p=0;
2112  Int_t firstBin=0;
2113  Double_t y;
2114 
2115  for(int i=0;i<nBins;i++){
2116  y=yVals[i];
2117  if(i>0){
2118  if(y<yVals[i-1] && trending==0){
2119  if(TMath::Abs(y-yVals[firstBin]>p2p)){
2120  p2p=TMath::Abs(y-yVals[firstBin]);
2121  }
2122  }
2123  else if(y<yVals[i-1] && (trending==1 || trending==2)){
2124  trending=0;
2125  firstBin=i-1;
2126  if(TMath::Abs(y-yVals[firstBin]>p2p)){
2127  p2p=TMath::Abs(y-yVals[firstBin]);
2128  }
2129  }
2130  else if(y>yVals[i-1] && (trending==0 || trending==2)){
2131  trending=1;
2132  firstBin=i-1;
2133  if(TMath::Abs(y-yVals[firstBin]>p2p)){
2134  p2p=TMath::Abs(y-yVals[firstBin]);
2135  }
2136  }
2137  else if(y>yVals[i-1] && trending==1){
2138  if(TMath::Abs(y-yVals[firstBin]>p2p)){
2139  p2p=TMath::Abs(y-yVals[firstBin]);
2140  }
2141  }
2142  else if(y==yVals[i-1]){
2143  trending=2;
2144  }
2145  else if(trending==3){
2146  if(y<yVals[i-1]){
2147  trending=0;
2148  firstBin=0;
2149  }
2150  if(y>yVals[i-1]){
2151  trending=1;
2152  firstBin=0;
2153  }
2154  }
2155  else{
2156  std::cout << "trending cock up!" << std::endl;
2157  std::cout << "y " << y << " yVals[i] " << yVals[i] << " yVals[i-1] " << yVals[i-1] << std::endl;
2158  return -1;
2159  }
2160  }
2161  }
2162 
2163  p2p/=2.;
2164 
2165  rms=sqrt(meanSq-mean*mean);
2166  peakToPeak = p2p;
2167 
2168  return p2p/rms;
2169 
2170 }
2171 
2172 
2173 
2174 
2175 //______________________________________________________________
2176 Double_t FFTtools::getWaveformPeak(const TGraph *gr)
2177 {
2178 
2179  Int_t nBins = gr->GetN();
2180  Double_t yMax = -9999;
2181  Double_t y,x;
2182 
2183  for(int i=0;i<nBins;i++){
2184  gr->GetPoint(i,x,y);
2185  if(y>yMax)
2186  yMax = y;
2187  }
2188 
2189  return yMax;
2190 }
2191 
2192 
2193 
2194 //______________________________________________________________
2195 Double_t FFTtools::getEnvelopeSNR(const TGraph *gr){
2196  Double_t dummyPeak;
2197  Double_t dummyRms;
2198  Double_t dummyTime;
2199  Double_t snr = getEnvelopeSNR(gr,dummyPeak,dummyRms,dummyTime);
2200  return snr;
2201 }
2202 
2203 
2204 
2205 
2206 //______________________________________________________________
2207 Double_t FFTtools::getEnvelopeSNR(const TGraph *gr,Double_t &peak,Double_t &rms,Double_t &timeOfPeak)
2208 {
2209 
2210  Int_t nRMS=25;
2211 
2212  Int_t nBins = gr->GetN();
2213  Double_t *xVals = gr->GetX();
2214  Double_t *yVals = gr->GetY();
2215 
2216  Double_t mean=0.;
2217  Double_t meanSq=0.;
2218 
2219  for(int i=0;i<nRMS;i++){
2220  mean+=yVals[i];
2221  meanSq+=yVals[i]*yVals[i];
2222  }
2223  mean/=static_cast<double>(nRMS);
2224  meanSq/=static_cast<double>(nRMS);
2225 
2226  Double_t p=0;
2227  Double_t t=0;
2228  Double_t y;
2229  Double_t x;
2230 
2231  for(int i=0;i<nBins;i++){
2232  if(yVals[i]<0){
2233  std::cout << "this isn't an envelope!!!" << std::endl;
2234  return -1;
2235  }
2236  y=yVals[i];
2237  x=xVals[i];
2238  if(i>0){
2239  if(y>p){
2240  p=y;
2241  t=x;
2242  }
2243  }
2244  }
2245 
2246  rms=sqrt(meanSq-mean*mean);
2247  peak = p;
2248  timeOfPeak = t;
2249 
2250  return peak/rms;
2251 
2252 }
2253 
2254 
2255 
2256 TGraph *FFTtools::convertMagnitudeToTimeDomain(const TGraph *inputMag)
2257 {
2258  Double_t *freqs=inputMag->GetX();
2259  Double_t *newVmmhz=inputMag->GetY();
2260  Int_t numFreqs=inputMag->GetN();
2261  Double_t *vmhz = new Double_t [numFreqs];
2262  Int_t numPoints=2*(numFreqs-1);
2263  FFTWComplex *freqDom = new FFTWComplex [numFreqs];
2264  Double_t df=freqs[1]-freqs[0];
2265  for(int i=0;i<numFreqs;i++) {
2266  vmhz[i]=newVmmhz[i]/1e6;
2267  // freqDom[i].re=vmhz[i];
2268  // freqDom[i].im=0;
2269  freqDom[i].im=vmhz[i];
2270  freqDom[i].re=0;
2271  }
2272  Double_t *tempV=FFTtools::doInvFFT(numPoints,freqDom);
2273  Double_t *newT = new Double_t [numPoints];
2274  Double_t *newV = new Double_t [numPoints];
2275  Double_t dt=1./(numPoints*df);
2276  for(int i=0;i<numPoints;i++) {
2277  if(i<numPoints/2) {
2278  Int_t tempInd=(numPoints/2)-(i+1);
2279  // std::cout << "First: " << i << "\t" << tempInd << "\n";
2280  newT[tempInd]=-i*dt;
2281  newV[tempInd]=tempV[i]*df*numPoints/sqrt(2);
2282  //The sqrt(2) is for the positive and negative frequencies
2283  }
2284  else {
2285  Int_t tempInd=numPoints+(numPoints/2)-(i+1);
2286  // std::cout << "Second: " << i << "\t" << tempInd << "\n";
2287  newT[tempInd]=(numPoints-i)*dt;
2288  newV[tempInd]=tempV[i]*df*numPoints/sqrt(2);
2289  //The sqrt(2) is for the positive and negative frequencies
2290  }
2291  }
2292  // for(int i=0;i<numPoints;i++) {
2293 // std::cout << i << "\t" << newT[i] << "\n";
2294 // }
2295  TGraph *grWave = new TGraph(numPoints,newT,newV);
2296  delete [] vmhz;
2297  delete [] newT;
2298  delete [] newV;
2299  delete [] freqDom;
2300  return grWave;
2301 
2302 }
2303 
2304 Double_t FFTtools::simpleInterploate(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x)
2305 {
2306  return ((y2 - y1)* ((x - x1) / (x2-x1)) + y1);
2307 }
2308 
2309 TGraph *FFTtools::getConvolution(const TGraph *grA, const TGraph *grB)
2310 {
2311  Int_t numPointsA=grA->GetN();
2312  Int_t numPointsB=grB->GetN();
2313 
2314  Double_t *tA=grA->GetX();
2315  Double_t *inA=grA->GetY();
2316  Double_t *inB=grB->GetY();
2317 
2318  Double_t t0=tA[0];
2319  Double_t deltaT=tA[1]-tA[0];
2320 
2321  //First up make them the same size
2322  Int_t numPoints=numPointsA;
2323  if(numPointsB>numPoints) {
2324  numPoints=numPointsB;
2325  }
2326  Double_t *A= new Double_t[numPoints];
2327  Double_t *B= new Double_t[numPoints];
2328  Double_t *T= new Double_t[numPoints];
2329 
2330  for(int i=0;i<numPoints;i++) {
2331  Int_t indA=(i-(numPoints-numPointsA)/2);
2332  T[i]=t0+indA*deltaT;
2333  if(indA<0 || indA>=numPointsA)
2334  A[i]=0;
2335  else
2336  A[i]=inA[indA];
2337 
2338  Int_t indB=(i-(numPoints-numPointsB)/2);
2339  if(indB<0 || indB>=numPointsB)
2340  B[i]=0;
2341  else
2342  B[i]=inB[indB];
2343 
2344  // std::cout << i << "\t" << indA << "\t" << indB << "\t" << A[i] << "\t" << B[i] << "\n";
2345  }
2346 
2347  Int_t numFreqs=(numPoints/2)+1;
2348  FFTWComplex *fftA=doFFT(numPoints,A);
2349  FFTWComplex *fftB=doFFT(numPoints,B);
2350  // FFTWComplex *fftAB= new FFTWComplex [numFreqs];
2351  Double_t freq=0;
2352  Double_t deltaF=1./(numPoints*deltaT);
2353  for(int i=0;i<numFreqs;i++) {
2354  // fftAB[i]=(fftA[i]*fftB[i]);
2355  fftA[i]*=fftB[i];
2356 
2357  // std::cout << "vals\t" << fftAB[i] << "\t" << fftA[i] << "\t" << fftB[i] << std::endl;
2358  // std::cout << "diffs\t" << (fftAB[i] - fftA[i]) << "..\t" << (fftAB[i] - fftB[i]) << std::endl;
2359  // std::cout << "elemets\t"
2360  // << fftAB[i].re - fftA[i].re << ", " << fftAB[i].im - fftA[i].im << "...\t"
2361  // << fftAB[i].re - fftB[i].re << "\t" << fftAB[i].im - fftB[i].im << std::endl;
2362  // std::cout << std::endl;
2363 
2364  // std::cout << freq << "\t" << fftAB[i].getAbs() << "\t" << fftA[i].getAbs() << "\t" << fftB[i].getAbs()
2365  // << "\t" << fftA[i].getAbs()*fftB[i].getAbs() << "\n";
2366  // std::cout << freq << "\t" << fftAB[i].getPhase() << "\t" << fftA[i].getPhase() << "\t" << fftB[i].getPhase()
2367  // << "\t" << fftA[i].getPhase()+fftB[i].getPhase() << "\n";
2368  freq+=deltaF;
2369  }
2370 
2371  // Double_t *AB=doInvFFT(numPoints,fftAB);
2372  Double_t *AB=doInvFFT(numPoints,fftA);
2373  Double_t *newAB = new Double_t[numPoints];
2374  for(int i=0;i<numPoints;i++) {
2375  if(i<numPoints/2) {
2376  newAB[i]=AB[(numPoints/2)+i];
2377  //newAB[i]=AB[i];
2378  }
2379  else {
2380  newAB[i]=AB[i-(numPoints/2)];
2381  //newAB[i]=AB[i];
2382  }
2383  }
2384  TGraph *grConv = new TGraph(numPoints,T,newAB);
2385  // delete [] fftAB;
2386  delete [] fftA;
2387  delete [] fftB;
2388  delete [] A;
2389  delete [] B;
2390  delete [] T;
2391  delete [] AB;
2392  delete [] newAB;
2393 
2394  return grConv;
2395 }
2396 
2397 
2398 
2400 {
2401  Int_t numPointsA=grA->GetN();
2402  Int_t numPointsB=grB->GetN();
2403  if(numPointsA!=numPointsB) {
2404  std::cout << "gr method " << numPointsA << " " << numPointsB << "\n";
2405  TGraph *grRet =getConvolution((TGraph*)grA,(TGraph*)grB);
2406  RFSignal *rfRet = new RFSignal(grRet);
2407  delete grRet;
2408  return rfRet;
2409  }
2410 
2411 // std::cout << "rf method " << numPointsA << " " << numPointsB << "\n";
2412  Double_t *tA=grA->GetX();
2413  Double_t deltaT=tA[1]-tA[0];
2414 
2415  Int_t numPoints=numPointsA;
2416  Int_t numFreqs=grA->getNumFreqs();
2417  FFTWComplex *fftA=grA->getComplexNums();
2418  FFTWComplex *fftB=grB->getComplexNums();
2419  FFTWComplex *fftAB= new FFTWComplex [numFreqs];
2420  Double_t freq=0;
2421  Double_t deltaF=1./(numPoints*deltaT);
2422  for(int i=0;i<numFreqs;i++) {
2423  fftAB[i]=fftA[i];
2424  fftAB[i]*=fftB[i];
2425  freq+=deltaF;
2426  }
2427 
2428  Double_t *AB=doInvFFT(numPoints,fftAB);
2429  Double_t *newAB = new Double_t[numPoints];
2430  for(int i=0;i<numPoints;i++) {
2431  if(i<numPoints/2) {
2432  newAB[i]=AB[(numPoints/2)+i];
2433  //newAB[i]=AB[i];
2434  }
2435  else {
2436  newAB[i]=AB[i-(numPoints/2)];
2437  //newAB[i]=AB[i];
2438  }
2439  }
2440  RFSignal *grConv = new RFSignal(numPoints,tA,newAB);
2441  delete [] fftAB;
2442  delete [] AB;
2443  delete [] newAB;
2444  return grConv;
2445 }
2446 
2447 TGraph *FFTtools::interpolateCorrelateAndAverage(Double_t deltaTInt,Int_t numGraphs, TGraph **grPtrPtr)
2448 {
2449  TGraph **grInt = new TGraph* [numGraphs];
2450  for(int i=0;i<numGraphs;i++)
2451  grInt[i]=getInterpolatedGraph(grPtrPtr[i],deltaTInt);
2452  TGraph *grAvg=correlateAndAverage(numGraphs,grInt);
2453  for(int i=0;i<numGraphs;i++)
2454  delete grInt[i];
2455  delete [] grInt;
2456  return grAvg;
2457 
2458 }
2459 
2460 //___________________________________________//
2461 TGraph *FFTtools::correlateAndAverage(Int_t numGraphs, TGraph **grPtrPtr)
2462 {
2463  //Assume they are all at same sampling rate
2464 
2465  // Can't correlate and average if there's only one graph.
2466  // So return 0
2467  if(numGraphs<2) return NULL;
2468 
2469  // TGraph *grA = grPtrPtr[0];
2470  TGraph *grA = (TGraph*) grPtrPtr[0]->Clone(); // Make copy of graph rather than using first graph.
2471 
2472  // Copy times from grA into new array.
2473  Int_t numPoints=grA->GetN();
2474  Double_t *timeVals= grA->GetX();
2475  Double_t *safeTimeVals = new Double_t[numPoints];
2476  Double_t *sumVolts = new Double_t [numPoints];
2477  for(int i=0;i<numPoints;i++)
2478  safeTimeVals[i]=timeVals[i];
2479 
2480 
2481  // Loop over graph array.
2482  int countWaves=1;
2483  for(int graphNum=1;graphNum<numGraphs;graphNum++) {
2484  TGraph *grB = grPtrPtr[graphNum];
2485  if(grB->GetN()<numPoints)
2486  numPoints=grB->GetN();
2487  TGraph *grCorAB = FFTtools::getCorrelationGraph(grA,grB);
2488 
2489  Int_t peakBin = FFTtools::getPeakBin(grCorAB);
2490  // Double_t *deltaTVals=grCorAB->GetX();
2491  // cout << peakBin << "\t" << grCorAB->GetN() << endl;
2492  Int_t offset=peakBin-(grCorAB->GetN()/2);
2493  // cout << deltaTVals[peakBin] << "\t" << safeTimeVals[offset] << endl;
2494 
2495  Double_t *aVolts = grA->GetY();
2496  Double_t *bVolts = grB->GetY();
2497 
2498  for(int ind=0;ind<numPoints;ind++) {
2499  int aIndex=ind;
2500  int bIndex=ind-offset;
2501 
2502  if(bIndex>=0 && bIndex<numPoints) {
2503  sumVolts[ind]=(aVolts[aIndex]+bVolts[bIndex]);
2504  }
2505  else {
2506  sumVolts[ind]=aVolts[aIndex];
2507  }
2508  }
2509 
2510 
2511  TGraph *grComAB = new TGraph(numPoints,safeTimeVals,sumVolts);
2512 
2513  // delete grB;
2514  delete grCorAB;
2515  // if(graphNum>1)
2516  delete grA;
2517  grA=grComAB;
2518  countWaves++;
2519 
2520  }
2521  for(int i=0;i<numPoints;i++) {
2522  sumVolts[i]/=countWaves;
2523  }
2524  Double_t meanVal=TMath::Mean(numPoints,sumVolts);
2525  for(int i=0;i<numPoints;i++) {
2526  sumVolts[i]-=meanVal;
2527  }
2528  delete grA;
2529  TGraph *grRet = new TGraph(numPoints,safeTimeVals,sumVolts);
2530  delete [] safeTimeVals;
2531  delete [] sumVolts;
2532  return grRet;
2533 }
2534 
2535 TGraph *FFTtools::correlateAndAveragePredeterminedZone(Int_t numGraphs, TGraph **grPtrPtr, Int_t *correlationBinPtr, Int_t binWiggleRoom = 30)
2536 {
2537  if(numGraphs<2) return NULL;
2538 
2539  TGraph *grA = (TGraph*) grPtrPtr[0]->Clone(); // Make copy of graph rather than using first graph.
2540 
2541  Int_t numPoints=grA->GetN();
2542  Double_t *timeVals= grA->GetX();
2543  Double_t *safeTimeVals = new Double_t[numPoints];
2544  Double_t *sumVolts = new Double_t [numPoints];
2545  for(int i=0;i<numPoints;i++)
2546  safeTimeVals[i]=timeVals[i];
2547 
2548  int countWaves=1;
2549  for(int graphNum=1;graphNum<numGraphs;graphNum++) {
2550  TGraph *grB = grPtrPtr[graphNum];
2551  if(grB->GetN()<numPoints)
2552  numPoints=grB->GetN();
2553  TGraph *grCorAB = FFTtools::getCorrelationGraph(grA,grB);
2554 
2555  // Here we limit the correlation graph around the predetermined peak bin
2556  // i.e. from a set of multiple waveforms where we have found some event-wide peak bin from correlation
2557  Int_t correlationBin = correlationBinPtr[graphNum-1];
2558 
2559  Int_t peakBin = FFTtools::getPeakBin(grCorAB,correlationBin - binWiggleRoom, correlationBin + binWiggleRoom);
2560 
2561  // End zoned method
2562 
2563  Int_t offset=peakBin-(grCorAB->GetN()/2);
2564 
2565  Double_t *aVolts = grA->GetY();
2566  Double_t *bVolts = grB->GetY();
2567 
2568  for(int ind=0;ind<numPoints;ind++) {
2569  int aIndex=ind;
2570  int bIndex=ind-offset;
2571 
2572  if(bIndex>=0 && bIndex<numPoints) {
2573  sumVolts[ind]=(aVolts[aIndex]+bVolts[bIndex]);
2574  }
2575  else {
2576  sumVolts[ind]=aVolts[aIndex];
2577  }
2578  }
2579 
2580  TGraph *grComAB = new TGraph(numPoints,safeTimeVals,sumVolts);
2581 
2582  delete grCorAB;
2583  delete grA;
2584  grA=grComAB;
2585  countWaves++;
2586 
2587  }
2588  for(int i=0;i<numPoints;i++) {
2589  sumVolts[i]/=countWaves;
2590  }
2591  Double_t meanVal=TMath::Mean(numPoints,sumVolts);
2592  for(int i=0;i<numPoints;i++) {
2593  sumVolts[i]-=meanVal;
2594  }
2595  delete grA;
2596  TGraph *grRet = new TGraph(numPoints,safeTimeVals,sumVolts);
2597  delete [] safeTimeVals;
2598  delete [] sumVolts;
2599  return grRet;
2600 }
2601 
2602 
2603 
2604 
2605 
2606 
2607 
2608 //___________________________________________//
2609 double FFTtools::sinc(double x, double eps)
2610 {
2611  if (fabs(x)<=eps)
2612  {
2613  return 1.;
2614  }
2615  else
2616  {
2617  return sin(TMath::Pi()*x) / (TMath::Pi()* x);
2618  }
2619 
2620 }
2621 
2622 
2623 
2624 
2625 
2626 //___________________________________________//
2627 void FFTtools::rotate(TGraph *g, int rot)
2628 {
2629  rot *=-1; //because of way trigger cell is defined
2630  int N = g->GetN();
2631  if (rot < 0)
2632  {
2633  rot+= N*(1+(-rot-1)/N);;
2634  }
2635  rot %= N;
2636  std::rotate(g->GetY(), g->GetY() + rot, g->GetY() + N);
2637 }
2638 
2639 
2640 //___________________________________________//
2641 double * FFTtools::FFTCorrelation(int length, const FFTWComplex * A, const FFTWComplex * B, FFTWComplex * work, int min_i, int max_i, int order)
2642 {
2643 
2644  int fftlen = length/2 +1;
2645  if (max_i <= 0 || max_i >= fftlen) max_i = fftlen-1;
2646  if (min_i < 0) min_i = 0;
2647 
2648 
2649 
2650  bool work_given = work;
2651  if (!work)
2652  {
2653  work = new FFTWComplex[fftlen];
2654  }
2655  else
2656  {
2657  memset(work,0,sizeof(FFTWComplex) * fftlen);
2658  }
2659 
2660  double rmsA = 0;
2661  double rmsB = 0;
2662  for(int i=0;i<fftlen;i++)
2663  {
2664  double reFFT1=A[i].re;
2665  double imFFT1=A[i].im;
2666  double reFFT2=B[i].re;
2667  double imFFT2=B[i].im;
2668 
2669 
2670 
2671  double weight = 1;
2672 
2673  if (min_i > 0)
2674  {
2675  weight /= (1 + TMath::Power(double(min_i)/i,2*order));
2676  }
2677 
2678  if (max_i < fftlen - 1)
2679  {
2680  weight /=( 1 +TMath::Power(double(i)/max_i,2*order));
2681  }
2682 
2683 
2684  if (i > 0) //don't add DC component to RMS!
2685  {
2686  rmsA += weight*(reFFT1 * reFFT1 + imFFT1 * imFFT1) * 2 / (length*length);
2687  rmsB += weight*(reFFT2 * reFFT2 + imFFT2 * imFFT2) * 2 / (length*length);
2688  }
2689  work[i].re=weight*(reFFT1*reFFT2+imFFT1*imFFT2)/length;
2690  work[i].im=weight*(imFFT1*reFFT2-reFFT1*imFFT2)/length;
2691  }
2692 
2693  double *answer=FFTtools::doInvFFT(length,work);
2694 
2695  double norm = (rmsA && rmsB) ? 1./(sqrt(rmsA*rmsB)) : 1;
2696  for (int i = 0; i< length; i++)
2697  {
2698  answer[i] *=norm;
2699  }
2700 
2701  if (!work_given)
2702  {
2703  delete [] work;
2704  }
2705 
2706  return answer;
2707 
2708 }
2709 
2710 
2711 #ifndef FFTTOOLS_COMPAT_MODE
2712 //___________________________________________//
2713 void FFTtools::applyWindow(TGraph *g, const FFTWindowType* win)
2714 {
2715  win->apply(g->GetN(), g->GetY());
2716 }
2717 #endif
2718 
2719 
2720 //___________________________________________//
2721 void FFTtools::inPlaceShift(int N, double *x)
2722 {
2723 
2724  for (int i = 0; i < N/2; i++)
2725  {
2726  double tmp = x[i];
2727  x[i] = x[i+N/2];
2728  x[i+N/2] = tmp;
2729  }
2730 }
2731 
2732 
2733 //___________________________________________//
2734 double FFTtools::getDt(const TGraph * g, int realN)
2735 {
2736 
2737  int n = realN ? realN : g->GetN();
2738  double x0 = g->GetX()[0];
2739  double x1 = g->GetX()[g->GetN()-1];
2740  return (x1-x0)/(n-0.5);
2741 }
2742 
2743 
2744 //___________________________________________//
2745 void FFTtools::polySubtract(TGraph *g, int order)
2746 {
2747  TF1 f("polysub",TString::Format("pol%d",order));
2748  g->Fit(&f,"NQ");
2749  for (int i = 0; i < g->GetN(); i++)
2750  {
2751  g->GetY()[i]-= f.Eval(g->GetX()[i]);
2752  }
2753 }
2754 
2755 
2756 //___________________________________________//
2757 double * FFTtools::directConvolve(int N, const double * x, int M, const double *h, double *y, int delay, DirectConvolveEdgeBehavior edge)
2758 {
2759 
2760 
2761  if (!y) y = new double[N];
2762  double start_val = edge == ZEROES_OUTSIDE ? 0 : x[0];
2763  double end_val = edge == ZEROES_OUTSIDE ? 0 : x[N-1];
2764  for (int i = 0; i < N; i++)
2765  {
2766  y[i] = 0;
2767  for (int j = delay-M/2; j < delay +(M+1)/2; j++)
2768  {
2769  double X = 0;
2770  if (i + j < 0)
2771  {
2772  X = start_val ;
2773  }
2774  else if ( i + j >= N)
2775  {
2776  X = end_val;
2777  }
2778  else
2779  {
2780  X = x[i+j];
2781  }
2782 
2783  y[i] += X * h[delay + M/2+j];
2784  }
2785  }
2786 
2787  return y;
2788 }
2789 
2790 
2791 //___________________________________________//
2792 double FFTtools::randomRayleigh(double sigma, TRandom * rng)
2793 {
2794  double u = rng ? rng->Uniform(0,1) : gRandom->Uniform(0,1);
2795  return sigma * sqrt(-2*log(u));
2796 }
2797 
2798 //___________________________________________//
2799 template<typename T>
2800 static void unwrap(size_t N, T * vals, T period)
2801 {
2802  T adjust = 0;
2803  for (size_t i = 1; i < N; i++)
2804  {
2805  if (vals[i] - vals[i-1] + adjust > period/2)
2806  {
2807  adjust -= period;
2808  }
2809  else if (vals[i] - vals[i-1] + adjust < -period/2)
2810  {
2811  adjust += period;
2812  }
2813 
2814  vals[i] += adjust;
2815  }
2816 }
2817 
2818 //___________________________________________//
2819 template <typename T>
2820 static void wrap(size_t N, T * vals, T period, T center)
2821 {
2822  T start = center - period/2;
2823  for (size_t i = 0; i < N; i++)
2824  {
2825  int nsub = FFTtools::fast_floor((vals[i]-start) / period);
2826  vals[i] -= nsub * period;
2827  }
2828 }
2829 
2830 //___________________________________________//
2831 template <typename T>
2832 static void wrap(size_t N, T * vals, T period)
2833 {
2834  wrap<T>(N,vals,period,period/2);
2835 
2836 }
2837 
2838 //___________________________________________//
2839 void FFTtools::wrap(size_t N, float * vals, float period)
2840 {
2841  ::wrap<float>(N, vals, period);
2842 }
2843 
2844 //___________________________________________//
2845 void FFTtools::unwrap(size_t N, float * vals, float period)
2846 {
2847  ::unwrap<float>(N, vals, period);
2848 }
2849 
2850 //___________________________________________//
2851 void FFTtools::wrap(size_t N, double * vals, double period)
2852 {
2853  ::wrap<double>(N, vals, period);
2854 }
2855 
2856 //___________________________________________//
2857 void FFTtools::unwrap(size_t N, double * vals, double period)
2858 {
2859  ::unwrap<double>(N, vals, period);
2860 }
2861 
2862 
2863 //___________________________________________//
2864 void FFTtools::wrap(size_t N, float * vals, float period, float center)
2865 {
2866  ::wrap<float>(N, vals, period, center);
2867 }
2868 
2869 
2870 
2871 //___________________________________________//
2872 void FFTtools::wrap(size_t N, double * vals, double period, double center)
2873 {
2874  ::wrap<double>(N, vals, period, center);
2875 }
2876 
2877 
2878 
2879 
2880 //___________________________________________//
2881 double FFTtools::evalEvenGraph(const TGraph * g, double t)
2882 {
2883  double t0 = g->GetX()[0];
2884  if (t < t0) return 0; //return 0 if before first sample
2885  double dt = g->GetX()[1] - t0;
2886 
2887  int bin_low = int ((t-t0)/dt);
2888 
2889  if (bin_low >= g->GetN()) return 0;
2890  if (bin_low == g->GetN()-1) return g->GetY()[g->GetN()-1];
2891 
2892  int bin_high = bin_low + 1;
2893  double frac = (t - (t0 + dt * bin_low)) / dt;
2894 
2895  double val_low = g->GetY()[bin_low];
2896  double val_high = g->GetY()[bin_high];
2897 
2898  return frac * val_high + (1-frac) * val_low;
2899 
2900 }
2901 
2902 
2903 
2904 //___________________________________________//
2905 int FFTtools::saveWisdom(const char * file)
2906 {
2907  // return fftw_export_wisdom_to_filename(file);
2908 
2909  // No fftw_export_wisdom_to_filename(const char*) in ancient fftw :(
2910  // Apparently it returns non-zero on success, I will wrap that too.
2911  FILE* filePtr = fopen(file, "w");
2912  int retVal = 0;
2913  if(filePtr){
2914  fftw_export_wisdom_to_file(filePtr);
2915  retVal = 1;
2916  fclose(filePtr);
2917  }
2918  else{
2919  std::cerr << "Warning! " << __PRETTY_FUNCTION__ << " could not open " << file << " in write mode."
2920  << std::endl;
2921  retVal = 0;
2922  }
2923  return retVal;
2924 }
2925 
2926 //___________________________________________//
2927 int FFTtools::loadWisdom(const char * file)
2928 {
2929 
2930  // return fftw_import_wisdom_from_filename(file);
2931 
2932  // No fftw_export_wisdom_to_filename(const char*) in ancient fftw :(
2933  // Apparently it returns non-zero on success, I will wrap that too.
2934  FILE* filePtr = fopen(file, "r");
2935  int retVal = 0;
2936  if(filePtr){
2937  fftw_import_wisdom_from_file(filePtr);
2938  retVal = 1;
2939  fclose(filePtr);
2940  }
2941  else{
2942  std::cerr << "Warning! " << __PRETTY_FUNCTION__ << " could not open " << file << " in read mode."
2943  << std::endl;
2944  retVal = 0;
2945  }
2946  return retVal;
2947 
2948 }
2949 
2950 
2951 //___________________________________________//
2952 
2953 
2954 
2955 
2956 void FFTtools::stokesParameters(int N, const double * __restrict x, const double * __restrict xh,
2957  const double * __restrict y, const double * __restrict yh,
2958  double * __restrict I, double * __restrict Q, double * __restrict U, double * __restrict V,
2959  double * __restrict Iins, double * __restrict Qins, double * __restrict Uins, double * __restrict Vins,
2960  bool only_max
2961  )
2962 {
2963  double sumI=0;
2964  double sumQ=0;
2965  double sumU=0;
2966  double sumV=0;
2967 
2968  double max_dI = 0;
2969 
2970  for (int i = 0; i <N; i++)
2971  {
2972  std::complex<double> X(x[i], xh[i]);
2973  std::complex<double> Y(y[i], yh[i]);
2974 
2975  bool is_max = false;
2976 
2977  if (I || Iins || only_max)
2978  {
2979  double dI = std::norm(X) + std::norm(Y);
2980  sumI +=dI;
2981 
2982  if (only_max && dI > max_dI)
2983  {
2984  is_max = true;
2985  max_dI =dI;
2986  }
2987 
2988  if (Iins && !only_max) Iins[i] = dI;
2989  if (Iins && is_max) *Iins = dI;
2990 
2991  }
2992 
2993  if (Q || Qins)
2994  {
2995  double dQ = std::norm(X) - std::norm(Y);
2996  sumQ += dQ;
2997  if (Qins && !only_max) Qins[i] = dQ;
2998  if (Qins && is_max) *Qins = dQ;
2999  }
3000 
3001  if (U || Uins)
3002  {
3003  double dU = 2 * ( X * std::conj(Y)).real();
3004  sumU += dU;
3005  if (Uins && !only_max) Uins[i] = dU;
3006  if (Uins && is_max) *Uins = dU;
3007  }
3008 
3009  if (V || Vins)
3010  {
3011  double dV =-2* ( X * std::conj(Y)).imag();
3012  sumV += dV;
3013  if (Vins && !only_max) Vins[i] = dV;
3014  if (Vins && is_max) *Vins = dV;
3015  }
3016  }
3017 
3018  if (I) *I = sumI/N;
3019  if (Q) *Q = sumQ/N;
3020  if (U) *U = sumU/N;
3021  if (V) *V = sumV/N;
3022 
3023 }
3024 
3025 #ifdef ENABLE_VECTORIZE
3026 #include "vectorclass.h"
3027 #include "vectormath_trig.h"
3028 #define VEC Vec4d
3029 #define VEC_N 4
3030 #define VEC_T double
3031 #endif
3032 
3033 
3034 void FFTtools::dftAtFreqAndMultiples(const TGraph * g, double f, int nmultiples, double * phase, double *amp, double * real, double * imag)
3035 {
3036 
3037  if (nmultiples < 1) return;
3038  if (nmultiples == 1) return dftAtFreq(g,f,phase,amp,real,imag);
3039 
3040  double w = 2 * TMath::Pi() * f;
3041 
3042  const double * t = g->GetX();
3043  const double * y = g->GetX();
3044  int N = g->GetN();
3045 
3046  //build up sin table
3047  double sin_f[N], cos_f[N];
3048  double sin_nf[N], cos_nf[N];
3049 
3050  double vcos = 0;
3051  double vsin = 0;
3052 
3053 #ifdef ENABLE_VECTORIZE
3054  VEC vecy;
3055  VEC vect;
3056  VEC vw = w;
3057 
3058  int leftover = N % VEC_N;
3059  int nit = N / VEC_N + (leftover ? 1 : 0);
3060 
3061  // do first pass and compute base frequency;
3062 
3063  for (int i = 0; i < nit; i++)
3064  {
3065  if (i < nit -1 || !leftover)
3066  {
3067  vect.load(t+VEC_N*i);
3068  vecy.load(y+VEC_N*i);
3069  }
3070  else
3071  {
3072  vect.load_partial(leftover, t+VEC_N*i);
3073  vecy.load_partial(leftover, y+VEC_N*i);
3074  }
3075 
3076 
3077  VEC ang = vect * vw;
3078  VEC vec_sin, vec_cos;
3079  vec_sin = sincos(&vec_cos, ang);
3080 
3081 
3082 
3083  if ( i < nit -1 || !leftover)
3084  {
3085  vec_sin.store(sin_f + i * VEC_N);
3086  vec_cos.store(cos_f + i * VEC_N);
3087  }
3088  else
3089  {
3090 
3091  vec_sin.store_partial(leftover, sin_f + i * VEC_N);
3092  vec_cos.store_partial(leftover, cos_f + i * VEC_N);
3093  }
3094 
3095 
3096  vec_sin *= vecy;
3097  vec_cos *= vecy;
3098  vsin += horizontal_add(vec_sin);
3099  vcos += horizontal_add(vec_cos);
3100  }
3101 
3102 
3103 #else
3104 
3105  //do first pass and compute base frequency
3106 
3107 
3108  for (int i = 0; i < N; i++)
3109  {
3110  double c,s;
3111  SINCOS(w* t[i], &s,&c);
3112  sin_f[i] = s;
3113  cos_f[i] = c;
3114  double v = y[i];
3115  vcos += v*c;
3116  vsin += v*s;
3117  }
3118 #endif
3119 
3120  if (phase) phase[0] = atan2(vsin,vcos);
3121  if (amp) amp[0] = sqrt(vsin*vsin + vcos*vcos);
3122  if (real) real[0] = vcos;
3123  if (imag) imag[0] = vsin;
3124 
3125  memcpy(sin_nf, sin_f, sizeof(sin_f));
3126  memcpy(cos_nf, cos_f, sizeof(cos_f));
3127 
3128 
3129 
3130  for (int j = 1; j < nmultiples; j++)
3131  {
3132  vcos = 0;
3133  vsin = 0;
3134 
3135 #ifdef ENABLE_VECTORIZE
3136  VEC vsin_f;
3137  VEC vcos_f;
3138  VEC vsin_nf;
3139  VEC vcos_nf;
3140  for (int i = 0; i < nit; i++)
3141  {
3142  if (i < nit -1 || !leftover)
3143  {
3144  vect.load(t+VEC_N*i);
3145  vecy.load(y+VEC_N*i);
3146  vsin_f.load(sin_f + VEC_N * i);
3147  vcos_f.load(cos_f + VEC_N * i);
3148  vsin_nf.load(sin_nf + VEC_N * i);
3149  vcos_nf.load(cos_nf + VEC_N * i);
3150  }
3151  else
3152  {
3153  vect.load_partial(leftover, t+VEC_N*i);
3154  vecy.load_partial(leftover, y+VEC_N*i);
3155  vsin_f.load_partial(leftover, sin_f + VEC_N * i);
3156  vcos_f.load_partial(leftover, cos_f + VEC_N * i);
3157  vsin_nf.load_partial(leftover, sin_nf + VEC_N * i);
3158  vcos_nf.load_partial(leftover, cos_nf + VEC_N * i);
3159  }
3160 
3161  VEC vec_sin = vcos_f * vcos_nf - vsin_f * vsin_nf;
3162  VEC vec_cos = vcos_f * vsin_nf + vsin_f * vcos_nf;
3163 
3164  if ( i < nit -1 || !leftover)
3165  {
3166  vec_sin.store(sin_nf + i * VEC_N);
3167  vec_cos.store(cos_nf + i * VEC_N);
3168  }
3169  else
3170  {
3171 
3172  vec_sin.store_partial(leftover, sin_nf + i * VEC_N);
3173  vec_cos.store_partial(leftover, cos_nf + i * VEC_N);
3174  }
3175 
3176  vec_sin *= vecy;
3177  vec_cos *= vecy;
3178 
3179  vsin += horizontal_add(vec_sin);
3180  vcos += horizontal_add(vec_cos);
3181  }
3182 
3183 #else
3184  for (int i = 0; i < N; i++)
3185  {
3186  double tempcos = cos_f[i] * cos_nf[i] - sin_f[i] * sin_nf[i];
3187  double tempsin = cos_f[i] * sin_nf[i] + sin_f[i] *cos_nf[i];
3188  cos_nf[i] = tempcos;
3189  sin_nf[i] = tempsin;
3190 
3191  vcos += tempcos * y[i];
3192  vsin += tempsin * y[i];
3193  }
3194 #endif
3195 
3196  if (phase) phase[j] = atan2(vsin,vcos);
3197  if (amp) amp[j] = sqrt(vsin*vsin + vcos*vcos);
3198  if (real) real[j] = vcos;
3199  if (imag) imag[j] = vsin;
3200 
3201  }
3202 
3203 }
3204 
3205 
3206 void FFTtools::dftAtFreq(const TGraph * g, double f, double * phase , double * amp, double * real, double * imag)
3207 {
3208 
3209  double w = 2 * TMath::Pi() * f;
3210  double vcos = 0;
3211  double vsin = 0;
3212 
3213  const double * t = g->GetX();
3214  const double * y = g->GetY();
3215  int N = g->GetN();
3216 
3217 #ifdef ENABLE_VECTORIZE
3218 
3219  VEC vw= w;
3220  VEC vecy;
3221  VEC vect ;
3222 
3223  int leftover = N % VEC_N;
3224  int nit = N/VEC_N + (leftover ? 1 : 0);
3225 
3226  for (int i = 0; i < nit; i++)
3227  {
3228  if (i < nit -1 || !leftover)
3229  {
3230  vect.load(t+VEC_N*i);
3231  vecy.load(y+VEC_N*i);
3232  }
3233  else
3234  {
3235  vect.load_partial(leftover, t+VEC_N*i);
3236  vecy.load_partial(leftover, y+VEC_N*i);
3237  }
3238 
3239  VEC ang = vect * vw;
3240  VEC vec_sin, vec_cos;
3241  vec_sin = sincos(&vec_cos, ang);
3242 
3243  vec_sin *= vecy;
3244  vec_cos *= vecy;
3245  vsin += horizontal_add(vec_sin);
3246  vcos += horizontal_add(vec_cos);
3247  }
3248 #else
3249  for (int i = 0; i < N; i++)
3250  {
3251  double c,s;
3252  SINCOS(w*t[i], &s,&c);
3253  double v = y[i];
3254  vcos +=c*v;
3255  vsin +=s*v;
3256  }
3257 #endif
3258  if (real)
3259  *real = vcos;
3260 
3261  if (imag)
3262  *imag = vsin;
3263 
3264  if (phase)
3265  *phase=atan2(vsin,vcos);
3266 
3267  if (amp)
3268  *amp = sqrt(vsin*vsin + vcos*vcos);
3269 }
3270 
3271 
3272 
3273 
3275 
3276 
3277 
3278 FFTWComplex * FFTtools::makeMinimumPhase(int N, const double * G, double mindb)
3279 {
3280  double minval = TMath::Power(10,mindb/20);
3281  double min = log(minval);
3282 
3283 
3284  double * logmag = new double[N];
3285  FFTWComplex * output = new FFTWComplex[N];
3286 
3287  for (int i = 0; i < N; i++)
3288  {
3289  logmag[i]= G[i] < minval ? min : log(G[i]);
3290  }
3291 
3292  double * phase = getHilbertTransform(N, logmag);
3293 
3294  for (int i = 0; i < N; i++)
3295  {
3296  double mag = G[i] < minval ? minval : G[i];
3297 
3298  if ( i == 0 || i == N-1)
3299  {
3300  output[i].re = mag;
3301  output[i].im = 0;
3302 
3303  }
3304  else
3305  {
3306  output[i].re = mag * cos(phase[i]);
3307  output[i].im = mag * sin(phase[i]);
3308  }
3309  }
3310 
3311  delete [] logmag;
3312  delete [] phase;
3313  return output;
3314 }
3315 
3316 
3317 TGraph * FFTtools::makeMinimumPhase(const TGraph * gin,double mindb)
3318 {
3319 
3320  FFTWComplex * G = doFFT(gin->GetN(), gin->GetY());
3321  int nfft = gin->GetN()/2+1;
3322  double * mag = new double[nfft];
3323  for (int i = 0; i < nfft; i++) mag[i] = G[i].getAbs();
3324  FFTWComplex * Y = makeMinimumPhase(nfft, mag, mindb);
3325  TGraph * out = new TGraph(*gin);
3326  TString str;
3327  str.Form("minphase_%s",gin->GetName());
3328  out->SetName(str.Data());
3329  str.Form("Minimum Phase %s",gin->GetTitle());
3330  out->SetTitle(str.Data());
3331  double * y = doInvFFT(out->GetN(), Y);
3332  for (int i = 0; i < out->GetN(); i++) out->GetY()[i] = y[i];
3333 
3334  delete [] mag;
3335  delete [] Y;
3336  delete [] G;
3337  delete [] y;
3338  return out;
3339 }
3340 
3341 TGraph * FFTtools::makeFixedDelay(const TGraph * gin, double delay)
3342 {
3343 
3344  TGraph * out = new TGraph(*gin);
3345  TString str;
3346 
3347  str.Form("fixeddelay%s",gin->GetName());
3348  out->SetName(str.Data());
3349  str.Form("Fixed Delay (%g) %s",delay, gin->GetTitle());
3350  out->SetTitle(str.Data());
3351 
3352  double dt = gin->GetX()[1] - gin->GetX()[0];
3353  double dw = TMath::Pi()*2/(gin->GetN() * dt);
3354  FFTWComplex * G = doFFT(gin->GetN(), gin->GetY());
3355  for (int i = 0; i < gin->GetN()/2; i++)
3356  {
3357  double mag = G[i].getAbs();
3358  double ph = -delay * i*dw;
3359  G[i] = FFTWComplex(mag*cos(ph), mag*sin(ph));
3360  }
3361  double * y = doInvFFT(out->GetN(), G);
3362  for (int i = 0; i < out->GetN(); i++) out->GetY()[i] = y[i];
3363 
3364  delete [] G;
3365  delete [] y;
3366 
3367  return out;
3368 }
3369 
3370 
3371 
3372 double FFTtools::checkCausality(int N, const FFTWComplex * signal)
3373 {
3374  double * real = new double[N];
3375  double * imag = new double[N];
3376 
3377  for (int i = 0; i < N; i++)
3378  {
3379  real[i] = signal[i].re;
3380  imag[i] = signal[i].im;
3381  }
3382 
3383  double * hilbert = getHilbertTransform(N, real);
3384 
3385  double sum2=0;
3386  for (int i = 0; i < N; i++)
3387  {
3388  double diff=hilbert[i]-imag[i];
3389  sum2+= diff*diff;
3390  }
3391 
3392 
3393  delete real;
3394  delete hilbert;
3395  delete imag;
3396 
3397  return sqrt(sum2/N);
3398 }
3399 
3400 
3401 
3402 double * FFTtools::rmsEnvelope(int N, double W,
3403  const double * __restrict__ x,
3404  const double * __restrict__ y,
3405  double * __restrict__ out)
3406 {
3407  if (!out) out = new double[N];
3408 
3409  double sumV2 = 0;
3410  int min_i = 0;
3411  int navg = 0;
3412  for (int i = 0; i < N; i++)
3413  {
3414  sumV2 += y[i]*y[i];
3415  navg++;
3416 
3417  while(x[min_i] < x[i] - W)
3418  {
3419  sumV2 -= y[min_i]*y[min_i];
3420  navg--;
3421  min_i++;
3422  }
3423 
3424  out[i] = sqrt(2*sumV2/navg);
3425  }
3426 
3427  return out;
3428 }
3429 
3430 double * FFTtools::peakEnvelope(int N, double min,
3431  const double * __restrict__ x,
3432  const double * __restrict__ y,
3433  double * __restrict__ out)
3434 {
3435  if (!out) out = new double[N];
3436 
3437  /* zero out */
3438  memset(out,0, N * sizeof(double));
3439 
3440  int first_out = -1;
3441  int last_out = 0;
3442  /* start by finding out the peaks. We'll put them in out. */
3443  for (int i = 0; i < N; )
3444  {
3445 
3446  //first check if it we are at a local max
3447  if (! ((i == 0 || fabs(y[i]) > fabs(y[i-1])) && (i == N-1 || fabs(y[i]) > fabs(y[i+i]))) )
3448  {
3449  i++;
3450  continue;
3451  }
3452 
3453 // printf("%g %g\n", x[i],y[i]);
3454 
3455  //cool, we are at a local max. let's check if it's the biggest within min
3456 
3457  int ii = i+1;
3458 
3459  while (ii < N && x[ii] < x[i] + min)
3460  {
3461  if (fabs(y[ii]) > fabs(y[i]))
3462  {
3463  /* oh shoot, we're not a max, let's move i to here and break out */
3464  i = ii;
3465  break;
3466  }
3467  ii++;
3468  }
3469 
3470  if (i == ii) /* that means we were not a max */
3471  continue;
3472 
3473  /* yay, we are at a local max, and there is nothing bigger in within min */
3474  out[i] = fabs(y[i]);
3475 // printf( "it's good!\n");
3476 
3477  if (first_out < 0) first_out = i;
3478  if (i > last_out) last_out = i;
3479 
3480  i = ii; // skip!
3481  }
3482 
3483 
3484  /* hold before first max */
3485  for (int i =0; i < first_out; i++ )
3486  out[i] = out[first_out];
3487 
3488  double x0 = x[first_out];
3489  double y0 = out[first_out];
3490  int i = first_out;
3491 
3493  while (i< last_out)
3494  {
3495  int next_out = i+1;
3496  while(!out[++next_out]);
3497 
3498  double x1 = x[next_out];
3499  double y1 = out[next_out];
3500 
3501 // printf("(%g %g:%g %g)\n", x0,y0,x1,y1);
3502 
3503  double m = (y1-y0)/(x1-x0);
3504  for ( ; i < next_out; i++)
3505  {
3506  out[i] = y0 + (x[i] - x0) * m;
3507  }
3508 
3509  x0 = x1;
3510  y0 = y1;
3511  i = next_out +1;
3512  }
3513 
3514  /* hold after last max */
3515  for (int i =last_out+1; i < N; i++ )
3516  out[i] = out[last_out];
3517 
3518 
3519  return out;
3520 
3521 }
void rotate(TGraph *g, int rot)
Definition: FFTtools.cxx:2627
double getDt(const TGraph *g, int realN=0)
Definition: FFTtools.cxx:2734
TGraph * getNormalisedCorrelationGraphTimeDomain(const TGraph *gr1, const TGraph *gr2, Int_t *zeroOffset=0, Int_t useDtRange=0, Double_t dtMin=-1000, Double_t dtMax=1000)
Returns the normalised correlation of two TGraphs.
Definition: FFTtools.cxx:627
struct __attribute__((packed))
Debugging use only TURF scaler data.
Double_t getPeakVal(const TGraph *gr, int *index=0)
Find the peak (maximum positive) in a TGraph.
Definition: FFTtools.cxx:1510
DirectConvolveEdgeBehavior
Definition: FFTtools.h:693
Double_t getPeakSqVal(const TGraph *gr, int *index=0)
Find the peak (v^2) in a TGraph.
Definition: FFTtools.cxx:1550
TGraph * combineGraphsUsingFFTs(Int_t numGraphs, TGraph **grPtr, const double *theWeights=0)
Returns the time domain result of a frequency domain sum of a number of TGraphs. In the sum each TGra...
Definition: FFTtools.cxx:570
double im
The imaginary part.
Definition: FFTWComplex.h:18
TGraph * multipleSimpleNotchFilters(const TGraph *grWave, Int_t numNotches, const Double_t minFreq[], const Double_t maxFreq[])
This returns a TGraph which has had N simple notch band filters applied.
Definition: FFTtools.cxx:2038
Double_t integratePower(const TGraph *gr, Int_t firstBin=-1, Int_t lastBin=-1)
The integral of the power in a TGraph (normally a PSD) (i.e the sum of bin content*bin width) ...
Definition: FFTtools.cxx:1406
TGraph * makePowerSpectrumPeriodogram(const TGraph *grWave)
Returns the power spectral density. Note the PSD returned is the periodogram (or if you prefer is nor...
Definition: FFTtools.cxx:1070
TGraph * makePowerSpectrumMilliVoltsNanoSeconds(const TGraph *grWave)
Returns the power spectral density in dB units. Note the PSD returned is normalised and divided by fr...
Definition: FFTtools.cxx:1147
TGraph * makePowerSpectrumVoltsSecondsPaddeddB(const TGraph *grWave, Int_t padFactor=4)
Returns the power spectral density in dB units of the input waveform zero-padded by some factor...
Definition: FFTtools.cxx:1346
Double_t welchWindow(Int_t j, Int_t n)
The Welch window function similar to the Bartlett window except that it falls off from the middle as ...
Definition: FFTtools.cxx:27
Double_t getWaveformSNR(const TGraph *gr)
This returns the SNR ratio of the input waveform.
Definition: FFTtools.cxx:2081
void doInvFFTClobber(int length, FFTWComplex *properly_aligned_input_that_will_likely_be_clobbered, double *properly_aligned_output)
Definition: FFTtools.cxx:408
TGraph * smoothFFT(const TGraph *gr, Int_t factor)
Returns a smoothed FFT where N-bins are averaged to reduce variance.
Definition: FFTtools.cxx:1715
TGraph * getHilbertEnvelope(const TGraph *grWave)
The Hilbert envelope of the input TGraph. This is defined as e_i=sqrt(v_i^2 + h_i^2), where e_i, v_i and h_i are the i-th sample of the envelope, input graph and hilbert transform of the input graph repsectively.
Definition: FFTtools.cxx:964
double randomRayleigh(double sigma=1, TRandom *rng=0)
Definition: FFTtools.cxx:2792
double * FFTCorrelation(int waveformlength, const FFTWComplex *A, const FFTWComplex *B, FFTWComplex *work=0, int min_i=0, int max_i=0, int order=1)
Definition: FFTtools.cxx:2641
FFTWComplex * doFFT(int length, const double *theInput)
Computes an FFT of an array of real numbers.
Definition: FFTtools.cxx:436
TGraph * divideGraphs(const TGraph *grA, const TGraph *grB)
Returns the ratio between two graphs (A/B).
Definition: FFTtools.cxx:1632
STL namespace.
TGraph * correlateAndAverage(Int_t numGraphs, TGraph **grPtrPtr)
This is designed for when you want to average a number of graphs of the same thing together...
Definition: FFTtools.cxx:2461
TGraph * cropWave(const TGraph *grWave, Double_t minTime, Double_t maxTime)
This returns a TGraph which has been cropped in.
Definition: FFTtools.cxx:2012
TGraph * getDerviative(const TGraph *grIn)
This returns a TGraph which is the derivative of the input graph.
Definition: FFTtools.cxx:1917
double * rmsEnvelope(int N, double W, const double *x, const double *y, double *out=0)
TGraph * padWaveToLength(const TGraph *grA, Int_t newLength)
Zero pad a wave making it up to newLength points.
Definition: FFTtools.cxx:1769
This is a wrapper class for an RF Signal.
Definition: RFSignal.h:12
TGraph * simpleNotchFilter(const TGraph *grWave, Double_t minFreq, Double_t maxFreq)
This returns a TGraph which has had a simple notch band filter applied.
Definition: FFTtools.cxx:1975
TGraph * subtractGraphs(const TGraph *grA, const TGraph *grB)
Returns the difference between two graphs (A-B).
Definition: FFTtools.cxx:1599
double * doInvFFT(int length, const FFTWComplex *theInput)
Computes an inverse FFT.
Definition: FFTtools.cxx:482
double * directConvolve(int N, const double *x, int M, const double *h, double *y=0, int delay=0, DirectConvolveEdgeBehavior edge_behavior=ZEROES_OUTSIDE)
Definition: FFTtools.cxx:2757
void polySubtract(TGraph *g, int order=1)
Definition: FFTtools.cxx:2745
double sinc(double x, double eps=0)
Definition: FFTtools.cxx:2609
Double_t sumPower(const TGraph *gr, Int_t firstBin=-1, Int_t lastBin=-1)
The linear sum of the power in a TGraph (normally a PSD)
Definition: FFTtools.cxx:1393
double * getCorrelation(const TGraph *gr1, const TGraph *gr2, int firstIndex, int lastIndex)
Computes the correlation of two subsets of TGraphs.
Definition: FFTtools.cxx:902
TGraph * makePowerSpectrumVoltsSecondsPadded(const TGraph *grWave, Int_t padFactor=4)
Returns the power spectral density of the input waveform zero-padded by some factor. Note the PSD returned is normalised and divided by frequency bin width (or if you prefer it is normalised to the time-integral squared amplitude of the time domain and then divided by frequency bin width). See this short note for my terminology. As the name suggests this function expects the input waveform to be a volts-seconds one.
Definition: FFTtools.cxx:1336
void inPlaceShift(int N, double *x)
Definition: FFTtools.cxx:2721
TGraph * convertMagnitudeToTimeDomain(const TGraph *inputMag)
Converts inputMag (linear units) to time domain by means of hilbert transform assuming R_signal = 1/s...
Definition: FFTtools.cxx:2256
void doInvFFTNoClobber(int length, const FFTWComplex *properly_aligned_input, double *properly_aligned_output)
Definition: FFTtools.cxx:372
TGraph * getInterpolatedGraph(const TGraph *grIn, Double_t deltaT)
Interpolation Routines that use ROOT::Math::Interpolator.
Definition: FFTtools.cxx:32
double getAbs(FFTWComplex &theNum)
Returns the magnitude of a complex number.
Definition: FFTtools.cxx:1388
TGraph * translateGraph(const TGraph *grWave, const Double_t deltaT)
Returns a graph translated by deltaT. Such that t&#39;=t+dt.
Definition: FFTtools.cxx:1619
TGraph * getNormalisedCorrelationGraph(const TGraph *gr1, const TGraph *gr2, Int_t *zeroOffset=0)
Returns the normalised correlation of two TGraphs.
Definition: FFTtools.cxx:709
void dftAtFreq(const TGraph *g, double freq, double *phase, double *amp=0, double *real=0, double *imag=0)
Definition: FFTtools.cxx:3206
TGraph * ratioSubtractOneGraphs(const TGraph *grA, const TGraph *grB)
Returns the one minus the ratio between two graphs (A/B).
Definition: FFTtools.cxx:1652
TGraph * getSimplePowerEnvelopeGraph(const TGraph *gr)
Returns the simple power envelope of a waveform. The waveform is first squared and then only local pe...
Definition: FFTtools.cxx:1817
This is a wrapper class for a complex number.
Definition: FFTWComplex.h:12
TGraph * getInterpolatedCorrelationGraph(const TGraph *grIn1, const TGraph *grIn2, Double_t deltaT)
Returns the correlation of two interpolated TGraphs.
Definition: FFTtools.cxx:838
void getPeakRmsRectified(const TGraph *gr, Double_t &peak, Double_t &rms, Int_t *index=0)
Find the peak (v) and RMS (of v) of a rectified TGraph.
Definition: FFTtools.cxx:1586
Double_t getWaveformPeak(const TGraph *gr)
This returns the largest (i.e most positive, or least negative) value.
Definition: FFTtools.cxx:2176
TGraph * interpolateCorrelateAndAverage(Double_t deltaTInt, Int_t numGraphs, TGraph **grPtrPtr)
This is designed for when you want to average a number of graphs of the same thing together...
Definition: FFTtools.cxx:2447
Double_t simpleInterploate(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x)
Linear interpolate to find the value at some point near two known points.
Definition: FFTtools.cxx:2304
TGraph * makePowerSpectrumVoltsSeconds(const TGraph *grWave)
Returns the power spectral density. Note the PSD returned is normalised and divided by frequency bin ...
Definition: FFTtools.cxx:1106
double checkCausality(int N, const FFTWComplex *signal)
Definition: FFTtools.cxx:3372
double * peakEnvelope(int N, double min_distance, const double *x, const double *y, double *out=0)
TGraph * makePowerSpectrumVoltsSecondsBartlett(const TGraph *grWave)
Returns the power spectral density of the input waveform convolved with a Bartlett Window...
Definition: FFTtools.cxx:1017
Double_t * combineValuesUsingFFTs(Int_t numArrays, Double_t **thePtrPtr, Int_t eachLength)
Returns the time domain result of a frequency domain sum of a number of arrays. As of writing this do...
Definition: FFTtools.cxx:538
TGraph * rectifyWave(const TGraph *gr, Int_t makeNeg=0)
Rectify a waveform, optionally returning an all negative waveform.
Definition: FFTtools.cxx:1799
TGraph * makeFixedDelay(const TGraph *g, double delay=1)
Definition: FFTtools.cxx:3341
TGraph * getCorrelationGraph(const TGraph *gr1, const TGraph *gr2, Int_t *zeroOffset=0)
Returns the correlation of two TGraphs.
Definition: FFTtools.cxx:754
void dftAtFreqAndMultiples(const TGraph *g, double freq, int nmultiples, double *phase, double *amp=0, double *real=0, double *imag=0)
Definition: FFTtools.cxx:3034
void getPeakRmsSqVal(const TGraph *gr, Double_t &peak, Double_t &rms, Int_t *index=0)
Find the peak (v^2) and RMS (of v^2) in a TGraph.
Definition: FFTtools.cxx:1570
TGraph * getInterpolatedGraphFreqDom(const TGraph *grIn, Double_t deltaT)
Interpolation Routines that zeropads the FFT.
Definition: FFTtools.cxx:84
double re
Destructor.
Definition: FFTWComplex.h:15
Inelasticity distributions: stores parametrizations and picks inelasticities.
Definition: Primaries.h:38
TGraph * makePowerSpectrum(const TGraph *grWave)
Returns the power spectral density. Note the PSD is unormalised (or if you prefer is normalised to th...
Definition: FFTtools.cxx:1031
TGraph * makeRawPowerSpectrum(const TGraph *grWave)
Returns the power spectral density in completely unormalised unit (as in Parseval&#39;s theorem is not ob...
Definition: FFTtools.cxx:1354
void applyWindow(TGraph *g, const FFTWindowType *w)
Definition: FFTtools.cxx:2713
TGraph * getBoxCar(const TGraph *grWave, Int_t halfWidth)
Smooth graph using box car smoothing.
Definition: FFTtools.cxx:984
Int_t getPeakBin(const TGraph *gr)
Find the peak (maximum positive) bin in a TGraph.
Definition: FFTtools.cxx:1456
TGraph * makePowerSpectrumVoltsSecondsdB(const TGraph *grWave)
Returns the power spectral density in dB units. Note the PSD returned is normalised and divided by fr...
Definition: FFTtools.cxx:1286
int fast_floor(double val)
Definition: FFTtools.h:721
void wrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2851
TGraph * correlateAndAveragePredeterminedZone(Int_t numGraphs, TGraph **grPtrPtr, Int_t *correlationBinPtr, Int_t binWiggleRoom)
Definition: FFTtools.cxx:2535
TGraph * makeInverseInverseSpectrum(const TGraph *grWave)
Returns the inverse FFT of the FFT of the input TGraph. Seems pointless.
Definition: FFTtools.cxx:919
TGraph * makePSVSBartlettPaddedOverlap(const TGraph *grWave, Int_t padFactor=4, Int_t numFreqs=64)
Returns the power spectral density of the input waveform. In this one we first zero pad the waveform ...
Definition: FFTtools.cxx:1856
void unwrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2857
TGraph * simplePassBandFilter(const TGraph *grWave, Double_t minFreq, Double_t maxFreq)
This returns a TGraph which has had a simple pass band filter applied.
Definition: FFTtools.cxx:1938
TGraph * getDerivative(const TGraph *grIn)
This returns a TGraph which is the derivative of the input graph.
Definition: FFTtools.cxx:1922
TGraph * getConvolution(const TGraph *grA, const TGraph *grB)
Convolution.
Definition: FFTtools.cxx:2309
double evalEvenGraph(const TGraph *g, double x)
Definition: FFTtools.cxx:2881
Double_t bartlettWindow(Int_t j, Int_t n)
The Bartlett window function (it&#39;s basically a triangle that peaks in the middle at 1 and goes to zer...
Definition: FFTtools.cxx:21
TGraph * padWave(const TGraph *grA, Int_t padFactor)
Zero pad a wave making it a factor of N longer.
Definition: FFTtools.cxx:1745
Double_t integrateVoltageSquared(const TGraph *gr, Int_t firstBin=-1, Int_t lastBin=-1)
The integral of the v^2*dt in a waveform. Now works for unevenly sampled waeforms.
Definition: FFTtools.cxx:1436
FFTWComplex * makeMinimumPhase(int N, const double *G, double mindb=-100)
Definition: FFTtools.cxx:3278
Double_t sumVoltageSquared(const TGraph *gr, Int_t firstBin, Int_t lastBin)
The sum of the voltage squared in a waveform.
Definition: FFTtools.cxx:1423
Double_t getPeakXvalue(const TGraph *gr)
Find the x value associated with the peak (maximum positive) in a TGraph.
Definition: FFTtools.cxx:1473
TGraph * getHilbertTransform(const TGraph *grWave)
The Hilbert transform of the input TGraph.
Definition: FFTtools.cxx:951
void takeDerivative(Int_t numPoints, const Double_t *inputX, const Double_t *inputY, Double_t *outputX, Double_t *outputY)
This fucntions just calculates the simple bin by bin dv/dt derivative of the input data...
Definition: FFTtools.cxx:1905
TGraph * dbGraphs(const TGraph *grA, const TGraph *grB)
Returns the ratio of two graphs as 10 *log(A/B)
Definition: FFTtools.cxx:1682