15 auto fft_re_im = [&size](
double* orig,
double*& re,
double*& im) {
16 TVirtualFFT* fft = TVirtualFFT::FFT(1, &size,
"R2C ES");
19 fft->GetPointsComplex(re, im);
23 double* refirst =
new double[size];
24 double* imfirst =
new double[size];
25 double* resecond =
new double[size];
26 double* imsecond =
new double[size];
27 double* reres =
new double[size];
28 double* imres =
new double[size];
30 fft_re_im(first, refirst, imfirst);
31 fft_re_im(second, resecond, imsecond);
37 for (
int i = 0; i < size; i++) {
38 cofirst(refirst[i], imfirst[i]);
39 cosecond(resecond[i], imsecond[i]);
41 cores = cofirst * cosecond /
static_cast<double>(size);
43 reres[i] = cores.Re();
44 imres[i] = cores.Im();
49 TVirtualFFT* fft_back = TVirtualFFT::FFT(1, &size,
"C2R ES");
50 fft_back->SetPointsComplex(reres, imres);
51 fft_back->Transform();
52 fft_back->GetPoints(result);
54 delete[] imres;
delete[] reres;
delete[] refirst;
delete[] imfirst;
delete[] resecond;
delete[] imsecond;
80void Filters::Deconvolute(
double*& result,
double* first,
double* second,
int size,
double sigma,
double x0,
double bin_size) {
83 auto fft_re_im = [&size](
double* orig,
double*& re,
double*& im) {
84 TVirtualFFT* fft = TVirtualFFT::FFT(1, &size,
"R2C ES");
87 fft->GetPointsComplex(re, im);
91 double* refirst =
new double[size];
92 double* imfirst =
new double[size];
93 double* resecond =
new double[size];
94 double* imsecond =
new double[size];
95 double* regauss =
new double[size];
96 double* imgauss =
new double[size];
97 double* reres =
new double[size];
98 double* imres =
new double[size];
99 double* gauss =
new double[size];
101 fft_re_im(first, refirst, imfirst);
102 fft_re_im(second, resecond, imsecond);
104 for (
int i = 0; i < size; i++) {
105 gauss[i] = TMath::Gaus(
static_cast<double>(i) * bin_size, x0, sigma);
107 fft_re_im(gauss, regauss, imgauss);
115 for (
int i = 0; i < size; i++) {
116 cofirst(refirst[i], imfirst[i]);
117 cosecond(resecond[i], imsecond[i]);
118 if (sigma > 0.) cogauss(regauss[i], imgauss[i]);
119 else cogauss(1., 0.);
121 cores = cofirst * cogauss / cosecond /
static_cast<double>(size);
123 reres[i] = cores.Re();
124 imres[i] = cores.Im();
127 TVirtualFFT* fft_back = TVirtualFFT::FFT(1, &size,
"C2R ES");
128 fft_back->SetPointsComplex(reres, imres);
129 fft_back->Transform();
130 fft_back->GetPoints(result);
133 delete[] imres;
delete[] reres;
delete[] refirst;
delete[] imfirst;
134 delete[] resecond;
delete[] imsecond;
delete[] regauss;
delete[] imgauss;
delete[] gauss;
160void Filters::SmoothArray(
double*& ar,
int nbins,
double sigma,
string method,
double bin_size,
double sigma2) {
162 if (method ==
"Box" || method ==
"Mean" || method ==
"Average")
BoxFilter(ar, nbins,
static_cast<int>(sigma));
163 else if (method ==
"GausFFT")
GausFFTFilter(ar, nbins, sigma, bin_size);
164 else if (method ==
"Gaus")
GausFilter(ar, nbins, sigma, bin_size);
165 else if (method ==
"Bilateral")
BilateralFilter(ar, nbins, sigma, sigma2, bin_size);
166 else if (method ==
"Bilateral2")
Bilateral2Filter(ar, nbins, sigma, sigma2, .05, bin_size);
167 else if (method ==
"Median")
MedianFilter(ar, nbins,
static_cast<int>(sigma));
169 cout <<
"Smooth method " << method <<
" not known. Using default Gaus method." << endl;
186 SmoothArray(ar, nbins, sigma,
"GausFFT", bin_size);
189 SmoothArray(ar, nbins, sigma,
"Bilateral", bin_size, sigma2);
192 SmoothArray(ar, nbins, sigma,
"Bilateral2", bin_size, sigma2);
209 for (
int i = 0; i < nbins; i++) {
212 int start = max(0, i - sigma);
213 int end = min(i + sigma, nbins - 1);
215 for (
int k = start; k <= end; k++) {
220 ar[i] = mean /
static_cast<double>(nmean);
232 double* artmp =
new double[nbins];
233 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
236 int nbins_6sigma =
static_cast<int>(ceil(6. * sigma / bin_size));
237 if (nbins_6sigma % 2 == 0) nbins_6sigma++;
238 if (nbins_6sigma > 1) {
239 double gauss_offset = floor(
static_cast<double>(nbins_6sigma) / 2.) * bin_size;
240 double gauss[nbins_6sigma];
241 for (
int i = 0; i < nbins_6sigma; i++) {
242 gauss[i] = TMath::Gaus(
static_cast<double>(i) * bin_size, gauss_offset, sigma);
245 double res = 0, norm = 0;
246 for (
int i = 0; i < nbins; i++) {
248 int start = max(0, nbins_6sigma / 2 - i);
249 int end = min(nbins - i + nbins_6sigma / 2, nbins_6sigma);
251 for (
int j = start; j < end; j++) {
252 res += gauss[j] * artmp[i + j - nbins_6sigma / 2];
255 if (norm != 0.) ar[i] = res / norm;
268 double* gauss =
new double[nbins];
271 double five_sigma = 5 * sigma;
272 double denom1 = -2. * sigma * sigma;
273 double denom2 = sigma * 2.506628;
275 for (
int i = 0; i < nbins; i++) {
276 double position =
static_cast<double>(i) * bin_size;
277 if (position < five_sigma) gauss[i] = exp(pow((position - five_sigma), 2) / denom1) / denom2;
282 for (
int i = 0; i < nbins; i++) {
300 double* artmp =
new double[nbins];
301 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
303 int nbins_3sigma =
static_cast<int>(ceil(3 * sigma_x / bin_size));
305 for (
int i = 0; i < nbins; i++) {
306 double weighted_sum = 0.0;
307 double sum_of_weights = 0.0;
309 for (
int j = max(0, i - nbins_3sigma); j < min(nbins - 1, i + nbins_3sigma); j++) {
311 double spatial_dist = abs(i - j) * bin_size;
312 double intensity_dist = abs(artmp[i] - artmp[j]);
315 double w_x = exp(-0.5 * (spatial_dist * spatial_dist) / (sigma_x * sigma_x));
316 double w_y = exp(-0.5 * (intensity_dist * intensity_dist) / (sigma_y * sigma_y));
317 double weight = w_x * w_y;
319 weighted_sum += artmp[j] * weight;
320 sum_of_weights += weight;
323 if (sum_of_weights != 0.) ar[i] = weighted_sum / sum_of_weights;
340 double* artmp =
new double[nbins];
341 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
343 double denom = -2. * sigma_y * sigma_y;
344 int x_shift =
static_cast<int>(sigma_x / bin_size);
346 double weightedSum = 0.;
347 double sumOfWeights = 0.;
349 double slope[nbins - 1];
350 double slope_weight[nbins - 1];
351 for (
int i = 0; i < nbins - 1; i++) {
352 slope[i] = ar[i + 1] - ar[i];
353 slope_weight[i] = 1. / (1. + pow(.5 * slope[i] / sigma_slope, 2.));
356 for (
int i = 0; i < nbins; i++) {
359 int start = max(0, i - x_shift);
360 int end = min(i + x_shift, nbins - 1);
362 for (
int j = start; j <= end; j++) {
363 double diff = artmp[i] - artmp[j];
364 double weight = exp(pow(diff, 2) / denom);
365 if (j < nbins - 1) weight *= slope_weight[j];
366 weightedSum += weight * artmp[j];
367 sumOfWeights += weight;
369 if (sumOfWeights != 0) ar[i] = weightedSum / sumOfWeights;
379 double* artmp =
new double[nbins];
380 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
382 int half_window = window_size / 2;
384 for (
int i = 0; i < nbins; i++) {
385 double* window =
new double[window_size];
386 int window_index = 0;
388 for (
int j = i - half_window; j <= i + half_window; j++) {
389 if (j >= 0 && j < nbins) {
390 window[window_index] = artmp[j];
396 sort(window, window + window_index);
397 double median = (window_index % 2 == 0) ?
398 (window[window_index / 2 - 1] + window[window_index / 2]) / 2. :
399 window[window_index / 2];
423 double* artmp =
new double[nbins];
424 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
427 int nbins_23sigma =
static_cast<int>(ceil((2. * sigma1 + 3. * sigma2) / bin_size));
428 int nbins_3sigma =
static_cast<int>(ceil(3. * sigma2 / bin_size));
429 double sdog[nbins_23sigma];
431 double denom1 = 2. * sigma1 * sigma1;
432 double denom2 = 2. * sigma2 * sigma2;
434 for (
int i = 0; i < nbins_23sigma; i++) {
435 sdog[i] = exp(-1. * pow(
static_cast<double>(i) * bin_size - 3. * sigma2, 2.) / denom1) -
436 factor * exp(-1. * pow(
static_cast<double>(i) * bin_size - 2. * sigma2, 2.) / denom2);
437 if (sdog[i] > 0.) norm += sdog[i];
439 if (norm == 0.) norm = 1.;
441 for (
int i = 0; i < nbins; i++) {
443 for (
int j = -1 * nbins_3sigma; j < nbins_23sigma - nbins_3sigma; j++) {
444 if (i + j >= 0 && i + j < nbins) res += sdog[j + nbins_3sigma] * artmp[i + j];
445 else if (i + j < 0) res += sdog[j + nbins_3sigma] * artmp[0];
446 else res += sdog[j + nbins_3sigma] * artmp[nbins - 1];
468 double* artmp =
new double[nbins];
469 for (
int i = 0; i < nbins; i++) artmp[i] = ar[i];
471 int shift_n =
static_cast<int>(ceil(shift / bin_size));
472 int nbins_response = shift_n +
static_cast<int>(3. * period / bin_size);
474 if (nbins_response > nbins) {
475 cout <<
"ERROR: nbins_response > nbins. Reduce shift or period." << endl;
476 nbins_response = nbins - 1;
479 cout <<
"ERROR: damping <= 0. Setting to 1 ns" << endl;
483 if (nbins_response % 2 == 0) nbins_response++;
484 double souf[nbins_response];
486 double exp_factor = -1. / damping;
487 double omega = 2. * M_PI / period;
488 double sum_norm = 0.;
489 for (
int i = 0; i < nbins_response; i++) {
490 double position =
static_cast<double>(i) * bin_size;
492 if (i < shift_n) souf[i] = 0.;
494 souf[i] = exp(exp_factor * (position - shift)) * sin(omega * (position - shift));
498 if (sum_norm == 0.) sum_norm = 1.;
500 for (
int i = 0; i < nbins; i++) {
502 for (
int j = max(0, nbins_response / 2 - i); j < min(nbins_response, nbins + nbins_response / 2 - i); j++) {
503 res += souf[nbins_response - j - 1] * artmp[i + j - nbins_response / 2];
505 ar[i] = res / sum_norm;
510 double x[nbins_response];
511 double x_full[nbins];
512 for (
int i = 0; i < nbins; i++) {
513 x_full[i] =
static_cast<double>(i) * bin_size;
514 if (i < nbins_response) x[i] =
static_cast<double>(i) * bin_size;
517 TCanvas* c_response =
new TCanvas(
"response",
"response", 800, 600);
518 TGraph* g_original =
new TGraph(nbins, x_full, artmp);
519 g_original->SetTitle(
"original");
520 g_original->SetMarkerStyle(34);
521 g_original->Draw(
"AP");
523 TGraph* g_response =
new TGraph(nbins_response, x, souf);
524 g_response->SetTitle(
"response");
525 g_response->SetLineColor(kBlue);
526 g_response->SetLineWidth(5);
527 g_response->SetLineStyle(7);
528 g_response->Draw(
"L same");
530 TGraph* g_result =
new TGraph(nbins, x_full, ar);
531 g_result->SetTitle(
"result");
532 g_result->SetLineColor(kRed);
533 g_result->SetLineWidth(3);
534 g_result->Draw(
"L same");
536 g_response->Scale(TMath::MaxElement(nbins, ar) / TMath::MaxElement(nbins_response, souf));
537 c_response->Update(); c_response->Modified();
538 gPad->BuildLegend(.5, .7, .9, .9);
539 c_response->SaveAs(
"response.png");
550 for (
int i = 1; i <= his->GetNbinsX(); i++) his->SetBinContent(i, yvals[i - 1]);
static void Deconvolute(double *&, double *, double *, int, double, double=0., double=0.)
Helper to perform partial deconvolution of two 1D arrays.
static void BilateralFilter(double *&, int, double, double, double)
Bilateral filter (non-linear) with 3 sigma kernel.
static void MedianFilter(double *&ar, int, int)
Median filter.
static void ResponseFilter(double *&, int, double=.4, double=1.2, double=.25, double=.3125)
Custom filter emulating primitive response function.
static void BoxFilter(double *&, int, int)
Simple running average (box) filter.
static void GausFFTFilter(double *&, int, double, double)
Gaussian smoothing with FFT convolution.
static void SecondOrderUnderdampedFilter(double *&, int, double, double, double, double=.3125, bool=false)
Shifted second order underdamped filter.
static void Convolute(double *&, double *, double *, int)
Helper to perform convolution of two 1D arrays.
static void GausFilter(double *&, int, double, double)
Gaussian smoothing with simple 3 sigma kernel.
static void Bilateral2Filter(double *&, int, int, double, double, double)
Nonlinear filter based on bilateral filter.
static void SmoothArray(double *&, int, double=.625, string="Gaus", double=.3125, double=1.5)
Apply smoothing array of double with length nbins.
static double * gety(TH1F *)
Get array of y values for a histogram.