5 #include "vdt/vdtMath.h" 30 if (ps.exists(
"adcPulse")) {
31 auto temp = ps.getParameter<std::vector<double> >(
"adcPulse");
32 for (
unsigned i = 0;
i <
temp.size(); ++
i) {
39 temp = ps.getParameter<std::vector<double> >(
"pulseAvgT");
40 for (
unsigned i = 0;
i <
temp.size(); ++
i) {
44 if (ps.exists(
"adcNbits")) {
45 uint32_t
adcNbits = ps.getParameter<uint32_t>(
"adcNbits");
48 edm::LogVerbatim(
"HGCFE") <<
"[HGCFEElectronics] " << adcNbits <<
" bit ADC defined" 49 <<
" with LSB=" << adcLSB_fC_ <<
" saturation to occur @ " << adcSaturation_fC_
53 if (ps.exists(
"tdcNbits")) {
54 uint32_t
tdcNbits = ps.getParameter<uint32_t>(
"tdcNbits");
57 edm::LogVerbatim(
"HGCFE") <<
"[HGCFEElectronics] " << tdcNbits <<
" bit TDC defined with LSB=" << tdcLSB_fC_
58 <<
" saturation to occur @ " << tdcSaturation_fC_ << std::endl;
60 if (ps.exists(
"targetMIPvalue_ADC"))
62 if (ps.exists(
"adcThreshold_fC"))
64 if (ps.exists(
"tdcOnset_fC"))
66 if (ps.exists(
"tdcForToAOnset_fC")) {
67 auto temp = ps.getParameter<std::vector<double> >(
"tdcForToAOnset_fC");
71 throw cms::Exception(
"BadConfiguration") <<
" HGCFEElectronics wrong size for ToA thresholds ";
74 if (ps.exists(
"toaLSB_ns"))
75 toaLSB_ns_ = ps.getParameter<
double>(
"toaLSB_ns");
76 if (ps.exists(
"tdcChargeDrainParameterisation")) {
77 for (
auto val : ps.getParameter<std::vector<double> >(
"tdcChargeDrainParameterisation")) {
81 if (ps.exists(
"tdcResolutionInPs"))
83 if (ps.exists(
"toaMode"))
84 toaMode_ = ps.getParameter<uint32_t>(
"toaMode");
86 if (ps.exists(
"jitterNoise_ns")) {
87 auto temp = ps.getParameter<std::vector<double> >(
"jitterNoise_ns");
91 throw cms::Exception(
"BadConfiguration") <<
" HGCFEElectronics wrong size for ToA jitterNoise ";
94 if (ps.exists(
"jitterConstant_ns")) {
95 auto temp = ps.getParameter<std::vector<double> >(
"jitterConstant_ns");
99 throw cms::Exception(
"BadConfiguration") <<
" HGCFEElectronics wrong size for ToA jitterConstant ";
107 DFr& dataFrame,
HGCSimHitData& chargeColl, uint32_t thrADC,
float lsbADC, uint32_t gainIdx,
float maxADC) {
111 for (
int it = 0; it < (
int)(chargeColl.size()); it++)
125 for (
int it = 0; it < (
int)(chargeColl.size()); it++) {
127 const uint32_t
adc = std::floor(
std::min(chargeColl[it], maxADC) / lsbADC);
129 newSample.
set(adc > thrADC,
false, gainIdx, 0, adc);
130 dataFrame.setSample(it, newSample);
137 std::ostringstream
msg;
138 dataFrame.print(msg);
146 DFr& dataFrame,
HGCSimHitData& chargeColl, uint32_t thrADC,
float lsbADC, uint32_t gainIdx,
float maxADC) {
150 for (
int it = 0; it < (
int)(chargeColl.size()); it++) {
151 const float charge(chargeColl[it]);
160 edm::LogVerbatim(
"HGCFE") <<
"\t Redistributing SARS ADC" << charge <<
" @ " << it;
162 for (
int ipulse = -2; ipulse < (
int)(
adcPulse_.size()) - 2; ipulse++) {
165 if (it + ipulse >= (
int)(dataFrame.size()))
167 const float chargeLeak = charge *
adcPulse_[(ipulse + 2)];
182 newSample.
set(adc > thrADC,
false, gainIdx, 0, adc);
183 dataFrame.setSample(it, newSample);
190 std::ostringstream
msg;
191 dataFrame.print(msg);
201 CLHEP::HepRandomEngine* engine,
219 bool debug = debug_state;
229 if (toaColl[fireBX] != 0.
f) {
230 timeToA = toaColl[fireBX];
233 timeToA = CLHEP::RandGaussQ::shoot(engine, timeToA, jitter);
236 if (timeToA >= 0.
f && timeToA <= 25.
f)
243 for (
int it = 0; it < (
int)(chargeColl.size()); ++it) {
250 float charge = chargeColl[it];
262 edm::LogVerbatim(
"HGCFE") <<
"\t q=" << charge <<
" fC with <toa>=" << toa <<
" ns, triggers ToT @ " << it
268 float totalCharge(charge), finalToA(toa), integTime(0);
273 float charge_offset = 0.f;
274 const float charge_kfC(totalCharge * 1
e-3);
286 const float charge_mod = charge_kfC - charge_offset;
287 const float newIntegTime =
292 const int newBusyBxs = std::floor(newIntegTime / 25.
f) + 1;
296 integTime = newIntegTime;
297 if (newBusyBxs == busyBxs)
303 edm::LogVerbatim(
"HGCFE") <<
"\t Intial busy estimate=" << integTime <<
" ns = " << newBusyBxs <<
" bxs" 306 edm::LogVerbatim(
"HGCFE") <<
"\t ...integrated charge overflows initial busy estimate, interating again" 311 busyBxs = newBusyBxs;
319 for (
int jt = 0; jt < it; ++jt) {
320 const unsigned int deltaT = (it - jt);
324 const float leakCharge = chargeColl[jt] *
adcPulse_[deltaT + 2];
325 totalCharge += leakCharge;
327 finalToA += leakCharge *
pulseAvgT_[deltaT + 2];
330 edm::LogVerbatim(
"HGCFE") <<
"\t\t leaking " << chargeColl[jt] <<
" fC @ deltaT=-" << deltaT <<
" -> +" 331 << leakCharge <<
" with avgT=" << pulseAvgT_[deltaT + 2] << std::endl;
335 for (
int jt = it + 1; jt < it + busyBxs && jt < dataFrame.size(); ++jt) {
340 const float extraCharge = chargeColl[jt];
341 if (extraCharge == 0.
f)
344 edm::LogVerbatim(
"HGCFE") <<
"\t\t adding " << extraCharge <<
" fC @ deltaT=+" << (jt - it) << std::endl;
346 totalCharge += extraCharge;
348 finalToA += extraCharge * toaColl[jt];
353 finalToA /= totalCharge;
358 edm::LogVerbatim(
"HGCFE") <<
"\t Final busy estimate=" << integTime <<
" ns = " << busyBxs <<
" bxs" << std::endl
359 <<
"\t Total integrated=" << totalCharge <<
" fC <toa>=" <<
toaFromToT[it]
360 <<
" (raw=" << finalToA <<
") ns " << std::endl;
363 if (it + busyBxs < (
int)(
newCharge.size())) {
364 const float deltaT2nextBx((busyBxs * 25 - integTime));
368 << deltaT2nextBx <<
" DeltaT/tau=" << deltaT2nextBx <<
" / " 370 << it + busyBxs <<
" bx (first free bx)" << std::endl;
371 newCharge[it + busyBxs] += tdcOnsetLeakage;
376 auto runChargeSharing = [&]() {
378 for (
int it = 0; it < (
int)(chargeColl.size()); ++it) {
384 for (ipulse = start; ipulse < stop; ++ipulse) {
385 const int itoffset = it + ipulse - 2;
437 true,
true, gainIdx, (uint16_t)(timeToA /
toaLSB_ns_), (uint16_t)(std::floor(saturatedCharge /
tdcLSB_fC_)));
441 newSample.
set(
false,
true, gainIdx, 0, 0);
445 const uint16_t
adc = std::floor(
std::min(newCharge[it], maxADC) / lsbADC);
447 newSample.
set(adc > thrADC,
false, gainIdx, (uint16_t)(timeToA /
toaLSB_ns_), adc);
451 dataFrame.setSample(it, newSample);
455 std::ostringstream
msg;
456 dataFrame.print(msg);
std::array< bool, hgc::nSamples > busyFlags
T getParameter(std::string const &) const
std::array< float, 3 > jitterConstant2_ns_
std::array< float, 3 > jitterNoise2_ns_
hgc::HGCSimHitData toaFromToT
std::array< HGCSimData_t, nSamples > HGCSimHitData
float getTimeJitter(float totalCharge, int thickness)
HGCFEElectronics(const edm::ParameterSet &ps)
CTOR.
uint32_t targetMIPvalue_ADC_
std::vector< float > noise_fC_
constexpr int adc(sample_type sample)
get the ADC sample (12 bits)
void setToAValid(bool toaFired)
std::array< bool, hgc::nSamples > totFlags
std::array< float, 6 > adcPulse_
void runShaperWithToT(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, int thickness)
implements pulse shape and switch to time over threshold including deadtime
std::array< float, 6 > pulseAvgT_
void runTrivialShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC)
converts charge to digis without pulse shape
std::vector< float > tdcChargeDrainParameterisation_
models the behavior of the front-end electronics
void set(bool thr, bool mode, uint16_t gain, uint16_t toa, uint16_t data)
void runSimpleShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC)
applies a shape to each time sample and propagates the tails to the subsequent time samples ...
hgc::HGCSimHitData newCharge
Power< A, B >::type pow(const A &a, const B &b)
std::array< float, 3 > tdcForToAOnset_fC_
std::array< bool, hgc::nSamples > toaFlags