#include "TCanvas.h" #include "TMath.h" #include "TH1.h" #include "TF1.h" #include "TRandom.h" #include "TSpectrum.h" #include "TVirtualFitter.h" // // Comment out the line below, if you want "peaks' heights". // Uncomment the line below, if you want "peaks' areas". // // #define __PEAKS_C_FIT_AREAS__ 1 /* fit peaks' areas */ Int_t npeaks = 30; Double_t fpeaks(Double_t *x, Double_t *par) { Double_t result = par[0] + par[1] * x[0]; for (Int_t p = 0; p < npeaks; p++) { Double_t norm = par[3 * p + 2]; // "height" or "area" Double_t mean = par[3 * p + 3]; Double_t sigma = par[3 * p + 4]; #if defined(__PEAKS_C_FIT_AREAS__) norm /= sigma * (TMath::Sqrt(TMath::TwoPi())); // "area" #endif /* defined(__PEAKS_C_FIT_AREAS__) */ result += norm * TMath::Gaus(x[0], mean, sigma); } return result; } void peaks(Int_t np = 10) { npeaks = TMath::Abs(np); TH1F *h = new TH1F("h", "test", 500, 0, 1000); // Generate n peaks at random Double_t par[3000]; par[0] = 0.8; par[1] = -0.6 / 1000; Int_t p; for (p = 0; p < npeaks; p++) { par[3 * p + 2] = 1; // "height" par[3 * p + 3] = 10 + gRandom->Rndm() * 980; // "mean" par[3 * p + 4] = 3 + 2 * gRandom->Rndm(); // "sigma" #if defined(__PEAKS_C_FIT_AREAS__) par[3 * p + 2] *= par[3 * p + 4] * (TMath::Sqrt(TMath::TwoPi())); // "area" #endif /* defined(__PEAKS_C_FIT_AREAS__) */ } TF1 *f = new TF1("f", fpeaks, 0, 1000, 2 + 3 * npeaks); f->SetNpx(1000); f->SetParameters(par); TCanvas *c1 = new TCanvas("c1", "c1", 10, 10, 1000, 900); c1->Divide(1, 2); c1->cd(1); h->FillRandom("f", 200000); h->Draw(); TH1F *h2 = (TH1F *)h->Clone("h2"); // Use TSpectrum to find the peak candidates TSpectrum *s = new TSpectrum(2 * npeaks); Int_t nfound = s->Search(h, 2, "", 0.10); printf("Found %d candidate peaks to fit\n", nfound); // Estimate background using TSpectrum::Background TH1 *hb = s->Background(h, 20, "same"); if (hb) c1->Update(); if (np < 0) return; // estimate linear background using a fitting method c1->cd(2); TF1 *fline = new TF1("fline", "pol1", 0, 1000); h->Fit("fline", "qn"); // Loop on all found peaks. Eliminate peaks at the background level par[0] = fline->GetParameter(0); par[1] = fline->GetParameter(1); npeaks = 0; Double_t *xpeaks; xpeaks = s->GetPositionX(); for (p = 0; p < nfound; p++) { Double_t xp = xpeaks[p]; Int_t bin = h->GetXaxis()->FindBin(xp); Double_t yp = h->GetBinContent(bin); if (yp - TMath::Sqrt(yp) < fline->Eval(xp)) continue; par[3 * npeaks + 2] = yp; // "height" par[3 * npeaks + 3] = xp; // "mean" par[3 * npeaks + 4] = 3; // "sigma" #if defined(__PEAKS_C_FIT_AREAS__) par[3 * npeaks + 2] *= par[3 * npeaks + 4] * (TMath::Sqrt(TMath::TwoPi())); // "area" #endif /* defined(__PEAKS_C_FIT_AREAS__) */ npeaks++; } printf("Found %d useful peaks to fit\n", npeaks); printf("Now fitting: Be patient\n"); TF1 *fit = new TF1("fit", fpeaks, 0, 1000, 2 + 3 * npeaks); // We may have more than the default 25 parameters TVirtualFitter::Fitter(h2, 10 + 3 * npeaks); fit->SetParameters(par); fit->SetNpx(1000); h2->Fit("fit"); }