Belle II Software  release-08-01-10
TimeDigitizer.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <top/modules/TOPDigitizer/TimeDigitizer.h>
10 #include <top/geometry/TOPGeometryPar.h>
11 #include <mdst/dataobjects/MCParticle.h>
12 #include <framework/logging/Logger.h>
13 #include <TRandom.h>
14 
15 using namespace std;
16 
17 namespace Belle2 {
22  namespace TOP {
23 
24  unsigned TimeDigitizer::s_storageDepth = 0;
25  unsigned TimeDigitizer::s_readoutWindows = 0;
26  int TimeDigitizer::s_offsetWindows = 0;
27  unsigned TimeDigitizer::s_window = 0;
28  bool TimeDigitizer::s_maskSamples = false;
29  DBObjPtr<TOPCalTimeWalk>* TimeDigitizer::s_timeWalk = 0;
30 
31  TimeDigitizer::TimeDigitizer(int moduleID, int pixelID, double timeOffset,
32  double calErrorsSq, int shift, double rmsNoise,
33  const TOPSampleTimes& sampleTimes):
34  m_moduleID(moduleID), m_pixelID(pixelID), m_timeOffset(timeOffset),
35  m_calErrorsSq(calErrorsSq), m_rmsNoise(rmsNoise), m_sampleTimes(&sampleTimes),
36  m_windowShift(shift)
37  {
38  const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
39  m_channel = channelMapper.getChannel(pixelID);
40  if (!channelMapper.isChannelValid(m_channel)) {
41  B2ERROR("TimeDigitizer::TimeDigitizer: invalid channel");
42  return;
43  }
44 
45  unsigned bs = 0;
46  channelMapper.splitChannelNumber(m_channel, bs, m_carrier, m_asic, m_chan);
47 
48  const auto& frontEndMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
49  const auto* map = frontEndMapper.getMap(m_moduleID, bs);
50  if (!map) {
51  B2ERROR("TimeDigitizer::TimeDigitizer: no valid frontend map found");
52  return;
53  }
54 
55  m_scrodID = map->getScrodID();
56  m_valid = true;
57 
58  }
59 
60  void TimeDigitizer::addTimeOfHit(double t, double pulseHeight, EType type,
61  const TOPSimHit* simHit)
62  {
63  Hit hit;
64  hit.pulseHeight = pulseHeight;
65  hit.type = type;
66  hit.simHit = simHit;
67  switch (type) {
68  case static_cast<int>(c_Hit):
70  break;
71  case static_cast<int>(c_ChargeShare):
73  break;
74  case static_cast<int>(c_CrossTalk):
75  hit.shape = 0;
76  B2ERROR("TOP::TimeDigitizer: waveform shape of cross-talk not yet available");
77  break;
78  case static_cast<int>(c_CalPulse):
80  break;
81  default:
82  hit.shape = 0;
83  }
84  m_times.insert(std::pair<double, const Hit>(t, hit));
85  }
86 
87  //-------- simplified pile-up and double-hit-resolution model ------- //
88  // this function will probably be removed in the future, therefore I don't
89  // care about some hard-coded values
90 
91  typedef std::multimap<double, const TimeDigitizer::Hit>::const_iterator Iterator;
92 
94  StoreArray<TOPDigit>& digits,
95  int threshold,
96  int thresholdCount,
97  double timeJitter) const
98  {
99 
100  if (m_times.empty()) return;
101 
102  // get parameters of the model
103  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
104  const auto& tdc = geo->getNominalTDC();
105  double hitResolveTime = tdc.getDoubleHitResolution();
106  double pileupTime = tdc.getPileupTime();
107 
108  // split time pattern into multiple hits (according to double-hit resolution)
109  std::vector<Iterator> ranges;
110  ranges.push_back(m_times.begin());
111  double prevTime = m_times.begin()->first;
112  for (Iterator it = m_times.begin(); it != m_times.end(); ++it) {
113  if (it->first - prevTime > hitResolveTime) ranges.push_back(it);
114  prevTime = it->first;
115  }
116  ranges.push_back(m_times.end());
117 
118  // loop over splitted regions
119  for (unsigned k = 0; k < ranges.size() - 1; k++) {
120 
121  // temporary containers
122  std::vector<double> times;
123  std::vector<double> weights;
124  std::vector<const TOPSimHit*> simHits;
125 
126  // take only hits within pileup time and discard others
127  prevTime = ranges[k]->first;
128  for (Iterator it = ranges[k]; it != ranges[k + 1]; ++it) {
129  if (it->first - prevTime > pileupTime) break;
130  times.push_back(it->first);
131  double pulseHeight = gRandom->Gaus(it->second.pulseHeight, m_rmsNoise);
132  weights.push_back(pulseHeight);
133  simHits.push_back(it->second.simHit);
134  prevTime = it->first;
135  }
136 
137  // determine pulse height
138  double height = 0;
139  for (const auto& weight : weights) height += weight;
140 
141  // set weights
142  for (auto& weight : weights) weight /= height;
143 
144  // generate pulse width
145  double width = gRandom->Gaus(2.3, 0.4);
146  if (width < 0.5) width = 0.5;
147 
148  // determine detection time
149  double time = 0;
150  for (unsigned j = 0; j < times.size(); j++) time += times[j] * weights[j];
151 
152  // add additional time jitter
153  if (timeJitter > 0) time += gRandom->Gaus(0., timeJitter);
154 
155  // emulate feature extraction data
156 
157  double mean = time + width / 2;
158  double sigma = width / 2.35482;
159 
160  int samplePeak = tdc.getSample(mean);
161  if (mean - tdc.getSampleTime(samplePeak) > tdc.getSampleWidth() / 2) samplePeak++;
162  short vPeak = height * gauss(tdc.getSampleTime(samplePeak), mean, sigma);
163  if (vPeak < threshold) continue;
164  if (vPeak > 3000) vPeak = 3000; // saturation - roughly (e.g. 4096 - pedestal)
165 
166  double halfWid = sigma * sqrt(-2 * log(0.5 * vPeak / height));
167  int sampleRise = tdc.getSample(mean - halfWid);
168  if (!tdc.isSampleValid(sampleRise)) continue;
169  short vRise0 = height * gauss(tdc.getSampleTime(sampleRise), mean, sigma);
170  short vRise1 = height * gauss(tdc.getSampleTime(sampleRise + 1), mean, sigma);
171 
172  int sampleFall = tdc.getSample(mean + halfWid);
173  if (!tdc.isSampleValid(sampleFall + 1)) continue;
174  short vFall0 = height * gauss(tdc.getSampleTime(sampleFall), mean, sigma);
175  short vFall1 = height * gauss(tdc.getSampleTime(sampleFall + 1), mean, sigma);
176 
177  if (threshold > 0) {
178  double halfDt = sigma * sqrt(-2 * log(threshold / height));
179  int overThr = tdc.getSample(mean + halfDt) - tdc.getSample(mean - halfDt);
180  if (overThr < thresholdCount) continue;
181  }
182 
183  // determine integral
184  int numSamples = (sampleFall - sampleRise) * 4; // according to topcaf
185  double sigmaIntegral = 0;
186  if (numSamples > 1) sigmaIntegral = m_rmsNoise * sqrt(numSamples - 1);
187  double integral = gRandom->Gaus(height * 7.0, sigmaIntegral);
188 
189  // append new raw digit
190  auto* rawDigit = rawDigits.appendNew(m_scrodID, TOPRawDigit::c_MC);
191  rawDigit->setCarrierNumber(m_carrier);
192  rawDigit->setASICNumber(m_asic);
193  rawDigit->setASICChannel(m_chan);
194  rawDigit->setASICWindow(s_window);
195  rawDigit->setSampleRise(sampleRise);
196  rawDigit->setDeltaSamplePeak(samplePeak - sampleRise);
197  rawDigit->setDeltaSampleFall(sampleFall - sampleRise);
198  rawDigit->setValueRise0(vRise0);
199  rawDigit->setValueRise1(vRise1);
200  rawDigit->setValueFall0(vFall0);
201  rawDigit->setValueFall1(vFall1);
202  rawDigit->setValuePeak(vPeak);
203  rawDigit->setIntegral(integral);
204 
205  double rawTime = rawDigit->getCFDLeadingTime();
206  double cfdTime = rawTime * tdc.getSampleWidth() - tdc.getOffset();
207  double cfdWidth = rawDigit->getFWHM() * tdc.getSampleWidth();
208  int sampleDivisions = 0x1 << tdc.getSubBits();
209  int tfine = int(rawTime * sampleDivisions) % sampleDivisions;
210  if (tfine < 0) tfine += sampleDivisions;
211  rawDigit->setTFine(tfine);
212 
213  // append new digit
214 
215  auto* digit = digits.appendNew(m_moduleID, m_pixelID, rawTime);
216  digit->setTime(cfdTime);
217  digit->setTimeError(timeJitter);
218  digit->setPulseHeight(rawDigit->getValuePeak());
219  digit->setIntegral(rawDigit->getIntegral());
220  digit->setPulseWidth(cfdWidth);
221  digit->setChannel(m_channel);
222  digit->setFirstWindow(rawDigit->getASICWindow());
223  digit->setStatus(TOPDigit::c_OffsetSubtracted);
224  if (m_sampleTimes->isCalibrated()) {
225  digit->addStatus(TOPDigit::c_TimeBaseCalibrated);
226  }
227  digit->addRelationTo(rawDigit);
228 
229  // set relations to simulated hits and MC particles
230 
231  std::map<MCParticle*, double> relatedMCParticles;
232  for (unsigned j = 0; j < simHits.size(); j++) {
233  const auto* simHit = simHits[j];
234  const double& weight = weights[j];
235  if (simHit) {
236  digit->addRelationTo(simHit, weight);
237  RelationVector<MCParticle> particles = simHit->getRelationsFrom<MCParticle>();
238  for (unsigned i = 0; i < particles.size(); ++i) {
239  relatedMCParticles[particles[i]] += particles.weight(i) * weight;
240  }
241  }
242  }
243  for (const auto& x : relatedMCParticles) digit->addRelationTo(x.first, x.second);
244 
245  } // end loop over splitted regions
246  }
247 
248 
249  // -------- full waveform digitization ------- //
250 
252  StoreArray<TOPRawDigit>& rawDigits,
253  StoreArray<TOPDigit>& digits,
254  int threshold,
255  int hysteresis,
256  int thresholdCount) const
257  {
258 
259  // get parameters of the model
260 
261  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
262  const auto& tdc = geo->getNominalTDC();
263 
264  // generate waveform
265 
266  std::vector<unsigned short> windowNumbers;
267  int offsetWindows = s_offsetWindows + m_windowShift;
268  int winnum = s_window + offsetWindows;
269  if (winnum < 0) winnum += s_storageDepth;
270  windowNumbers.push_back(winnum % s_storageDepth);
271  for (unsigned i = 1; i < s_readoutWindows; i++) {
272  windowNumbers.push_back((windowNumbers.back() + 1) % s_storageDepth);
273  }
274  std::vector<double> baselines(windowNumbers.size(), 0);
275  std::vector<double> rmsNoises(windowNumbers.size(), m_rmsNoise);
276  double averagePedestal = tdc.getAveragePedestal();
277  std::vector<double> pedestals(windowNumbers.size(), averagePedestal);
278  int adcRange = tdc.getADCRange();
279 
280  int startSample = -offsetWindows * TOPRawWaveform::c_WindowSize;
281  auto wfData = generateWaveform(startSample, baselines, rmsNoises, pedestals,
282  adcRange);
283 
284  // store waveform
285 
286  auto* waveform = waveforms.appendNew(m_moduleID, m_pixelID, m_channel, m_scrodID,
287  windowNumbers[0], 0, wfData);
288  waveform->setStorageWindows(windowNumbers);
289  waveform->setPedestalSubtractedFlag(true);
290 
291  // do feature extraction
292 
293  waveform->featureExtraction(threshold, hysteresis, thresholdCount);
294 
295  // digits
296 
297  for (const auto& feature : waveform->getFeatureExtractionData()) {
298  int sampleRise = feature.sampleRise;
299  if (sampleRise < 0) continue;
300  unsigned iwin = sampleRise / TOPRawWaveform::c_WindowSize;
301  if (iwin >= windowNumbers.size()) continue;
302  sampleRise -= iwin * TOPRawWaveform::c_WindowSize; // should fit raw data bits
303  if (s_maskSamples and (sampleRise % 64) > 55) continue;
304 
305  unsigned DsamplePeak = feature.samplePeak - feature.sampleRise;
306  if ((DsamplePeak & 0x0F) != DsamplePeak) continue; // does not fit raw data bits
307 
308  unsigned DsampleFall = feature.sampleFall - feature.sampleRise;
309  if ((DsampleFall & 0x0F) != DsampleFall) continue; // does not fit raw data bits
310 
311  std::vector<unsigned short> winNumbers;
312  for (unsigned i = iwin; i < windowNumbers.size(); i++) {
313  winNumbers.push_back(windowNumbers[i]);
314  }
315 
316  // append new raw digit and set it
317  auto* rawDigit = rawDigits.appendNew(m_scrodID, TOPRawDigit::c_ProductionDebug);
318  rawDigit->setCarrierNumber(m_carrier);
319  rawDigit->setASICNumber(m_asic);
320  rawDigit->setASICChannel(m_chan);
321  rawDigit->setASICWindow(windowNumbers[iwin]);
322  rawDigit->setStorageWindows(winNumbers);
323  rawDigit->setSampleRise(sampleRise);
324  rawDigit->setDeltaSamplePeak(DsamplePeak);
325  rawDigit->setDeltaSampleFall(DsampleFall);
326  rawDigit->setValueRise0(feature.vRise0);
327  rawDigit->setValueRise1(feature.vRise1);
328  rawDigit->setValueFall0(feature.vFall0);
329  rawDigit->setValueFall1(feature.vFall1);
330  rawDigit->setValuePeak(feature.vPeak);
331  rawDigit->setIntegral(feature.integral);
332  double rawTimeLeading = rawDigit->getCFDLeadingTime(); // time in [samples]
333  int sampleDivisions = 0x1 << tdc.getSubBits();
334  int tfine = int(rawTimeLeading * sampleDivisions) % sampleDivisions;
335  if (tfine < 0) tfine += sampleDivisions;
336  rawDigit->setTFine(tfine);
337  rawDigit->addRelationTo(waveform);
338 
339  double rawTimeFalling = rawDigit->getCFDFallingTime(); // time in [samples]
340  double rawTimeErr = rawDigit->getCFDLeadingTimeError(m_rmsNoise); // in [samples]
341 
342  // convert to [ns] using time base calibration
343  int nwin = iwin + offsetWindows;
344  rawTimeLeading += nwin * TOPRawDigit::c_WindowSize;
345  rawTimeFalling += nwin * TOPRawDigit::c_WindowSize;
346 
347  double cfdTime = m_sampleTimes->getTime(s_window, rawTimeLeading) - m_timeOffset;
348  double width = m_sampleTimes->getDeltaTime(s_window,
349  rawTimeFalling,
350  rawTimeLeading);
351  int sample = static_cast<int>(rawTimeLeading);
352  if (rawTimeLeading < 0) sample--;
353  double timeError = rawTimeErr * m_sampleTimes->getTimeBin(s_window, sample);
354  double timeErrorSq = timeError * timeError + m_calErrorsSq;
355  int pulseHeight = rawDigit->getValuePeak();
356 
357  if (s_timeWalk) {
358  cfdTime -= (*s_timeWalk)->getTimeWalk(pulseHeight);
359  timeErrorSq += (*s_timeWalk)->getSigmaSq(pulseHeight);
360  }
361 
362  // append new digit and set it
363  auto* digit = digits.appendNew(m_moduleID, m_pixelID, rawTimeLeading);
364  digit->setTime(cfdTime);
365  digit->setTimeError(sqrt(timeErrorSq));
366  digit->setPulseHeight(pulseHeight);
367  digit->setIntegral(rawDigit->getIntegral());
368  digit->setPulseWidth(width);
369  digit->setChannel(m_channel);
370  digit->setFirstWindow(s_window);
371  if (m_sampleTimes->isCalibrated()) {
372  digit->addStatus(TOPDigit::c_TimeBaseCalibrated);
373  }
374  digit->addRelationTo(rawDigit);
375 
376  // check validity of feature extraction
377 
378  if (!rawDigit->isFEValid() or rawDigit->isPedestalJump()) {
379  digit->setHitQuality(TOPDigit::c_Junk);
380  }
381 
382  // set relations to simulated hits and MC particles, largest weight first
383 
384  std::multimap<double, const Hit*, std::greater<double>> weights;
385  for (const auto& hit : m_times) {
386  double hitTime = hit.first;
387  double weight = 0;
388  const auto* pulseShape = hit.second.shape;
389  if (pulseShape) {
390  weight = fabs(pulseShape->getValue(cfdTime - hitTime));
391  }
392  if (weight > 0.01) {
393  weight *= hit.second.pulseHeight;
394  weights.insert(std::pair<double, const Hit*>(weight, &hit.second));
395  }
396  }
397  double sum = 0;
398  for (const auto& w : weights) sum += w.first;
399  if (sum == 0) continue; // noisy hit
400 
401  std::map<MCParticle*, double> relatedMCParticles;
402  for (const auto& w : weights) {
403  auto weight = w.first / sum;
404  const auto* simHit = w.second->simHit;
405  if (simHit and weight > 0) {
406  digit->addRelationTo(simHit, weight);
407  RelationVector<MCParticle> particles = simHit->getRelationsFrom<MCParticle>();
408  for (unsigned i = 0; i < particles.size(); ++i) {
409  relatedMCParticles[particles[i]] += particles.weight(i) * weight;
410  }
411  } else if (w.second->type == c_CalPulse and weight > 0.90) {
412  digit->setHitQuality(TOPDigit::c_CalPulse);
413  }
414  }
415  for (const auto& x : relatedMCParticles) digit->addRelationTo(x.first, x.second);
416  }
417 
418  }
419 
420 
421  vector<short> TimeDigitizer::generateWaveform(int startSample,
422  const vector<double>& baselines,
423  const vector<double>& rmsNoises,
424  const vector<double>& pedestals,
425  int adcRange) const
426  {
427 
428  if (baselines.empty() or baselines.size() != rmsNoises.size() or
429  baselines.size() != pedestals.size())
430  B2FATAL("TOP::TimeDigitizer: inconsistent vector sizes");
431 
432  // model parameters
433 
434  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
435  const auto& tdc = geo->getNominalTDC();
436  const auto& signalShape = geo->getSignalShape();
437 
438  double dt = tdc.getSampleWidth();
439  double fmax = 1 / (2 * dt); // Nyquist frequency
440  double tau1 = 1 / (2 * M_PI * signalShape.getPole1());
441  double tau2 = 1 / (2 * M_PI * signalShape.getPole2());
442  double bw1 = 1 / (4 * tau1); // bandwidth of first order filter
443  double bw2 = 1 / (4 * (tau1 + tau2)); // bandwidth of second order filter
444 
445  // construct waveform vector containing white noise
446 
447  vector<double> waveform;
448  for (auto rms : rmsNoises) {
449  double rms0 = rms * sqrt(fmax / bw2);
450  for (unsigned i = 0; i < TOPRawWaveform::c_WindowSize; i++) {
451  waveform.push_back(gRandom->Gaus(0, rms0));
452  }
453  }
454 
455  // noise smoothing according to second order low pass filter
456 
457  double a1 = exp(-dt / tau1);
458  double v0 = gRandom->Gaus(0, rmsNoises[0] * sqrt(bw1 / bw2));
459  double prevValue = v0;
460  for (auto& value : waveform) { // first order filter (pole1)
461  value = a1 * prevValue + (1 - a1) * value;
462  prevValue = value;
463  }
464  double a2 = exp(-dt / tau2);
465  prevValue = v0;
466  for (auto& value : waveform) { // first order filter again (pole2)
467  value = a2 * prevValue + (1 - a2) * value;
468  prevValue = value;
469  }
470 
471  // add possible baseline shifts
472 
473  int k = 0;
474  for (auto baseline : baselines) {
475  for (unsigned i = 0; i < TOPRawWaveform::c_WindowSize; i++) {
476  waveform[k] += baseline;
477  k++;
478  }
479  }
480 
481  // add signal
482 
483  for (const auto& hit : m_times) {
484  double hitTime = hit.first;
485  double pulseHeight = hit.second.pulseHeight;
486  const auto* pulseShape = hit.second.shape;
487  if (not pulseShape) continue;
488  double timeWalk = generateTimeWalk(hitTime, pulseShape->getPeakingTime());
489  int size = waveform.size();
490  for (int sample = 0; sample < size; sample++) {
491  double t = m_sampleTimes->getTime(s_window, sample - startSample) - m_timeOffset;
492  waveform[sample] += pulseHeight * pulseShape->getValue(t - timeWalk - hitTime);
493  }
494  }
495 
496  // model saturation effects and convert to short
497  // (exact modelling would require pedestals for each sample)
498 
499  vector<short> wf;
500  k = 0;
501  for (auto pedestal : pedestals) {
502  for (unsigned i = 0; i < TOPRawWaveform::c_WindowSize; i++) {
503  int adc = waveform[k] + pedestal;
504  if (adc < 0) adc = 0;
505  if (adc > adcRange) adc = adcRange;
506  adc -= pedestal;
507  wf.push_back(adc);
508  k++;
509  }
510  }
511 
512  return wf;
513  }
514 
515 
516  double TimeDigitizer::generateTimeWalk(double hitTime, double peakTime) const
517  {
518  if (not s_timeWalk) return 0;
519 
520  double pulseHeight = 0;
521  for (const auto& hit : m_times) {
522  double hTime = hit.first;
523  const auto* pulseShape = hit.second.shape;
524  if (not pulseShape) continue;
525  pulseHeight += hit.second.pulseHeight * pulseShape->getValue(hTime - hitTime + peakTime);
526  }
527 
528  double t = (*s_timeWalk)->getTimeWalk(pulseHeight);
529  double sig = (*s_timeWalk)->getSigma(pulseHeight);
530 
531  return gRandom->Gaus(t, sig);
532  }
533 
534  } // TOP namespace
536 } // Belle2 namespace
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
Class for type safe access to objects that are referred to in relations.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
const TOPNominalTDC & getNominalTDC() const
Returns nominal time-to-digit conversion parameters.
Definition: TOPGeometry.h:218
const TOPSignalShape & getSignalShape() const
Returns single photon signal shape.
Definition: TOPGeometry.h:224
const TOPSignalShape & getCalPulseShape() const
Returns calibration pulse shape.
Definition: TOPGeometry.h:230
double getDoubleHitResolution() const
Returns double hit resolution time.
@ c_ProductionDebug
from production debugging format
Definition: TOPRawDigit.h:46
@ c_MC
from MC digitization
Definition: TOPRawDigit.h:43
@ c_WindowSize
number of samples per window
Definition: TOPRawDigit.h:54
@ c_WindowSize
number of samples per ASIC window
Calibration constants of a singe ASIC channel: time axis (sample times)
bool isCalibrated() const
Returns calibration status.
double getDeltaTime(int window, double sample2, double sample1) const
Returns time difference between sample2 and sample1.
double getTime(int window, double sample) const
Returns time w.r.t SSTin that corresponds to the window number.
Class to store simulated hits of Cherenkov photons on PMT's input for digitization module (TOPDigitiz...
Definition: TOPSimHit.h:27
const TOPFrontEndMap * getMap(int moduleID, int bs) const
Return map from TOP module side.
const TOPGeometry * getGeometry() const
Returns pointer to geometry object using basf2 units.
const FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
std::vector< short > generateWaveform(int startSample, const std::vector< double > &baselines, const std::vector< double > &rmsNoises, const std::vector< double > &pedestals, int ADCRange) const
Generate waveform.
unsigned m_asic
ASIC number.
int m_windowShift
additional wf window shift due to asic mis-alignment
unsigned m_scrodID
SCROD ID.
double m_rmsNoise
r.m.s of noise [ADC counts]
static unsigned s_storageDepth
ASIC analog storage depth.
unsigned m_channel
hardware channel number (0-based)
static DBObjPtr< TOPCalTimeWalk > * s_timeWalk
pointer to DB object
double m_calErrorsSq
calibration uncertainties squared
const TOPSampleTimes * m_sampleTimes
sample times
int m_moduleID
module ID (1-based)
bool m_valid
true, if module/pixel is mapped to hardware
static int s_offsetWindows
number of windows before first wf window
double generateTimeWalk(double hitTime, double peakTime) const
Generate time walk by taking into account pile-up of hits.
static unsigned s_window
first window number
double gauss(double x, double mean, double sigma) const
Gauss function (pulse shape approximation)
void addTimeOfHit(double t, double pulseHeight, EType type, const TOPSimHit *simHit=0)
Add time of simulated hit.
static bool s_maskSamples
mask samples at window boundary (phase-2)
double m_timeOffset
time offset [ns]
std::multimap< double, const Hit > m_times
hits sorted by time
static unsigned s_readoutWindows
number of readout windows
unsigned m_carrier
carrier board number
EType
hit type enumerators
Definition: TimeDigitizer.h:40
unsigned m_chan
ASIC channel number.
void digitize(StoreArray< TOPRawDigit > &rawDigits, StoreArray< TOPDigit > &digits, int threshold=0, int thresholdCount=0, double timeJitter=0) const
Do time digitization using simplified pile-up and double-hit-resolution model.
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
double getTimeBin(int window, int sampleNumber) const
Returns time bin of a given sample number and window (e.g.
map< unsigned, size_t >::const_iterator Iterator
Iteratior for m_map.
Abstract base class for different kinds of events.
hit data other than time
Definition: TimeDigitizer.h:50