CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
HGCFEElectronics.cc
Go to the documentation of this file.
3 
4 using namespace hgc_digi;
5 
6 //
7 template<class DFr>
9  toaMode_(WEIGHTEDBYE)
10 {
11  tdcResolutionInNs_ = 1e-9; // set time resolution very small by default
12 
13  fwVersion_ = ps.getParameter< uint32_t >("fwVersion");
14  edm::LogVerbatim("HGCFE") << "[HGCFEElectronics] running with version " << fwVersion_ << std::endl;
15  if( ps.exists("adcPulse") )
16  {
17  adcPulse_ = ps.getParameter< std::vector<double> >("adcPulse");
18  pulseAvgT_ = ps.getParameter< std::vector<double> >("pulseAvgT");
19  }
20  adcSaturation_fC_=-1.0;
21  if( ps.exists("adcNbits") )
22  {
23  uint32_t adcNbits = ps.getParameter<uint32_t>("adcNbits");
24  adcSaturation_fC_ = ps.getParameter<double>("adcSaturation_fC");
25  adcLSB_fC_=adcSaturation_fC_/pow(2.,adcNbits);
26  edm::LogVerbatim("HGCFE")
27  << "[HGCFEElectronics] " << adcNbits << " bit ADC defined"
28  << " with LSB=" << adcLSB_fC_
29  << " saturation to occur @ " << adcSaturation_fC_ << std::endl;
30  }
31 
32  tdcSaturation_fC_=-1.0;
33  if( ps.exists("tdcNbits") )
34  {
35  uint32_t tdcNbits = ps.getParameter<uint32_t>("tdcNbits");
36  tdcSaturation_fC_ = ps.getParameter<double>("tdcSaturation_fC");
37  tdcLSB_fC_=tdcSaturation_fC_/pow(2.,tdcNbits);
38  edm::LogVerbatim("HGCFE")
39  << "[HGCFEElectronics] " << tdcNbits << " bit TDC defined with LSB="
40  << tdcLSB_fC_ << " saturation to occur @ " << tdcSaturation_fC_ << std::endl;
41  }
42  if( ps.exists("adcThreshold_fC") ) adcThreshold_fC_ = ps.getParameter<double>("adcThreshold_fC");
43  if( ps.exists("tdcOnset_fC") ) tdcOnset_fC_ = ps.getParameter<double>("tdcOnset_fC");
44  if( ps.exists("toaLSB_ns") ) toaLSB_ns_ = ps.getParameter<double>("toaLSB_ns");
45  if( ps.exists("tdcChargeDrainParameterisation") ) tdcChargeDrainParameterisation_ = ps.getParameter< std::vector<double> >("tdcChargeDrainParameterisation");
46  if( ps.exists("tdcResolutionInPs") ) tdcResolutionInNs_ = ps.getParameter<double>("tdcResolutionInPs")*1e-3; // convert to ns
47  if( ps.exists("toaMode") ) toaMode_ = ps.getParameter<uint32_t>("toaMode");
48 }
49 
50 
51 //
52 template<class DFr>
53 void HGCFEElectronics<DFr>::runTrivialShaper(DFr &dataFrame, HGCSimHitData& chargeColl)
54 {
55  bool debug(false);
56 
57 #ifdef EDM_ML_DEBUG
58  for(int it=0; it<(int)(chargeColl.size()); it++) debug |= (chargeColl[it]>adcThreshold_fC_);
59 #endif
60 
61  if(debug) edm::LogVerbatim("HGCFE") << "[runTrivialShaper]" << std::endl;
62 
63  //set new ADCs
64 
65  for(int it=0; it<(int)(chargeColl.size()); it++)
66  {
67  //brute force saturation, maybe could to better with an exponential like saturation
68  const uint32_t adc=std::floor( std::min(chargeColl[it],adcSaturation_fC_) / adcLSB_fC_ );
69  HGCSample newSample;
70  newSample.set(chargeColl[it]>adcThreshold_fC_,false,0,adc);
71  dataFrame.setSample(it,newSample);
72 
73  if(debug) edm::LogVerbatim("HGCFE") << adc << " (" << chargeColl[it] << "/" << adcLSB_fC_ << ") ";
74  }
75 
76  if(debug) {
77  std::ostringstream msg;
78  dataFrame.print(msg);
79  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
80  }
81 }
82 
83 //
84 template<class DFr>
85 void HGCFEElectronics<DFr>::runSimpleShaper(DFr &dataFrame, HGCSimHitData& chargeColl)
86 {
87  //convolute with pulse shape to compute new ADCs
88  newCharge.fill(0.f);
89  bool debug(false);
90  for(int it=0; it<(int)(chargeColl.size()); it++)
91  {
92  const float charge(chargeColl[it]);
93  if(charge==0) continue;
94 
95 #ifdef EDM_ML_DEBUG
96  debug|=(charge>adcThreshold_fC_);
97 #endif
98 
99  if(debug) edm::LogVerbatim("HGCFE") << "\t Redistributing SARS ADC" << charge << " @ " << it;
100 
101  for(int ipulse=-2; ipulse<(int)(adcPulse_.size())-2; ipulse++)
102  {
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;
107 
108  if(debug) edm::LogVerbatim("HGCFE") << " | " << it+ipulse << " " << chargeLeak;
109  }
110 
111  if(debug) edm::LogVerbatim("HGCFE") << std::endl;
112  }
113 
114  //set new ADCs
115  for(int it=0; it<(int)(newCharge.size()); it++)
116  {
117  //brute force saturation, maybe could to better with an exponential like saturation
118  const float saturatedCharge(std::min(newCharge[it],adcSaturation_fC_));
119  HGCSample newSample;
120  newSample.set(newCharge[it]>adcThreshold_fC_,false,0,floor(saturatedCharge/adcLSB_fC_));
121  dataFrame.setSample(it,newSample);
122 
123  if(debug) edm::LogVerbatim("HGCFE") << std::floor(saturatedCharge/adcLSB_fC_) << " (" << saturatedCharge << "/" << adcLSB_fC_ <<" ) " ;
124  }
125 
126  if(debug) {
127  std::ostringstream msg;
128  dataFrame.print(msg);
129  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
130  }
131 }
132 
133 //
134 template<class DFr>
135 void HGCFEElectronics<DFr>::runShaperWithToT(DFr &dataFrame, HGCSimHitData& chargeColl, HGCSimHitData& toaColl, CLHEP::HepRandomEngine* engine)
136 {
137  busyFlags.fill(false);
138  totFlags.fill(false);
139  newCharge.fill( 0.f );
140  toaFromToT.fill( 0.f );
141 
142 #ifdef EDM_ML_DEBUG
143  constexpr bool debug(true);
144 #else
145  constexpr bool debug(false);
146 #endif
147 
148  //first identify bunches which will trigger ToT
149  if(debug) edm::LogVerbatim("HGCFE") << "[runShaperWithToT]" << std::endl;
150  for(int it=0; it<(int)(chargeColl.size()); ++it)
151  {
152  //if already flagged as busy it can't be re-used to trigger the ToT
153  if(busyFlags[it]) continue;
154 
155  //if below TDC onset will be handled by SARS ADC later
156  float charge = chargeColl[it];
157  if(charge < tdcOnset_fC_) continue;
158 
159  //raise TDC mode
160  float toa = toaColl[it];
161  totFlags[it]=true;
162 
163  if(debug) edm::LogVerbatim("HGCFE") << "\t q=" << charge << " fC with <toa>=" << toa << " ns, triggers ToT @ " << it << std::endl;
164 
165  //compute total charge to be integrated and integration time
166  //needs a loop as ToT will last as long as there is charge to dissipate
167  int busyBxs(0);
168  float totalCharge(charge), finalToA(toa), integTime(0);
169  while(true) {
170  //compute integration time in ns and # bunches
171  //float newIntegTime(0);
172  int poffset = 0;
173  float charge_offset = 0.f;
174  const float charge_kfC(totalCharge*1e-3);
175  if(charge_kfC<tdcChargeDrainParameterisation_[3]) {
176  //newIntegTime=tdcChargeDrainParameterisation_[0]*pow(charge_kfC,2)+tdcChargeDrainParameterisation_[1]*charge_kfC+tdcChargeDrainParameterisation_[2];
177  } else if(charge_kfC<tdcChargeDrainParameterisation_[7]) {
178  poffset = 4;
179  charge_offset = tdcChargeDrainParameterisation_[3];
180  //newIntegTime=tdcChargeDrainParameterisation_[4]*pow(charge_kfC-tdcChargeDrainParameterisation_[3],2)+tdcChargeDrainParameterisation_[5]*(charge_kfC-tdcChargeDrainParameterisation_[3])+tdcChargeDrainParameterisation_[6];
181  } else {
182  poffset = 8;
183  charge_offset = tdcChargeDrainParameterisation_[7];
184  //newIntegTime=tdcChargeDrainParameterisation_[8]*pow(charge_kfC-tdcChargeDrainParameterisation_[7],2)+tdcChargeDrainParameterisation_[9]*(charge_kfC-tdcChargeDrainParameterisation_[7])+tdcChargeDrainParameterisation_[10];
185  }
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] );
190 
191 
192 
193  const int newBusyBxs=std::floor(newIntegTime/25.f)+1;
194 
195  //if no update is needed regarding the number of bunches,
196  //then the ToT integration time has converged
197  integTime=newIntegTime;
198  if(newBusyBxs==busyBxs) break;
199 
200  //update charge integrated during ToT
201  if(debug)
202  {
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;
205  }
206 
207  //update number of busy bunches
208  busyBxs=newBusyBxs;
209 
210  //reset charge to be integrated
211  totalCharge=charge;
212  if(toaMode_==WEIGHTEDBYE) finalToA=toa*charge;
213 
214  //add leakage from previous bunches in SARS ADC mode
215  for(int jt=0; jt<it; ++jt)
216  {
217  if(totFlags[jt] || busyFlags[jt]) continue;
218 
219  const float chargeDep_jt(chargeColl[jt]);
220  if(chargeDep_jt==0) continue;
221 
222  const int deltaT=(it-jt);
223  if(deltaT+2>(int)(adcPulse_.size())) continue;
224 
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;
227 
228  totalCharge += leakCharge;
229  if(toaMode_==WEIGHTEDBYE) finalToA += leakCharge*pulseAvgT_[deltaT+2];
230  }
231 
232  //add contamination from posterior bunches
233  for(int jt=it+1; jt<it+busyBxs && jt<dataFrame.size() ; ++jt)
234  {
235  //this charge will be integrated in TDC mode
236  //disable for SARS ADC
237  busyFlags[jt]=true;
238 
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;
242 
243  totalCharge += extraCharge;
244  if(toaMode_==WEIGHTEDBYE) finalToA += extraCharge*toaColl[jt];
245  }
246 
247  //finalize ToA contamination
248  if(toaMode_==WEIGHTEDBYE) finalToA /= totalCharge;
249  }
250 
251  toaFromToT[it] = CLHEP::RandGaussQ::shoot(engine,finalToA,tdcResolutionInNs_);
252  newCharge[it] = (totalCharge-tdcOnset_fC_);
253 
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;
256 
257  //last fC (tdcOnset) are dissipated trough pulse
258  if(it+busyBxs<(int)(newCharge.size()))
259  {
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;
267  }
268  }
269 
270  //including the leakage from bunches in SARS ADC when not declared busy or in ToT
271  for(int it=0; it<(int)(chargeColl.size()); it++)
272  {
273  //if busy, charge has been already integrated
274  if(totFlags[it] || busyFlags[it]) continue;
275  const float charge(chargeColl[it]);
276  if(charge==0) continue;
277 
278  if(debug) edm::LogVerbatim("HGCFE") << "\t SARS ADC pulse activated @ " << it << " : ";
279  for(int ipulse=-2; ipulse<(int)(adcPulse_.size())-2; ipulse++)
280  {
281  if(it+ipulse<0) continue;
282  if(it+ipulse>=(int)(newCharge.size())) continue;
283 
284  //notice that if the channel is already busy,
285  //it has already been affected by the leakage of the SARS ADC
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;
290  if(debug) edm::LogVerbatim("HGCFE") << newCharge[it+ipulse] << ") ";
291  }
292 
293  if(debug) edm::LogVerbatim("HGCFE") << std::endl;
294  }
295 
296  //set new ADCs and ToA
297  if(debug) edm::LogVerbatim("HGCFE") << "\t final result : ";
298  for(int it=0; it<(int)(newCharge.size()); it++)
299  {
300  if(debug) edm::LogVerbatim("HGCFE") << chargeColl[it] << " -> " << newCharge[it] << " ";
301 
302  HGCSample newSample;
303  if(totFlags[it] || busyFlags[it])
304  {
305  if(totFlags[it])
306  {
307  float finalToA(toaFromToT[it]);
308  while(finalToA<0) finalToA+=25.;
309  while(finalToA>25) finalToA-=25;
310 
311  //brute force saturation, maybe could to better with an exponential like saturation
312  float saturatedCharge(std::min(newCharge[it],tdcSaturation_fC_));
313  newSample.set(true,true,finalToA/toaLSB_ns_,floor(saturatedCharge/tdcLSB_fC_));
314  }
315  else
316  {
317  newSample.set(false,true,0,0);
318  }
319  }
320  else
321  {
322  //brute force saturation, maybe could to better with an exponential like saturation
323  float saturatedCharge(std::min(newCharge[it],adcSaturation_fC_));
324  newSample.set(newCharge[it]>adcThreshold_fC_,false,0,saturatedCharge/adcLSB_fC_);
325  }
326  dataFrame.setSample(it,newSample);
327  }
328 
329  if(debug) {
330  std::ostringstream msg;
331  dataFrame.print(msg);
332  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
333  }
334 }
335 
336 // cause the compiler to generate the appropriate code
338 template class HGCFEElectronics<HGCEEDataFrame>;
339 template class HGCFEElectronics<HGCHEDataFrame>;
340 
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 &parameterName) const
checks if a parameter exists
wrapper for a data word
Definition: HGCSample.h:13
#define constexpr
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.
double f[11][100]
T min(T a, T b)
Definition: MathUtil.h:58
void runShaperWithToT(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine)
implements pulse shape and switch to time over threshold including deadtime
#define debug
Definition: HDRShower.cc:19
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)
Definition: HGCSample.h:33
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40