Protodune.cxx
Go to the documentation of this file.
1 
2 /***************************************************************************/
3 /* Noise filter (NF) module for protoDUNE-SP */
4 /***************************************************************************/
5 /* features: */
6 /* - frequency-domain resampling (sticky code and FEMB time clock) */
7 /* - undershoot correction */
8 /* - partial undershoot correction */
9 /* - 50 kHz collection plane noise filter */
10 /* - ledge waveform identification (multiple ledges) */
11 
15 
17 
18 #include <cmath>
19 #include <complex>
20 #include <iostream>
21 #include <set>
22 
23 WIRECELL_FACTORY(pdStickyCodeMitig,
26 WIRECELL_FACTORY(pdOneChannelNoise,
27  WireCell::SigProc::Protodune::OneChannelNoise,
28  WireCell::IChannelFilter, WireCell::IConfigurable)
29 WIRECELL_FACTORY(pdRelGainCalib,
30  WireCell::SigProc::Protodune::RelGainCalib,
31  WireCell::IChannelFilter, WireCell::IConfigurable)
32 
33 using namespace WireCell::SigProc;
34 
35 int LedgeIdentify1(WireCell::Waveform::realseq_t& signal, double baseline, int LedgeStart[3], int LedgeEnd[3]){
36  // find a maximum of 3 ledges in one waveform
37  // the number of ledges is returned
38  // the start and end of ledge is stored in the array
39  int UNIT = 10;//5; // rebin unit
40  int CONTIN = 10;//20; // length of the continuous region
41  int JUMPS = 2;//4; // how many bins can accidental jump
42  // We recommend UNIT*CONTIN = 100, UNIT*JUMPS = 20
43  std::vector<int> averaged; // store the rebinned waveform
44  int up = signal.size()/UNIT;
45  int nticks = signal.size();
46  // rebin
47  for(int i=0;i<up;i++){
48  int temp = 0;
49  for(int j=0;j<UNIT;j++){
50  temp += signal.at(i*UNIT+j);
51  }
52  averaged.push_back(temp);
53  }
54  // relax the selection cuts if there is a large signal
55  auto imax = std::min_element(signal.begin(), signal.end());
56  double max_value = *imax;
57  if(max_value-baseline>1000) { CONTIN /=1.25; JUMPS *= 1.2; }
58  // start judging
59  int NumberOfLedge = 0 ; // to be returned
60  int StartOfLastLedgeCandidate = 0; // store the last ledge candidate
61  for(int LE = 0; LE < 3; LE++){ // find three ledges
62  if(LE>0 && StartOfLastLedgeCandidate == 0 ) break; // no ledge candidate in the last round search
63  if(StartOfLastLedgeCandidate>nticks-200) break;// the last candidate is too late in the window
64  if(NumberOfLedge>0 && (LedgeEnd[NumberOfLedge-1]+200)>nticks) break; // the end last ledge reaches the end of readout window
65  int ledge = 0;
66  int decreaseD = 0, tolerence=0;
67  int start = 0;// end = 0; // temporary start and end
68  int StartWindow = 0; // where to start
69  if(StartOfLastLedgeCandidate==0) {
70  StartWindow = 0;
71  }
72  else{
73  if(NumberOfLedge == 0) // no ledge found. start from 200 ticks after the last candidate
74  StartWindow = (StartOfLastLedgeCandidate+200)/UNIT;
75  else{
76  if(StartOfLastLedgeCandidate>LedgeEnd[NumberOfLedge-1]) // the last candidate is not a real ledge
77  // StartWindow = (StartOfLastLedgeCandidate+200)/UNIT;
78  StartWindow = (StartOfLastLedgeCandidate+50)/UNIT;
79  else // the last candidate is a real ledge
80  StartWindow = (LedgeEnd[NumberOfLedge-1]+30)/UNIT;
81  }
82  }
83  for(int i=StartWindow+1;i<up-1;i++){
84  if(averaged.at(i)<averaged.at(i-1)) {
85  if(decreaseD==0) start = i;
86  decreaseD +=1;
87  }
88  else {
89  if(averaged.at(i+1)<averaged.at(i-1)&&tolerence<JUMPS&&decreaseD>0){ // we can ignore several jumps in the decreasing region
90  decreaseD+=2;
91  tolerence++;
92  i = i+1;
93  }
94  else{
95  if(decreaseD>CONTIN){
96  ledge = 1;
97  StartOfLastLedgeCandidate = start*UNIT;
98  break;
99  }
100  else{
101  decreaseD = 0;
102  tolerence=0;
103  start = 0;
104  // end = 0;
105  }
106  }
107  }
108  }
109  // find the sharp start edge
110  // if(ledge == 1&&LedgeStart>30){
111  // int edge = 0;
112  // int i = LedgeStart/UNIT-1;
113  // if(averaged.at(i)>averaged.at(i-1)&&averaged.at(i-1)>averaged.at(i-2)){ // find a edge
114  // edge = 1;
115  // }
116  // if(edge == 0) ledge = 0; // if no edge, this is not ledge
117  // if((averaged.at(i)-averaged.at(i-2)<10*UNIT)&&(averaged.at(i)-averaged.at(i-3)<10*UNIT)) // slope cut
118  // ledge = 0;
119  // if(averaged.at(LedgeStart/UNIT)-baseline*UNIT>300*UNIT) ledge = 0; // ledge is close to the baseline
120  // }
121  // determine the end of ledge
122  // case 1: find a jump of 5 ADC in the rebinned waveform
123  // case 2: a continuous 20 ticks has an average close to baseline, and a RMS larger than 3 ADC
124  // case 3: reaching the tick 6000 but neither 1 nor 2 occurs
125  int tempLedgeEnd = 0;
126  if(ledge ==1){
127  for(int i = StartOfLastLedgeCandidate/UNIT; i<up-1; i++){ // case 1
128  if(averaged.at(i+1)-averaged.at(i)>5*UNIT) {
129  tempLedgeEnd = i*UNIT+5;
130  if(tempLedgeEnd>nticks) tempLedgeEnd = nticks-1;
131  break;
132  }
133  }
134 
135  if(tempLedgeEnd == 0) { // not find a jump, case 2
137  for(int i = StartOfLastLedgeCandidate+80;i<nticks-20;i+=20){
138  for(int j=i;j<20+i;j++){
139  tempA.at(j-i) = signal.at(j);
140  }
141  auto stat = WireCell::Waveform::mean_rms(tempA);
142  if(stat.first-baseline<2&&stat.second>3){
143  tempLedgeEnd = i;
144  break;
145  }
146  }
147  }
148  if(tempLedgeEnd == 0) tempLedgeEnd = nticks-1;
149  }
150  // test the decay time
151  // if(ledge == 1&&StartOfLastLedgeCandidate>20){
152  if(ledge==1){
153  double height = signal.at(StartOfLastLedgeCandidate+1)- signal.at(tempLedgeEnd);
154  if(height<0) ledge = 0; // not a ledge
155  if((tempLedgeEnd-StartOfLastLedgeCandidate) > 80){ // test the decay if the ledge length is longenough
156  double height50 = 0;
157  height50 = signal.at(StartOfLastLedgeCandidate+51);
158  double height50Pre = signal.at(StartOfLastLedgeCandidate+1)- height*(1-exp(-50/100.)); // minimum 100 ticks decay time
159  // if the measured is much smaller than the predicted, this is not ledge
160  if(height50-height50Pre<-12/*-8*/) ledge = 0;
161  // cout << "height50-height50Pre: " << height50-height50Pre << endl;
162  }
163  }
164 
165  // // // find the sharp start edge
166  // if(ledge == 1&&StartOfLastLedgeCandidate>30){
167  // // int edge = 0;
168  // // int i = StartOfLastLedgeCandidate/UNIT-1;
169  // // if(averaged.at(i)>averaged.at(i-1)&&averaged.at(i-1)>averaged.at(i-2)){ // find a edge
170  // // edge = 1;
171  // // }
172  // // if(edge == 0) ledge = 0; // if no edge, this is not ledge
173  // // if((averaged.at(i)-averaged.at(i-2)<10*UNIT)&&(averaged.at(i)-averaged.at(i-3)<10*UNIT)) // slope cut
174  // // ledge = 0;
175  // // if(averaged.at(StartOfLastLedgeCandidate/UNIT)-baseline*UNIT>150*UNIT) ledge = 0; // ledge is close to the baseline
176 
177  // // if(signal.at(tempLedgeEnd) - baseline > 100) ledge=0; // [wgu] ledge end is close to the baseline
178  // if(averaged.at(tempLedgeEnd/UNIT)-baseline*UNIT>5.*UNIT) ledge = 0;
179  // // cout << "averaged.at(StartOfLastLedgeCandidate/UNIT) - baseline*UNIT = " << averaged.at(StartOfLastLedgeCandidate/UNIT)-baseline*UNIT << std::endl;
180  // }
181 
182  if(ledge==1){ // ledge is close to the baseline
183  if(averaged.at(tempLedgeEnd/UNIT)-baseline*UNIT>5.*UNIT) ledge = 0;
184 
185  if(averaged.at(StartOfLastLedgeCandidate/UNIT)-baseline*UNIT>100*UNIT) ledge = 0;
186  }
187 
188  if(ledge==1 && StartOfLastLedgeCandidate>1000){ // ledge always follows a pulse
189  // std::cerr << "[wgu] ch: " << m_ch << " StartOfLastLedgeCandidate: " << StartOfLastLedgeCandidate << std::endl;
190  float hmax=0;
191  for(int i=StartOfLastLedgeCandidate-1000; i<StartOfLastLedgeCandidate-100; i++){
192  if(signal.at(i)>hmax) hmax= signal.at(i);
193  }
194  if(hmax-baseline<200) ledge=0; // no large pre-signal
195  // std::cerr << "[wgu] hmax: " << hmax << std::endl;
196  }
197 
198 
199  if(ledge == 1){
200  LedgeStart[NumberOfLedge] = std::max(StartOfLastLedgeCandidate-20, 0);
201  LedgeEnd[NumberOfLedge] = std::min(tempLedgeEnd+10, (int)signal.size()); // FIXME: ends at a threshold
202  NumberOfLedge++;
203  }
204  } // LE
205 
206  return NumberOfLedge;
207 
208 }
209 
210 
211 // adapted from WCP
212 // FIXME: some hardcoded 6000 ticks
213 bool LedgeIdentify(WireCell::Waveform::realseq_t& signal/*TH1F* h2*/, double baseline, int & LedgeStart, int & LedgeEnd){
214  int ledge = false;
215  int UNIT = 10;//5; // rebin unit
216  int CONTIN = 10;//20; // length of the continuous region
217  int JUMPS = 2;//4; // how many bins can accidental jump
218  std::vector<int> averaged; // store the rebinned waveform
219  int up = signal.size()/UNIT;// h2->GetNbinsX()/UNIT;
220  int nticks = signal.size();// h2->GetNbinsX();
221  // rebin
222  for(int i=0;i<up;i++){
223  int temp = 0;
224  for(int j=0;j<UNIT;j++){
225  temp += signal.at(i*UNIT+j); //h2->GetBinContent(i*UNIT+1+j);
226  }
227  averaged.push_back(temp);
228  }
229  // refine the selection cuts if there is a large signal
230  auto imax = std::min_element(signal.begin(), signal.end());
231  double max_value = *imax;
232 
233  // if(h2->GetMaximum()-baseline>1000) { CONTIN = 16; JUMPS = 5; }
234  if(max_value-baseline>1000) { CONTIN = 16; JUMPS = 5; }
235  // start judging
236  int decreaseD = 0, tolerence=0;
237  int start = 0;
238  // int end = 0; // never used?
239  for(int i=1;i<up-1;i++){
240  if(averaged.at(i)<averaged.at(i-1)) {
241  if(decreaseD==0) start = i;
242  decreaseD +=1;
243  }
244  else {
245  if(averaged.at(i+1)<averaged.at(i-1)&&tolerence<JUMPS&&decreaseD>0){ // we can ignore several jumps in the decreasing region
246  decreaseD+=2;
247  tolerence++;
248  i = i+1;
249  }
250  else{
251  if(decreaseD>CONTIN){
252  ledge = true;
253  LedgeStart = start*UNIT;
254  break;
255  }
256  else{
257  decreaseD = 0;
258  tolerence=0;
259  start = 0;
260  // end = 0;// end never used?
261  }
262  }
263  }
264  }
265  // find the sharp start edge
266  if(ledge &&LedgeStart>30){
267  // int edge = 0;
268  // int i = LedgeStart/UNIT-1;
269  // if(averaged.at(i)>averaged.at(i-1)&&averaged.at(i-1)>averaged.at(i-2)){ // find a edge
270  // edge = 1;
271  // }
272  // if(edge == 0) ledge = false; // if no edge, this is not ledge
273  // if((averaged.at(i)-averaged.at(i-2)<10*UNIT)&&(averaged.at(i)-averaged.at(i-3)<10*UNIT)) // slope cut
274  // ledge = false;
275  if(averaged.at(LedgeStart/UNIT)-baseline*UNIT>150*UNIT) ledge = false; // ledge is close to the baseline
276  }
277  // test the decay time
278  if(ledge &&LedgeStart>20){
279  double height = 0;
280  if(LedgeStart<5750) { // calculate the height of edge
281  // double tempHeight = h2 ->GetBinContent(LedgeStart+1+200) + h2 ->GetBinContent(LedgeStart+1+220) + h2 ->GetBinContent(LedgeStart+1+180) + h2 ->GetBinContent(LedgeStart+1+240);
282  // height = h2 ->GetBinContent(LedgeStart+1) - tempHeight/4;
283  double tempHeight = signal.at(LedgeStart+200) + signal.at(LedgeStart+220) + signal.at(LedgeStart+180) + signal.at(LedgeStart+240);
284  height = signal.at(LedgeStart) - tempHeight/4;
285  height /= 0.7;
286  }
287  // else height = h2 ->GetBinContent(LedgeStart+1) - h2 ->GetBinContent(6000);
288  else height = signal.at(LedgeStart) - signal.back();
289  if(height<0) height = 80; // norminal value
290  if(height>30&&LedgeStart<5900){ // test the decay with a relatively large height
291  double height50 = 0, height100 = 0;
292  // height50 = h2 ->GetBinContent(LedgeStart+51);
293  // height100 = h2 ->GetBinContent(LedgeStart+101);
294  // double height50Pre = h2 ->GetBinContent(LedgeStart+1)- height*(1-exp(-50/100.)); // minimum 100 ticks decay time
295  // double height100Pre = h2 ->GetBinContent(LedgeStart+1) - height*(1-exp(-100./100)); // minimum 100 ticks decay time
296 
297  height50 = signal.at(LedgeStart+50);
298  height100 = signal.at(LedgeStart+100);
299  double height50Pre = signal.at(LedgeStart)- height*(1-std::exp(-50/100.)); // minimum 100 ticks decay time
300  double height100Pre = signal.at(LedgeStart) - height*(1-std::exp(-100./100)); // minimum 100 ticks decay time
301  // if the measured is much smaller than the predicted, this is not ledge
302  if(height50-height50Pre<-8) ledge = false;
303  if(height100-height100Pre<-8) ledge = false;
304  }
305  }
306 
307  // determine the end of ledge
308  // case 1: find a jump of 10 ADC in the rebinned waveform
309  // case 2: a continuous 20 ticks has an average close to baseline, and a RMS larger than 3 ADC
310  // case 3: reaching the tick 6000 but neither 1 nor 2 occurs
311  if(ledge){
312  LedgeEnd = 0;
313  for(int i = LedgeStart/UNIT; i<up-1; i++){ // case 1
314  if(averaged.at(i+1)-averaged.at(i)>50) {
315  LedgeEnd = i*UNIT+5;
316  break;
317  }
318  }
319  if(LedgeEnd == 0) { // not find a jump, case 2
320  // double tempA[20];
322  for(int i = LedgeStart+80;i<nticks-20;i+=20){
323  for(int j=i;j<20+i;j++){
324  // tempA[j-i] = h2->GetBinContent(j+1);
325  tempA.at(j-i) = signal.at(j);
326  }
327  auto wfinfo = WireCell::Waveform::mean_rms(tempA);
328  // if(TMath::Mean(20,tempA)-baseline<2&&TMath::RMS(20,tempA)>3){
329  if(wfinfo.first - baseline < 2 && wfinfo.second > 3){
330  LedgeEnd = i;
331  break;
332  }
333  }
334  }
335  if(LedgeEnd == 0) LedgeEnd = 6000;
336  }
337  // done, release the memory
338  // vector<int>(averaged).swap(averaged); // is it necessary?
339  return ledge;
340 
341 }
342 
343 
344 
345 // adapted from WCP
346 // int judgePlateau(int channel, TH1F* h2,double baseline, double & PlateauStart, double & PlateauStartEnd){
347 // int continueN = 0;
348 // int threshold = 200;
349 // int maximumF = 50;
350 // int maxBin = h2->GetMaximumBin();
351 // for(int i=maxBin+10;i<5880&&i<maxBin+500;i++){
352 // int plateau = 1;
353 // int max = 0, min = 10000;
354 // for(int j=i;j<i+20;j++){
355 // int binC = h2->GetBinContent(j+1);
356 // if(binC<baseline+threshold||binC>h2->GetMaximum()-500) {
357 // plateau = 0;
358 // break;
359 // }
360 // if(binC>max) max = binC;
361 // if(binC<min) min = binC;
362 // }
363 // if(plateau==1&&max-min<maximumF){ // plateau found
364 // PlateauStart = i;
365 // PlateauStartEnd = i+20;
366 // for(int k = i+20; k<6000;k++){
367 // if( h2->GetBinContent(k+1)<baseline+threshold){
368 // PlateauStartEnd = k-1;
369 // break;
370 // }
371 // }
372 // return 1;
373 // }
374 // }
375 // return 0;
376 // }
377 
378 
381  float stky_sig_like_val,
382  float stky_sig_like_rms){
383 
384  const int nsiglen = signal.size();
385  std::pair<double,double> temp = WireCell::Waveform::mean_rms(signal);
386  for(auto const& rng: rng_list){
387  int start = rng.first -1;
388  int end = rng.second + 1;
389  if (start >=0 && end <nsiglen){
390  std::vector<float> digits;
391  for(int i=start+1; i<end; i++){
392  digits.push_back(signal.at(i));
393  }
394 
395  auto min = std::max_element(digits.begin(), digits.end());
396  auto max = std::min_element(digits.begin(), digits.end());
397  double max_value = *max;
398  double min_value = *min;
399 
400  double start_content = signal.at(start);
401  double end_content = signal.at(end);
402  bool isSignalLike = false;
403  if(rng.second == rng.first) isSignalLike = true; //single sticky, do FFT interp later
404  else{
405  // peak > stky_sig_like_val [unit in adc]
406  // two ends > stky_sig_like_rms [unit in rms]
407  if(max_value - temp.first > stky_sig_like_val){
408  if( (start_content - temp.first > stky_sig_like_rms*temp.second)
409  && (end_content - temp.first > stky_sig_like_rms*temp.second) ){
410  isSignalLike = true;
411  }
412  }
413  else if(temp.first - min_value > stky_sig_like_val){
414  if( (temp.first - start_content > stky_sig_like_rms*temp.second)
415  && (temp.first - end_content > stky_sig_like_rms*temp.second) ){
416  isSignalLike = true;
417  }
418 
419  }
420  }
421 
422  if (! isSignalLike) { // only apply linear interpolation on non-signal-like region
423  for (int i = start+1; i<end; i++){
424  double content = start_content + (end_content - start_content) /(end-start) *(i-start);
425  signal.at(i) = content;
426  }
427  }
428  }
429  else if(start<0 && end <nsiglen){// sticky at the first tick
430  for(int i=0; i<end; i++){
431  signal.at(i) = signal.at(end);
432  }
433 
434  }
435  else if(start>=0 && end==nsiglen){// sticky at the last tick
436  for(int i=start+1; i<end; i++){
437  signal.at(i) = signal.at(start);
438  }
439  }
440  }
441  return true;
442 }
443 
446  const int nsiglen = signal.size();
447  // group into two subsamples ("even" & "odd")
448  int nsublen = nsiglen/2;
449  int nsublen2 = nsiglen - nsublen;
450  WireCell::Waveform::realseq_t signal_even(nsublen); // 0-th bin, 2, 4, etc.
451  WireCell::Waveform::realseq_t signal_odd(nsublen2);
452  for(int j=0; j<nsiglen; j++){
453  if(j%2==0) signal_even.at(j/2) = signal.at(j);
454  else signal_odd.at((j-1)/2) = signal.at(j);
455  }
456 
457  // dft resampling for "even", see example in test_zero_padding.cxx
458  auto tran_even = WireCell::Waveform::dft(signal_even);
459  tran_even.resize(nsublen*2);
460  if(nsublen%2==0){
461  std::rotate(tran_even.begin()+nsublen/2, tran_even.begin()+nsublen, tran_even.end());
462  }
463  else{
464  std::rotate(tran_even.begin()+(nsublen+1)/2, tran_even.begin()+nsublen, tran_even.end());
465  }
466  // inverse FFT
467  auto signal_even_fc = WireCell::Waveform::idft(tran_even);
468  float scale = tran_even.size() / nsublen;
469  WireCell::Waveform::scale(signal_even_fc, scale);
470 
471  // similar for "odd"
472  auto tran_odd = WireCell::Waveform::dft(signal_odd);
473  tran_odd.resize(nsublen2*2);
474  if(nsublen2%2==0){
475  std::rotate(tran_odd.begin()+nsublen2/2, tran_odd.begin()+nsublen2, tran_odd.end());
476  }
477  else{
478  std::rotate(tran_odd.begin()+(nsublen2+1)/2, tran_odd.begin()+nsublen2, tran_odd.end());
479  }
480  auto signal_odd_fc = WireCell::Waveform::idft(tran_odd);
481  float scale2 = tran_odd.size() / nsublen2;
482  WireCell::Waveform::scale(signal_odd_fc, scale2);
483 
484  // replace the linear interpolation with dft interpolation
485  for (size_t j = 0; j<rng_list.size();j++){
486  int start = rng_list.at(j).first -1 ;
487  int end = rng_list.at(j).second + 1 ;
488  if (start >=0 && end <=nsiglen){
489  for (int i = start+1; i<end; i++){
490  if(i%2==0){// predict "even" with "odd"
491  signal.at(i) = signal_odd_fc.at(i-1);
492  }
493  else{
494  signal.at(i) = signal_even_fc.at(i);
495  }
496  }
497  }
498  }
499 
500  return true;
501 }
502 
503 
505  double toffset,
506  std::vector<std::pair<int,int> >& st_ranges){
507  const int nsiglen = signal.size();
508  // group into two subsamples ("even" & "odd")
509  int nsublen = nsiglen/2;
510  int nsublen2 = nsiglen - nsublen;
511  WireCell::Waveform::realseq_t signal_even(nsublen); // 0-th bin, 2, 4, etc.
512  WireCell::Waveform::realseq_t signal_odd(nsublen2);
513  for(int j=0; j<nsiglen; j++){
514  if(j%2==0) signal_even.at(j/2) = signal.at(j);
515  else signal_odd.at((j-1)/2) = signal.at(j);
516  }
517 
518  // dft shift for "even"
519  auto tran_even = WireCell::Waveform::dft(signal_even);
520  double f0 = 1./nsublen;
521  const double PI = std::atan(1.0)*4;
522  for(size_t i=0; i<tran_even.size(); i++){
523  double fi = i * f0;
524  double omega = 2*PI*fi;
525  auto z = tran_even.at(i);
526  std::complex<float> z1(0, omega*toffset);
527  // std::complex<double> z2 = z * std::exp(z1);
528  tran_even.at(i) = z * std::exp(z1);
529  }
530  // inverse FFT
531  auto signal_even_fc = WireCell::Waveform::idft(tran_even);
532  // float scale = 1./tran_even.size();
533  // WireCell::Waveform::scale(signal_even_fc, 1./nsublen);
534 
535  // similar to "odd"
536  auto tran_odd = WireCell::Waveform::dft(signal_odd);
537  f0 = 1./nsublen2;
538  for(size_t i=0; i<tran_odd.size(); i++){
539  double fi = i * f0;
540  double omega = 2*PI*fi;
541  auto z = tran_odd.at(i);
542  std::complex<float> z1(0, omega*toffset);
543  // std::complex z2 = z * std::exp(z1);
544  tran_odd.at(i) = z * std::exp(z1);
545  }
546  //
547  auto signal_odd_fc = WireCell::Waveform::idft(tran_odd);
548  // float scale = 1./tran_odd.size();
549  // WireCell::Waveform::scale(signal_odd_fc, 1./nsublen2);
550 
551  // replace the linear interpolation with dft interpolation
552  for (size_t j = 0; j<st_ranges.size();j++){
553  int start = st_ranges.at(j).first -1 ;
554  int end = st_ranges.at(j).second + 1 ;
555  if (start >=0 && end <=nsiglen){
556  for (int i = start+1; i<end; i++){
557  if(i%2==0){ // predict "even" with "odd"
558  int ind = (i-1)/2. - toffset;
559  if(ind>=0 && ind<nsublen2) signal.at(i) = signal_odd_fc.at(ind);
560  // std::cerr << "lc:fc= " << signal_lc.at(i) << " " << signel_even_fc.at() << std::endl;
561  }
562  else{
563  int ind = i/2. - toffset;
564  if(ind>=0 && ind<nsublen) signal.at(i) = signal_even_fc.at(ind);
565  }
566  }
567  }
568  }
569 
570  return true;
571 }
572 
573 bool Protodune::FftScaling(WireCell::Waveform::realseq_t& signal, int nsamples){
574  const int nsiglen = signal.size();
575  auto tran = WireCell::Waveform::dft(signal);
576  tran.resize(nsamples);
577  if(nsiglen%2==0){ // ref test_zero_padding.cxx
578  std::rotate(tran.begin()+nsiglen/2, tran.begin()+nsiglen, tran.end());
579  }
580  else{
581  std::rotate(tran.begin()+(nsiglen+1)/2, tran.begin()+nsiglen, tran.end());
582  }
583  // inverse FFT
584  auto signal_fc = WireCell::Waveform::idft(tran);
585  WireCell::Waveform::scale(signal_fc, nsamples / nsiglen);
586  signal = signal_fc;
587 
588  return true;
589 }
590 
591 /*
592  * Classes
593  */
594 
595 
596 /*
597  * Configuration base class used for a couple filters
598  */
599 Protodune::ConfigFilterBase::ConfigFilterBase(const std::string& anode, const std::string& noisedb)
600  : m_anode_tn(anode)
601  , m_noisedb_tn(noisedb) {}
604 {
605  m_anode_tn = get(cfg, "anode", m_anode_tn);
606  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
607  m_noisedb_tn = get(cfg, "noisedb", m_noisedb_tn);
608  m_noisedb = Factory::find_tn<IChannelNoiseDatabase>(m_noisedb_tn);
609  //std::cerr << "ConfigFilterBase: \n" << cfg << "\n";
610 }
612 {
614  cfg["anode"] = m_anode_tn;
615  cfg["noisedb"] = m_noisedb_tn;
616  return cfg;
617 }
618 
619 
620 
622  float stky_sig_like_val, float stky_sig_like_rms, int stky_max_len)
623  : m_anode_tn(anode)
624  , m_noisedb_tn(noisedb)
625  , m_stky_sig_like_val(stky_sig_like_val)
626  , m_stky_sig_like_rms(stky_sig_like_rms)
627  , m_stky_max_len(stky_max_len)
628 
629 {
630 }
632 {
633 }
634 
636 {
637  m_anode_tn = get(cfg, "anode", m_anode_tn);
638  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
639  if (!m_anode) {
640  THROW(KeyError() << errmsg{"failed to get IAnodePlane: " + m_anode_tn});
641  }
642 
643  m_noisedb_tn = get(cfg, "noisedb", m_noisedb_tn);
644  m_noisedb = Factory::find_tn<IChannelNoiseDatabase>(m_noisedb_tn);
645 
646  m_extra_stky.clear();
647  auto jext = cfg["extra_stky"];
648  if(!jext.isNull()){
649  for(auto jone: jext) {
650  auto jchans = jone["channels"];
651  for (auto jchan: jchans){
652  int channel = jchan.asInt();
653  // std::cerr << "[wgu] ch# " << channel << " has " << jone["bits"].size() << " extra stky bits:" << std::endl;
654  for(auto bit: jone["bits"]){
655  // std::cerr << "[wgu] " << bit.asInt() << std::endl;
656  m_extra_stky[channel].push_back((short int)bit.asInt());
657  }
658  }
659 
660  }
661  }
662 
663  if (cfg.isMember("stky_sig_like_val")){
664  m_stky_sig_like_val = get(cfg, "stky_sig_like_val", m_stky_sig_like_val);
665  }
666 
667  if (cfg.isMember("stky_sig_like_rms")){
668  m_stky_sig_like_rms = get(cfg, "stky_sig_like_rms", m_stky_sig_like_rms);
669  }
670 
671  if (cfg.isMember("stky_max_len")){
672  m_stky_max_len = get(cfg, "stky_max_len", m_stky_max_len);
673  }
674 }
676 {
678  cfg["anode"] = m_anode_tn;
679  cfg["noisedb"] = m_noisedb_tn;
680  cfg["stky_sig_like_val"] = m_stky_sig_like_val;
681  cfg["stky_sig_like_rms"] = m_stky_sig_like_rms;
682  cfg["stky_max_len"] = m_stky_max_len;
683  return cfg;
684 }
685 
687 {
689 
690  const int nsiglen = signal.size();
691  // tag sticky bins
692  WireCell::Waveform::BinRange sticky_rng;
693  WireCell::Waveform::BinRangeList sticky_rng_list;
694  std::vector<short int> extra;
695  if (m_extra_stky.find(ch) != m_extra_stky.end()){
696  extra = m_extra_stky.at(ch);
697  }
698 
699  for(int i=0; i<nsiglen; i++){
700  int val = signal.at(i);
701  int mod = val % 64;
702  auto it = std::find(extra.begin(), extra.end(), mod);
703  // bool is_stky = (mod==0 || mod==1 || mod==63 || it!=extra.end());
704  if( it != extra.end()) {
705  if (sticky_rng_list.empty()){
706  sticky_rng_list.push_back(std::make_pair(i,i));
707  }else if ( (sticky_rng_list.back().second + 1) == i){
708  sticky_rng_list.back().second = i;
709  }else{
710  sticky_rng_list.push_back(std::make_pair(i,i));
711  }
712  }
713  }
714 
715 
716  // auto signal_lc = signal; // copy, need to keep original signal
718  FftInterpSticky(signal, sticky_rng_list);
719  // FftShiftSticky(signal_lc, 0.5, st_ranges); // alternative approach, shift by 0.5 tick
720  // signal = signal_lc;
721  int ent_stkylen =0;
722  for(auto rng: sticky_rng_list){
723  int stkylen= rng.second-rng.first;
724  if(stkylen> m_stky_max_len){
725  ret["sticky"][ch].push_back(rng);
726  ent_stkylen += stkylen;
727  }
728  }
729  // std::cerr << "[wgu] ch: " << ch << " long_stkylen: " << long_stkylen << std::endl;
730 
731  //Now calculate the baseline ...
732  std::pair<double,double> temp = WireCell::Waveform::mean_rms(signal);
733  auto temp_signal = signal;
734  for (size_t i=0;i!=temp_signal.size();i++){
735  if (fabs(temp_signal.at(i)-temp.first)>6*temp.second){
736  temp_signal.at(i) = temp.first;
737  }
738  }
739  float baseline = WireCell::Waveform::median_binned(temp_signal);
740 
741  // Ledge
742  auto wpid = m_anode->resolve(ch);
743  const int iplane = wpid.index();
744  if (iplane==2){
745  int ledge_start[3], ledge_end[3];
746  int nledge = LedgeIdentify1(signal, baseline, ledge_start, ledge_end);
747  for(int LE=0; LE<nledge; LE++){
748  // check overlap of sticky in a ledge
749  float overlap=0;
750  for(auto rng: sticky_rng_list){
751  int redge = std::min(rng.second, ledge_end[LE]);
752  int ledge = std::max(rng.first, ledge_start[LE]);
753  if(redge>=ledge) overlap += (redge-ledge+1);
754  }
755  if( overlap < 0.5 * (ledge_end[LE]-ledge_start[LE]) ){
756  WireCell::Waveform::BinRange ledge_bins;
757  ledge_bins.first = ledge_start[LE];
758  ledge_bins.second = ledge_end[LE];
759  ret["ledge"][ch].push_back(ledge_bins); // FIXME: maybe collection plane only?
760  // std::cerr << "[wgu] ledge found, ch "<< ch << " , bins= [" << ledge_bins.first << " , " << ledge_bins.second << " ], sticky overlap: " << overlap/(ledge_end[LE]-ledge_start[LE]) << std::endl;
761  }
762  }
763  }
764 
765  return ret;
766 }
767 
768 
769 
771 {
773 }
774 
775 
777  : ConfigFilterBase(anode, noisedb)
778  , m_check_partial() // fixme, here too.
779  , m_resmp()
780 {
781 }
783 {
784 }
785 
787 {
788  m_anode_tn = get(cfg, "anode", m_anode_tn);
789  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
790  if (!m_anode) {
791  THROW(KeyError() << errmsg{"failed to get IAnodePlane: " + m_anode_tn});
792  }
793 
794  m_noisedb_tn = get(cfg, "noisedb", m_noisedb_tn);
795  m_noisedb = Factory::find_tn<IChannelNoiseDatabase>(m_noisedb_tn);
796 
797  m_resmp.clear();
798  auto jext = cfg["resmp"];
799  if(!jext.isNull()){
800  for(auto jone: jext) {
801  int smpin = jone["sample_from"].asInt();
802  for(auto jch: jone["channels"]){
803  int channel = jch.asInt();
804  m_resmp[channel] = smpin;
805  }
806  }
807  }
808 
809 }
811 {
813  cfg["anode"] = m_anode_tn;
814  cfg["noisedb"] = m_noisedb_tn;
815  return cfg;
816 }
817 
819 {
821 
822  // do we need a nominal baseline correction?
823  // float baseline = m_noisedb->nominal_baseline(ch);
824 
825  // correct the FEMB 302 clock issue
826  auto it = m_resmp.find(ch);
827  if (it != m_resmp.end()) {
828  int smpin = m_resmp.at(ch);
829  int smpout = signal.size();
830  signal.resize(smpin);
831  FftScaling(signal, smpout);
832  // std::cerr << "[wgu] ch: " << ch << " smpin: " << smpin << " smpout: " << smpout << std::endl;
833  }
834  // if( (ch>=2128 && ch<=2175) // W plane
835  // || (ch>=1520 && ch<=1559) // V plane
836  // || (ch>=440 && ch<=479) // U plane
837  // ){
838  // signal.resize(5996);
839  // FftScaling(signal, 6000);
840  // }
841 
842  // correct rc undershoot
843  auto spectrum = WireCell::Waveform::dft(signal);
844  bool is_partial = m_check_partial(spectrum); // Xin's "IS_RC()"
845 
846  if(!is_partial){
847  auto const& spec = m_noisedb->rcrc(ch); // rc_layers set to 1 in channel noise db
848  WireCell::Waveform::shrink(spectrum, spec);
849  }
850 
851  // remove the "50kHz" noise in some collection channels
852  // FIXME: do we need a channel list input?
853  auto wpid = m_anode->resolve(ch);
854  const int iplane = wpid.index();
855  if(iplane==2){
856  auto mag = WireCell::Waveform::magnitude(spectrum);
857  mag.at(0)=0;
858  Microboone::RawAdapativeBaselineAlg(mag); // subtract "linear" background in spectrum
859 
860 
861  auto const& spec = m_noisedb->noise(ch);
862  // std::cout << "[wgu] " << spec.at(10).real() << std::endl;
863  // std::cout << "[wgu] " << spec.at(148).real() << std::endl;
864  // std::cout << "[wgu] " << spec.at(149).real() << std::endl;
865  // std::cout << "[wgu] " << spec.at(160).real() << std::endl;
866  // std::cout << "[wgu] " << spec.at(161).real() << std::endl;
867  // WireCell::Waveform::scale(spectrum, spec);
868 
869  // spec -> freqBins;
870  std::vector< std::pair<int,int> > freqBins;
871  for(int i=0; i<(int)spec.size(); i++){
872  float flag_re = spec.at(i).real();
873  // if(i<3000) std::cout << "[wgu] spec # " << i << " : " << flag_re << std::endl;
874  if (flag_re<0.5) { // found a tagged bin
875  if (freqBins.empty()){
876  freqBins.push_back(std::make_pair(i,i));
877  }
878  else if (i == freqBins.back().second +1) {
879  freqBins.back().second = i;
880  }
881  else {
882  freqBins.push_back(std::make_pair(i,i));
883  }
884  }
885  }
886 
887  // std::cout << "[wgu] freqBins.size(): " << freqBins.size() << std::endl;
888  // for(auto br: freqBins) {
889  // std::cout << "[wgu] hibin: " << br.second << " lobin: " << br.first << std::endl;
890  // }
891 
892 
893  int n_harmonic = 0;
894  for(int iter=0; iter<5; iter++){
895  // std::cout << "[wgu] iter= " << iter << std::endl;
896 
897  for(auto bin: freqBins) {
898  int istart = bin.first;
899  int iend = bin.second +1;
900  int nslice = iend - istart;
901  // std::cout << "hibin: " << iend << " lobin: " << istart << std::endl;
902 
903  // }
904 
905 
906  // for(int i=0; i<57; i++){ // 150 - 3000th freq bin
907  // int nslice = 50;
908  // int istart = 150 + nslice*i;
909  // int iend = istart + nslice;
910  // std::cerr << istart << " " << iend << std::endl;
911  WireCell::Waveform::realseq_t mag_slice(nslice); // slice of magnitude spectrum
912  std::copy(mag.begin() + istart, mag.begin() + iend, mag_slice.begin());
913  std::pair<double,double> stat = WireCell::Waveform::mean_rms(mag_slice);
914  // std::cerr << "[wgu] mean/rms: " << stat.first << " " << stat.second << std::endl;
915  double cut = stat.first + 2.7*stat.second;
916  if (istart>1050){ //if(i>17){
917  cut = stat.first + 3*stat.second;
918  }
919  // if(stat.second>1300){
920  // cut = stat.first + stat.second;
921  // }
922  for(int j=istart; j<iend; j++){
923  float content = mag.at(j);
924  if(content > cut){
925  spectrum.at(j).real(0);
926  spectrum.at(j).imag(0);
927  spectrum.at(mag.size()+1-j).real(0);
928  spectrum.at(mag.size()+1-j).imag(0);
929  mag.at(j) = 0;
930  mag.at(mag.size()+1-j) = 0;
931  n_harmonic ++;
932  }
933  }
934 
935  // for(int j=0; j<nslice; j++){
936  // float content = mag_slice.at(j) - stat.first;
937 
938  // if(iend<1000){
939  // if(content>2000 && content>5.*stat.second){
940  // int tbin = istart + j;
941  // spectrum.at(tbin).real(0);
942  // spectrum.at(tbin).imag(0);
943  // spectrum.at(6000+1-tbin).real(0); // FIXME: assuming 6000 ticks
944  // spectrum.at(6000+1-tbin).imag(0);
945  // // std::cerr << "[wgu] chan: " << ch << " , freq tick: " << tbin << " , amp: " << content << std::endl;
946  // }
947  // }
948  // else if(content>250 && content>10.*stat.second){
949  // spectrum.at(j).real(0);
950  // spectrum.at(j).imag(0);
951  // spectrum.at(6000+1-j).real(0); // FIXME: assuming 6000 ticks
952  // spectrum.at(6000+1-j).imag(0);
953  // }
954  // }
955  }
956  }
957 
958  if (n_harmonic>5){
959  WireCell::Waveform::BinRange temp_harmonic_bins;
960  temp_harmonic_bins.first = 0;
961  temp_harmonic_bins.second = signal.size();
962  ret["harmonic"][ch].push_back(temp_harmonic_bins);
963  }
964 
965  }
966 
967 
968  // remove the DC component
969  spectrum.front() = 0;
970  signal = WireCell::Waveform::idft(spectrum);
971 
972  //Now calculate the baseline ...
973  std::pair<double,double> temp = WireCell::Waveform::mean_rms(signal);
974  auto temp_signal = signal;
975  for (size_t i=0;i!=temp_signal.size();i++){
976  if (fabs(temp_signal.at(i)-temp.first)>6*temp.second){
977  temp_signal.at(i) = temp.first;
978  }
979  }
980  float baseline = WireCell::Waveform::median_binned(temp_signal);
981  //correct baseline
982  WireCell::Waveform::increase(signal, baseline *(-1));
983 
984 
985  // Now do the adaptive baseline for the bad RC channels
986  if (is_partial) {
987  // add something
988  WireCell::Waveform::BinRange temp_chirped_bins;
989  temp_chirped_bins.first = 0;
990  temp_chirped_bins.second = signal.size();
991 
992  if (iplane!=2) { // not collection
993  ret["lf_noisy"][ch].push_back(temp_chirped_bins);
994  //std::cout << "Partial " << ch << std::endl;
995  }
996  Microboone::SignalFilter(signal);
999  }
1000 
1001  const float min_rms = m_noisedb->min_rms_cut(ch);
1002  const float max_rms = m_noisedb->max_rms_cut(ch);
1003  //
1004  // temp = Derivations::CalcRMS(signal);
1005  // if(ch==14431) std::cerr << "[wgu] channel: " << ch << " rms: " << temp.second << std::endl;
1006  // if(temp.second<min_rms || temp.second>max_rms){
1007  // WireCell::Waveform::BinRange temp_chirped_bins;
1008  // temp_chirped_bins.first = 0;
1009  // temp_chirped_bins.second = signal.size();
1010  // ret["noisy"][ch].push_back(temp_chirped_bins);
1011  // }
1012  // alternative RMS tagging
1013  Microboone::SignalFilter(signal);
1014  bool is_noisy = Microboone::NoisyFilterAlg(signal,min_rms,max_rms);
1016  if(is_noisy){
1017  WireCell::Waveform::BinRange temp_chirped_bins;
1018  temp_chirped_bins.first = 0;
1019  temp_chirped_bins.second = signal.size();
1020  ret["noisy"][ch].push_back(temp_chirped_bins);
1021  }
1022 
1023  return ret;
1024 }
1025 
1026 
1027 
1029 {
1031 }
1032 
1033 
1035  float gain_def, float gain_min_cut, float gain_max_cut)
1036  : m_anode_tn(anode)
1037  , m_noisedb_tn(noisedb)
1038  , m_gain_def(gain_def)
1039  , m_gain_min_cut(gain_min_cut)
1040  , m_gain_max_cut(gain_max_cut)
1041 {
1042 }
1044 {
1045 }
1046 
1048 {
1049  m_anode_tn = get(cfg, "anode", m_anode_tn);
1050  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
1051  if (!m_anode) {
1052  THROW(KeyError() << errmsg{"failed to get IAnodePlane: " + m_anode_tn});
1053  }
1054 
1055  m_noisedb_tn = get(cfg, "noisedb", m_noisedb_tn);
1056  m_noisedb = Factory::find_tn<IChannelNoiseDatabase>(m_noisedb_tn);
1057 
1058  if (cfg.isMember("gain_def")) {
1059  m_gain_def = get(cfg, "gain_def", m_gain_def);
1060  }
1061 
1062  if (cfg.isMember("gain_min_cut")){
1063  m_gain_min_cut = get(cfg, "gain_min_cut", m_gain_min_cut);
1064  }
1065 
1066  if (cfg.isMember("gain_max_cut")){
1067  m_gain_max_cut = get(cfg, "gain_max_cut", m_gain_max_cut);
1068  }
1069 
1070  m_rel_gain.clear();
1071  for (auto jch : cfg["rel_gain"]) {
1072  m_rel_gain.push_back(jch.asDouble());
1073  }
1074 
1075 }
1077 {
1079  cfg["anode"] = m_anode_tn;
1080  cfg["noisedb"] = m_noisedb_tn;
1081  cfg["gain_def"] = m_gain_def;
1082  cfg["gain_min_cut"] = m_gain_min_cut;
1083  cfg["gain_max_cut"] = m_gain_max_cut;
1084  return cfg;
1085 }
1086 
1088 {
1090 
1091  size_t nsiglen = signal.size();
1092  // FIXME: already subtracted in OneChannelNoise::apply(). Need to calculate again?
1093  // std::pair<double,double> temp = WireCell::Waveform::mean_rms(signal);
1094  // auto temp_signal = signal;
1095  // for (size_t i=0;i!=temp_signal.size();i++){
1096  // if (fabs(temp_signal.at(i)-temp.first)>6*temp.second){
1097  // temp_signal.at(i) = temp.first;
1098  // }
1099  // }
1100  // float baseline = WireCell::Waveform::median_binned(temp_signal);
1101  float baseline = 0.;
1102 
1103  float gain_fac = m_rel_gain.at(ch);
1104 
1105  bool isDefVal = false;
1106  if ( gain_fac > m_gain_max_cut || gain_fac < m_gain_min_cut ) {
1107  // std::cerr << "[wgu] gain_max_cut: " << m_gain_max_cut << " gain_min_cut: " << m_gain_min_cut << std::endl;
1108  // std::cerr << "[wgu] ch: " << ch << " relative gain: " << gain_fac << std::endl;
1109  gain_fac = m_gain_def;
1110  isDefVal = true;
1111  }
1112 
1113  if ( !isDefVal) {
1114  for (size_t ind=0; ind<nsiglen; ind++) {
1115  float sigout = gain_fac * (signal.at(ind) - baseline);
1116  sigout += baseline;
1117  signal.at(ind) = sigout;
1118  }
1119  }
1120 
1121  return ret;
1122 }
1123 
1124 
1125 
1127 {
1129 }
1130 
1131 // Local Variables:
1132 // mode: c++
1133 // c-basic-offset: 4
1134 // End:
WireCell::IConfigurable WIRECELL_FACTORY(pdRelGainCalib, WireCell::SigProc::Protodune::RelGainCalib, WireCell::IChannelFilter, WireCell::IConfigurable) using namespace WireCell int LedgeIdentify1(WireCell::Waveform::realseq_t &signal, double baseline, int LedgeStart[3], int LedgeEnd[3])
Definition: Protodune.cxx:35
bool SignalFilter(WireCell::Waveform::realseq_t &sig)
Definition: Microboone.cxx:648
std::pair< int, int > BinRange
A half-open range of bins (from first bin to one past last bin)
Definition: Waveform.h:38
realseq_t real(const compseq_t &seq)
Return the real part of the sequence.
Definition: Waveform.cxx:55
Sequence< real_t > realseq_t
Definition: Waveform.h:31
bool FftInterpSticky(WireCell::Waveform::realseq_t &signal, std::vector< std::pair< int, int > > &st_ranges)
std::vector< T > Waveform
Definition: IWaveformTool.h:21
Waveform::realseq_t signal_t
bool LedgeIdentify(WireCell::Waveform::realseq_t &signal, double baseline, int &LedgeStart, int &LedgeEnd)
Definition: Protodune.cxx:213
std::string string
Definition: nybbler.cc:12
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
virtual WireCell::Waveform::ChannelMaskMap apply(int channel, signal_t &sig) const
bool FftShiftSticky(WireCell::Waveform::realseq_t &signal, double toffset, std::vector< std::pair< int, int > > &st_ranges)
struct vector vector
cfg
Definition: dbjson.py:29
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
Definition: Protodune.cxx:611
bool LinearInterpSticky(WireCell::Waveform::realseq_t &signal, std::vector< std::pair< int, int > > &st_ranges, float stky_sig_like_val, float stky_sig_like_rms)
const int nticks
constexpr double PI
IChannelNoiseDatabase::pointer m_noisedb
Definition: Protodune.h:86
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
Definition: Protodune.cxx:675
virtual void configure(const WireCell::Configuration &config)
Accept a configuration.
Definition: Protodune.cxx:1047
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:72
IChannelNoiseDatabase::pointer m_noisedb
Definition: Protodune.h:145
std::map< int, std::vector< short int > > m_extra_stky
Definition: Protodune.h:88
compseq_t dft(realseq_t seq)
Definition: Waveform.cxx:141
void shrink(Sequence< Val > &seq, const Sequence< Val > &other)
Shrink (divide) seq values by values from the other sequence.
Definition: Waveform.h:162
std::map< std::string, ChannelMasks > ChannelMaskMap
Collect channel masks by some label.
Definition: Waveform.h:59
void increase(Sequence< Val > &seq, Val scalar)
Increase (shift) sequence values by scalar.
Definition: Waveform.h:129
WIRECELL_FACTORY(pdStickyCodeMitig, WireCell::SigProc::Protodune::StickyCodeMitig, WireCell::IChannelFilter, WireCell::IConfigurable) WIRECELL_FACTORY(pdOneChannelNoise
double z
std::vector< BinRange > BinRangeList
A list of bin ranges.
Definition: Waveform.h:41
OneChannelNoise(const std::string &anode_tn="AnodePlane", const std::string &noisedb="OmniChannelNoiseDB")
Definition: Protodune.cxx:776
const double height
#define THROW(e)
Definition: Exceptions.h:25
static int max(int a, int b)
bool NoisyFilterAlg(WireCell::Waveform::realseq_t &spec, float min_rms, float max_rms)
Definition: Microboone.cxx:542
real_t median_binned(realseq_t &wave)
Definition: Waveform.cxx:81
bool RawAdapativeBaselineAlg(WireCell::Waveform::realseq_t &sig)
Definition: Microboone.cxx:693
bool RemoveFilterFlags(WireCell::Waveform::realseq_t &sig)
Definition: Microboone.cxx:821
Definition: Main.h:22
virtual void configure(const WireCell::Configuration &config)
Accept a configuration.
Definition: Protodune.cxx:635
virtual WireCell::Waveform::ChannelMaskMap apply(int channel, signal_t &sig) const
IChannelNoiseDatabase::pointer m_noisedb
Definition: Protodune.h:46
void scale(Sequence< Val > &seq, Val scalar)
Scale (multiply) sequence values by scalar.
Definition: Waveform.h:146
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
Definition: Protodune.cxx:1076
realseq_t idft(compseq_t spec)
Definition: Waveform.cxx:149
std::map< int, signal_t > channel_signals_t
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
realseq_t magnitude(const compseq_t &seq)
Return the magnitude or absolute value of the sequence.
Definition: Waveform.cxx:65
std::pair< double, double > mean_rms(const realseq_t &wave)
Definition: Waveform.cxx:24
virtual void configure(const WireCell::Configuration &config)
Accept a configuration.
Definition: Protodune.cxx:603
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
Definition: format.h:1970
StickyCodeMitig(const std::string &anode_tn="AnodePlane", const std::string &noisedb="OmniChannelNoiseDB", float stky_sig_like_val=15.0, float stky_sig_like_rms=2.0, int stky_max_len=5)
Definition: Protodune.cxx:621
blobvec_t overlap(const blobref_t &blob, const blobproj_t &proj, layer_index_t layer)
Json::Value Configuration
Definition: Configuration.h:50
QTextStream & bin(QTextStream &s)
T copy(T const &v)
realseq_t imag(const compseq_t &seq)
Return the imaginary part of the sequence.
Definition: Waveform.cxx:60
void configure(const WireCell::Configuration &config)
Accept a configuration.
Definition: Protodune.cxx:786
RelGainCalib(const std::string &anode_tn="AnodePlane", const std::string &noisedb="OmniChannelNoiseDB", float gain_def=1.0, float gain_min_cut=0.8, float gain_max_cut=1.25)
Definition: Protodune.cxx:1034
virtual WireCell::Waveform::ChannelMaskMap apply(int channel, signal_t &sig) const
WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
Definition: Protodune.cxx:810
bool FftScaling(WireCell::Waveform::realseq_t &signal, int nsamples)
Thrown when a wrong key or has been encountered.
Definition: Exceptions.h:43