wavecatcher-analysis
Loading...
Searching...
No Matches
Filters.cc
Go to the documentation of this file.
1#include "Filters.h"
2
12void Filters::Convolute(double*& result, double* first, double* second, int size) {
13
14 // FFT real -> im
15 auto fft_re_im = [&size](double* orig, double*& re, double*& im) {
16 TVirtualFFT* fft = TVirtualFFT::FFT(1, &size, "R2C ES");
17 fft->SetPoints(orig);
18 fft->Transform();
19 fft->GetPointsComplex(re, im);
20 delete fft;
21 };
22
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];
29
30 fft_re_im(first, refirst, imfirst);
31 fft_re_im(second, resecond, imsecond);
32
33 TComplex cofirst;
34 TComplex cosecond;
35 TComplex cores;
36
37 for (int i = 0; i < size; i++) {
38 cofirst(refirst[i], imfirst[i]);
39 cosecond(resecond[i], imsecond[i]);
40
41 cores = cofirst * cosecond / static_cast<double>(size);
42
43 reres[i] = cores.Re();
44 imres[i] = cores.Im();
45 }
46
47
48 //cout << "performing IFFT ... ";
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);
53 delete fft_back;
54 delete[] imres; delete[] reres; delete[] refirst; delete[] imfirst; delete[] resecond; delete[] imsecond;
55}
56
65void Filters::Convolute(double*& first, double* second, int size) {
66 Convolute(first, first, second, size);
67}
68
80void Filters::Deconvolute(double*& result, double* first, double* second, int size, double sigma, double x0, double bin_size) {
81
82 // FFT real -> im
83 auto fft_re_im = [&size](double* orig, double*& re, double*& im) {
84 TVirtualFFT* fft = TVirtualFFT::FFT(1, &size, "R2C ES");
85 fft->SetPoints(orig);
86 fft->Transform();
87 fft->GetPointsComplex(re, im);
88 delete fft;
89 };
90
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];
100
101 fft_re_im(first, refirst, imfirst);
102 fft_re_im(second, resecond, imsecond);
103 if (sigma > 0.) {
104 for (int i = 0; i < size; i++) {
105 gauss[i] = TMath::Gaus(static_cast<double>(i) * bin_size, x0, sigma);
106 }
107 fft_re_im(gauss, regauss, imgauss);
108 }
109
110 TComplex cofirst;
111 TComplex cosecond;
112 TComplex cogauss;
113 TComplex cores;
114
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.);
120
121 cores = cofirst * cogauss / cosecond / static_cast<double>(size);
122
123 reres[i] = cores.Re();
124 imres[i] = cores.Im();
125 }
126
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);
131 delete fft_back;
132
133 delete[] imres; delete[] reres; delete[] refirst; delete[] imfirst;
134 delete[] resecond; delete[] imsecond; delete[] regauss; delete[] imgauss; delete[] gauss;
135}
136
160void Filters::SmoothArray(double*& ar, int nbins, double sigma, string method, double bin_size, double sigma2) {
161
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));
168 else {
169 cout << "Smooth method " << method << " not known. Using default Gaus method." << endl;
170 GausFilter(ar, nbins, sigma, bin_size);
171 }
172}
174
179void Filters::SmoothArray(double*& ar, int nbins, double sigma, int method, double bin_size, double sigma2) {
180
181 switch (method) {
182 case 0:
183 SmoothArray(ar, nbins, sigma, "Box");
184 break;
185 case 1:
186 SmoothArray(ar, nbins, sigma, "GausFFT", bin_size);
187 break;
188 case 3:
189 SmoothArray(ar, nbins, sigma, "Bilateral", bin_size, sigma2);
190 break;
191 case 4:
192 SmoothArray(ar, nbins, sigma, "Bilateral2", bin_size, sigma2);
193 break;
194 case 5:
195 SmoothArray(ar, nbins, sigma, "Median");
196 break;
197 default:
198 SmoothArray(ar, nbins, sigma, "Gaus", bin_size);
199 break;
200 }
201}
202
207void Filters::BoxFilter(double*& ar, int nbins, int sigma) {
208 // calculate running average from -sigma until +sigma (sigma = number of bins)
209 for (int i = 0; i < nbins; i++) {
210 double mean = 0.;
211 int nmean = 0;
212 int start = max(0, i - sigma);
213 int end = min(i + sigma, nbins - 1);
214
215 for (int k = start; k <= end; k++) {
216 mean += ar[k];
217 nmean++;
218 }
219 if (nmean != 0) {
220 ar[i] = mean / static_cast<double>(nmean);
221 }
222 }
223}
224
230void Filters::GausFilter(double*& ar, int nbins, double sigma, double bin_size) {
231 // gauss kernel 3*sigma
232 double* artmp = new double[nbins];
233 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
234
235 // calculate running average from -sigma until +sigma (sigma = number of bins)
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);
243 }
244
245 double res = 0, norm = 0;
246 for (int i = 0; i < nbins; i++) {
247 res = 0., norm = 0.;
248 int start = max(0, nbins_6sigma / 2 - i);
249 int end = min(nbins - i + nbins_6sigma / 2, nbins_6sigma);
250
251 for (int j = start; j < end; j++) {
252 res += gauss[j] * artmp[i + j - nbins_6sigma / 2];
253 norm += gauss[j];
254 }
255 if (norm != 0.) ar[i] = res / norm;
256 }
257 }
258 delete[] artmp;
259}
260
266void Filters::GausFFTFilter(double*& ar, int nbins, double sigma, double bin_size) {
267 // convolution with gauss clipped at +-5 sigma (very inefficient and slow)
268 double* gauss = new double[nbins];
269
270 double sum = 0.;
271 double five_sigma = 5 * sigma;
272 double denom1 = -2. * sigma * sigma;
273 double denom2 = sigma * 2.506628;
274
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;
278 else gauss[i] = 0.;
279 sum += gauss[i];
280 }
281
282 for (int i = 0; i < nbins; i++) {
283 gauss[i] /= sum;
284 }
285
286 Convolute(ar, gauss, nbins);
287 delete[] gauss;
288}
289
299void Filters::BilateralFilter(double*& ar, int nbins, double sigma_x, double sigma_y, double bin_size) {
300 double* artmp = new double[nbins];
301 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
302
303 int nbins_3sigma = static_cast<int>(ceil(3 * sigma_x / bin_size));
304
305 for (int i = 0; i < nbins; i++) {
306 double weighted_sum = 0.0;
307 double sum_of_weights = 0.0;
308
309 for (int j = max(0, i - nbins_3sigma); j < min(nbins - 1, i + nbins_3sigma); j++) {
310 // Calculate spatial and intensity distances
311 double spatial_dist = abs(i - j) * bin_size;
312 double intensity_dist = abs(artmp[i] - artmp[j]);
313
314 // weights
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;
318
319 weighted_sum += artmp[j] * weight;
320 sum_of_weights += weight;
321 }
322
323 if (sum_of_weights != 0.) ar[i] = weighted_sum / sum_of_weights;
324 }
325 delete[] artmp;
326}
327
338void Filters::Bilateral2Filter(double*& ar, int nbins, int sigma_x, double sigma_y, double sigma_slope, double bin_size) {
339 // Asymmetric smoothing using a gauss of the change of the data relative to the central bin in a window for weighting
340 double* artmp = new double[nbins];
341 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
342
343 double denom = -2. * sigma_y * sigma_y;
344 int x_shift = static_cast<int>(sigma_x / bin_size);
345
346 double weightedSum = 0.;
347 double sumOfWeights = 0.;
348
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.));
354 }
355
356 for (int i = 0; i < nbins; i++) {
357 weightedSum = 0.;
358 sumOfWeights = 0.;
359 int start = max(0, i - x_shift);
360 int end = min(i + x_shift, nbins - 1);
361
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;
368 }
369 if (sumOfWeights != 0) ar[i] = weightedSum / sumOfWeights;
370 }
371 delete[] artmp;
372}
373
378void Filters::MedianFilter(double*& ar, int nbins, int window_size) {
379 double* artmp = new double[nbins];
380 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
381
382 int half_window = window_size / 2;
383
384 for (int i = 0; i < nbins; i++) {
385 double* window = new double[window_size];
386 int window_index = 0;
387
388 for (int j = i - half_window; j <= i + half_window; j++) {
389 if (j >= 0 && j < nbins) {
390 window[window_index] = artmp[j];
391 window_index++;
392 }
393 }
394
395 // calculate the median
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];
400
401 ar[i] = median;
402
403 delete[] window;
404 }
405 delete[] artmp;
406}
407
421void Filters::ResponseFilter(double*& ar, int nbins, double sigma1, double sigma2, double factor, double bin_size) {
422
423 double* artmp = new double[nbins];
424 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
425
426 // shifted difference of two gauss functions (~smoothed derivative)
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];
430
431 double denom1 = 2. * sigma1 * sigma1;
432 double denom2 = 2. * sigma2 * sigma2;
433 double norm = 0.;
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];
438 }
439 if (norm == 0.) norm = 1.;
440
441 for (int i = 0; i < nbins; i++) {
442 double res = 0.;
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];
447 }
448 ar[i] = res / norm;
449 }
450 delete[] artmp;
451}
452
466void Filters::SecondOrderUnderdampedFilter(double*& ar, int nbins, double period, double damping, double shift, double bin_size, bool do_plot) {
467
468 double* artmp = new double[nbins];
469 for (int i = 0; i < nbins; i++) artmp[i] = ar[i];
470
471 int shift_n = static_cast<int>(ceil(shift / bin_size));
472 int nbins_response = shift_n + static_cast<int>(3. * period / bin_size);
473
474 if (nbins_response > nbins) {
475 cout << "ERROR: nbins_response > nbins. Reduce shift or period." << endl;
476 nbins_response = nbins - 1;
477 }
478 if (damping <= 0) {
479 cout << "ERROR: damping <= 0. Setting to 1 ns" << endl;
480 damping = 1;
481 }
482
483 if (nbins_response % 2 == 0) nbins_response++;
484 double souf[nbins_response];
485
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;
491
492 if (i < shift_n) souf[i] = 0.;
493 else {
494 souf[i] = exp(exp_factor * (position - shift)) * sin(omega * (position - shift));
495 sum_norm += souf[i];
496 }
497 }
498 if (sum_norm == 0.) sum_norm = 1.;
499
500 for (int i = 0; i < nbins; i++) {
501 double res = 0.;
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];
504 }
505 ar[i] = res / sum_norm;
506 }
507
508 // plot the results
509 if (do_plot) {
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;
515 }
516
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");
522
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");
529
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");
535
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");
540 }
541 delete[] artmp;
542}
543
547void Filters::SecondOrderUnderdampedFilter(TH1F*& his, int nbins, double period, double damping, double shift, double bin_size, bool do_plot) {
548 double* yvals = Helpers::gety(his);
549 SecondOrderUnderdampedFilter(yvals, nbins, period, damping, shift, bin_size, do_plot);
550 for (int i = 1; i <= his->GetNbinsX(); i++) his->SetBinContent(i, yvals[i - 1]);
551 delete[] yvals;
552}
static void Deconvolute(double *&, double *, double *, int, double, double=0., double=0.)
Helper to perform partial deconvolution of two 1D arrays.
Definition Filters.cc:80
static void BilateralFilter(double *&, int, double, double, double)
Bilateral filter (non-linear) with 3 sigma kernel.
Definition Filters.cc:299
static void MedianFilter(double *&ar, int, int)
Median filter.
Definition Filters.cc:378
static void ResponseFilter(double *&, int, double=.4, double=1.2, double=.25, double=.3125)
Custom filter emulating primitive response function.
Definition Filters.cc:421
static void BoxFilter(double *&, int, int)
Simple running average (box) filter.
Definition Filters.cc:207
static void GausFFTFilter(double *&, int, double, double)
Gaussian smoothing with FFT convolution.
Definition Filters.cc:266
static void SecondOrderUnderdampedFilter(double *&, int, double, double, double, double=.3125, bool=false)
Shifted second order underdamped filter.
Definition Filters.cc:466
static void Convolute(double *&, double *, double *, int)
Helper to perform convolution of two 1D arrays.
Definition Filters.cc:12
static void GausFilter(double *&, int, double, double)
Gaussian smoothing with simple 3 sigma kernel.
Definition Filters.cc:230
static void Bilateral2Filter(double *&, int, int, double, double, double)
Nonlinear filter based on bilateral filter.
Definition Filters.cc:338
static void SmoothArray(double *&, int, double=.625, string="Gaus", double=.3125, double=1.5)
Apply smoothing array of double with length nbins.
Definition Filters.cc:160
static double * gety(TH1F *)
Get array of y values for a histogram.
Definition Helpers.cc:125