LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
WireCellNoiseFilter_module.cc
Go to the documentation of this file.
1 // Framework includes
3 
8 
12 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
13 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
14 #include "larevt/CalibrationDBI/Interface/DetPedestalProvider.h"
15 #include "larevt/CalibrationDBI/Interface/DetPedestalService.h"
16 #include "larevt/CalibrationDBI/Interface/ElectronicsCalibProvider.h"
17 #include "larevt/CalibrationDBI/Interface/ElectronicsCalibService.h"
18 
20 
21 #include "WireCellAux/DftTools.h"
22 #include "WireCellAux/SimpleFrame.h"
23 #include "WireCellAux/SimpleTrace.h"
24 #include "WireCellIface/IDFT.h"
25 #include "WireCellSigProc/Microboone.h"
26 #include "WireCellSigProc/OmnibusNoiseFilter.h"
27 #include "WireCellSigProc/SimpleChannelNoiseDB.h"
28 #include "WireCellUtil/NamedFactory.h"
29 #include "WireCellUtil/Units.h"
30 
31 #include <numeric> // iota
32 #include <string>
33 
34 using namespace WireCell;
35 using WireCell::Aux::SimpleFrame;
36 using WireCell::Aux::SimpleTrace;
37 using WireCell::Aux::DftTools::fwd_r2c;
38 
39 namespace noisefilteralg {
40 
42 
43  public:
44  explicit WireCellNoiseFilter(fhicl::ParameterSet const& pset);
45  virtual ~WireCellNoiseFilter();
46 
47  void produce(art::Event& evt);
48  void reconfigure(fhicl::ParameterSet const& pset);
49 
50  private:
51  void DoNoiseFilter(art::Event const& evt,
52  const std::vector<raw::RawDigit>&,
53  std::vector<raw::RawDigit>&) const;
54 
55  //******************************
56  //Variables Taken from FHICL File
57  IDFT::pointer m_dft; // revised FFT API
58  std::string fDigitModuleLabel; // label for rawdigit module
59  bool fDoNoiseFiltering; // Allows for a "pass through" mode
60  size_t fNumTicksToDropFront; // If we are truncating then this is non-zero
61  size_t fWindowSize; // Number of ticks in the output RawDigit
62 
63  // services
64  }; //end class Noise
65 
66  //-------------------------------------------------------------------
67  WireCellNoiseFilter::WireCellNoiseFilter(fhicl::ParameterSet const& pset) : EDProducer(pset)
68  {
69  this->reconfigure(pset);
70  produces<std::vector<raw::RawDigit>>();
71  }
72 
73  //-------------------------------------------------------------------
75 
76  //-------------------------------------------------------------------
78  {
79  auto dft_tn = pset.get<std::string>("dft", "FftwDFT");
80  m_dft = Factory::find_tn<IDFT>(dft_tn);
81  fDigitModuleLabel = pset.get<std::string>("DigitModuleLabel", "daq");
82  fDoNoiseFiltering = pset.get<bool>("DoNoiseFiltering", true);
83  fNumTicksToDropFront = pset.get<size_t>("NumTicksToDropFront", 2400);
84  fWindowSize = pset.get<size_t>("WindowSize", 6400);
85  }
86 
87  //-------------------------------------------------------------------
89  {
90  // Recover services we will need
91  const lariov::DetPedestalProvider& pedestalValues =
93 
95  evt.getByLabel(fDigitModuleLabel, rawDigitHandle);
96 
97  // Define the output vector (in case we don't do anything)
98  std::unique_ptr<std::vector<raw::RawDigit>> filteredRawDigit(new std::vector<raw::RawDigit>);
99 
100  if (rawDigitHandle.isValid() && rawDigitHandle->size() > 0) {
101  const std::vector<raw::RawDigit>& rawDigitVector(*rawDigitHandle);
102 
103  // Make sure we have the correct window size (e.g. window size = 9600 but data is 9595)
104  size_t windowSize(std::min(fWindowSize, rawDigitVector.at(0).NADC()));
105 
106  if (fNumTicksToDropFront + windowSize > rawDigitVector.at(0).NADC())
107  throw cet::exception("WireCellNoiseFilter")
108  << "Ticks to drop + windowsize larger than input buffer\n";
109 
110  if (fDoNoiseFiltering)
111  DoNoiseFilter(evt, rawDigitVector, *filteredRawDigit);
112  else {
113  // Enable truncation
114  size_t startBin(fNumTicksToDropFront);
115  size_t stopBin(startBin + windowSize);
116 
117  raw::RawDigit::ADCvector_t outputVector(windowSize);
118 
119  for (const auto& rawDigit : rawDigitVector) {
120  if (rawDigit.NADC() < windowSize) continue;
121 
122  const raw::RawDigit::ADCvector_t& rawAdcVec = rawDigit.ADCs();
123 
124  unsigned int channel = rawDigit.Channel();
125  float pedestal = pedestalValues.PedMean(channel);
126 
127  std::copy(
128  rawAdcVec.begin() + startBin, rawAdcVec.begin() + stopBin, outputVector.begin());
129 
130  filteredRawDigit->emplace_back(
131  raw::RawDigit(channel, outputVector.size(), outputVector, raw::kNone));
132  filteredRawDigit->back().SetPedestal(pedestal, 2.0);
133  }
134  }
135  }
136 
137  //filtered raw digits
138  evt.put(std::move(filteredRawDigit));
139  }
140 
142  const std::vector<raw::RawDigit>& inputWaveforms,
143  std::vector<raw::RawDigit>& outputWaveforms) const
144  {
145  auto const runNum = e.run();
146 
147  // Recover services we will need
148  const lariov::ChannelStatusProvider& channelStatus =
150  const lariov::DetPedestalProvider& pedestalValues =
152  const lariov::ElectronicsCalibProvider& elec_provider =
154  const geo::GeometryCore& geometry = *lar::providerFrom<geo::Geometry>();
155  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e);
156 
157  const unsigned int n_channels = inputWaveforms.size();
158 
159  // S&C microboone sampling parameter database
160  const double tick = sampling_rate(clock_data); // 0.5 * units::microsecond;
161  const size_t nsamples = inputWaveforms.at(0).NADC();
162  const size_t windowSize = std::min(fWindowSize, nsamples);
163 
164  // Q&D microboone channel map
165  geo::TPCID const tpcid{0, 0};
166  std::vector<int> uchans(geometry.Nwires({tpcid, 0})), vchans(geometry.Nwires({tpcid, 1})),
167  wchans(geometry.Nwires({tpcid, 2}));
168  const int nchans = uchans.size() + vchans.size() + wchans.size();
169  std::iota(uchans.begin(), uchans.end(), 0);
170  std::iota(vchans.begin(), vchans.end(), vchans.size());
171  std::iota(wchans.begin(), wchans.end(), vchans.size() + uchans.size());
172 
173  // Q&D nominal baseline
174  const double unombl = 2048.0, vnombl = 2048.0, wnombl = 400.0;
175 
176  // Q&D miss-configured channel database
177  std::vector<int> miscfgchan;
178  for (int channelIdx = 0; channelIdx < nchans; channelIdx++) {
179  if (elec_provider.ExtraInfo(channelIdx).GetBoolData("is_misconfigured")) {
180  miscfgchan.push_back(channelIdx);
181  }
182  }
183 
184  const double from_gain_mVfC = 4.7, to_gain_mVfC = 14.0, from_shaping = 1.0 * units::microsecond,
185  to_shaping = 2.0 * units::microsecond;
186 
187  // Recover bad channels from the database
188  std::vector<int> bad_channels;
189  for (int channelIdx = 0; channelIdx < nchans; channelIdx++)
190  if (channelStatus.IsBad(channelIdx)) bad_channels.push_back(channelIdx);
191 
192  // Q&D RC+RC time constant - all have same.
193  const double rcrc = 1.0 * units::millisecond;
194  std::vector<int> rcrcchans(nchans);
195  std::iota(rcrcchans.begin(), rcrcchans.end(), 0);
196 
197  //harmonic noises
198  std::vector<int> harmonicchans(uchans.size() + vchans.size());
199  std::iota(harmonicchans.begin(), harmonicchans.end(), 0);
200 
201  std::vector<int> special_chans;
202  special_chans.push_back(2240);
203 
204  WireCell::SigProc::SimpleChannelNoiseDB::mask_t h36kHz(0, 169, 173);
205  WireCell::SigProc::SimpleChannelNoiseDB::mask_t h108kHz(0, 513, 516);
206  WireCell::SigProc::SimpleChannelNoiseDB::mask_t hspkHz(0, 17, 19);
207  WireCell::SigProc::SimpleChannelNoiseDB::multimask_t hharmonic;
208  hharmonic.push_back(h36kHz);
209  hharmonic.push_back(h108kHz);
210  WireCell::SigProc::SimpleChannelNoiseDB::multimask_t hspecial;
211  hspecial.push_back(h36kHz);
212  hspecial.push_back(h108kHz);
213  hspecial.push_back(hspkHz);
214 
215  float u_resp_array[120] = {
216  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
217  0.0, 0.0, 0.0, 0.0, 0.364382, 0.387949,
218  0.411053, 0.433979, 0.456863, 0.479746, 0.502641, 0.52554,
219  0.548441, 0.57134, 0.591765, 0.609448, 0.626848, 0.644094,
220  0.661364, 0.678859, 0.695231, 0.710462, 0.726147, 0.742373,
221  0.761332, 0.783313, 0.806325, 0.830412, 0.857676, 0.888412,
222  0.920705, 0.954624, 0.990242, 1.02766, 1.06121, 1.09027,
223  1.12037, 1.15157, 1.18392, 1.21748, 1.25229, 1.28824,
224  1.32509, 1.36256, 1.40051, 1.43907, 1.47857, 1.51933,
225  1.56134, 1.60404, 1.72665, 1.94005, 2.16994, 2.42041,
226  2.69475, 3.07222, 3.67375, 4.60766, 5.91864, 7.30178,
227  8.3715, 8.94736, 8.93705, 8.40339, 7.2212, 5.76382,
228  3.8931, 1.07893, -3.52481, -11.4593, -20.4011, -29.1259,
229  -34.9544, -36.9358, -35.3303, -31.2068, -25.8614, -20.3613,
230  -15.3794, -11.2266, -7.96091, -5.50138, -3.71143, -2.44637,
231  -1.57662, -0.99733, -0.62554, -0.393562, -0.249715, -0.15914,
232  -0.100771, -0.062443, -0.037283, -0.0211508, -0.0112448, -0.00552085,
233  -0.00245133, -0.000957821, -0.000316912, -8.51679e-05, -2.21299e-05, -1.37496e-05,
234  -1.49806e-05, -1.36935e-05, -9.66758e-06, -5.20773e-06, -7.4787e-07, 3.71199e-06,
235  8.17184e-06, 1.26317e-05, 1.70916e-05, 2.15514e-05, 2.60113e-05, 3.04711e-05};
236  float v_resp_array[120] = {
237  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
238  0.0, 0.0, 0.0, 0.0, 0.0865303, 0.0925559,
239  0.0983619, 0.104068, 0.109739, 0.115403, 0.121068, 0.126735,
240  0.132403, 0.138072, 0.143739, 0.149408, 0.155085, 0.160791,
241  0.166565, 0.172454, 0.178514, 0.184795, 0.191341, 0.198192,
242  0.205382, 0.212944, 0.220905, 0.229292, 0.238129, 0.247441,
243  0.257256, 0.267601, 0.278502, 0.28999, 0.298745, 0.304378,
244  0.310105, 0.315921, 0.321818, 0.327796, 0.333852, 0.339967,
245  0.346098, 0.352169, 0.358103, 0.363859, 0.36945, 0.374915,
246  0.380261, 0.385401, 0.39016, 0.394378, 0.39804, 0.401394,
247  0.405145, 0.410714, 0.4205, 0.437951, 0.467841, 0.516042,
248  0.587738, 0.694157, 0.840763, 1.01966, 1.22894, 1.5612,
249  2.12348, 3.31455, 5.59355, 9.10709, 14.1756, 18.4603,
250  19.9517, 17.4166, 10.6683, 1.40656, -10.0638, -19.034,
251  -23.654, -24.0558, -21.4418, -17.3229, -12.9485, -9.08912,
252  -6.05941, -3.86946, -2.38669, -1.43678, -0.853335, -0.503951,
253  -0.296551, -0.173029, -0.0990099, -0.0547172, -0.0287882, -0.0142758,
254  -0.00661815, -0.00284757, -0.00115702, -0.000456456, -0.000183439, -8.04214e-05,
255  -4.20533e-05, -2.62903e-05, -1.64098e-05, -6.68039e-06, 3.04903e-06, 1.27784e-05,
256  2.25079e-05, 3.22373e-05, 4.19667e-05, 5.16961e-05, 6.14255e-05, 7.11549e-05};
257  WireCell::Waveform::realseq_t u_resp(nsamples);
258  WireCell::Waveform::realseq_t v_resp(nsamples);
259  for (int i = 0; i != 120; i++) {
260  u_resp.at(i) = u_resp_array[i];
261  v_resp.at(i) = v_resp_array[i];
262  }
263  // WireCell::Waveform::compseq_t u_resp_freq = WireCell::Waveform::dft(u_resp);
264  // WireCell::Waveform::compseq_t v_resp_freq = WireCell::Waveform::dft(v_resp);
265  WireCell::Waveform::compseq_t u_resp_freq = fwd_r2c(m_dft, u_resp);
266  WireCell::Waveform::compseq_t v_resp_freq = fwd_r2c(m_dft, v_resp);
267 
268  int uplane_time_shift = 79;
269  int vplane_time_shift = 82;
270 
271  // do the coherent subtraction
272  std::vector<std::vector<int>> channel_groups;
273  for (unsigned int i = 0; i != 172; i++) {
274  //for (int i=150;i!=151;i++){
275  std::vector<int> channel_group;
276  for (int j = 0; j != 48; j++) {
277  channel_group.push_back(i * 48 + j);
278  }
279  channel_groups.push_back(channel_group);
280  }
281 
282  auto noise = new WireCell::SigProc::SimpleChannelNoiseDB;
283  // initialize
284  noise->set_sampling(tick, nsamples);
285  // set nominal baseline
286  noise->set_nominal_baseline(uchans, unombl);
287  noise->set_nominal_baseline(vchans, vnombl);
288  noise->set_nominal_baseline(wchans, wnombl);
289 
290  noise->set_response(uchans, u_resp_freq);
291  noise->set_response(vchans, v_resp_freq);
292 
293  noise->set_response_offset(uchans, uplane_time_shift);
294  noise->set_response_offset(vchans, vplane_time_shift);
295 
296  noise->set_pad_window_front(uchans, 20);
297  noise->set_pad_window_back(uchans, 10);
298  noise->set_pad_window_front(vchans, 10);
299  noise->set_pad_window_back(vchans, 10);
300  noise->set_pad_window_front(wchans, 10);
301  noise->set_pad_window_back(wchans, 10);
302 
303  // set misconfigured channels
304  noise->set_gains_shapings(miscfgchan, from_gain_mVfC, to_gain_mVfC, from_shaping, to_shaping);
305  // do the RCRC
306  noise->set_rcrc_constant(rcrcchans, rcrc);
307  // set initial bad channels
308  noise->set_bad_channels(bad_channels);
309  // set the harmonic filter
310  noise->set_filter(harmonicchans, hharmonic);
311  noise->set_filter(special_chans, hspecial);
312  noise->set_channel_groups(channel_groups);
313 
314  for (unsigned int i = 0; i != uchans.size(); i++) {
315  if (uchans.at(i) < 100) {
316  noise->set_min_rms_cut_one(uchans.at(i), 1);
317  noise->set_max_rms_cut_one(uchans.at(i), 5);
318  }
319  else if (uchans.at(i) < 2000) {
320  noise->set_min_rms_cut_one(uchans.at(i), 1.9);
321  noise->set_max_rms_cut_one(uchans.at(i), 11);
322  }
323  else {
324  noise->set_min_rms_cut_one(uchans.at(i), 0.9);
325  noise->set_max_rms_cut_one(uchans.at(i), 5);
326  }
327  }
328  for (unsigned int i = 0; i != vchans.size(); i++) {
329  if (vchans.at(i) < 290 + (int)uchans.size()) {
330  noise->set_min_rms_cut_one(vchans.at(i), 1);
331  noise->set_max_rms_cut_one(vchans.at(i), 5);
332  }
333  else if (vchans.at(i) < 2200 + (int)uchans.size()) {
334  noise->set_min_rms_cut_one(vchans.at(i), 1.9);
335  noise->set_max_rms_cut_one(vchans.at(i), 11);
336  }
337  else {
338  noise->set_min_rms_cut_one(vchans.at(i), 1);
339  noise->set_max_rms_cut_one(vchans.at(i), 5);
340  }
341  }
342 
343  // these are the one after the Hardware Fix
344  if (runNum > 8000) {
345  for (unsigned int i = 0; i != uchans.size(); i++) {
346  if (uchans.at(i) < 600) {
347  noise->set_min_rms_cut_one(uchans.at(i), 1 + (1.7 - 1) / 600. * i);
348  noise->set_max_rms_cut_one(uchans.at(i), 5);
349  }
350  else if (uchans.at(i) < 1800) {
351  noise->set_min_rms_cut_one(uchans.at(i), 1.7);
352  noise->set_max_rms_cut_one(uchans.at(i), 11);
353  }
354  else {
355  noise->set_min_rms_cut_one(uchans.at(i), 1 + (1.7 - 1) / 600. * (2399 - i));
356  noise->set_max_rms_cut_one(uchans.at(i), 5);
357  }
358  }
359  for (unsigned int i = 0; i != vchans.size(); i++) {
360  if (vchans.at(i) < 600 + (int)uchans.size()) {
361  noise->set_min_rms_cut_one(vchans.at(i), 0.8 + (1.7 - 0.8) / 600. * i);
362  noise->set_max_rms_cut_one(vchans.at(i), 5);
363  }
364  else if (vchans.at(i) < 1800 + (int)uchans.size()) {
365  noise->set_min_rms_cut_one(vchans.at(i), 1.7);
366  noise->set_max_rms_cut_one(vchans.at(i), 11);
367  }
368  else {
369  noise->set_min_rms_cut_one(vchans.at(i), 0.8 + (1.7 - 0.8) / 600. * (2399 - i));
370  noise->set_max_rms_cut_one(vchans.at(i), 5);
371  }
372  }
373  }
374 
375  noise->set_min_rms_cut(wchans, 1.3);
376  noise->set_max_rms_cut(wchans, 8.0);
377 
378  //Define database object
379  std::shared_ptr<WireCell::IChannelNoiseDatabase> noise_sp(noise);
380 
381  auto one = new WireCell::SigProc::Microboone::OneChannelNoise;
382  one->set_channel_noisedb(noise_sp);
383  std::shared_ptr<WireCell::IChannelFilter> one_sp(one);
384  auto many = new WireCell::SigProc::Microboone::CoherentNoiseSub;
385  many->set_channel_noisedb(noise_sp);
386  std::shared_ptr<WireCell::IChannelFilter> many_sp(many);
387 
388  //define noisefilter object
389  WireCell::SigProc::OmnibusNoiseFilter bus;
390  bus.set_channel_filters({one_sp});
391  bus.set_grouped_filters({many_sp});
392  bus.set_channel_noisedb(noise_sp);
393 
394  // Enable truncation
395  size_t startBin(fNumTicksToDropFront);
396  size_t stopBin(startBin + windowSize);
397 
398  //load waveforms into traces
400  for (unsigned int ich = 0; ich < n_channels; ich++) {
401  if (inputWaveforms.at(ich).NADC() < windowSize) continue;
402 
403  const raw::RawDigit::ADCvector_t& rawAdcVec = inputWaveforms.at(ich).ADCs();
404 
405  WireCell::ITrace::ChargeSequence charges;
406 
407  charges.resize(nsamples);
408 
409  std::transform(rawAdcVec.begin(), rawAdcVec.end(), charges.begin(), [](auto& adcVal) {
410  return float(adcVal);
411  });
412 
413  unsigned int chan = inputWaveforms.at(ich).Channel();
414  SimpleTrace* st = new SimpleTrace(chan, 0.0, charges);
415  traces.push_back(WireCell::ITrace::pointer(st));
416  }
417 
418  //Load traces into frame
419  SimpleFrame* sf = new SimpleFrame(0, 0, traces);
420  WireCell::IFrame::pointer frame = WireCell::IFrame::pointer(sf);
421  WireCell::IFrame::pointer quiet = NULL;
422 
423  //Do filtering
424  bus(frame, quiet);
425 
426  //std::cout << "HERE" << std::endl;
427  //return;
428  if (quiet == NULL) return;
429 
430  //Output results
431  std::vector<short> waveform(windowSize);
432 
433  auto quiet_traces = quiet->traces();
434  for (auto quiet_trace : *quiet_traces.get()) {
435  //int tbin = quiet_trace->tbin();
436  unsigned int channel = quiet_trace->channel();
437 
438  auto& quiet_charges = quiet_trace->charge();
439 
440  // Recover the database version of the pedestal, we'll offset the waveforms so it matches
441  float pedestal = pedestalValues.PedMean(channel);
442 
443  std::transform(quiet_charges.begin() + startBin,
444  quiet_charges.begin() + stopBin,
445  waveform.begin(),
446  [pedestal](auto charge) { return std::round(charge + pedestal); });
447 
448  outputWaveforms.emplace_back(raw::RawDigit(channel, waveform.size(), waveform, raw::kNone));
449  outputWaveforms.back().SetPedestal(pedestal, 1.75);
450  }
451 
452  return;
453  }
454 
456 
457 } //end namespace WireCellNoiseFilteralg
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:68
microsecond_as<> microsecond
Type of time stored in microseconds, in double precision.
Definition: spacetime.h:116
void DoNoiseFilter(art::Event const &evt, const std::vector< raw::RawDigit > &, std::vector< raw::RawDigit > &) const
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
Definition: RawDigit.h:72
Definition of basic raw digits.
no compression
Definition: RawTypes.h:9
millisecond_as<> millisecond
Type of time stored in milliseconds, in double precision.
Definition: spacetime.h:99
unsigned int noise()
Definition: chem4.cc:261
bool isValid() const noexcept
Definition: Handle.h:203
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
T get(std::string const &key) const
Definition: ParameterSet.h:314
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:73
The data type to uniquely identify a TPC.
Definition: geo_types.h:381
Description of geometry of one entire detector.
Definition: GeometryCore.h:119
void reconfigure(fhicl::ParameterSet const &pset)
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
TCEvent evt
Definition: DataStructs.cxx:8
Float_t e
Definition: plot.C:35
RunNumber_t run() const
Definition: Event.cc:29
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33