#include <CSCWireElectronicsSim.h>
Public Member Functions | |
CSCWireElectronicsSim (const edm::ParameterSet &p) | |
configurable parameters | |
void | fillDigis (CSCWireDigiCollection &digis) |
void | setFraction (float newFraction) |
Private Member Functions | |
float | calculateAmpResponse (float t) const |
virtual int | channelIndex (int channel) const |
we code strip indices from 1-80, and wire indices start at 100 | |
virtual void | initParameters () |
initialization for each layer | |
virtual int | readoutElement (int element) const |
virtual float | timeOfFlightCalibration (int wireGroup) const |
Private Attributes | |
float | theFraction |
float | theWireNoise |
float | theWireThreshold |
Model the readout electronics chain for EMU CSC wires
Definition at line 21 of file CSCWireElectronicsSim.h.
CSCWireElectronicsSim::CSCWireElectronicsSim | ( | const edm::ParameterSet & | p | ) |
configurable parameters
Definition at line 13 of file CSCWireElectronicsSim.cc.
References CSCBaseElectronicsSim::fillAmpResponse().
: CSCBaseElectronicsSim(p), theFraction(0.5), theWireNoise(0.0), theWireThreshold(0.) { fillAmpResponse(); }
float CSCWireElectronicsSim::calculateAmpResponse | ( | float | t | ) | const [private, virtual] |
Implements CSCBaseElectronicsSim.
Definition at line 160 of file CSCWireElectronicsSim.cc.
References funct::exp(), lumiNorm::norm, p1, and funct::pow().
{ static const float fC_by_ns = 1000000; static const float resistor = 20000; static const float amplifier_pole = 1/7.5; static const float fastest_chamber_exp_risetime = 10.; static const float p0=amplifier_pole; static const float p1=1/fastest_chamber_exp_risetime; static const float dp = p0 - p1; // ENABLE DISC: static const float norm = -12 * resistor * p1 * pow(p0/dp, 4) / fC_by_ns; float enable_disc_volts = norm*( exp(-p0*t) *(1 + t*dp + pow(t*dp,2)/2 + pow(t*dp,3)/6 ) - exp(-p1*t) ); static const float collectionFraction = 0.12; static const float igain = 1./0.005; // volts per fC return enable_disc_volts * igain * collectionFraction; }
virtual int CSCWireElectronicsSim::channelIndex | ( | int | channel | ) | const [inline, private, virtual] |
we code strip indices from 1-80, and wire indices start at 100
Reimplemented from CSCBaseElectronicsSim.
Definition at line 43 of file CSCWireElectronicsSim.h.
Referenced by fillDigis().
{return channel+100;}
void CSCWireElectronicsSim::fillDigis | ( | CSCWireDigiCollection & | digis | ) |
Definition at line 35 of file CSCWireElectronicsSim.cc.
References CSCBaseElectronicsSim::addLinks(), CSCChamberSpecs::chamberType(), channelIndex(), CSCBaseElectronicsSim::doNoise_, CSCAnalogSignal::getBinValue(), CSCAnalogSignal::getSize(), i, CSCBaseElectronicsSim::layerId(), LogTrace, CSCBaseElectronicsSim::theBunchSpacing, CSCBaseElectronicsSim::theBunchTimingOffsets, theFraction, CSCBaseElectronicsSim::theOffsetOfBxZero, CSCBaseElectronicsSim::theRandGaussQ, CSCBaseElectronicsSim::theSamplingTime, CSCBaseElectronicsSim::theSignalMap, CSCBaseElectronicsSim::theSignalStartTime, CSCBaseElectronicsSim::theSpecs, CSCBaseElectronicsSim::theTimingCalibrationError, theWireNoise, theWireThreshold, dtT0WireCalibration_cfg::threshold, and timeOfFlightCalibration().
Referenced by CSCDigitizer::doAction().
{ if(theSignalMap.empty()) { return; } // Loop over analog signals, run the fractional discriminator on each one, // and save the DIGI in the layer. for(CSCSignalMap::iterator mapI = theSignalMap.begin(), lastSignal = theSignalMap.end(); mapI != lastSignal; ++mapI) { int wireGroup = (*mapI).first; const CSCAnalogSignal & signal = (*mapI).second; LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: dump of wire signal follows... " << signal; int signalSize = signal.getSize(); int timeWord = 0; // and this will remain if too early or late (<bx-6 or >bx+9) // the way we handle noise in this chamber is by randomly varying // the threshold float threshold = theWireThreshold; if (doNoise_) { threshold += theRandGaussQ->fire() * theWireNoise; } for(int ibin = 0; ibin < signalSize; ++ibin) { if(signal.getBinValue(ibin) > threshold) { // jackpot. Now define this signal as everything up until // the signal goes below zero. int lastbin = signalSize; int i; for(i = ibin; i < signalSize; ++i) { if(signal.getBinValue(i) < 0.) { lastbin = i; break; } } float qMax = 0.0; // in this loop, find the max charge and the 'fifth' electron arrival for ( i = ibin; i < lastbin; ++i) { float next_charge = signal.getBinValue(i); if(next_charge > qMax) { qMax = next_charge; } } int bin_firing_FD = 0; for ( i = ibin; i < lastbin; ++i) { if( signal.getBinValue(i) >= qMax * theFraction ) { bin_firing_FD = i; //@@ Long-standing but unlikely minor bug, I (Tim) think - following 'break' was missing... //@@ ... So if both ibins 0 and 1 could fire FD, we'd flag the firing bin as 1 not 0 //@@ (since the above test was restricted to bin_firing_FD==0 too). break; } } float tofOffset = timeOfFlightCalibration(wireGroup); int chamberType = theSpecs->chamberType(); // Note that CSCAnalogSignal::superimpose does not reset theTimeOffset to the earliest // of the two signal's time offsets. If it did then we could handle signals from any // time range e.g. form pileup events many bx's from the signal bx (bx=0). // But then we would be wastefully storing signals over times which we can never // see in the real detector, because only hits within a few bx's of bx=0 are read out. // Instead, the working time range for wire hits is always started from // theSignalStartTime, set as a parameter in the config file. // On the other hand, if any of the overlapped CSCAnalogSignals happens to have // a timeOffset earlier than theSignalStartTime (which is currently set to -100 ns) // then we're in trouble. For pileup events this would mean events from collisions // earlier than 4 bx before the signal bx. float fdTime = theSignalStartTime + theSamplingTime*bin_firing_FD; if(doNoise_) { fdTime += theTimingCalibrationError[chamberType] * theRandGaussQ->fire(); } float bxFloat = (fdTime - tofOffset- theBunchTimingOffsets[chamberType]) / theBunchSpacing + theOffsetOfBxZero; int bxInt = static_cast<int>(bxFloat); if(bxFloat >= 0 && bxFloat < 16) { timeWord |= (1 << bxInt ); // discriminator stays high for 35 ns if(bxFloat-bxInt > 0.6) { timeWord |= (1 << (bxInt+1) ); } } // Wire digi as of Oct-2006 adapted to real data: time word has 16 bits with set bit // flagging appropriate bunch crossing, and bx 0 corresponding to the 7th bit, 'bit 6': // 1st bit set (bit 0) <-> bx -6 // 2nd 1 <-> bx -5 // ... ... .... // 7th 6 <-> bx 0 // 8th 7 <-> bx +1 // ... ... .... // 16th 15 <-> bx +9 // skip over all the time bins used for this digi ibin = lastbin; } // if over threshold } // loop over time bins in signal // Only create a wire digi if there is a wire hit within [-6 bx, +9 bx] if(timeWord != 0) { CSCWireDigi newDigi(wireGroup, timeWord); LogTrace("CSCWireElectronicsSim") << newDigi; digis.insertDigi(layerId(), newDigi); addLinks(channelIndex(wireGroup)); } } // loop over wire signals }
void CSCWireElectronicsSim::initParameters | ( | ) | [private, virtual] |
initialization for each layer
Implements CSCBaseElectronicsSim.
Definition at line 23 of file CSCWireElectronicsSim.cc.
References e_SI, CSCBaseElectronicsSim::nElements, CSCLayerGeometry::numberOfWireGroups(), funct::pow(), CSCBaseElectronicsSim::theLayerGeometry, CSCBaseElectronicsSim::theShapingTime, CSCBaseElectronicsSim::theSpecs, theWireNoise, theWireThreshold, and CSCChamberSpecs::wireNoise().
{ nElements = theLayerGeometry->numberOfWireGroups(); theWireNoise = theSpecs->wireNoise(theShapingTime) * e_SI * pow(10.0,15); theWireThreshold = theWireNoise * 8; }
int CSCWireElectronicsSim::readoutElement | ( | int | element | ) | const [private, virtual] |
Implements CSCBaseElectronicsSim.
Definition at line 31 of file CSCWireElectronicsSim.cc.
References CSCBaseElectronicsSim::theLayerGeometry, and CSCLayerGeometry::wireGroup().
{ return theLayerGeometry->wireGroup(element); }
void CSCWireElectronicsSim::setFraction | ( | float | newFraction | ) | [inline] |
Definition at line 27 of file CSCWireElectronicsSim.h.
References theFraction.
{theFraction = newFraction;};
float CSCWireElectronicsSim::timeOfFlightCalibration | ( | int | wireGroup | ) | const [private, virtual] |
Definition at line 185 of file CSCWireElectronicsSim.cc.
References CSCLayer::centerOfWireGroup(), LogTrace, PV3DBase< T, PVType, FrameType >::mag(), CSCLayerGeometry::numberOfWireGroups(), CSCBaseElectronicsSim::theLayer, and CSCBaseElectronicsSim::theLayerGeometry.
Referenced by fillDigis().
{ // calibration is done for groups of 8 wire groups, facetiously // called wireGroupGroups int middleWireGroup = wireGroup - wireGroup%8 + 4; int numberOfWireGroups = theLayerGeometry->numberOfWireGroups(); if(middleWireGroup > numberOfWireGroups) middleWireGroup = numberOfWireGroups; GlobalPoint centerOfGroupGroup = theLayer->centerOfWireGroup(middleWireGroup); float averageDist = centerOfGroupGroup.mag(); float averageTOF = averageDist * cm / c_light; // Units of c_light: mm/ns LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: TofCalib wg = " << wireGroup << " mid wg = " << middleWireGroup << " av dist = " << averageDist << " av tof = " << averageTOF; return averageTOF; }
float CSCWireElectronicsSim::theFraction [private] |
Definition at line 48 of file CSCWireElectronicsSim.h.
Referenced by fillDigis(), and setFraction().
float CSCWireElectronicsSim::theWireNoise [private] |
Definition at line 49 of file CSCWireElectronicsSim.h.
Referenced by fillDigis(), and initParameters().
float CSCWireElectronicsSim::theWireThreshold [private] |
Definition at line 50 of file CSCWireElectronicsSim.h.
Referenced by fillDigis(), and initParameters().