PDSNoiseFilter_module.cc
Go to the documentation of this file.
1 //=========================================================
2 // OpDetDigitizerDUNE_module.cc
3 // This module produces digitized output
4 // (creating OpDetWaveform)
5 // from photon detectors taking SimPhotonsLite as input.
6 //
7 // Gleb Sinev, Duke, 2015
8 // Based on OpMCDigi_module.cc
9 
10 
11 // This module was modified to filter the raw waveforms
12 // from protoDUNE SP using two combined techniques:
13 // 1) mobile average
14 // 2) denoising code
15 //
16 // Marina Reggiani-Guzzo & Dante Totani, October 2018
17 //=========================================================
18 
19 
20 // Framework includes
21 
28 #include "cetlib_except/exception.h"
29 #include "fhiclcpp/ParameterSet.h"
31 #include "fhiclcpp/types/Atom.h"
34 
35 
36 // ART extensions
37 #include "nurandom/RandomUtils/NuRandomService.h"
38 
39 // LArSoft includes
41 
42 // C++ includes
43 #include <vector>
44 #include <string>
45 
46 // ROOT includes
47 #include <Rtypes.h>
48 
49 using std::string;
50 using std::vector;
51 
52 
53 
54 // Define the configuration
55 
56 namespace opdet {
57 
59 
60  public:
61  // Define the configuration
62  struct Config {
63  using Name = fhicl::Name;
65 
66  fhicl::Atom<string> InputModule { Name("InputModule"), Comment("Module which produced raw waveforms") };
67  fhicl::Sequence<string> InputLabels { Name("InputLabels"), Comment("Labels of the raw waveforms. Will be reused for output.") };
68  // Additional fhicl parameters here
69  };
71 
72 
74 
75  void produce(art::Event&);
76 
77  private:
78 
79  // The parameters read from the FHiCL file
80  string fInputModule; // Input tag for OpDet collection
81  vector<string> fInputLabels; // Input tag for OpDet collection
82  // Additional fhicl parameters here
83 
84  std::vector<float> filter( std::vector<short unsigned int> vec, Int_t nBins);
85  void TV1D_denoise(vector<float> input, vector<float>& secondFilter, const int width, const float lambda);
86  };
87 
88 }
89 
90 
91 namespace opdet {
92 
93  //---------------------------------------------------------------------------
94  // Constructor
96  : EDProducer{config},
97  fInputModule(config().InputModule()),
98  fInputLabels(config().InputLabels())
99  // Additional fhicl parameters here
100  {
101  // Tell ART what we intend to produce
102  for (auto label : fInputLabels) {
103  produces< vector< raw::OpDetWaveform > >(label);
104  }
105  }
106 
107  //---------------------------------------------------------------------------
109  {
110 
111  // Loop over the input labels
112  for (auto label : fInputLabels) {
113 
114  // Read the waveforms in from the event record
116  auto wfHandle = evt.getHandle< vector< raw::OpDetWaveform > >(itag1);
117 
118  // Check that they are valid
119  if (!wfHandle.isValid()) {
120  mf::LogWarning("PDSNoiseFilter") << "No waveforms for label" << label;
121  continue;
122  }
123 
124  // Handle -> data
125  vector< raw::OpDetWaveform > in_waveforms = *wfHandle;
126 
127  // Create a unique_ptr to store the output
128  auto out_waveforms = std::make_unique< vector< raw::OpDetWaveform > >();
129 
130  // Loop through the waveforms applying filtering.
131  for (auto const& in_wave : in_waveforms) {
132 
133  //raw::OpDetWaveform out_wave(in_wave.TimeStamp(), in_wave.ChannelNumber(), in_wave.size());
134 
135  Int_t nBins = in_wave.size(); // size of the input vector
136  std::vector<short unsigned int > out_wave(nBins); // vector in which the filtered waveform will be saved
137  std::vector<short unsigned int > out_wave_double(nBins);
138  for(Int_t i=0; i<nBins; i++) out_wave_double[i]=2*in_wave[i];
139  // careful, it doesn't work for vector<short>, but it does for vector<short unsigned int>
140 
141  //####################################################################
142  // Beginning of the Main Code
143  //####################################################################
144 
145  //std:vector<short> out_wave(nBins); // don't worry about the shifted baseline due to the integer of the output
146  float convert = 0; // variable used to convert from float to short
147  short convert2 = 0; // sum 0.5 to the final result to try to recover the lost information from the float-short conversion
148  std::vector<float> filtered = filter(out_wave_double,nBins); // filtered waveform
149 
150  // loop to convert the filtered output from float to short
151  // and save it into the out_wave vector
152  for(Int_t i=0; i<nBins; i++){
153  convert = filtered[i];
154  convert2 = (short) convert + 0.5;
155  out_wave[i] = convert2;
156  }
157 
158  //####################################################################
159  // End of the Main Code
160  //####################################################################
161 
162  raw::OpDetWaveform out_waveFinal(in_wave.TimeStamp(), in_wave.ChannelNumber(), out_wave);
163 
164  out_waveforms->emplace_back(std::move(out_waveFinal));
165 
166  }
167 
168  evt.put(std::move(out_waveforms),label);
169  }
170 
171  }
172 
173  //####################################################################
174  // Mobile Average Function
175  //####################################################################
176 
177  std::vector<float> PDSNoiseFilter::filter( std::vector<short unsigned int> vec, Int_t nBins){
178 
179  Int_t mobileAVG = 5; // stablish how big the mobile average will be
180  Double_t avg = 0; // saves the average value for each bin
181  vector<float> firstFilter(nBins); // values after mobile average
182  vector<float> secondFilter(nBins); // values after mobile average
183  Int_t nComp = vec.size(); // size of the vector
184  Int_t c1=0; // counter for n>mobileAVG and n<nComp-mobileAVG
185  Int_t c2=0; // counter for n<=mobileAVG
186  Int_t c0=0; // counter for n>=nComp-mobileAVG
187 
188  for(Int_t n=0; n<nComp ; n++){
189  if(n>mobileAVG && n<nComp-mobileAVG){
190  for(Int_t i=n-mobileAVG; i<=n+mobileAVG; i++){avg = avg + vec[i]; c0=c0+1;}
191  avg = avg/c0;
192  firstFilter[n] = avg;
193  avg=0;
194  c0=0;
195  }
196  else{
197  if(n<=mobileAVG){
198  for(Int_t i=0; i<=n+mobileAVG; i++){ avg = avg + vec[i]; c1=c1+1;}
199  avg = avg/c1;
200  firstFilter[n] = avg;
201  avg = 0;
202  c1=0;
203  }
204  else if(n>=nComp-mobileAVG){
205  for(Int_t i=n-mobileAVG; i<nComp; i++) {avg = avg + vec[i]; c2=c2+1;}
206  avg = avg/c2;
207  firstFilter[n] = avg;
208  avg = 0;
209  c2=0;
210  }
211  }
212  }
213 
214  TV1D_denoise(firstFilter,secondFilter,nBins,10);
215 
216 
217 
218  return secondFilter;
219  }
220 
221  //####################################################################
222  // Denoise Function
223  //####################################################################
224 
225  void PDSNoiseFilter::TV1D_denoise(vector<float> input, vector<float>& secondFilter, const int width, const float lambda) {
226 
227  if (width>0) { /*to avoid invalid memory access to input[0]*/
228  int k=0, k0=0; /*k: current sample location, k0: beginning of current segment*/
229  float umin=lambda, umax=-lambda;/*u is the dual variable*/
230  float vmin=input[0]-lambda, vmax=input[0]+lambda;/*bounds for the segment's value*/
231  int kplus=0, kminus=0; /*last positions where umax=-lambda, umin=lambda, respectively*/
232  const float twolambda=2.0*lambda;/*auxiliary variable*/
233  const float minlambda=-lambda;/*auxiliary variable*/
234  for (;;) {/*simple loop, the exit test is inside*/
235  while (k==width-1) {/*we use the right boundary condition*/
236  if (umin<0.0) { /*vmin is too high -> negative jump necessary*/
237  do secondFilter[k0++]=vmin; while (k0<=kminus);
238  umax=(vmin=input[kminus=k=k0])+(umin=lambda)-vmax;
239  } else if (umax>0.0) { /*vmax is too low -> positive jump necessary*/
240  do secondFilter[k0++]=vmax; while (k0<=kplus);
241  umin=(vmax=input[kplus=k=k0])+(umax=minlambda)-vmin;
242  } else {
243  vmin+=umin/(k-k0+1);
244  do secondFilter[k0++]=vmin; while(k0<=k);
245  return;
246  }
247  }
248  if ((umin+=input[k+1]-vmin)<minlambda) {/*negative jump necessary*/
249  do secondFilter[k0++]=vmin; while (k0<=kminus);
250  vmax=(vmin=input[kplus=kminus=k=k0])+twolambda;
251  umin=lambda; umax=minlambda;
252  } else if ((umax+=input[k+1]-vmax)>lambda) {/*positive jump necessary*/
253  do secondFilter[k0++]=vmax; while (k0<=kplus);
254  vmin=(vmax=input[kplus=kminus=k=k0])-twolambda;
255  umin=lambda; umax=minlambda;
256  } else { /*no jump necessary, we continue*/
257  k++;
258  if (umin>=lambda) {/*update of vmin*/
259  vmin+=(umin-lambda)/((kminus=k)-k0+1);
260  umin=lambda;
261  }
262  if (umax<=minlambda) {/*update of vmax*/
263  vmax+=(umax+lambda)/((kplus=k)-k0+1);
264  umax=minlambda;
265  }
266  }
267 
268  }
269 
270  }
271 
272  }
274 }
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
fhicl::Sequence< string > InputLabels
struct vector vector
ChannelGroupService::Name Name
PDSNoiseFilter(Parameters const &config)
void TV1D_denoise(vector< float > input, vector< float > &secondFilter, const int width, const float lambda)
static int input(void)
Definition: code.cpp:15695
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
static Config * config
Definition: config.cpp:1054
std::void_t< T > n
def move(depos, offset)
Definition: depos.py:107
def convert(inputfile, outputfile="wire-cell-garfield-fine-response.json.bz2", average=False, shaped=False)
Definition: garfield.py:262
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
std::vector< float > filter(std::vector< short unsigned int > vec, Int_t nBins)
#define Comment
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
TCEvent evt
Definition: DataStructs.cxx:7