11 #include <beast/csi/geometry/CsiGeometryPar.h>
12 #include <beast/csi/modules/CsIDigitizerModule.h>
13 #include <beast/csi/dataobjects/CsiDigiHit.h>
14 #include <beast/csi/dataobjects/CsiSimHit.h>
15 #include <beast/csi/dataobjects/CsiHit.h>
16 #include <framework/dataobjects/EventMetaData.h>
17 #include <framework/datastore/StoreObjPtr.h>
23 #include <framework/core/RandomNumbers.h>
27 #define PI 3.14159265358979323846
45 m_aDigiHit("CsiDigiHits"),
46 m_calibConstants(16, 5),
47 m_noiseLevels(16, 0.25e-3),
57 setDescription(
"Digitizer for the BEAST CsI system");
60 addParam(
"Resolution", m_Resolution,
"Resolution (in mV) of the ACD", 4.8828e-4);
61 addParam(
"SampleRate", m_SampleRate,
"Sample rate (in samples/sec) of the ADC", 250e6);
62 addParam(
"nWaveforms", m_nWaveforms,
"Number of waveforms to save. 0: none, -1: all ", 0);
65 CsIDigitizerModule::~CsIDigitizerModule()
69 void CsIDigitizerModule::initialize()
72 B2DEBUG(100,
"Initializing ");
75 m_aSimHit.isRequired();
76 m_aDigiHit.registerInDataStore();
79 m_dt = 1e9 / m_SampleRate;
84 for (uint i = 0; i != m_LY.size(); ++i) {
94 for (
int i = 8; i < 16; i++) {
100 void CsIDigitizerModule::beginRun()
105 void CsIDigitizerModule::event()
108 int m_currentEventNumber = eventMetaDataPtr->getEvent();
110 B2DEBUG(80,
"Digitingevent " << m_currentEventNumber);
113 if (m_aSimHit.getEntries() > 0) {
114 int hitNum = m_aSimHit.getEntries();
119 for (
int i = 0 ; i < 16 ; i++) {
120 m_SimHitTimes[i].clear();
121 m_SimHitEdeps[i].clear();
125 B2DEBUG(150,
"Looping over CsISimHits");
126 for (
int i = 0; i < hitNum; i++) {
139 double localPos = (15. - (hitPos - cellPos) *
143 double propagTime = m_SampleRate *
144 (0.0600 * localPos + (tof / CLHEP::ns)) * 1E-9;
147 m_SimHitTimes[m_cellID].push_back(propagTime);
148 m_SimHitEdeps[m_cellID].push_back(edep);
163 for (
int iCh = 0; iCh < 16; iCh++) {
165 int n = m_SimHitTimes[iCh].size();
169 B2DEBUG(140,
"Generating Time signal");
171 m_TrueEdep = genTimeSignal(&tempSignal, m_SimHitEdeps[iCh], m_SimHitTimes[iCh], iCh, m_dt, m_nSamples,
false);
174 B2DEBUG(140,
"Launching Charge integration");
175 bool recordWaveform =
false;
176 if ((m_nWaveforms == -1) || (m_nWFcounter < m_nWaveforms)) {
178 recordWaveform =
true;
179 B2DEBUG(80,
"Recording WF");
181 uint16_t max = doChargeIntegration(tempSignal, 128, &m_Baseline, &m_Charge, &m_Time, &m_Waveform,
182 &m_DPPCIBits, 5, 1.2e4, 1e4, 1e3, recordWaveform);
185 m_aDigiHit.appendNew();
186 m_hitNum = m_aDigiHit.getEntries() - 1;
187 m_aDigiHit[m_hitNum]->setCellId(iCh);
188 m_aDigiHit[m_hitNum]->setCharge(m_Charge);
189 m_aDigiHit[m_hitNum]->setTime(m_Time);
190 m_aDigiHit[m_hitNum]->setBaseline(m_Baseline);
191 m_aDigiHit[m_hitNum]->setTrueEdep(m_TrueEdep);
193 m_aDigiHit[m_hitNum]->setMaxVal(max);
195 m_aDigiHit[m_hitNum]->setWaveform(&m_Waveform);
196 m_aDigiHit[m_hitNum]->setStatusBits(&m_DPPCIBits);
204 void CsIDigitizerModule::endRun()
208 void CsIDigitizerModule::terminate()
212 uint16_t CsIDigitizerModule::doChargeIntegration(
Signal _u,
int _NsamBL, uint16_t* _BSL, uint32_t* _Q,
213 uint32_t* _t, vector<uint16_t>* _Waveform,
214 vector<uint8_t>* _DPPCIBits,
int _Treshold,
215 double _TriggerHoldoff,
double _GateWidth,
216 double _GateOffset,
bool _recordTraces)
219 B2DEBUG(80,
"Arguments: " << &_u <<
", " << _NsamBL <<
", " << _BSL <<
", " << _Q <<
", " << _t
220 <<
", " << _Waveform <<
", " << _Treshold <<
", " << _TriggerHoldoff <<
", " << _GateWidth
221 <<
", " << _GateOffset <<
", " << _recordTraces);
223 vector<int> x = doDigitization(_u, m_Resolution);
227 TH1I h_trigger(
"h_trigger",
"Trigger", nSam, 0, nSam - 1);
228 TH1I h_gate(
"h_gate",
"Gate", nSam, 0, nSam - 1);
229 TH1I h_holdoff(
"h_holdoff",
"Holdoff", nSam, 0, nSam - 1);
230 TH1I h_baseline(
"h_baseline",
"Baseline", nSam, 0, nSam - 1);
231 TH1I h_charge(
"h_charge",
"Charge", nSam, 0, nSam - 1);
232 TH1F h_signal(
"h_signal",
"Continous signal", nSam, 0, nSam - 1);
233 TH1I h_digsig(
"h_digsig",
"Digital signal", nSam, 0, nSam - 1);
236 int max_gated = (int) floor(_GateWidth / m_dt);
237 int gate_offset = (int) floor(_GateOffset / m_dt);
238 int max_holdoff = (int) floor(_TriggerHoldoff / m_dt);
246 bool holdoff =
false;
248 bool trigger =
false;
252 int iFirstTrigger = 0;
253 list<int> baselineBuffer;
254 vector<int>::iterator it;
255 float tempBaseline = 0.0;
258 const double invMaxNavgBL = 1.0 / _NsamBL;
259 double invNavgBL = 0.0;
261 _Waveform->resize(nSam, 0);
262 _DPPCIBits->resize(nSam, 0);
264 B2DEBUG(140,
"Scanning vector: all should have nSam=" << nSam);
268 for (it = x.begin(); (it != x.end()); ++it, ++i) {
273 _Waveform->at(i) = *it;
274 _DPPCIBits->at(i) = trigger + (gate << 1) + (holdoff << 2) + (stop << 3);
278 h_trigger.Fill(i, (
int) trigger) ;
279 h_gate.Fill(i, (
int) gate) ;
280 h_holdoff.Fill(i, (
int) holdoff) ;
281 h_baseline.Fill(i, baseline) ;
282 h_charge.Fill(i, charge) ;
283 h_digsig.Fill(i, *it) ;
284 h_signal.Fill(i, _u.at(i)) ;
287 if (!gate && !holdoff) {
289 baselineBuffer.push_back(*it);
292 if ((i + 1) > _NsamBL) {
293 baselineBuffer.pop_front();
294 invNavgBL = invMaxNavgBL;
296 invNavgBL = (1.0 / i);
300 for (list<int>::iterator itbl = baselineBuffer.begin(); itbl != baselineBuffer.end(); ++itbl)
301 tempBaseline += (
float) * itbl;
303 tempBaseline *= invNavgBL;
305 baseline = (int) round(tempBaseline);
307 trigger = (*it - baseline) > _Treshold;
310 if (trigger && !iFirstTrigger)
316 charge += (*(it - gate_offset) - baseline);
328 holdoff = trigger || (holdoff && (n_holdoff < max_holdoff));
329 gate = trigger || (gate && (n_gated < max_gated));
331 stop = iFirstTrigger && !gate && !holdoff;
336 *_t = (uint)(iFirstTrigger + 2.0 * (gRandom->Rndm() - 0.5));
338 if (not(_recordTraces)) {
369 vector<int> CsIDigitizerModule::doDigitization(
Signal _v,
double _LSB)
371 vector<int> output(_v.size(), 0);
372 double invLSB = 1.0 / _LSB;
375 for (Signal::iterator it = _v.begin() ; it != _v.end(); ++it, ++i) {
376 output.at(i) = (int) round(*it * invLSB);
382 double CsIDigitizerModule::genTimeSignal(
Signal* _output,
Signal _energies,
Signal _times,
int _iChannel,
int _dt,
int _nsam,
386 double invdt = 1.0 / _dt;
390 double sumEnergies = 0.0;
392 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it) {
400 Signal edepos(_nsam, 0.0);
403 int ioffset = floor(_nsam * 0.25);
404 B2DEBUG(150,
"Filling edepos vector. Container length is " << _nsam);
406 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it, ++i) {
407 sumEnergies += _energies.at(i);
409 int timeIndex = ((int)(*it - t0) * invdt + ioffset);
410 if ((timeIndex - 1) > (int) edepos.size()) {
411 B2WARNING(
" genTimeSignal: TimeIndex greater than length of signal container. Skipping deposit of " << _energies.at(i) <<
"GeV");
413 edepos.at(timeIndex) += _energies.at(i);
417 B2DEBUG(80,
"Generating time responses for channel " << _iChannel);
418 B2DEBUG(80,
" Fast time constant " << m_tFast[_iChannel]);
419 B2DEBUG(80,
" Slow time constant " << m_tSlow[_iChannel]);
425 Signal Qcathode = firstOrderResponse((1 - m_tRatio[_iChannel]) * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0,
426 _dt, m_tSlow[_iChannel], 0.0);
429 if (m_tRatio[_iChannel]) {
430 Signal QcathodeF = firstOrderResponse(m_tRatio[_iChannel] * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0, _dt,
431 m_tFast[_iChannel], 0.0);
434 for (Signal::iterator it = Qcathode.begin() ; it != Qcathode.end(); ++it, ++j)
435 *it += QcathodeF.at(j);
438 Signal Vanode = firstOrderResponse(1.602e-10 * m_Zl * invdt * m_PmtGain[_iChannel], Qcathode, 0, _dt, m_tRisePMT, m_tTransitPMT);
441 B2DEBUG(150,
"Adding noise. Container length is " << Vanode.size());
442 addNoise(&Vanode, m_noiseLevels[_iChannel], 5e-3 * gRandom->Rndm() + 1e-2);
448 for (i = 1; i < _nsam; i++)
449 t.at(i) = t.at(i - 1) + _dt;
451 TGraph gPlot1(_nsam, &t[0], &edepos[0]);
452 gPlot1.SaveAs(
"EdeposOut.root");
454 TGraph gPlot2(_nsam, &t[0], &Qcathode[0]);
455 gPlot2.SaveAs(
"QOut.root");
457 TGraph gPlot3(_nsam, &t[0], &Vanode[0]);
458 gPlot3.SaveAs(
"VOut.root");
467 int CsIDigitizerModule::addNoise(
Signal* y,
double _rms,
double _offset)
469 for (Signal::iterator it = y->begin() ; it != y->end(); ++it)
470 *it += _offset + gRandom->Gaus(0, _rms);
493 Signal CsIDigitizerModule::firstOrderResponse(
double _gain,
Signal _u,
double _y0,
double _dt,
double _tau,
double _delay)
496 B2DEBUG(80,
"Generating 1st order response with arguments");
497 B2DEBUG(80,
" _gain: " << _gain);
498 B2DEBUG(80,
" length(_u): " << _u.size());
499 B2DEBUG(80,
" _y0: " << _y0);
500 B2DEBUG(80,
" _dt: " << _dt);
501 B2DEBUG(80,
" _tau: " << _tau);
502 B2DEBUG(80,
" _delay: " << _delay);
513 static const double invSix = 1.0 / 6.0;
514 double invtau = 1.0 / _tau;
518 int n_delay = (int) round(_delay / _dt);
519 Signal::iterator it = _u.begin();
520 double _u_0 = _u.front();
521 _u.insert(it , n_delay, _u_0);
525 for (
int i = 0, j = 0; i < (n - 1); i++) {
527 k[0] = f(i , _u[i], _u[j], y[i] , invtau);
528 k[1] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[0], invtau);
529 k[2] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[1], invtau);
530 k[3] = f(j , _u[i], _u[j], y[i] + _dt * k[2], invtau);
532 y.push_back(y[i] + _dt * invSix * (k[0] + 2 * k[1] + 2 * k[2] + k[3]));
538 for (Signal::iterator it2 = y.begin() ; it2 != y.end(); ++it2)
546 double CsIDigitizerModule::f(
double fi,
double u_i,
double u_j,
double y,
double invtau)
549 double u = u_i * (fi - floor(fi)) + u_j * (ceil(fi) - fi);
551 return u - invtau * y;