97 double timeJitter)
const
106 double pileupTime = tdc.getPileupTime();
109 std::vector<Iterator> ranges;
110 ranges.push_back(
m_times.begin());
111 double prevTime =
m_times.begin()->first;
113 if (it->first - prevTime > hitResolveTime) ranges.push_back(it);
114 prevTime = it->first;
116 ranges.push_back(
m_times.end());
119 for (
unsigned k = 0; k < ranges.size() - 1; k++) {
122 std::vector<double> times;
123 std::vector<double> weights;
124 std::vector<const TOPSimHit*> simHits;
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;
139 for (
const auto& weight : weights) height += weight;
142 for (
auto& weight : weights) weight /= height;
145 double width = gRandom->Gaus(2.3, 0.4);
146 if (width < 0.5) width = 0.5;
150 for (
unsigned j = 0; j < times.size(); j++) time += times[j] * weights[j];
153 if (timeJitter > 0) time += gRandom->Gaus(0., timeJitter);
157 double mean = time + width / 2;
158 double sigma = width / 2.35482;
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;
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);
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);
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;
184 int numSamples = (sampleFall - sampleRise) * 4;
185 double sigmaIntegral = 0;
186 if (numSamples > 1) sigmaIntegral =
m_rmsNoise *
sqrt(numSamples - 1);
187 double integral = gRandom->Gaus(height * 7.0, sigmaIntegral);
192 rawDigit->setASICNumber(
m_asic);
193 rawDigit->setASICChannel(
m_chan);
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);
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);
216 digit->setTime(cfdTime);
217 digit->setTimeError(timeJitter);
218 digit->setPulseHeight(rawDigit->getValuePeak());
219 digit->setIntegral(rawDigit->getIntegral());
220 digit->setPulseWidth(cfdWidth);
222 digit->setFirstWindow(rawDigit->getASICWindow());
223 digit->setStatus(TOPDigit::c_OffsetSubtracted);
225 digit->addStatus(TOPDigit::c_TimeBaseCalibrated);
227 digit->addRelationTo(rawDigit);
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];
236 digit->addRelationTo(simHit, weight);
238 for (
unsigned i = 0; i < particles.size(); ++i) {
239 relatedMCParticles[particles[i]] += particles.weight(i) * weight;
243 for (
const auto& x : relatedMCParticles) digit->addRelationTo(x.first, x.second);
256 int thresholdCount)
const
266 std::vector<unsigned short> windowNumbers;
268 int winnum =
s_window + offsetWindows;
272 windowNumbers.push_back((windowNumbers.back() + 1) %
s_storageDepth);
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();
281 auto wfData =
generateWaveform(startSample, baselines, rmsNoises, pedestals,
287 windowNumbers[0], 0, wfData);
288 waveform->setStorageWindows(windowNumbers);
289 waveform->setPedestalSubtractedFlag(
true);
293 waveform->featureExtraction(threshold, hysteresis, thresholdCount);
297 for (
const auto& feature : waveform->getFeatureExtractionData()) {
298 int sampleRise = feature.sampleRise;
299 if (sampleRise < 0)
continue;
301 if (iwin >= windowNumbers.size())
continue;
305 unsigned DsamplePeak = feature.samplePeak - feature.sampleRise;
306 if ((DsamplePeak & 0x0F) != DsamplePeak)
continue;
308 unsigned DsampleFall = feature.sampleFall - feature.sampleRise;
309 if ((DsampleFall & 0x0F) != DsampleFall)
continue;
311 std::vector<unsigned short> winNumbers;
312 for (
unsigned i = iwin; i < windowNumbers.size(); i++) {
313 winNumbers.push_back(windowNumbers[i]);
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();
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);
339 double rawTimeFalling = rawDigit->getCFDFallingTime();
340 double rawTimeErr = rawDigit->getCFDLeadingTimeError(
m_rmsNoise);
343 int nwin = iwin + offsetWindows;
351 int sample =
static_cast<int>(rawTimeLeading);
352 if (rawTimeLeading < 0) sample--;
355 int pulseHeight = rawDigit->getValuePeak();
358 cfdTime -= (*s_timeWalk)->getTimeWalk(pulseHeight);
359 timeErrorSq += (*s_timeWalk)->getSigmaSq(pulseHeight);
364 digit->setTime(cfdTime);
365 digit->setTimeError(
sqrt(timeErrorSq));
366 digit->setPulseHeight(pulseHeight);
367 digit->setIntegral(rawDigit->getIntegral());
368 digit->setPulseWidth(width);
372 digit->addStatus(TOPDigit::c_TimeBaseCalibrated);
374 digit->addRelationTo(rawDigit);
378 if (!rawDigit->isFEValid() or rawDigit->isPedestalJump()) {
379 digit->setHitQuality(TOPDigit::c_Junk);
384 std::multimap<double, const Hit*, std::greater<double>> weights;
385 for (
const auto& hit :
m_times) {
386 double hitTime = hit.first;
388 const auto* pulseShape = hit.second.shape;
390 weight = fabs(pulseShape->getValue(cfdTime - hitTime));
393 weight *= hit.second.pulseHeight;
394 weights.insert(std::pair<double, const Hit*>(weight, &hit.second));
398 for (
const auto& w : weights) sum += w.first;
399 if (sum == 0)
continue;
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);
408 for (
unsigned i = 0; i < particles.size(); ++i) {
409 relatedMCParticles[particles[i]] += particles.weight(i) * weight;
411 }
else if (w.second->type == c_CalPulse and weight > 0.90) {
412 digit->setHitQuality(TOPDigit::c_CalPulse);
415 for (
const auto& x : relatedMCParticles) digit->addRelationTo(x.first, x.second);
422 const vector<double>& baselines,
423 const vector<double>& rmsNoises,
424 const vector<double>& pedestals,
428 if (baselines.empty() or baselines.size() != rmsNoises.size() or
429 baselines.size() != pedestals.size())
430 B2FATAL(
"TOP::TimeDigitizer: inconsistent vector sizes");
436 const auto& signalShape = geo->getSignalShape();
438 double dt = tdc.getSampleWidth();
439 double fmax = 1 / (2 * dt);
440 double tau1 = 1 / (2 * M_PI * signalShape.getPole1());
441 double tau2 = 1 / (2 * M_PI * signalShape.getPole2());
442 double bw1 = 1 / (4 * tau1);
443 double bw2 = 1 / (4 * (tau1 + tau2));
447 vector<double> waveform;
448 for (
auto rms : rmsNoises) {
449 double rms0 = rms *
sqrt(fmax / bw2);
451 waveform.push_back(gRandom->Gaus(0, rms0));
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) {
461 value = a1 * prevValue + (1 - a1) * value;
464 double a2 = exp(-dt / tau2);
466 for (
auto& value : waveform) {
467 value = a2 * prevValue + (1 - a2) * value;
474 for (
auto baseline : baselines) {
476 waveform[k] += baseline;
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;
489 int size = waveform.size();
490 for (
int sample = 0; sample < size; sample++) {
492 waveform[sample] += pulseHeight * pulseShape->getValue(t - timeWalk - hitTime);
501 for (
auto pedestal : pedestals) {
503 int adc = waveform[k] + pedestal;
504 if (adc < 0) adc = 0;
505 if (adc > adcRange) adc = adcRange;
A Class to store the Monte Carlo particle information.