4 using namespace hgc_digi;
15 if( ps.
exists(
"adcPulse") )
21 if( ps.
exists(
"adcNbits") )
23 uint32_t adcNbits = ps.
getParameter<uint32_t>(
"adcNbits");
27 <<
"[HGCFEElectronics] " << adcNbits <<
" bit ADC defined"
28 <<
" with LSB=" << adcLSB_fC_
29 <<
" saturation to occur @ " << adcSaturation_fC_ << std::endl;
33 if( ps.
exists(
"tdcNbits") )
35 uint32_t tdcNbits = ps.
getParameter<uint32_t>(
"tdcNbits");
39 <<
"[HGCFEElectronics] " << tdcNbits <<
" bit TDC defined with LSB="
40 << tdcLSB_fC_ <<
" saturation to occur @ " << tdcSaturation_fC_ << std::endl;
58 for(
int it=0; it<(int)(chargeColl.size()); it++) debug |= (chargeColl[it]>adcThreshold_fC_);
65 for(
int it=0; it<(int)(chargeColl.size()); it++)
68 const uint32_t
adc=std::floor(
std::min(chargeColl[it],adcSaturation_fC_) / adcLSB_fC_ );
70 newSample.
set(chargeColl[it]>adcThreshold_fC_,
false,0,adc);
71 dataFrame.setSample(it,newSample);
73 if(debug)
edm::LogVerbatim(
"HGCFE") << adc <<
" (" << chargeColl[it] <<
"/" << adcLSB_fC_ <<
") ";
77 std::ostringstream
msg;
90 for(
int it=0; it<(int)(chargeColl.size()); it++)
92 const float charge(chargeColl[it]);
93 if(charge==0)
continue;
96 debug|=(charge>adcThreshold_fC_);
99 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t Redistributing SARS ADC" << charge <<
" @ " << it;
101 for(
int ipulse=-2; ipulse<(int)(adcPulse_.size())-2; ipulse++)
103 if(it+ipulse<0)
continue;
104 if(it+ipulse>=(
int)(dataFrame.size()))
continue;
105 const float chargeLeak=charge*adcPulse_[(ipulse+2)]/adcPulse_[2];
106 newCharge[it+ipulse]+= chargeLeak;
108 if(debug)
edm::LogVerbatim(
"HGCFE") <<
" | " << it+ipulse <<
" " << chargeLeak;
115 for(
int it=0; it<(int)(newCharge.size()); it++)
118 const float saturatedCharge(
std::min(newCharge[it],adcSaturation_fC_));
120 newSample.
set(newCharge[it]>adcThreshold_fC_,
false,0,floor(saturatedCharge/adcLSB_fC_));
121 dataFrame.setSample(it,newSample);
123 if(debug)
edm::LogVerbatim(
"HGCFE") << std::floor(saturatedCharge/adcLSB_fC_) <<
" (" << saturatedCharge <<
"/" << adcLSB_fC_ <<
" ) " ;
127 std::ostringstream
msg;
128 dataFrame.print(msg);
137 busyFlags.fill(
false);
138 totFlags.fill(
false);
139 newCharge.fill( 0.
f );
140 toaFromToT.fill( 0.
f );
150 for(
int it=0; it<(int)(chargeColl.size()); ++it)
153 if(busyFlags[it])
continue;
156 float charge = chargeColl[it];
157 if(charge < tdcOnset_fC_)
continue;
160 float toa = toaColl[it];
163 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t q=" << charge <<
" fC with <toa>=" << toa <<
" ns, triggers ToT @ " << it << std::endl;
168 float totalCharge(charge), finalToA(toa), integTime(0);
173 float charge_offset = 0.f;
174 const float charge_kfC(totalCharge*1
e-3);
175 if(charge_kfC<tdcChargeDrainParameterisation_[3]) {
177 }
else if(charge_kfC<tdcChargeDrainParameterisation_[7]) {
179 charge_offset = tdcChargeDrainParameterisation_[3];
183 charge_offset = tdcChargeDrainParameterisation_[7];
186 const float charge_mod = charge_kfC - charge_offset;
187 const float newIntegTime = ( ( tdcChargeDrainParameterisation_[poffset]*charge_mod +
188 tdcChargeDrainParameterisation_[poffset+1] )*charge_mod +
189 tdcChargeDrainParameterisation_[poffset+2] );
193 const int newBusyBxs=std::floor(newIntegTime/25.
f)+1;
197 integTime=newIntegTime;
198 if(newBusyBxs==busyBxs)
break;
203 if(busyBxs==0)
edm::LogVerbatim(
"HGCFE") <<
"\t Intial busy estimate="<< integTime <<
" ns = " << newBusyBxs <<
" bxs" << std::endl;
204 else edm::LogVerbatim(
"HGCFE") <<
"\t ...integrated charge overflows initial busy estimate, interating again" << std::endl;
212 if(toaMode_==WEIGHTEDBYE) finalToA=toa*
charge;
215 for(
int jt=0; jt<it; ++jt)
217 if(totFlags[jt] || busyFlags[jt])
continue;
219 const float chargeDep_jt(chargeColl[jt]);
220 if(chargeDep_jt==0)
continue;
222 const int deltaT=(it-jt);
223 if(deltaT+2>(
int)(adcPulse_.size()))
continue;
225 const float leakCharge( chargeDep_jt*adcPulse_[deltaT+2]/adcPulse_[2] );
226 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t\t leaking " << chargeDep_jt <<
" fC @ deltaT=-" << deltaT <<
" -> +" << leakCharge <<
" with avgT=" << pulseAvgT_[deltaT+2] << std::endl;
228 totalCharge += leakCharge;
229 if(toaMode_==WEIGHTEDBYE) finalToA += leakCharge*pulseAvgT_[deltaT+2];
233 for(
int jt=it+1; jt<it+busyBxs && jt<dataFrame.size() ; ++jt)
239 const float extraCharge=chargeColl[jt];
240 if(extraCharge==0)
continue;
241 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t\t adding " << extraCharge <<
" fC @ deltaT=+" << (jt-it) << std::endl;
243 totalCharge += extraCharge;
244 if(toaMode_==WEIGHTEDBYE) finalToA += extraCharge*toaColl[jt];
248 if(toaMode_==WEIGHTEDBYE) finalToA /= totalCharge;
251 toaFromToT[it] = CLHEP::RandGaussQ::shoot(engine,finalToA,tdcResolutionInNs_);
252 newCharge[it] = (totalCharge-tdcOnset_fC_);
254 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t Final busy estimate="<< integTime <<
" ns = " << busyBxs <<
" bxs" << std::endl
255 <<
"\t Total integrated=" << totalCharge <<
" fC <toa>=" << toaFromToT[it] <<
" (raw=" << finalToA <<
") ns " << std::endl;
258 if(it+busyBxs<(
int)(newCharge.size()))
260 const float deltaT2nextBx((busyBxs*25-integTime));
261 const float tdcOnsetLeakage(tdcOnset_fC_*
exp(-deltaT2nextBx/tdcChargeDrainParameterisation_[11]));
262 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t Leaking remainder of TDC onset " << tdcOnset_fC_
263 <<
" fC, to be dissipated in " << deltaT2nextBx
264 <<
" DeltaT/tau=" << deltaT2nextBx <<
" / " << tdcChargeDrainParameterisation_[11]
265 <<
" ns, adds " << tdcOnsetLeakage <<
" fC @ " << it+busyBxs <<
" bx (first free bx)" << std::endl;
266 newCharge[it+busyBxs] += tdcOnsetLeakage;
271 for(
int it=0; it<(int)(chargeColl.size()); it++)
274 if(totFlags[it] || busyFlags[it])
continue;
275 const float charge(chargeColl[it]);
276 if(charge==0)
continue;
278 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t SARS ADC pulse activated @ " << it <<
" : ";
279 for(
int ipulse=-2; ipulse<(int)(adcPulse_.size())-2; ipulse++)
281 if(it+ipulse<0)
continue;
282 if(it+ipulse>=(
int)(newCharge.size()))
continue;
286 if(totFlags[it] || busyFlags[it+ipulse])
continue;
287 const float chargeLeak=charge*adcPulse_[(ipulse+2)]/adcPulse_[2];
288 if(debug)
edm::LogVerbatim(
"HGCFE") <<
" | " << it+ipulse <<
" " << chargeLeak <<
"( " << charge <<
"->";
289 newCharge[it+ipulse]+=chargeLeak;
298 for(
int it=0; it<(int)(newCharge.size()); it++)
300 if(debug)
edm::LogVerbatim(
"HGCFE") << chargeColl[it] <<
" -> " << newCharge[it] <<
" ";
303 if(totFlags[it] || busyFlags[it])
307 float finalToA(toaFromToT[it]);
308 while(finalToA<0) finalToA+=25.;
309 while(finalToA>25) finalToA-=25;
312 float saturatedCharge(
std::min(newCharge[it],tdcSaturation_fC_));
313 newSample.
set(
true,
true,finalToA/toaLSB_ns_,floor(saturatedCharge/tdcLSB_fC_));
317 newSample.
set(
false,
true,0,0);
323 float saturatedCharge(
std::min(newCharge[it],adcSaturation_fC_));
324 newSample.
set(newCharge[it]>adcThreshold_fC_,
false,0,saturatedCharge/adcLSB_fC_);
326 dataFrame.setSample(it,newSample);
330 std::ostringstream
msg;
331 dataFrame.print(msg);
int adc(sample_type sample)
get the ADC sample (12 bits)
T getParameter(std::string const &) const
void runTrivialShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl)
converts charge to digis without pulse shape
std::vector< double > adcPulse_
bool exists(std::string const ¶meterName) const
checks if a parameter exists
std::array< HGCSimData_t, nSamples > HGCSimHitData
void runSimpleShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl)
applies a shape to each time sample and propagates the tails to the subsequent time samples ...
HGCFEElectronics(const edm::ParameterSet &ps)
CTOR.
void runShaperWithToT(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine)
implements pulse shape and switch to time over threshold including deadtime
std::vector< double > tdcChargeDrainParameterisation_
std::vector< double > pulseAvgT_
models the behavior of the front-end electronics
void set(bool thr, bool mode, uint16_t toa, uint16_t data)
Power< A, B >::type pow(const A &a, const B &b)