Belle II Software development
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
15using namespace std;
16
17namespace Belle2 {
22 namespace TOP {
23
27 unsigned TimeDigitizer::s_window = 0;
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
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);
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);
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 ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
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)
TimeDigitizer(int moduleID, int pixelID, double timeOffset, double calErrorsSq, int shift, double rmsNoise, const TOPSampleTimes &sampleTimes)
Constructor.
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.
Abstract base class for different kinds of events.
STL namespace.
hit data other than time
Definition: TimeDigitizer.h:50