void FFT() { //This tutorial illustrates the Fast Fourier Transforms interface in ROOT. //FFT transform types provided in ROOT: // - "C2CFORWARD" - a complex input/output discrete Fourier transform (DFT) // in one or more dimensions, -1 in the exponent // - "C2CBACKWARD"- a complex input/output discrete Fourier transform (DFT) // in one or more dimensions, +1 in the exponent // - "R2C" - a real-input/complex-output discrete Fourier transform (DFT) // in one or more dimensions, // - "C2R" - inverse transforms to "R2C", taking complex input // (storing the non-redundant half of a logically Hermitian array) // to real output // - "R2HC" - a real-input DFT with output in ¡Èhalfcomplex¡É format, // i.e. real and imaginary parts for a transform of size n stored as // r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1 // - "HC2R" - computes the reverse of FFTW_R2HC, above // - "DHT" - computes a discrete Hartley transform // Sine/cosine transforms: // DCT-I (REDFT00 in FFTW3 notation) // DCT-II (REDFT10 in FFTW3 notation) // DCT-III(REDFT01 in FFTW3 notation) // DCT-IV (REDFT11 in FFTW3 notation) // DST-I (RODFT00 in FFTW3 notation) // DST-II (RODFT10 in FFTW3 notation) // DST-III(RODFT01 in FFTW3 notation) // DST-IV (RODFT11 in FFTW3 notation) //First part of the tutorial shows how to transform the histograms //Second part shows how to transform the data arrays directly //Authors: Anna Kreshuk and Jens Hoffmann //********* Histograms ********// //prepare the canvas for drawing TCanvas *myc = new TCanvas("myc", "Fast Fourier Transform", 800, 600); myc->SetFillColor(45); TPad *c1_1 = new TPad("c1_1", "c1_1",0.01,0.67,0.49,0.99); TPad *c1_2 = new TPad("c1_2", "c1_2",0.51,0.67,0.99,0.99); TPad *c1_3 = new TPad("c1_3", "c1_3",0.01,0.34,0.49,0.65); TPad *c1_4 = new TPad("c1_4", "c1_4",0.51,0.34,0.99,0.65); TPad *c1_5 = new TPad("c1_5", "c1_5",0.01,0.01,0.49,0.32); TPad *c1_6 = new TPad("c1_6", "c1_6",0.51,0.01,0.99,0.32); c1_1->Draw(); c1_2->Draw(); c1_3->Draw(); c1_4->Draw(); c1_5->Draw(); c1_6->Draw(); c1_1->SetFillColor(30); c1_1->SetFrameFillColor(42); c1_2->SetFillColor(30); c1_2->SetFrameFillColor(42); c1_3->SetFillColor(30); c1_3->SetFrameFillColor(42); c1_4->SetFillColor(30); c1_4->SetFrameFillColor(42); c1_5->SetFillColor(30); c1_5->SetFrameFillColor(42); c1_6->SetFillColor(30); c1_6->SetFrameFillColor(42); c1_1->cd(); TH1::AddDirectory(kFALSE); //A function to sample TF1 *fsin = new TF1("fsin", "sin(x)*sin(x)/(x*x)", 0, 4*TMath::Pi()); fsin->Draw(); Int_t n=25; TH1D *hsin = new TH1D("hsin", "hsin", n+1, 0, 4*TMath::Pi()); Double_t x; //Fill the histogram with function values for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); hsin->SetBinContent(i+1, fsin->Eval(x)); } hsin->Draw("same"); fsin->GetXaxis()->SetLabelSize(0.05); fsin->GetYaxis()->SetLabelSize(0.05); c1_2->cd(); //Compute the transform and look at the magnitude of the output TH1 *hm =0; TVirtualFFT::SetTransform(0); hm = hsin->FFT(hm, "MAG"); hm->SetTitle("Magnitude of the 1st transform"); hm->Draw(); //NOTE: for "real" frequencies you have to divide the x-axes range with the range of your function //(in this case 4*Pi); y-axes has to be rescaled by a factor of 1/SQRT(n) to be right: this is not done automatically! hm->SetStats(kFALSE); hm->GetXaxis()->SetLabelSize(0.05); hm->GetYaxis()->SetLabelSize(0.05); c1_3->cd(); //Look at the phase of the output TH1 *hp = 0; hp = hsin->FFT(hp, "PH"); hp->SetTitle("Phase of the 1st transform"); hp->Draw(); hp->SetStats(kFALSE); hp->GetXaxis()->SetLabelSize(0.05); hp->GetYaxis()->SetLabelSize(0.05); //Look at the DC component and the Nyquist harmonic: Double_t re, im; //That's the way to get the current transform object: TVirtualFFT *fft = TVirtualFFT::GetCurrentTransform(); c1_4->cd(); //Use the following method to get just one point of the output fft->GetPointComplex(0, re, im); printf("1st transform: DC component: %f\n", re); fft->GetPointComplex(n/2+1, re, im); printf("1st transform: Nyquist harmonic: %f\n", re); //Use the following method to get the full output: Double_t *re_full = new Double_t[n]; Double_t *im_full = new Double_t[n]; fft->GetPointsComplex(re_full,im_full); //Now let's make a backward transform: TVirtualFFT *fft_back = TVirtualFFT::FFT(1, &n, "C2R M K"); fft_back->SetPointsComplex(re_full,im_full); fft_back->Transform(); TH1 *hb = 0; //Let's look at the output hb = TH1::TransformHisto(fft_back,hb,"Re"); hb->SetTitle("The backward transform result"); hb->Draw(); //NOTE: here you get at the x-axes number of bins and not real values //(in this case 25 bins has to be rescaled to a range between 0 and 4*Pi; //also here the y-axes has to be rescaled (factor 1/bins) hb->SetStats(kFALSE); hb->GetXaxis()->SetLabelSize(0.05); hb->GetYaxis()->SetLabelSize(0.05); delete fft_back; fft_back=0; //********* Data array - same transform ********// //Allocate an array big enough to hold the transform output //Transform output in 1d contains, for a transform of size N, //N/2+1 complex numbers, i.e. 2*(N/2+1) real numbers //our transform is of size n+1, because the histogram has n+1 bins Double_t *in = new Double_t[2*((n+1)/2+1)]; Double_t re_2,im_2; for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fsin->Eval(x); } //Make our own TVirtualFFT object (using option "K") //Third parameter (option) consists of 3 parts: //-transform type: // real input/complex output in our case //-transform flag: // the amount of time spent in planning // the transform (see TVirtualFFT class description) //-to create a new TVirtualFFT object (option "K") or use the global (default) Int_t n_size = n+1; TVirtualFFT *fft_own = TVirtualFFT::FFT(1, &n_size, "R2C ES K"); if (!fft_own) return; fft_own->SetPoints(in); fft_own->Transform(); //Copy all the output points: fft_own->GetPoints(in); //Draw the real part of the output c1_5->cd(); TH1 *hr = 0; hr = TH1::TransformHisto(fft_own, hr, "RE"); hr->SetTitle("Real part of the 3rd (array) tranfsorm"); hr->Draw(); hr->SetStats(kFALSE); hr->GetXaxis()->SetLabelSize(0.05); hr->GetYaxis()->SetLabelSize(0.05); c1_6->cd(); TH1 *him = 0; him = TH1::TransformHisto(fft_own, him, "IM"); him->SetTitle("Im. part of the 3rd (array) transform"); him->Draw(); him->SetStats(kFALSE); him->GetXaxis()->SetLabelSize(0.05); him->GetYaxis()->SetLabelSize(0.05); myc->cd(); //Now let's make another transform of the same size //The same transform object can be used, as the size and the type of the transform //haven't changed TF1 *fcos = new TF1("fcos", "cos(x)+cos(0.5*x)+cos(2*x)+1", 0, 4*TMath::Pi()); for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fcos->Eval(x); } fft_own->SetPoints(in); fft_own->Transform(); fft_own->GetPointComplex(0, re_2, im_2); printf("2nd transform: DC component: %f\n", re_2); fft_own->GetPointComplex(n/2+1, re_2, im_2); printf("2nd transform: Nyquist harmonic: %f\n", re_2); delete fft_own; delete [] in; delete [] re_full; delete [] im_full; }
// DOFF do fit fft 1=fit 2=fft+fit // fit cointains: baselineshift; fft; // void ro_readwav(char* fname , int start=0, int stop=0, int DOFF=0,char *OPT="WWN0Q", char *clerun="run"){ FILE *f; int i,j=0; Short_t ssample[10]; UShort_t buffer[2200]; // usually 600 //============ OPEN FILE========== READ 1st word f=fopen( fname , "r" ); fread( ssample, sizeof(Short_t), 1 , f ); printf("i ... sample size = %d ... one integer is %d bytes\n", ssample[0] , sizeof(Short_t) ); // read the rest =================== 1st sample fread( buffer, sizeof(Short_t), ssample[0]-1, f ); for (i=0;i<ssample[0];i++){buffer[i]=0;} // clean buffer printf("%s\n", "buffer clean"); //----------------- DECLARATIONS #2 TH1F *hch[8]; // channel histograms: 0-7 FW for (i=0;i<8;i++){hch[i]=NULL;} TH1F *hchf[8]; // chan fit for (i=0;i<8;i++){hchf[i]=NULL;} TH1F *htime[8]; // I cannot Fill time histo !? for (i=0;i<8;i++){htime[i]=NULL;} TH2F* bidim[8]; // slope vs ene for (i=0;i<8;i++){bidim[i]=NULL;} // TH2F* ede=new TH2F("ede","E x dE matrix",400,0,8000,400,0,8000); TH1F *h; // WAVE HISTOGRAM ============ MAIN HISTOGRAM char hname[20]; // histo channels int result; int sizeOfStr=16; // SIZE OF struct with b,ch,t,E // ---- structure data: Short_t b,ch, evnt, ene ; // board channel energy unsigned long long time=0; // tets differences unsigned long long timelast=0; Short_t extr; float avg=0.0; // fit parameters: double* pars; //==============================FILE TTREE ================ struct Tdata{ ULong64_t t; //l time Int_t n; // i event number Int_t ch; // i channel Int_t e; //i energy Float_t efit; //F energy from fit Float_t xi; //F Xi2 from fit Float_t s; //F s - slope from fit //-------------------COINCIDENCES from NOW ----------- Int_t e0; // COINC CASE E0 Int_t e1; // COINC CASE E0 Int_t dt; //I +- Int_t efit0; Int_t efit1; Int_t s0; Int_t s1; } event; char outname[300]; // OUT = infile.root char wc[100];int wci=0; // sprintf(outname,"%s_%06d_%06d.root", fname , start, stop ); sprintf(outname,"%s_%06d_%06d.root" , clerun, start, stop ); TFile *fo=new TFile( outname ,"recreate"); TTree *to=new TTree("pha","dpp_pha_data"); to->Branch("time",&event.t,"t/l"); to->Branch("data",&event.n,"n/i:ch/i:e/i:efit/F:xi/F:s/F"); to->Branch("coin",&event.e0,"e0/i:e1/i:dt/I:efit0/I:efit1/I:s0/I:s1/I"); MyCoinc *mc=new MyCoinc(0,1); // guard channels 0 + 1 // // // //##################################### LOOP ##################### int JMIN=start; int JMAX=stop; if (stop==0){JMAX=999999999;} // JMAX=111; // limit for test for (j=0;j<=JMAX;j++){ event.n=j; event.e=0; event.efit=0; event.xi=0; event.s=0; event.efit0=0; event.efit1=0; event.s0=0; event.s1=0; // ch t result=fread( buffer,sizeof(Short_t) , sizeOfStr, f ); if (result<sizeOfStr) break; //---------------- FW header decode b=buffer[0]; ch=buffer[1]; evnt=buffer[2]; //[8]-[11] ... time //--------------- Time decode time=0; time=buffer[11]; time=time<<16; time=time+buffer[10]; time=time<<16; time=time+buffer[9]; time=time<<16; time=time+buffer[8]; timelast=time; ene=buffer[12]; extr=buffer[13]; // printf( "ch/evnt/ene %3d %3d %3d E=%3d %3d\n", ch, evnt, ene, extr ); // printf("%lld ======= %3d \n", time, ene); event.t=time; event.e=ene; event.ch=ch; //================ FILL ENERGY HISTO if (hch[ ch ]==NULL){ sprintf(hname,"hifw_%02d", ch); hch[ ch ]= new TH1F( hname,hname,16000,0,16000); } // printf("%s\n", "J loop hifw ok"); hch[ch]->Fill( ene ); //================ FILL TIME HISTO if (htime[ch]==NULL){ sprintf(hname,"hitime_%02d", ch); // htime[ch]= new TH1F( hname,"timeprofile;[seconds]",1000000,0,100); int seconds=1000; htime[ch]= new TH1F( hname,"hname",seconds*100,0,seconds); printf("defined %d. htime\n",ch); } htime[ch]->Fill( float(time/100000000.) ); if (j%1000==0){printf( "j=%d ...\n", j );} // if ( j>= start){ //=======PARALLEL LOOP=============== //===============================================LOAD WAVEFORM result = fread( buffer,sizeof(Short_t) , ssample[0], f ); if (result< ssample[0]) break; // ============ FIT / ANALYZE ================ int makefit=0; if ((j>=start)&&(j<stop) ){ makefit=1;} if (DOFF==0){ makefit=0;} //no reason, but ok if (makefit==1){ //====CREATE HISTOGRAM wave ==>>> VARIANT:create/analyze/root it/delete // if (j-start<100){ sprintf(hname,"wave_%06d", j); // here I keep the channel h=new TH1F( hname,hname, ssample[0],0,ssample[0] ); // }// create only when #<100; then REUSE "h" //====== prepare ZERO (one analyze parameter now) avg=0.0; for (i=0;i<50;i++){avg=avg+buffer[i];} avg=avg/(50.); // HISTOGRAM IS FILLED HERE: // ### ======= Fill SHIFTED buffer TO ZERO histogram for (i=0;i<ssample[0];i++){ // i add ch 0/1 to the end! h->SetBinContent( i+1, buffer[i] - avg ); // 0-1 is #1 } // ### FFT HERE // if (DOFF==2){ //====================++FFT BEGIN ============= int n=ssample[0]; TH1 *hmsm =0; TH1 *hpsm =0; hmsm=h->FFT(hmsm,"MAG"); hpsm=h->FFT(hpsm,"PH"); TVirtualFFT *fft = TVirtualFFT::GetCurrentTransform(); Double_t *re_full = new Double_t[ssample[0]]; Double_t *im_full = new Double_t[ssample[0]]; fft->GetPointsComplex(re_full,im_full); for (int j=0;j<ssample[0]/2; j++){ hmsm->SetBinContent( j, re_full[j] ); hpsm->SetBinContent( j, im_full[j] ); } // for (int j=16;j>11;j--){ hmsm->Smooth(2); hpsm->Smooth(2); for (int j=16;j>5;j--){ hmsm->SetBinContent( j, 0.8*re_full[j] ); hpsm->SetBinContent( j, 0.8*im_full[j] ); } hmsm->Smooth(2); hpsm->Smooth(2); for (int j=0;j<ssample[0]/2;j++){ re_full[j]=hmsm->GetBinContent(j); im_full[j]=hpsm->GetBinContent(j); } TVirtualFFT *fft_back = TVirtualFFT::FFT(1, &n, "C2R M K"); fft_back->SetPointsComplex(re_full,im_full); fft_back->Transform(); TH1 *hb = 0; hb = TH1::TransformHisto(fft_back,hb,"Re"); double mx= mx=hb->GetMaximum(); double omax= h->GetMaximum(); hb->Scale( omax/mx ); delete fft_back; delete [] re_full; delete [] im_full; if (gPad!=NULL){ h->Draw(); hb->Draw("same");hb->SetLineColor(3); gPad->Modified(); gPad->Update(); } for (int j=0;j<ssample[0];j++){ h->SetBinContent( j, hb->GetBinContent(j) ); } delete hb; delete hmsm; delete hpsm; // sleep(1); // h->Draw(); gPad->Modified(); gPad->Update(); }// ========================================= FFT HERE END // ### =========== fit 1 ========== pars=fit1( ssample[0], h , OPT ); // FIT 400 points in a sample printf("%06d/ %6.1f %5.2f %5.2f \n", j, pars[0], pars[1] ,pars[2] ); if ( bidim[ch]==NULL ){ sprintf(hname,"bishape_%02d", ch); bidim[ch]=new TH2F( hname,"shapes;Energy;slope in channels", 2500,0,2500,450,2,45); } bidim[ch]->Fill( pars[0], pars[1] ); // sleep(1); //##### DEBUG HERE"..................... // # pars[1]===S // # pars[0]==E // if ( (ch==0)&&(pars[0]>960.) ){ /* if ( (ch==0)&&(pars[1]>100.) ){ printf("S problem @ %d chan %d S=%f\n",j,ch, pars[1]); sleep(5); } */ //================ FILL ENERGY FIT HISTO if (hchf[ ch ]==NULL){ sprintf(hname,"hifit_%02d", ch); hchf[ ch ]= new TH1F( hname,hname,16000,0,16000); } hchf[ch]->Fill( pars[0] ); event.efit=pars[0]; event.s=10*pars[1]; event.xi=10*pars[2]; if ( strstr(OPT,"WWN0Q")!=NULL) { delete h; // printf("%s %s\n","...DELEING histogram ", OPT); }else{ h->Write(); printf("%s","...writing histogram to file\n"); } //write to tree if not N0Q } // fit ---------------------------------------------END-- // =========== FIT / ANALYZE ============= END =========== if ( event.efit>16000){ event.efit=0; event.s=0; event.xi=0; } event.e0=0; event.e1=0; event.dt=0; //=================COINCIDENCES ========== BEGIN ====== // and if result == 1 : coincidence was found.... if (1==mc->add( ch, event.t, event.e, event.efit, event.xi,event.s) ){ // event.efit event.e0=mc->getlastC0(); event.e1=mc->getlastC1(); event.efit0=mc->getlastC0fit(); event.efit1=mc->getlastC1fit(); event.s0=mc->getlastC0s(); event.s1=mc->getlastC1s(); event.dt=-mc->getlastDT(); if ( (event.dt>400)||(event.dt<-400)){ printf("%4d mc ============================\n", event.dt); } } //============================ COINCIDENCES END ===== if (makefit==1){ delete pars; } // no pars if no fit // if (h!=NULL){delete h;} // delete WAVE HISTOGRAM //==========SAVE TTREE====== // if (makefit==1){ to->Fill(); // } // } // ===========PARALLEL LOOP =========== } //------- j < JMAX ------=====================================END fclose(f); if (j>=JMAX){ // i dont create thousands of th1f anymore printf("!... limit in number of histograms reached....%d. STOP \n", j); }else{ printf("!... total number of histograms == %d \n", j); } if ( (gPad!=NULL)&&(bidim[0]!=NULL)){ bidim[0]->Draw("col"); } double dlt=(timelast/100/1000); printf("%7.3f s =last time\n", dlt/1000.); //====SAVE============================== for (ch=0;ch<8;ch++){ // printf("ch == %d\n", ch); if (hch[ch]!=NULL){ hch[ch]->Write();} if (htime[ch]!=NULL){ htime[ch]->Write();} if (bidim[ch]!=NULL){ bidim[ch]->Write();} } // ede->Write(); // ttree:===================== // mc->print(); TH2F* mcbi=(TH2F*) mc->getbidim(); // this is coincidences stored in [mc] TH2F* mcbifi=(TH2F*) mc->getfitbidim(); // this is fit coincidences stored in [mc] TH1F* mchidt=(TH1F*) mc->gethidt(); mcbi->Write(); mcbifi->Write(); mchidt->Write(); to->Print(); to->Write(); fo->Close(); } //######################################################## END ##############
void FFT() { // Histograms // ========= //prepare the canvas for drawing TCanvas *myc = new TCanvas("myc", "Fast Fourier Transform", 800, 600); myc->SetFillColor(45); TPad *c1_1 = new TPad("c1_1", "c1_1",0.01,0.67,0.49,0.99); TPad *c1_2 = new TPad("c1_2", "c1_2",0.51,0.67,0.99,0.99); TPad *c1_3 = new TPad("c1_3", "c1_3",0.01,0.34,0.49,0.65); TPad *c1_4 = new TPad("c1_4", "c1_4",0.51,0.34,0.99,0.65); TPad *c1_5 = new TPad("c1_5", "c1_5",0.01,0.01,0.49,0.32); TPad *c1_6 = new TPad("c1_6", "c1_6",0.51,0.01,0.99,0.32); c1_1->Draw(); c1_2->Draw(); c1_3->Draw(); c1_4->Draw(); c1_5->Draw(); c1_6->Draw(); c1_1->SetFillColor(30); c1_1->SetFrameFillColor(42); c1_2->SetFillColor(30); c1_2->SetFrameFillColor(42); c1_3->SetFillColor(30); c1_3->SetFrameFillColor(42); c1_4->SetFillColor(30); c1_4->SetFrameFillColor(42); c1_5->SetFillColor(30); c1_5->SetFrameFillColor(42); c1_6->SetFillColor(30); c1_6->SetFrameFillColor(42); c1_1->cd(); TH1::AddDirectory(kFALSE); //A function to sample TF1 *fsin = new TF1("fsin", "sin(x)+sin(2*x)+sin(0.5*x)+1", 0, 4*TMath::Pi()); fsin->Draw(); Int_t n=25; TH1D *hsin = new TH1D("hsin", "hsin", n+1, 0, 4*TMath::Pi()); Double_t x; //Fill the histogram with function values for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); hsin->SetBinContent(i+1, fsin->Eval(x)); } hsin->Draw("same"); fsin->GetXaxis()->SetLabelSize(0.05); fsin->GetYaxis()->SetLabelSize(0.05); c1_2->cd(); //Compute the transform and look at the magnitude of the output TH1 *hm =0; TVirtualFFT::SetTransform(0); hm = hsin->FFT(hm, "MAG"); hm->SetTitle("Magnitude of the 1st transform"); hm->Draw(); //NOTE: for "real" frequencies you have to divide the x-axes range with the range of your function //(in this case 4*Pi); y-axes has to be rescaled by a factor of 1/SQRT(n) to be right: this is not done automatically! hm->SetStats(kFALSE); hm->GetXaxis()->SetLabelSize(0.05); hm->GetYaxis()->SetLabelSize(0.05); c1_3->cd(); //Look at the phase of the output TH1 *hp = 0; hp = hsin->FFT(hp, "PH"); hp->SetTitle("Phase of the 1st transform"); hp->Draw(); hp->SetStats(kFALSE); hp->GetXaxis()->SetLabelSize(0.05); hp->GetYaxis()->SetLabelSize(0.05); //Look at the DC component and the Nyquist harmonic: Double_t re, im; //That's the way to get the current transform object: TVirtualFFT *fft = TVirtualFFT::GetCurrentTransform(); c1_4->cd(); //Use the following method to get just one point of the output fft->GetPointComplex(0, re, im); printf("1st transform: DC component: %f\n", re); fft->GetPointComplex(n/2+1, re, im); printf("1st transform: Nyquist harmonic: %f\n", re); //Use the following method to get the full output: Double_t *re_full = new Double_t[n]; Double_t *im_full = new Double_t[n]; fft->GetPointsComplex(re_full,im_full); //Now let's make a backward transform: TVirtualFFT *fft_back = TVirtualFFT::FFT(1, &n, "C2R M K"); fft_back->SetPointsComplex(re_full,im_full); fft_back->Transform(); TH1 *hb = 0; //Let's look at the output hb = TH1::TransformHisto(fft_back,hb,"Re"); hb->SetTitle("The backward transform result"); hb->Draw(); //NOTE: here you get at the x-axes number of bins and not real values //(in this case 25 bins has to be rescaled to a range between 0 and 4*Pi; //also here the y-axes has to be rescaled (factor 1/bins) hb->SetStats(kFALSE); hb->GetXaxis()->SetLabelSize(0.05); hb->GetYaxis()->SetLabelSize(0.05); delete fft_back; fft_back=0; // Data array - same transform // =========================== //Allocate an array big enough to hold the transform output //Transform output in 1d contains, for a transform of size N, //N/2+1 complex numbers, i.e. 2*(N/2+1) real numbers //our transform is of size n+1, because the histogram has n+1 bins Double_t *in = new Double_t[2*((n+1)/2+1)]; Double_t re_2,im_2; for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fsin->Eval(x); } //Make our own TVirtualFFT object (using option "K") //Third parameter (option) consists of 3 parts: //- transform type: // real input/complex output in our case //- transform flag: // the amount of time spent in planning // the transform (see TVirtualFFT class description) //- to create a new TVirtualFFT object (option "K") or use the global (default) Int_t n_size = n+1; TVirtualFFT *fft_own = TVirtualFFT::FFT(1, &n_size, "R2C ES K"); if (!fft_own) return; fft_own->SetPoints(in); fft_own->Transform(); //Copy all the output points: fft_own->GetPoints(in); //Draw the real part of the output c1_5->cd(); TH1 *hr = 0; hr = TH1::TransformHisto(fft_own, hr, "RE"); hr->SetTitle("Real part of the 3rd (array) tranfsorm"); hr->Draw(); hr->SetStats(kFALSE); hr->GetXaxis()->SetLabelSize(0.05); hr->GetYaxis()->SetLabelSize(0.05); c1_6->cd(); TH1 *him = 0; him = TH1::TransformHisto(fft_own, him, "IM"); him->SetTitle("Im. part of the 3rd (array) transform"); him->Draw(); him->SetStats(kFALSE); him->GetXaxis()->SetLabelSize(0.05); him->GetYaxis()->SetLabelSize(0.05); myc->cd(); //Now let's make another transform of the same size //The same transform object can be used, as the size and the type of the transform //haven't changed TF1 *fcos = new TF1("fcos", "cos(x)+cos(0.5*x)+cos(2*x)+1", 0, 4*TMath::Pi()); for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fcos->Eval(x); } fft_own->SetPoints(in); fft_own->Transform(); fft_own->GetPointComplex(0, re_2, im_2); printf("2nd transform: DC component: %f\n", re_2); fft_own->GetPointComplex(n/2+1, re_2, im_2); printf("2nd transform: Nyquist harmonic: %f\n", re_2); delete fft_own; delete [] in; delete [] re_full; delete [] im_full; }
void FFT() { //This tutorial illustrates the Fast Fourier Transforms interface in ROOT. //FFT transform types provided in ROOT: // - "C2CFORWARD" - a complex input/output discrete Fourier transform (DFT) // in one or more dimensions, -1 in the exponent // - "C2CBACKWARD"- a complex input/output discrete Fourier transform (DFT) // in one or more dimensions, +1 in the exponent // - "R2C" - a real-input/complex-output discrete Fourier transform (DFT) // in one or more dimensions, // - "C2R" - inverse transforms to "R2C", taking complex input // (storing the non-redundant half of a logically Hermitian array) // to real output // - "R2HC" - a real-input DFT with output in ¡Èhalfcomplex¡É format, // i.e. real and imaginary parts for a transform of size n stored as // r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1 // - "HC2R" - computes the reverse of FFTW_R2HC, above // - "DHT" - computes a discrete Hartley transform // Sine/cosine transforms: // DCT-I (REDFT00 in FFTW3 notation) // DCT-II (REDFT10 in FFTW3 notation) // DCT-III(REDFT01 in FFTW3 notation) // DCT-IV (REDFT11 in FFTW3 notation) // DST-I (RODFT00 in FFTW3 notation) // DST-II (RODFT10 in FFTW3 notation) // DST-III(RODFT01 in FFTW3 notation) // DST-IV (RODFT11 in FFTW3 notation) //First part of the tutorial shows how to transform the histograms //Second part shows how to transform the data arrays directly //Authors: Anna Kreshuk and Jens Hoffmann //********* Histograms ********// //prepare the canvas for drawing TCanvas *myc = new TCanvas("myc", "Fast Fourier Transform", 800, 600); myc->SetFillColor(45); TPad *c1_1 = new TPad("c1_1", "c1_1",0.01,0.67,0.49,0.99); TPad *c1_2 = new TPad("c1_2", "c1_2",0.51,0.67,0.99,0.99); TPad *c1_3 = new TPad("c1_3", "c1_3",0.01,0.34,0.49,0.65); TPad *c1_4 = new TPad("c1_4", "c1_4",0.51,0.34,0.99,0.65); TPad *c1_5 = new TPad("c1_5", "c1_5",0.01,0.01,0.49,0.32); TPad *c1_6 = new TPad("c1_6", "c1_6",0.51,0.01,0.99,0.32); c1_1->Draw(); c1_2->Draw(); c1_3->Draw(); c1_4->Draw(); c1_5->Draw(); c1_6->Draw(); c1_1->SetFillColor(30); c1_1->SetFrameFillColor(42); c1_2->SetFillColor(30); c1_2->SetFrameFillColor(42); c1_3->SetFillColor(30); c1_3->SetFrameFillColor(42); c1_4->SetFillColor(30); c1_4->SetFrameFillColor(42); c1_5->SetFillColor(30); c1_5->SetFrameFillColor(42); c1_6->SetFillColor(30); c1_6->SetFrameFillColor(42); c1_1->cd(); TH1::AddDirectory(kFALSE); //A function to sample TF1 *fsin = new TF1("fsin", "exp(-(x-679.)/40.0)*TMath::Erfc(-(1/sqrt(2))*((x-679.)/2.0 + 0.05))", 0, 1023); TF1 *model = new TF1("model", "[0]*exp(-(x-[1])/[2])*TMath::Erfc(-(1/sqrt(2))*((x-[1])/[3] + [3]/[2]))", 0, 1023); model->SetParameter( 0, 1. ); model->SetParameter( 1, 679. ); model->SetParameter( 2, 40. ); model->SetParameter( 3, 2. ); model->SetLineColor( kViolet ); TF1 *model2 = new TF1("model2", "[0]*exp(-(x-[1])/[2])*TMath::Erfc(-(1/sqrt(2))*((x-[1])/[3] + [3]/[2])) + [4]*sin(2*TMath::Pi()*[5]*x)", 0, 1023); model2->SetParameter( 0, 1. ); model2->SetParameter( 1, 679. ); model2->SetParameter( 2, 40. ); model2->SetParameter( 3, 2. ); model2->SetParameter( 4, 0.05 ); model2->SetParameter( 5, 2. ); model2->SetLineColor( kViolet ); //fsin->Draw(); Int_t n=1024; TH1D *hsin = new TH1D("hsin", "hsin", n+1, 0, 1023); Double_t x; //hsin->Fit( model,"MLR" ); //Fill the histogram with function values for (Int_t i=0; i<=n; i++){ /* if( i >= n/2 ) { x = (Double_t(i-(n/2+1))/n)*(160*TMath::Pi()); } else { x = -80*TMath::Pi()+(Double_t(i)/n)*(160*TMath::Pi()); } */ x = (Double_t(i)/n)*(1024); //std::cout << "n: " << i << " x: " << x << std::endl; hsin->SetBinContent(i+1, fsin->Eval(x)); } hsin->Fit( model2,"MLR" ); //TFile* fn = new TFile("/Users/cmorgoth/Software/git/TimingAna_New/CIT_Laser_022015_69_ana.root", "READ"); TFile* fn = new TFile("/Users/cmorgoth/Work/data/LaserDataAtCaltech/02282015/CIT_Laser_022015_69_ana.root", "READ"); TH1F* pulse = (TH1F*)fn->Get("CH2pulse"); //hsin->Draw("same"); hsin->SetLineColor(kGreen-4); hsin->Draw(); model->Draw("same"); //pulse->SetAxisRange(650, 780, "X"); pulse->Scale(22.0); pulse->Draw("same"); fsin->GetXaxis()->SetLabelSize(0.05); fsin->GetYaxis()->SetLabelSize(0.05); c1_2->cd(); //Compute the transform and look at the magnitude of the output TH1 *hm =0; TVirtualFFT::SetTransform(0); //hm = hsin->FFT(hm, "MAG"); hm = pulse->FFT(hm, "MAG"); hm->SetTitle("Magnitude of the 1st transform"); //hm->Draw(); double sf = 5e3;//to go from sample to picosecons and also from Hz to MHz double range = sf*(double)n/(1023.); int n_bin_fft = hm->GetNbinsX(); TH1F* hmr = new TH1F( "hmr" ,"Magnitude of the 1st transform Rescaled", n_bin_fft, 0, range); for( int i = 1; i <= n_bin_fft; i++) { double bc = hm->GetBinContent( i )/sqrt( n ); hmr->SetBinContent( i, bc ); } hmr->SetXTitle("f (MHz)"); hmr->Draw(); //Transfor to the theoretical function TH1 *hm2 =0; TVirtualFFT::SetTransform(0); hm2 = hsin->FFT(hm2, "MAG"); hm2->SetLineColor(2); //hm2->Draw("same"); TH1F* hmr2 = new TH1F( "hmr2" ,"Magnitude of the 1st transform Rescaled", n_bin_fft, 0, range); for( int i = 1; i <= n_bin_fft; i++) { double bc = hm2->GetBinContent( i )/sqrt( n ); hmr2->SetBinContent( i, bc ); } hmr2->SetLineColor( kRed ); hmr2->Draw("same"); //NOTE: for "real" frequencies you have to divide the x-axes range with the range of your function //(in this case 4*Pi); y-axes has to be rescaled by a factor of 1/SQRT(n) to be right: this is not done automatically! hm->SetStats(kFALSE); hm->GetXaxis()->SetLabelSize(0.05); hm->GetYaxis()->SetLabelSize(0.05); c1_3->cd(); //Look at the phase of the output TH1 *hp = 0; hp = hsin->FFT(hp, "PH"); hp->SetTitle("Phase of the 1st transform"); hp->Draw(); hp->SetStats(kFALSE); hp->GetXaxis()->SetLabelSize(0.05); hp->GetYaxis()->SetLabelSize(0.05); //Look at the DC component and the Nyquist harmonic: Double_t re, im; //That's the way to get the current transform object: TVirtualFFT *fft = TVirtualFFT::GetCurrentTransform(); c1_4->cd(); //Use the following method to get just one point of the output fft->GetPointComplex(0, re, im); printf("1st transform: DC component: %f\n", re); fft->GetPointComplex(n/2+1, re, im); printf("1st transform: Nyquist harmonic: %f\n", re); //Use the following method to get the full output: Double_t *re_full = new Double_t[n]; Double_t *im_full = new Double_t[n]; fft->GetPointsComplex(re_full,im_full); //Now let's make a backward transform: TVirtualFFT *fft_back = TVirtualFFT::FFT(1, &n, "C2R M K"); fft_back->SetPointsComplex(re_full,im_full); fft_back->Transform(); TH1 *hb = 0; //Let's look at the output hb = TH1::TransformHisto(fft_back,hb,"Re"); hb->SetTitle("The backward transform result"); hb->Draw(); //NOTE: here you get at the x-axes number of bins and not real values //(in this case 25 bins has to be rescaled to a range between 0 and 4*Pi; //also here the y-axes has to be rescaled (factor 1/bins) hb->SetStats(kFALSE); hb->GetXaxis()->SetLabelSize(0.05); hb->GetYaxis()->SetLabelSize(0.05); delete fft_back; fft_back=0; //********* Data array - same transform ********// //Allocate an array big enough to hold the transform output //Transform output in 1d contains, for a transform of size N, //N/2+1 complex numbers, i.e. 2*(N/2+1) real numbers //our transform is of size n+1, because the histogram has n+1 bins Double_t *in = new Double_t[2*((n+1)/2+1)]; Double_t re_2,im_2; for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fsin->Eval(x); } //Make our own TVirtualFFT object (using option "K") //Third parameter (option) consists of 3 parts: //-transform type: // real input/complex output in our case //-transform flag: // the amount of time spent in planning // the transform (see TVirtualFFT class description) //-to create a new TVirtualFFT object (option "K") or use the global (default) Int_t n_size = n+1; TVirtualFFT *fft_own = TVirtualFFT::FFT(1, &n_size, "R2C ES K"); if (!fft_own) return; fft_own->SetPoints(in); fft_own->Transform(); //Copy all the output points: fft_own->GetPoints(in); //Draw the real part of the output c1_5->cd(); TH1 *hr = 0; hr = TH1::TransformHisto(fft_own, hr, "RE"); hr->SetTitle("Real part of the 3rd (array) tranfsorm"); hr->Draw(); hr->SetStats(kFALSE); hr->GetXaxis()->SetLabelSize(0.05); hr->GetYaxis()->SetLabelSize(0.05); c1_6->cd(); TH1 *him = 0; him = TH1::TransformHisto(fft_own, him, "IM"); him->SetTitle("Im. part of the 3rd (array) transform"); him->Draw(); him->SetStats(kFALSE); him->GetXaxis()->SetLabelSize(0.05); him->GetYaxis()->SetLabelSize(0.05); myc->cd(); //Now let's make another transform of the same size //The same transform object can be used, as the size and the type of the transform //haven't changed TF1 *fcos = new TF1("fcos", "cos(x)+cos(0.5*x)+cos(2*x)+1", 0, 4*TMath::Pi()); for (Int_t i=0; i<=n; i++){ x = (Double_t(i)/n)*(4*TMath::Pi()); in[i] = fcos->Eval(x); } fft_own->SetPoints(in); fft_own->Transform(); fft_own->GetPointComplex(0, re_2, im_2); printf("2nd transform: DC component: %f\n", re_2); fft_own->GetPointComplex(n/2+1, re_2, im_2); printf("2nd transform: Nyquist harmonic: %f\n", re_2); delete fft_own; delete [] in; delete [] re_full; delete [] im_full; }