CMS 3D CMS Logo

CSCWireElectronicsSim.cc
Go to the documentation of this file.
8 
9 #include "CLHEP/Random/RandGaussQ.h"
10 #include "CLHEP/Units/GlobalPhysicalConstants.h"
11 #include "CLHEP/Units/GlobalSystemOfUnits.h"
12 
13 #include <iostream>
14 
15 
18  theFraction(0.5),
19  theWireNoise(0.0),
20  theWireThreshold(0.)
21 {
23 }
24 
25 
29  * e_SI * pow(10.0,15);
31 }
32 
33 
34 int CSCWireElectronicsSim::readoutElement(int element) const {
35  return theLayerGeometry->wireGroup(element);
36 }
37 
38 void CSCWireElectronicsSim::fillDigis(CSCWireDigiCollection & digis, CLHEP::HepRandomEngine* engine) {
39 
40  if(theSignalMap.empty()) {
41  return;
42  }
43 
44  // Loop over analog signals, run the fractional discriminator on each one,
45  // and save the DIGI in the layer.
46  for(CSCSignalMap::iterator mapI = theSignalMap.begin(),
47  lastSignal = theSignalMap.end();
48  mapI != lastSignal; ++mapI)
49  {
50  int wireGroup = (*mapI).first;
51  const CSCAnalogSignal & signal = (*mapI).second;
52  LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: dump of wire signal follows... "
53  << signal;
54  int signalSize = signal.getSize();
55 
56  int timeWord = 0; // and this will remain if too early or late (<bx-6 or >bx+9)
57 
58  // the way we handle noise in this chamber is by randomly varying
59  // the threshold
61  if (doNoise_) {
62  threshold += CLHEP::RandGaussQ::shoot(engine) * theWireNoise;
63  }
64  for(int ibin = 0; ibin < signalSize; ++ibin)
65  {
66  if(signal.getBinValue(ibin) > threshold)
67  {
68  // jackpot. Now define this signal as everything up until
69  // the signal goes below zero.
70  int lastbin = signalSize;
71  int i;
72  for(i = ibin; i < signalSize; ++i) {
73  if(signal.getBinValue(i) < 0.) {
74  lastbin = i;
75  break;
76  }
77  }
78 
79  float qMax = 0.0;
80  // in this loop, find the max charge and the 'fifth' electron arrival
81  for ( i = ibin; i < lastbin; ++i)
82  {
83  float next_charge = signal.getBinValue(i);
84  if(next_charge > qMax) {
85  qMax = next_charge;
86  }
87  }
88 
89  int bin_firing_FD = 0;
90  for ( i = ibin; i < lastbin; ++i)
91  {
92  if( signal.getBinValue(i) >= qMax * theFraction )
93  {
94  bin_firing_FD = i;
95  //@@ Long-standing but unlikely minor bug, I (Tim) think - following 'break' was missing...
96  //@@ ... So if both ibins 0 and 1 could fire FD, we'd flag the firing bin as 1 not 0
97  //@@ (since the above test was restricted to bin_firing_FD==0 too).
98  break;
99  }
100  }
101 
102  float tofOffset = timeOfFlightCalibration(wireGroup);
103  int chamberType = theSpecs->chamberType();
104 
105  // Note that CSCAnalogSignal::superimpose does not reset theTimeOffset to the earliest
106  // of the two signal's time offsets. If it did then we could handle signals from any
107  // time range e.g. form pileup events many bx's from the signal bx (bx=0).
108  // But then we would be wastefully storing signals over times which we can never
109  // see in the real detector, because only hits within a few bx's of bx=0 are read out.
110  // Instead, the working time range for wire hits is always started from
111  // theSignalStartTime, set as a parameter in the config file.
112  // On the other hand, if any of the overlapped CSCAnalogSignals happens to have
113  // a timeOffset earlier than theSignalStartTime (which is currently set to -100 ns)
114  // then we're in trouble. For pileup events this would mean events from collisions
115  // earlier than 4 bx before the signal bx.
116 
117  float fdTime = theSignalStartTime + theSamplingTime*bin_firing_FD;
118  if(doNoise_) {
119  fdTime += theTimingCalibrationError[chamberType] * CLHEP::RandGaussQ::shoot(engine);
120  }
121 
122  float bxFloat = (fdTime - tofOffset- theBunchTimingOffsets[chamberType]) / theBunchSpacing
124  int bxInt = static_cast<int>(bxFloat);
125  if(bxFloat >= 0 && bxFloat < 16)
126  {
127  timeWord |= (1 << bxInt );
128  // discriminator stays high for 35 ns
129  if(bxFloat-bxInt > 0.6)
130  {
131  timeWord |= (1 << (bxInt+1) );
132  }
133  }
134 
135  // Wire digi as of Oct-2006 adapted to real data: time word has 16 bits with set bit
136  // flagging appropriate bunch crossing, and bx 0 corresponding to the 7th bit, 'bit 6':
137 
138  // 1st bit set (bit 0) <-> bx -6
139  // 2nd 1 <-> bx -5
140  // ... ... ....
141  // 7th 6 <-> bx 0
142  // 8th 7 <-> bx +1
143  // ... ... ....
144  // 16th 15 <-> bx +9
145 
146  // skip over all the time bins used for this digi
147  ibin = lastbin;
148  } // if over threshold
149  } // loop over time bins in signal
150 
151  // Only create a wire digi if there is a wire hit within [-6 bx, +9 bx]
152  if(timeWord != 0)
153  {
154  CSCWireDigi newDigi(wireGroup, timeWord);
155  LogTrace("CSCWireElectronicsSim") << newDigi;
156  digis.insertDigi(layerId(), newDigi);
157  addLinks(channelIndex(wireGroup));
158  }
159  } // loop over wire signals
160 }
161 
162 
164  static const float fC_by_ns = 1000000;
165  static const float resistor = 20000;
166  static const float amplifier_pole = 1/7.5;
167  static const float fastest_chamber_exp_risetime = 10.;
168  static const float p0=amplifier_pole;
169  static const float p1=1/fastest_chamber_exp_risetime;
170 
171  static const float dp = p0 - p1;
172 
173  // ENABLE DISC:
174 
175  static const float norm = -12 * resistor * p1 * pow(p0/dp, 4) / fC_by_ns;
176 
177  float enable_disc_volts = norm*( exp(-p0*t) *(1 +
178  t*dp +
179  pow(t*dp,2)/2 +
180  pow(t*dp,3)/6 )
181  - exp(-p1*t) );
182  static const float collectionFraction = 0.12;
183  static const float igain = 1./0.005; // volts per fC
184  return enable_disc_volts * igain * collectionFraction;
185 }
186 
187 
189  // calibration is done for groups of 8 wire groups, facetiously
190  // called wireGroupGroups
191  int middleWireGroup = wireGroup - wireGroup%8 + 4;
192  int numberOfWireGroups = theLayerGeometry->numberOfWireGroups();
193  if(middleWireGroup > numberOfWireGroups)
194  middleWireGroup = numberOfWireGroups;
195 
196  GlobalPoint centerOfGroupGroup = theLayer->centerOfWireGroup(middleWireGroup);
197  float averageDist = centerOfGroupGroup.mag();
198  float averageTOF = averageDist * cm / c_light; // Units of c_light: mm/ns
199 
200  LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: TofCalib wg = " << wireGroup <<
201  " mid wg = " << middleWireGroup <<
202  " av dist = " << averageDist <<
203  " av tof = " << averageTOF;
204 
205  return averageTOF;
206 }
207 
std::vector< double > theBunchTimingOffsets
float calculateAmpResponse(float t) const override
const CSCChamberSpecs * theSpecs
const CSCLayerGeometry * theLayerGeometry
float getBinValue(int i) const
CSCWireElectronicsSim(const edm::ParameterSet &p)
configurable parameters
int numberOfWireGroups() const
int channelIndex(int channel) const override
we code strip indices from 1-80, and wire indices start at 100
int wireGroup(int wire) const
#define e_SI
T mag() const
Definition: PV3DBase.h:67
float wireNoise(float timeInterval) const
void fillDigis(CSCWireDigiCollection &digis, CLHEP::HepRandomEngine *)
void initParameters() override
initialization for each layer
int readoutElement(int element) const override
int getSize() const
#define LogTrace(id)
GlobalPoint centerOfWireGroup(int wireGroup) const
Definition: CSCLayer.cc:10
virtual void addLinks(int channelIndex)
int chamberType() const
CSCDetId layerId() const
the CSCDetId corresponding to the current layer
double p1[4]
Definition: TauolaWrapper.h:89
virtual float timeOfFlightCalibration(int wireGroup) const
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
std::vector< double > theTimingCalibrationError