5 #include "vdt/vdtMath.h" 31 if( ps.exists(
"adcPulse") )
33 auto temp = ps.getParameter< std::vector<double> >(
"adcPulse");
34 for(
unsigned i = 0;
i <
temp.size(); ++
i ) {
41 temp = ps.getParameter< std::vector<double> >(
"pulseAvgT");
42 for(
unsigned i = 0;
i <
temp.size(); ++
i ) {
46 if( ps.exists(
"adcNbits") )
48 uint32_t
adcNbits = ps.getParameter<uint32_t>(
"adcNbits");
52 <<
"[HGCFEElectronics] " << adcNbits <<
" bit ADC defined" 53 <<
" with LSB=" << adcLSB_fC_
54 <<
" saturation to occur @ " << adcSaturation_fC_ << std::endl;
57 if( ps.exists(
"tdcNbits") )
59 uint32_t
tdcNbits = ps.getParameter<uint32_t>(
"tdcNbits");
63 <<
"[HGCFEElectronics] " << tdcNbits <<
" bit TDC defined with LSB=" 64 << tdcLSB_fC_ <<
" saturation to occur @ " << tdcSaturation_fC_ << std::endl;
66 if( ps.exists(
"adcThreshold_fC") )
adcThreshold_fC_ = ps.getParameter<
double>(
"adcThreshold_fC");
67 if( ps.exists(
"tdcOnset_fC") )
tdcOnset_fC_ = ps.getParameter<
double>(
"tdcOnset_fC");
68 if( ps.exists(
"tdcForToAOnset_fC") ){
69 auto temp = ps.getParameter< std::vector<double> >(
"tdcForToAOnset_fC");
73 <<
" HGCFEElectronics wrong size for ToA thresholds ";
76 if( ps.exists(
"toaLSB_ns") )
toaLSB_ns_ = ps.getParameter<
double>(
"toaLSB_ns");
77 if( ps.exists(
"tdcChargeDrainParameterisation") ) {
78 for(
auto val : ps.getParameter< std::vector<double> >(
"tdcChargeDrainParameterisation") ) {
82 if( ps.exists(
"tdcResolutionInPs") )
tdcResolutionInNs_ = ps.getParameter<
double>(
"tdcResolutionInPs")*1
e-3;
83 if( ps.exists(
"toaMode") )
toaMode_ = ps.getParameter<uint32_t>(
"toaMode");
85 if( ps.exists(
"jitterNoise_ns") ){
86 auto temp = ps.getParameter< std::vector<double> >(
"jitterNoise_ns");
90 <<
" HGCFEElectronics wrong size for ToA jitterNoise ";
93 if( ps.exists(
"jitterConstant_ns") ){
94 auto temp = ps.getParameter< std::vector<double> >(
"jitterConstant_ns");
99 <<
" HGCFEElectronics wrong size for ToA jitterConstant ";
112 for(
int it=0; it<(
int)(chargeColl.size()); it++) debug |= (chargeColl[it]>
adcThreshold_fC_);
120 for(
int it=0; it<(
int)(chargeColl.size()); it++)
125 newSample.
set(chargeColl[it]>adj_thresh,
false,0,adc);
126 dataFrame.setSample(it,newSample);
132 std::ostringstream
msg;
133 dataFrame.print(msg);
145 for(
int it=0; it<(
int)(chargeColl.size()); it++)
147 const float charge(chargeColl[it]);
148 if(charge==0.
f)
continue;
154 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t Redistributing SARS ADC" << charge <<
" @ " << it;
156 for(
int ipulse=-2; ipulse<(
int)(
adcPulse_.size())-2; ipulse++)
158 if(it+ipulse<0)
continue;
159 if(it+ipulse>=(
int)(dataFrame.size()))
continue;
160 const float chargeLeak=charge*
adcPulse_[(ipulse+2)];
163 if(debug)
edm::LogVerbatim(
"HGCFE") <<
" | " << it+ipulse <<
" " << chargeLeak;
178 dataFrame.setSample(it,newSample);
184 std::ostringstream
msg;
185 dataFrame.print(msg);
206 bool debug = debug_state;
217 if(toaColl[fireBX] != 0.
f){
218 timeToA = toaColl[fireBX];
220 if(jitter != 0) timeToA = CLHEP::RandGaussQ::shoot(engine, timeToA, jitter);
222 if(timeToA >= 0.
f && timeToA <= 25.
f)
toaFlags[fireBX] =
true;
228 for(
int it=0; it<(
int)(chargeColl.size()); ++it)
235 float charge = chargeColl[it];
247 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t q=" << charge <<
" fC with <toa>=" << toa <<
" ns, triggers ToT @ " << it << std::endl;
252 float totalCharge(charge), finalToA(toa), integTime(0);
257 float charge_offset = 0.f;
258 const float charge_kfC(totalCharge*1
e-3);
270 const float charge_mod = charge_kfC - charge_offset;
275 const int newBusyBxs=std::floor(newIntegTime/25.
f)+1;
279 integTime=newIntegTime;
280 if(newBusyBxs==busyBxs)
break;
285 if(busyBxs==0)
edm::LogVerbatim(
"HGCFE") <<
"\t Intial busy estimate="<< integTime <<
" ns = " << newBusyBxs <<
" bxs" << std::endl;
286 else edm::LogVerbatim(
"HGCFE") <<
"\t ...integrated charge overflows initial busy estimate, interating again" << std::endl;
297 for(
int jt=0; jt<it; ++jt)
299 const unsigned int deltaT=(it-jt);
302 const float leakCharge = chargeColl[jt]*
adcPulse_[deltaT+2];
303 totalCharge += leakCharge;
306 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t\t leaking " << chargeColl[jt] <<
" fC @ deltaT=-" << deltaT <<
" -> +" << leakCharge <<
" with avgT=" << pulseAvgT_[deltaT+2] << std::endl;
310 for(
int jt=it+1; jt<it+busyBxs && jt<dataFrame.size() ; ++jt)
316 const float extraCharge=chargeColl[jt];
317 if(extraCharge==0.
f)
continue;
318 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t\t adding " << extraCharge <<
" fC @ deltaT=+" << (jt-it) << std::endl;
320 totalCharge += extraCharge;
330 if(debug)
edm::LogVerbatim(
"HGCFE") <<
"\t Final busy estimate="<< integTime <<
" ns = " << busyBxs <<
" bxs" << std::endl
331 <<
"\t Total integrated=" << totalCharge <<
" fC <toa>=" <<
toaFromToT[it] <<
" (raw=" << finalToA <<
") ns " << std::endl;
336 const float deltaT2nextBx((busyBxs*25-integTime));
339 <<
" fC, to be dissipated in " << deltaT2nextBx
341 <<
" ns, adds " << tdcOnsetLeakage <<
" fC @ " << it+busyBxs <<
" bx (first free bx)" << std::endl;
342 newCharge[it+busyBxs] += tdcOnsetLeakage;
347 auto runChargeSharing = [&]() {
349 for(
int it=0; it<(
int)(chargeColl.size()); ++it)
356 for(ipulse = start; ipulse < stop; ++ipulse) {
357 const int itoffset = it + ipulse - 2;
411 newSample.
set(
false,
true,0,0);
419 newSample.
set(newCharge[it]>adj_thresh,
false, (uint16_t)(timeToA/
toaLSB_ns_), (uint16_t)(std::floor(saturatedCharge/
adcLSB_fC_)));
422 dataFrame.setSample(it,newSample);
426 std::ostringstream
msg;
427 dataFrame.print(msg);
T getParameter(std::string const &) const
std::array< float, 3 > tdcForToAOnset_fC_
void runShaperWithToT(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, int thickness, CLHEP::HepRandomEngine *engine, float cce=1.0)
implements pulse shape and switch to time over threshold including deadtime
std::array< bool, hgc::nSamples > toaFlags
hgc::HGCSimHitData toaFromToT
std::array< bool, hgc::nSamples > totFlags
std::array< HGCSimData_t, nSamples > HGCSimHitData
float getTimeJitter(float totalCharge, int thickness)
HGCFEElectronics(const edm::ParameterSet &ps)
CTOR.
bool thresholdFollowsMIP_
std::array< bool, hgc::nSamples > busyFlags
std::vector< float > noise_fC_
constexpr int adc(sample_type sample)
get the ADC sample (12 bits)
void runSimpleShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, int thickness, float cce=1.0)
applies a shape to each time sample and propagates the tails to the subsequent time samples ...
void setToAValid(bool toaFired)
std::array< float, 6 > adcPulse_
std::array< float, 3 > jitterNoise2_ns_
void runTrivialShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, int thickness, float cce=1.0)
converts charge to digis without pulse shape
std::vector< float > tdcChargeDrainParameterisation_
models the behavior of the front-end electronics
std::array< float, 6 > pulseAvgT_
void set(bool thr, bool mode, uint16_t toa, uint16_t data)
hgc::HGCSimHitData newCharge
std::array< float, 3 > jitterConstant2_ns_
Power< A, B >::type pow(const A &a, const B &b)