testFancyFFTs.cxx
1 /* -*- C++ -*-.***************************************************************************************************
2  Author: Ben Strutt
3  Email: b.strutt.12@ucl.ac.uk
4 
5  Description:
6  C++ ROOT friendly class to do FFTs faster than FFTtools, but is mostly a shameless copy.
7  Will probably be pretty bare bones intially as I only really want this for doing Cross Correlations.
8 *************************************************************************************************************** */
9 
10 #include "TMath.h"
11 #include "TApplication.h"
12 #include "TGraph.h"
13 #include "TCanvas.h"
14 #include "TSystem.h"
15 
16 #include <assert.h>
17 
18 #include "FancyFFTs.h"
19 #include "RootTools.h"
20 
21 double sum(int n, double* x){
22  double sum = 0;
23  for(int i=0; i<n; i++){
24  sum += x[i];
25  }
26  return sum;
27 }
28 
29 int main(int argc, char *argv[]){
30 
31  TApplication* theApp = new TApplication("App", &argc, argv);
32 
33  const int n = 256;
34  double omega1 = 0.7;
35  double omega2 = 1.8;
36 
37  double ts[n];
38  double dt = 0.1;
39  double phi = TMath::Pi()/2;
40  double sineWave1[n];
41  double sineWave2[n];
42 
43  for(int i=0; i<n; i++){
44  double t = dt*i;
45  ts[i] = t;
46  sineWave1[i] = 3.3*TMath::Sin(omega1*t + phi);
47  sineWave2[i] = 1.6*TMath::Sin(omega2*t);
48  }
49 
50  TGraph* gr1 = new TGraph(n, ts, sineWave1);
51  gr1->SetName("grSineWave");
52  gr1->SetTitle("A sine wave; t (s); Amplitude (V)");
53  TGraph* gr2 = new TGraph(n, ts, sineWave2);
54  gr2->SetLineColor(kRed);
55 
56  TCanvas* c1 = new TCanvas("c1", "Fancy FFT Frivolities", 1200, 1600);
57  c1->Divide(2, 2);
58  c1->cd(1);
59  gr1->Draw();
60  gr2->Draw("l same");
61 
62  double* fs = FancyFFTs::getFreqArray(n, dt);
63 
64  std::cout << "Before doing anything: ";
66 
67  double* ps1 = FancyFFTs::getPowerSpectrum(n, sineWave1, dt, FancyFFTs::kSum);
68  double* ps2 = FancyFFTs::getPowerSpectrum(n, sineWave2, dt, FancyFFTs::kSum);
69 
70  std::cout << "After makeing two power spectrums of length " << n<< ": ";
72 
73  TGraph* gr3 = new TGraph(FancyFFTs::getNumFreqs(n), fs, ps1);
74  TGraph* gr4 = new TGraph(FancyFFTs::getNumFreqs(n), fs, ps2);
75  delete [] ps1;
76  delete [] ps2;
77 
78  gr4->SetLineColor(kRed);
79  gr3->SetTitle("Power spectrum of a sine wave; Frequency (Hz); Power (V^{2})");
80  c1->cd(2);
81  gr3->Draw();
82  gr4->Draw("same");
83  gPad->SetLogy(1);
84 
85 
86 
87 
88 
89 
90 
91 
92 
93  /* Tests...*/
94  std::cout << std::endl << std::endl << std::endl;
95  std::cout << "Doing some tests of normalization a la Parsevals Theorem." << std::endl;
96  std::cout << "If the program doesn't creash unceremoniously then we're all good :)" << std::endl;
97 
98  /* Parsevals theroem (used to normalize) */
99  double powTime = 0;
100  for(int i=0; i<gr1->GetN(); i++){
101  powTime += gr1->GetY()[i]*gr1->GetY()[i];
102  }
103  std::cout << "powTime = " << powTime << std::endl;
104 
105  double powFreq = RootTools::getSumOfYVals(gr3);
106 
107  std::cout << "powFreq = " << powFreq << std::endl;
108  std::cout << "powFreq/powTime = " << powFreq/powTime << std::endl;
109  std::cout << "powFreq-powTime = " << powFreq-powTime << std::endl;
110  std::cout << std::endl << std::endl << std::endl;
111 
112  /* Hardcore test of parsevals theorem: kSum normalization. */
113  assert(TMath::Abs(powFreq-powTime) < 1e-10);
114 
115 
116 
117 
118 
119 
120  double* ps1_ave = FancyFFTs::getPowerSpectrum(n, sineWave1, dt, FancyFFTs::kAverage);
121  double powFreq_ave = sum(FancyFFTs::getNumFreqs(n), ps1_ave);
122  std::cout << "powFreq_ave = " << powFreq_ave << std::endl;
123  std::cout << "powFreq_ave/powTime_ave = " << powFreq_ave/(powTime/n) << std::endl;
124  std::cout << "powFreq_ave-powTime_ave = " << powFreq_ave-(powTime/n) << std::endl;
125  std::cout << std::endl << std::endl << std::endl;
126 
127  /* Hardcore test of parsevals theorem: kAverage normalization. */
128  assert(TMath::Abs(powFreq_ave-(powTime/n)) < 1e-10);
129 
130  delete [] ps1_ave;
131 
132 
133  double* ps1_timeIntegral = FancyFFTs::getPowerSpectrum(n, sineWave1, dt, FancyFFTs::kTimeIntegral);
134  double powFreq_timeIntegral = sum(FancyFFTs::getNumFreqs(n), ps1_timeIntegral);
135  std::cout << "powFreq_timeIntegral = " << powFreq_timeIntegral << std::endl;
136  std::cout << "powFreq_timeIntegral/powTime_ave = " << powFreq_timeIntegral/(dt*powTime) << std::endl;
137  std::cout << "powFreq_timeIntegral-powTime_ave = " << powFreq_timeIntegral-(dt*powTime) << std::endl;
138  std::cout << std::endl << std::endl << std::endl;
139 
140  /* Hardcore test of parsevals theorem: kTimeIntegral normalization. */
141  assert(TMath::Abs(powFreq_timeIntegral-(dt*powTime)) < 1e-10);
142 
143  delete [] ps1_timeIntegral;
144 
145 
146 
147 
148 
149 
150 
151 
152 
153  c1->cd(3);
154  std::complex<double>* testFFT = FancyFFTs::doFFT(gr1->GetN(), gr1->GetY(), true);
155  double* testInvFFT = FancyFFTs::doInvFFT(gr1->GetN(), testFFT, true);
156  TGraph* grTestInv = new TGraph(gr1->GetN(), ts, testInvFFT);
157  grTestInv->SetTitle("Test of inverse fourier transform; Time (s); Amplitude (V)");
158  grTestInv->Draw();
159  delete [] testFFT;
160  delete [] testInvFFT;
161 
162 
163 
164  std::cout << "Checking conversion between fftw_complex and std::complex<double>... " << std::endl;
165  std::cout << "sizeof(std::complex<double>) = " << sizeof(std::complex<double>) << std::endl;
166  std::cout << "sizeof(fftw_complex) = " << sizeof(fftw_complex) << std::endl;
167  std::cout << "sizeof(double) = " << sizeof(double) << std::endl;
168 
169  std::complex<double> x(1, 1);
170  std::cout << "std::complex<double> x(1, 1) = " << x << std::endl;
171  fftw_complex y;
172  std::cout << "Doing memcpy(&y, &x, sizeof(fftw_complex))... " << std::endl;
173  memcpy(&y, &x, sizeof(fftw_complex));
174  std::cout << "fftw_complex y has y[0] = " << y[0] << " and y[1] = " << y[1] << std::endl;
175  std::cout << std::endl << std::endl;
176 
177  std::cout << "Now copying array of fftw_complex to std::complex<double> with mempcy..." << std::endl;
178  fftw_complex y2[2];
179  y2[0][0] = 1;
180  y2[0][1] = 2;
181  y2[1][0] = 3;
182  y2[1][1] = 4;
183  std::cout << "y2[2] = {{" << y2[0][0] << ", " << y2[0][1] << "}, {" << y2[1][0] << ", " << y2[1][1] << "}}"
184  << std::endl;
185  std::complex<double> x2[2];
186  std::cout << "Doing memcpy(x2, y2, 2*sizeof(fftw_complex))" << std::endl;
187  memcpy(x2, y2, 2*sizeof(fftw_complex));
188  std::cout << "x[0] = " << x2[0] << ", x[1] = " << x2[1] << std::endl;
189  std::cout << std::endl << std::endl;
190 
191 
192 
193 
194  c1->cd(4);
195  TGraph* gr1norm = RootTools::makeNormalized(gr1);
196  TGraph* gr2norm = RootTools::makeNormalized(gr2);
197  double* crossCorr1 = FancyFFTs::crossCorrelate(gr1norm->GetN(), gr1norm->GetY(), gr1norm->GetY());
198  double* crossCorr2 = FancyFFTs::crossCorrelate(gr1norm->GetN(), gr1norm->GetY(), gr2norm->GetY());
199  TGraph* grCor1 = new TGraph(gr1->GetN(), ts, crossCorr1);
200  TGraph* grCor2 = new TGraph(gr1->GetN(), ts, crossCorr2);
201  grCor1->SetTitle("Cross correlation");
202  grCor1->Draw();
203  grCor2->SetLineColor(kRed);
204  grCor2->Draw("l same");
205  gPad->Update();
206 
207 
208 
209 
210 
211 
212 
213 
214 
215  /* Draw pretty things */
216 
217  c1->Update();
218  gSystem->ProcessEvents();
219  std::cerr << "Select File->Quit to quit." << std::endl;
220  theApp->Run();
221 
222  return 0;
223 }
double * getPowerSpectrum(int len, double *input, double dt, conventionFlag normFlag, int threadInd=0)
Creates the power spectrum in an array of doubles of length (len/2 + 1).
Definition: FancyFFTs.cxx:77
double * crossCorrelate(int len, double *v1, double *v2, int threadInd=0)
Cross correlates the two input arrays.
Definition: FancyFFTs.cxx:541
complex< double > * doFFT(int len, double *input, bool copyOutputToNewArray, int threadInd=0)
Does a forward fast fourier transform on a real input array.
Definition: FancyFFTs.cxx:212
int printListOfKeys()
Prints the list of keys of plans to stdout.
Definition: FancyFFTs.cxx:501
Double_t getSumOfYVals(TGraph *gr)
Adds up all y-axis values of input TGraph.
Definition: RootTools.cxx:14
double * getFreqArray(int len, double dt)
Get the array of frequencies to go with FFT output, determined by the tranform length and dt...
Definition: FancyFFTs.cxx:394
int getNumFreqs(int len)
Get the number of frequencies from the number of samples.
Definition: FancyFFTs.cxx:416
TGraph * makeNormalized(TGraph *gr)
Creates new TGraph (leaving original unchanged) with mean = 0 & RMS = 1.
Definition: RootTools.cxx:343
double * doInvFFT(int len, complex< double > *input, bool copyOutputToNewArray, int threadInd=0)
Does an inverse fast fourier transform on an array of complex<double>s.
Definition: FancyFFTs.cxx:288