PdspNoiseRemoval_tool.cc
Go to the documentation of this file.
1 // PdspNoiseRemoval_tool.cc
2 // Jingbo Wang (UC Davis)
3 // Email: jiowang@ucdavis.edu
4 // January 2019
5 
6 #include "PdspNoiseRemoval.h"
7 #include <iostream>
8 #include "lardataobj/RawData/raw.h"
16 using std::string;
17 using std::cout;
18 using std::endl;
19 
20 //**********************************************************************
21 // Local methods.
22 //**********************************************************************
23 
24 namespace {
25 
26 // David Adams
27 // December 2019
28 // Copy a waveform and pad for use with FFT.
29 // Check the output waveform size and abort with message if it is not valid.
30 // The abort messages assume that size was obtained from the FFT service.
31 void copyWaveform(const std::vector<float>& adc, std::vector<float>& ch_waveform) {
32  const string myname = "PdspNoiseRemoval::copyWaveform: ";
33  size_t n_samples = adc.size();
34  if ( ch_waveform.size() < adc.size() ) {
35  cout << myname << "ERROR: ADC size: " << n_samples << " > FFT size: " << ch_waveform.size() << endl;
36  cout << myname << "ERROR: Increase FFTSize in the LArFFT service" << endl;
37  abort();
38  }
39  if ( ch_waveform.size() > 2*adc.size() ) {
40  cout << myname << "ERROR: FFT size: " << ch_waveform.size() << " > 2*(ADC size: " << n_samples << ")" << endl;
41  cout << myname << "ERROR: Decrease FFTSize in the LArFFT service" << endl;
42  abort();
43  }
44  std::copy(adc.begin(), adc.end(), ch_waveform.begin());
45  for ( size_t s = n_samples; s < ch_waveform.size(); ++s ) {
46  ch_waveform[s] = ch_waveform[2*n_samples - s - 1];
47  }
48 }
49 
50 }
51 
52 //**********************************************************************
53 // Class methods.
54 //**********************************************************************
55 
57 : m_LogLevel(ps.get<int>("LogLevel")) {
58  const string myname = "PdspNoiseRemoval::ctor: ";
59 
60  fRemoveHighFrequency = ps.get<bool>("RemoveHighFrequency");
61  fRemoveCoherent = ps.get<bool>("RemoveCoherent");
62  fCutoffFrequency = ps.get<float>("CutoffFrequency");
63  fCoherentOffline16 = ps.get<bool>("CoherentOffline16");
64  fCoherentDaq8 = ps.get<bool>("CoherentDaq8");
65  fCoherentDaq16 = ps.get<bool>("CoherentDaq16");
66  fCoherentFEMB128 = ps.get<bool>("CoherentFEMB128");
67  fCoherentOffline16Groups = ps.get<std::vector<size_t>>("CoherentOffline16Groups");
68  fCoherentDaq8Groups = ps.get<std::vector<size_t>>("CoherentDaq8Groups");
69  fCoherentDaq16Groups = ps.get<std::vector<size_t>>("CoherentDaq16Groups");
70  fCoherentFEMB128Groups = ps.get<std::vector<size_t>>("CoherentFEMB128Groups");
71  fUseBasicROIForCNR = ps.get<bool>("UseBasicROIForCNR");
72  fRoiStartThreshold = ps.get<float>("RoiStartThreshold");
73  fRoiEndThreshold = ps.get<float>("RoiEndThreshold");
74  fRoiPadLow = ps.get<int>("RoiPadLow");
75  fRoiPadHigh = ps.get<int>("RoiPadHigh");
76 
79  if(ps.get<std::string>("CorrMode") == "mean") { fMode = 1; }
80  else if(ps.get<std::string>("CorrMode") == "median") { fMode = 2; }
81  else {
82  std::cout << "PdspNoiseRemoval WARNING: correction set to mean value." << std::endl;
83  fMode = 1;
84  }
85  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
86  double binWidth = 1.0/(fFFT->FFTSize()*sampling_rate(clockData)*1.0e-6);
87  fLowPassCoeffs.resize(fFFT->FFTSize() / 2 + 1);
88  for(size_t i = 0; i < fLowPassCoeffs.size(); ++i) {
89  float f = binWidth * i;
90  fLowPassCoeffs[i] = 1.0 / sqrt(1.0 + pow(f/fCutoffFrequency, 8));
91  }
92 
93  if( m_LogLevel >= 1 ) {
94  cout << myname << " LogLevel: " << m_LogLevel << endl;
95  cout << myname << " RemoveHighFrequency: " << fRemoveHighFrequency << endl;
96  cout << myname << " RemoveCoherent: " << fRemoveCoherent << endl;
97  cout << myname << " CutoffFrequency: " << fCutoffFrequency << endl;
98  cout << myname << " CoherentOffline16: " << fCoherentOffline16 << endl;
99  cout << myname << " CoherentDaq8: " << fCoherentDaq8 << endl;
100  cout << myname << " CoherentDaq16: " << fCoherentDaq16 << endl;
101  cout << myname << " CoherentFEMB128: " << fCoherentFEMB128 << endl;
102  cout << myname << "CoherentOffline16Groups: [";
103  for(size_t i=0; i<fCoherentOffline16Groups.size(); i++) {
104  cout<< fCoherentOffline16Groups.at(i) <<", ";
105  }
106  cout << " ]" << endl;
107  cout << myname << "CoherentDaq8Groups: [";
108  for(size_t i=0; i<fCoherentDaq8Groups.size(); i++) {
109  cout<< fCoherentDaq8Groups.at(i) <<", ";
110  }
111  cout << " ]" << endl;
112  cout << myname << "CoherentDaq16Groups: [";
113  for(size_t i=0; i<fCoherentDaq16Groups.size(); i++) {
114  cout<< fCoherentDaq16Groups.at(i) <<", ";
115  }
116  cout << " ]" << endl;
117  cout << myname << "CoherentFEMB128Groups: [";
118  for(size_t i=0; i<fCoherentFEMB128Groups.size(); i++) {
119  cout<< fCoherentFEMB128Groups.at(i) <<", ";
120  }
121  cout << " ]" << endl;
122  cout << myname << " UseBasicROIForCNR: " << fUseBasicROIForCNR << endl;
123  cout << myname << " RoiStartThreshold: " << fRoiStartThreshold << endl;
124  cout << myname << " RoiEndThreshold: " << fRoiEndThreshold << endl;
125  cout << myname << " RoiPadLow: " << fRoiPadLow << endl;
126  cout << myname << " RoiPadHigh: " << fRoiPadHigh << endl;
127  }
128 }
129 
130 //**********************************************************************
132  const string myname = "PdspNoiseRemoval::updateMap: ";
133  if( updateWithView() ) return viewMap(acds);
134  DataMap ret(0);
135  if (acds.size() == 0) {
136  std::cout << myname << "WARNING: No channels found." << std::endl;
137  ret.setStatus(1);
138  return ret;
139  }
140 
142  removeHighFreq(acds);
143  }
144  if(fRemoveCoherent) {
145  if(fCoherentOffline16) {
147  removeCoherent(ch_groups, acds);
148  }
149  if(fCoherentFEMB128) {
150  auto ch_groups = makeGroupsByFEMBPlaneType(128, fCoherentFEMB128Groups);
151  removeCoherent(ch_groups, acds);
152  }
153  if(fCoherentDaq16) {
154  auto ch_groups = makeGroupsByDAQChannels(16, fCoherentDaq16Groups);
155  removeCoherent(ch_groups, acds);
156  }
157  if(fCoherentDaq8) {
158  auto ch_groups = makeGroupsByDAQChannels(8, fCoherentDaq8Groups);
159  removeCoherent(ch_groups, acds);
160  }
161  }
162  ret.setStatus(0);
163  return ret;
164 }
165 
166 //**********************************************************************
168 {
169  auto const & chStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
170  for(auto & entry : datamap) {
171  if ( chStatus.IsPresent(entry.first) && !chStatus.IsNoisy(entry.first) && entry.second.samples.size() ) {
172  fftFltInPlace(entry.second.samples, fLowPassCoeffs);
173  }
174  }
175 }
176 
177 //**********************************************************************
178 void PdspNoiseRemoval::fftFltInPlace(std::vector< float > & adc, const std::vector< float > & coeffs) const {
179  const string myname = "PdspNoiseRemoval::fftFltInPlace: ";
180  std::vector< TComplex > ch_spectrum(fFFT->FFTSize() / 2 + 1);
181  std::vector< float > ch_waveform(fFFT->FFTSize(), 0);
182  size_t n_samples = adc.size();
183  if ( m_LogLevel >= 3 ) cout << myname << "N_ADC = " << adc.size() << ", N_WF = " << ch_waveform.size() << endl;
184  copyWaveform(adc, ch_waveform);
185  fFFT->DoFFT(ch_waveform, ch_spectrum);
186  for(size_t c = 0; c < coeffs.size(); ++c) {
187  ch_spectrum[c] *= coeffs[c];
188  }
189  fFFT->DoInvFFT(ch_spectrum, ch_waveform);
190  std::copy(ch_waveform.begin(), ch_waveform.begin()+n_samples, adc.begin());
191 }
192 
193 //**********************************************************************
194 std::vector< float > PdspNoiseRemoval::fftFlt(const std::vector< float > & adc, const std::vector< float > & coeffs) const {
195  std::vector< TComplex > ch_spectrum(fFFT->FFTSize() / 2 + 1);
196  std::vector< float > ch_waveform(fFFT->FFTSize(), 0);
197  size_t n_samples = adc.size();
198  copyWaveform(adc, ch_waveform);
199  fFFT->DoFFT(ch_waveform, ch_spectrum);
200  for(size_t c = 0; c < coeffs.size(); ++c) {
201  ch_spectrum[c] *= coeffs[c];
202  }
203  fFFT->DoInvFFT(ch_spectrum, ch_waveform);
204  std::vector< float > flt_adc(n_samples);
205  std::copy(ch_waveform.begin(), ch_waveform.begin()+n_samples, flt_adc.begin());
206  return flt_adc;
207 }
208 
209 //**********************************************************************
210 GroupChannelMap PdspNoiseRemoval::makeGroupsByOfflineChannels(size_t gsize, const std::vector< size_t > & gidx) const {
211  GroupChannelMap groups;
212  auto const & chStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
213  const unsigned int nchan = fGeometry->Nchannels();
214  for(unsigned int ch = 0; ch < nchan; ++ch) {
215  size_t g = ch / gsize;
216  if(gidx.empty() || has(gidx, g)) {
217  if(chStatus.IsPresent(ch) && !chStatus.IsBad(ch) && !chStatus.IsNoisy(ch)) { groups[g].push_back(ch); }
218  }
219  }
220  return groups;
221 }
222 
223 //**********************************************************************
224 GroupChannelMap PdspNoiseRemoval::makeGroupsByDAQChannels(size_t gsize, const std::vector< size_t > & gidx) const {
225  GroupChannelMap groups;
226  auto const & chStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
227  const unsigned int nchan = fGeometry->Nchannels();
228  for(unsigned int ch = 0; ch < nchan; ++ch) {
229  size_t g = getDAQChan(ch) / gsize;
230  if(gidx.empty() || has(gidx, g)) {
231  if(chStatus.IsPresent(ch) && !chStatus.IsBad(ch) && !chStatus.IsNoisy(ch)) {
232  groups[g].push_back(ch);
233  }
234  }
235  }
236  return groups;
237 }
238 
239 //**********************************************************************
240 GroupChannelMap PdspNoiseRemoval::makeGroupsByFEMBPlaneType(size_t gsize, const std::vector< size_t > & gidx) const {
241  // Get channel map
243  GroupChannelMap groups;
244  auto const & chStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
245  const unsigned int nchan = fGeometry->Nchannels();
246  for(unsigned int ch = 0; ch < nchan; ++ch) {
247  //size_t g = ch / gsize;
248  size_t g = getDAQChan(ch) / gsize;
249  size_t plane = channelMap->PlaneFromOfflineChannel(ch);
250  if(gidx.empty() || has(gidx, g) ) {
251  if(chStatus.IsPresent(ch) && !chStatus.IsBad(ch) && !chStatus.IsNoisy(ch)) {
252  switch (plane) {
253  case 0: groups[3*g].push_back(ch);
254  break;
255  case 1: groups[3*g+1].push_back(ch);
256  break;
257  case 2: groups[3*g+2].push_back(ch);
258  break;
259  }
260  }
261  }
262  }
263  return groups;
264 }
265 
266 //**********************************************************************
267 void PdspNoiseRemoval::removeCoherent(const GroupChannelMap & ch_groups, AdcChannelDataMap& datamap) const {
268  if(datamap.empty()) return;
269  //PdspNoiseRemoval *th = const_cast <PdspNoiseRemoval *> (this);
270  //size_t n_samples = datamap.begin()->second.samples.size();
271  for(const auto & entry : ch_groups) {
272  const auto & channels = entry.second;
273  std::vector<float> correction;
274  if(fMode == 1) { // mean
275  correction = getMeanCorrection(channels, datamap);
276  }
277  else if(fMode == 2) { // median
278  correction = getMedianCorrection(channels, datamap);
279  }
280  for(unsigned int ch : channels) {
281  auto iacd = datamap.find(ch);
282  if(iacd == datamap.end()) continue;
283  AdcChannelData & acd = iacd->second;
284  if(acd.samples.size() == 0) continue;
285  if(acd.samples.size() > correction.size()) correction.resize(acd.samples.size(), 0.);
286  for(size_t s = 0; s < acd.samples.size(); ++s) {
287  acd.samples[s] -= correction[s];
288  }
289  }
290  }
291 }
292 
293 //**********************************************************************
294 std::vector<float> PdspNoiseRemoval::getMeanCorrection( const std::vector<unsigned int> & channels, const AdcChannelDataMap & datamap) const {
295  size_t n_samples = datamap.begin()->second.samples.size();
296  std::vector<size_t> ch_averaged(n_samples, 0);
297  std::vector<float> correction(n_samples, 0);
298  for(unsigned int ch : channels) {
299  auto iacd = datamap.find(ch);
300  if(iacd == datamap.end()) continue;
301  const AdcChannelData & acd = iacd->second;
302  if(acd.samples.size()>n_samples) {
303  ch_averaged.resize(acd.samples.size(), 0.);
304  correction.resize(acd.samples.size(), 0.);
305  }
306  if(fUseBasicROIForCNR) {
307  auto mask = roiMask(acd);
308  for(size_t s = 0; s < acd.samples.size(); ++s) {
309  if (!mask[s]) { continue; }
310  AdcFlag flag = (acd.flags.size()!=0 && s<acd.flags.size()) ? acd.flags[s] : AdcGood;
311  if(flag != AdcGood) { continue; }
312  correction[s] += acd.samples[s];
313  ch_averaged[s]++;
314  }
315  }
316  else {
317  for(size_t s = 0; s < acd.samples.size(); ++s) {
318  if(acd.signal[s]) { continue; }
319  AdcFlag flag = (acd.flags.size()!=0 && s<acd.flags.size()) ? acd.flags[s] : AdcGood;
320  if(flag != AdcGood) { continue; }
321  correction[s] += acd.samples[s];
322  ch_averaged[s]++;
323  }
324  }
325  }
326  for(size_t s = 0; s < correction.size(); ++s) {
327  if(ch_averaged[s] > 0) {
328  correction[s] /= ch_averaged[s];
329  }
330  }
331  return correction;
332 }
333 std::vector<float> PdspNoiseRemoval::getMedianCorrection( const std::vector<unsigned int> & channels, const AdcChannelDataMap & datamap) const {
334  size_t n_samples = datamap.begin()->second.samples.size();
335  std::vector< std::vector<float> > samples(n_samples);
336  for(unsigned int ch : channels) {
337  auto iacd = datamap.find(ch);
338  if(iacd == datamap.end()) continue;
339  const AdcChannelData & acd = iacd->second;
340  if(acd.samples.size()>n_samples) samples.resize(acd.samples.size());
341  if(fUseBasicROIForCNR) {
342  auto mask = roiMask(acd);
343  for(size_t s = 0; s < acd.samples.size(); ++s) {
344  if (!mask[s]) { continue; }
345  AdcFlag flag = (acd.flags.size()!=0 && s<acd.flags.size()) ? acd.flags[s] : AdcGood;
346  if(flag != AdcGood) { continue; }
347  samples[s].push_back(acd.samples[s]);
348  }
349  }
350  else {
351  for(size_t s = 0; s < acd.samples.size(); ++s) {
352  if(acd.signal[s]) { continue; }
353  AdcFlag flag = (acd.flags.size()!=0 && s<acd.flags.size()) ? acd.flags[s] : AdcGood;
354  if(flag != AdcGood) { continue; }
355  samples[s].push_back(acd.samples[s]);
356  }
357  }
358  }
359  std::vector<float> correction(samples.size());
360  for(size_t s = 0; s < samples.size(); ++s) {
361  size_t n = samples[s].size();
362  if(n < 2) { correction[s] = 0; continue; }
363  std::sort(samples[s].begin(), samples[s].end());
364  if((n % 2) == 0) { correction[s] = 0.5 * (samples[s][n/2] + samples[s][(n/2)-1]); }
365  else { correction[s] = samples[s][(n-1)/2]; }
366  }
367  return correction;
368 }
369 
370 //**********************************************************************
371 std::vector<bool> PdspNoiseRemoval::roiMask(const AdcChannelData & acd) const {
372  std::vector<bool> mask(acd.samples.size(), true);
373  if ( acd.samples.size() == 0 ) return mask;
374  auto acd_flt = fftFlt(acd.samples, fLowPassCoeffs);
375  bool inroi = false;
376  for (int i = 0; i < (int)acd_flt.size(); ++i) {
377  auto sig = acd_flt[i];
378  if (inroi){
379  if (sig > fRoiEndThreshold || sig < -1.0*fRoiEndThreshold) { mask[i] = false; }
380  else {
381  for (int p = 0; p <= fRoiPadHigh; ++p) { if ((i + p) < (int)mask.size()) { mask[i + p] = false; } }
382  inroi = false;
383  }
384  }
385  else {
386  if (sig > fRoiStartThreshold || sig < -1.0*fRoiStartThreshold) {
387  for (int p = fRoiPadLow; p >= 0; --p) { if (i - p >= 0) { mask[i - p] = false; } }
388  inroi = true;
389  }
390  }
391  }
392  return mask;
393 }
394 
395 //**********************************************************************
396 size_t PdspNoiseRemoval::getDAQChan(size_t LAr_chan) {
397  // Get channel map
399  size_t apa = channelMap->APAFromOfflineChannel(LAr_chan);
400  size_t wib = channelMap->WIBFromOfflineChannel(LAr_chan);
401  size_t femb = channelMap->FEMBFromOfflineChannel(LAr_chan);
402  size_t fembChan = channelMap->FEMBChannelFromOfflineChannel(LAr_chan);
403  size_t DaqChan = 2560*apa + 512* wib + 128* femb + fembChan; //does not depend on RCE or FELIX
404  return DaqChan;
405 }
406 //**********************************************************************
407 
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
std::vector< size_t > fCoherentDaq16Groups
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
QList< Entry > entry
const geo::Geometry * fGeometry
static constexpr double g
Definition: Units.h:144
short AdcFlag
Definition: AdcTypes.h:29
unsigned int FEMBChannelFromOfflineChannel(unsigned int offlineChannel) const
Returns FEMB channel.
void removeCoherent(const GroupChannelMap &ch_groups, AdcChannelDataMap &datamap) const
DataMap & setStatus(int stat)
Definition: DataMap.h:130
std::string string
Definition: nybbler.cc:12
virtual DataMap viewMap(const AdcChannelDataMap &acds) const
std::vector< size_t > fCoherentFEMB128Groups
constexpr T pow(T x)
Definition: pow.h:72
util::LArFFT * fFFT
std::vector< float > getMedianCorrection(const std::vector< unsigned int > &channels, const AdcChannelDataMap &datamap) const
std::vector< bool > roiMask(const AdcChannelData &adc) const
int16_t adc
Definition: CRTFragment.hh:202
void DoFFT(std::vector< T > &input, std::vector< TComplex > &output)
Definition: LArFFT.h:98
void removeHighFreq(AdcChannelDataMap &datamap) const
std::vector< float > fftFlt(const std::vector< float > &adc, const std::vector< float > &coeffs) const
art framework interface to geometry description
const AdcFlag AdcGood
Definition: AdcTypes.h:32
unsigned int APAFromOfflineChannel(unsigned int offlineChannel) const
Returns APA/crate.
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:120
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
QCollection::Item first()
Definition: qglist.cpp:807
GroupChannelMap makeGroupsByOfflineChannels(size_t gsize, const std::vector< size_t > &gidx) const
void fftFltInPlace(std::vector< float > &adc, const std::vector< float > &coeffs) const
int FFTSize() const
Definition: LArFFT.h:69
bool has(const std::vector< size_t > &v, size_t idx) const
std::void_t< T > n
T get(std::string const &key) const
Definition: ParameterSet.h:271
GroupChannelMap makeGroupsByFEMBPlaneType(size_t gsize, const std::vector< size_t > &gidx) const
p
Definition: test.py:223
std::vector< float > fLowPassCoeffs
static constexpr double ps
Definition: Units.h:99
unsigned int PlaneFromOfflineChannel(unsigned int offlineChannel) const
Returns plane.
virtual bool updateWithView() const
unsigned int WIBFromOfflineChannel(unsigned int offlineChannel) const
Returns WIB/slot.
std::unordered_map< unsigned int, std::vector< unsigned int > > GroupChannelMap
AdcFilterVector signal
DataMap updateMap(AdcChannelDataMap &acds) const override
GroupChannelMap makeGroupsByDAQChannels(size_t gsize, const std::vector< size_t > &gidx) const
std::vector< size_t > fCoherentOffline16Groups
Interface for experiment-specific channel quality info provider.
unsigned int FEMBFromOfflineChannel(unsigned int offlineChannel) const
Returns FEMB/fiber.
T copy(T const &v)
PdspNoiseRemoval(fhicl::ParameterSet const &ps)
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
std::vector< size_t > fCoherentDaq8Groups
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
Interface for experiment-specific service for channel quality info.
static size_t getDAQChan(size_t LAr_chan)
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
std::vector< float > getMeanCorrection(const std::vector< unsigned int > &channels, const AdcChannelDataMap &datamap) const
static QCString * s
Definition: config.cpp:1042
AdcSignalVector samples
QTextStream & endl(QTextStream &s)
AdcFlagVector flags