SimQieElectronics Class Reference

#include <SimQieElectronics.h>

Inheritance diagram for SimQieElectronics:

SimElectronics SimQiePerfectElectronics List of all members.

Public Member Functions

 SimQieElectronics (VldContext context, TRandom *random=NULL)
virtual ~SimQieElectronics (void)
virtual void Reset (const VldContext &newContext)
virtual void ReadoutDetector (SimPmtList &fPmtList)
virtual void Print (Option_t *option="") const
virtual void Config (Registry &config)
virtual void ReadoutPmt (SimPmt *pmt)
virtual Bool_t DynodeTrigger (SimPmt *pmt)
virtual int GenSimulatedADC (RawChannelId rcid, PlexPixelSpotId psid, double inCharge, int tdc)
void SetupTables (void)
 ClassDef (SimQieElectronics, 1)

Public Attributes

SimQieClock fClock
Double_t fFlipPoint [9]
Double_t fAdcDacSlope [8]
Double_t fFlipLowAdc [8]
Double_t fFlipHighAdc [8]
Int_t fQieDoLookup
Double_t fQieDacCharge
Double_t fQieDacPerRangeZeroAdc
Double_t fQiePedestalWidthAdc
Double_t fQieAdcRms
Int_t fQiePedestalDac
Int_t fQieSparsifyThresh
Int_t fDoLookupNonlinearity

Detailed Description

Id
SimQieElectronics.h,v 1.7 2006/03/08 23:22:57 tagg Exp

SimQIEElectronics

Simple implimentation of the QIEfront-end.

Assumes all channels identical. Assumes fast extraction mode. Assumes CNTRST happens at PPS, which is false.

Assumes real ND, not CalDet: no dynode trigger, no CalDet timing (a 0.01% timing correction), neither of which should be important.

n.tagg1@physics.ox.ac.uk

Definition at line 26 of file SimQieElectronics.h.


Constructor & Destructor Documentation

SimQieElectronics::SimQieElectronics ( VldContext  context,
TRandom *  random = NULL 
)

Definition at line 16 of file SimQieElectronics.cxx.

00017   : SimElectronics( context, random ),
00018     fClock(context),
00019     fQieDoLookup(1),
00020     fQieDacCharge(1.4*Munits::fC),
00021     fQieDacPerRangeZeroAdc(1.92),
00022     fQiePedestalWidthAdc(1.5),
00023     fQieAdcRms(0),
00024     fQiePedestalDac(50),
00025     fQieSparsifyThresh(70),
00026     fDoLookupNonlinearity(0)
00027 {
00028   SetupTables();
00029 }

virtual SimQieElectronics::~SimQieElectronics ( void   )  [inline, virtual]

Definition at line 31 of file SimQieElectronics.h.

00031 {};


Member Function Documentation

SimQieElectronics::ClassDef ( SimQieElectronics  ,
 
)

void SimQieElectronics::Config ( Registry config  )  [virtual]

Reimplemented from SimElectronics.

Definition at line 314 of file SimQieElectronics.cxx.

References fDoLookupNonlinearity, fQieAdcRms, fQieDacCharge, fQieDacPerRangeZeroAdc, fQieDoLookup, fQiePedestalDac, fQiePedestalWidthAdc, fQieSparsifyThresh, Registry::Get(), Msg::kWarning, MSG, and SetupTables().

00315 {
00316   // Modify the configuration.
00317   //
00318   // Use this method to set static members with the class configuration.
00319   config.Get("qieDoLookup",fQieDoLookup);
00320   config.Get("qieDacCharge",fQieDacCharge);
00321   config.Get("qieDacPerRangeZeroAdc",fQieDacPerRangeZeroAdc);
00322   config.Get("qiePedestalWidthAdc",fQiePedestalWidthAdc);
00323   config.Get("qieAdcRms",fQieAdcRms);
00324   config.Get("qiePedestalDac",fQiePedestalDac);
00325   config.Get("qieSparsifyThresh",fQieSparsifyThresh);
00326   config.Get("doLookupNonlinearity",fDoLookupNonlinearity);
00327 
00328   if(fQieSparsifyThresh<fQiePedestalDac) 
00329     MSG("DetSim",Msg::kWarning) << "WARNING: The QIE sparsification threshold " << std::endl
00330                                 << "         is less than the digital offset!" << std::endl
00331                                 << "         This turns off all sparsification!" << std::endl;
00332 
00333 
00334   SetupTables();
00335 }

Bool_t SimQieElectronics::DynodeTrigger ( SimPmt pmt  )  [virtual]

Definition at line 154 of file SimQieElectronics.cxx.

00155 {
00156   // No dynode simulation...yet.
00157   return true;  
00158 }

int SimQieElectronics::GenSimulatedADC ( RawChannelId  rcid,
PlexPixelSpotId  psid,
double  inCharge,
int  tdc 
) [virtual]

Reimplemented in SimQiePerfectElectronics.

Definition at line 209 of file SimQieElectronics.cxx.

References Calibrator::DecalLinearity(), fAdcDacSlope, Munits::fC, SimElectronics::fContext, fDoLookupNonlinearity, fFlipLowAdc, fFlipPoint, fQieAdcRms, fQieDacCharge, fQieDacPerRangeZeroAdc, fQieDoLookup, fQiePedestalDac, fQiePedestalWidthAdc, SimElectronics::fRandom, PlexHandle::GetStripEndId(), Calibrator::Instance(), PlexStripEndId::IsValid(), Msg::kVerbose, and MSG.

Referenced by ReadoutPmt().

00213 {
00214   //
00215   // This routine converts from a charge in fC to a 
00216   // QIE digitized charge.  Note that 'ADC' is an overloaded term here,
00217   // since these aren't ADC counts but rather lookup table values.
00218   // The units are actually DAC counts, which are 1.4 fC/ DAC.
00219   //
00220 
00221   // Convert to DAC charge units. These are the units of charge
00222   // used by the sharge injection system.
00223   double true_dacs = inCharge / fQieDacCharge;
00224 
00225   // Do nonlinearity curve.
00226   if (fDoLookupNonlinearity) {
00227     PlexHandle plex(fContext);
00228     PlexStripEndId seid = plex.GetStripEndId(psid);
00229     if(seid.IsValid())
00230       true_dacs = Calibrator::Instance().DecalLinearity(true_dacs, seid);
00231   }
00232 
00233   // Add some smear, by the pedestal RMS in DAC counts.
00234   double dacs = fRandom->Gaus(true_dacs, 
00235                               fQiePedestalWidthAdc * fQieDacPerRangeZeroAdc);
00236 
00237   // Figure out what range you're in.
00238  // Find the range and pos within range.
00239   int range = 0;
00240   if     (dacs < fFlipPoint[1])  range = 0;
00241   else if(dacs < fFlipPoint[2])  range = 1;
00242   else if(dacs < fFlipPoint[3])  range = 2;
00243   else if(dacs < fFlipPoint[4])  range = 3;
00244   else if(dacs < fFlipPoint[5])  range = 4;
00245   else if(dacs < fFlipPoint[6])  range = 5;
00246   else if(dacs < fFlipPoint[7])  range = 6;
00247   else                           range = 7;
00248 
00249 
00250   // Now find the ADC value.
00251   double adc = fFlipLowAdc[range] + fAdcDacSlope[range]*(dacs - fFlipPoint[range]);
00252 
00253   // Smear by a constant resolution function.
00254   // i.e. if all values are wrong by 1.2 ADC counts rms, this does it.
00255   // This is set to zero by default because it is difficult to seperate
00256   // the charge injector error from the ADC conversion error.
00257   if(fQieAdcRms>0)
00258     adc = fRandom->Gaus(adc,fQieAdcRms);
00259 
00260   // Make it an integer again.
00261   // Rounding is probably the most appropriate, given that we have correctly 
00262   // calibrated the pedestals and whatnot.
00263   
00264   if(adc>255) adc=255.;
00265   if(adc<0)   adc=0.;
00266   double iadc = TMath::Nint(adc);
00267 
00268   if(fQieDoLookup==0) {
00269     // We have turned off the lookup table, so we need to simply pack the output
00270     // word:
00271     int adc8bits = (int)iadc;
00272     int capid = tdc%4; // CapID rotates 0123 with the clock
00273     int dataword = (adc8bits & 0xFF) | (range << 8)  | (capid << 11); 
00274     return dataword;
00275   }
00276 
00277   // Go back through the lookup table.
00278   double outdac = (iadc-fFlipLowAdc[range]) / fAdcDacSlope[range] + fFlipPoint[range];
00279   
00280   // Add the digital offset
00281   outdac += fQiePedestalDac;
00282 
00283   // Round to a final value.
00284   // FIXME: Dave simply truncates this number in the lookup table, so I will too.
00285   // This may change.
00286   int final_dac = (int) ( floor(outdac) );
00287   
00288   if(final_dac < 0) final_dac = 0; // The floor of the lookup table.
00289 
00290   if(final_dac > 0xffff) final_dac = 0xffff; // Final check to ensure it packs into a 16 bit word.
00291   MSG("DetSim",Msg::kVerbose) 
00292     << "QIE: " << inCharge/Munits::fC << "fC -> "
00293     << " True DACs " << true_dacs
00294     << " Range: " << range
00295     << " ADC: " << adc
00296     << " -> DAC: " << final_dac << endl;
00297   return final_dac;
00298 }

void SimQieElectronics::Print ( Option_t *  option = ""  )  const [virtual]

Reimplemented from SimElectronics.

Reimplemented in SimQiePerfectElectronics.

Definition at line 302 of file SimQieElectronics.cxx.

References Munits::fC, fDoLookupNonlinearity, fQieDacCharge, fQieDacPerRangeZeroAdc, fQieDoLookup, fQiePedestalDac, fQiePedestalWidthAdc, and fQieSparsifyThresh.

00303 {
00304   printf("SimQieElectronics: qieDoLookup           %s\n",(fQieDoLookup)?("true"):("false"));
00305   printf("                   qieDacCharge          %.2f fC\n", fQieDacCharge/Munits::fC);
00306   printf("                   qieDacPerRangeZeroAdc %.2f DACs\n",fQieDacPerRangeZeroAdc);
00307   printf("                   qiePedestalWidthAdc   %.2f Range-zero ADCs\n",fQiePedestalWidthAdc);
00308   printf("                   qiePedestalDac        %d DAC\n",fQiePedestalDac);
00309   printf("                   qieSparsifyThresh     %d DAC\n",fQieSparsifyThresh);
00310   printf("                   doLookupNonlinearity  %s \n",fDoLookupNonlinearity?("on"):("off") );
00311 }

void SimQieElectronics::ReadoutDetector ( SimPmtList fPmtList  )  [virtual]

Reimplemented from SimElectronics.

Definition at line 38 of file SimQieElectronics.cxx.

References SimElectronics::fContext, RawChannelId::GetElecType(), PlexHandle::GetRawChannelId(), ElecType::kQIE, and ReadoutPmt().

00039 {
00040   PlexHandle plex(fContext);
00041   SimPmtList::iterator it;
00042   for(it = pmtList.begin(); it!= pmtList.end(); it++)  {
00043     SimPmt* pmt = it->second;
00044     if(pmt) {
00045       RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(1));
00046       // Make sure the PMT reads out to QIE electronics:      
00047       if ( (rcid.GetElecType()==ElecType::kQIE) ) {       
00048         ReadoutPmt( pmt );
00049       }
00050     }
00051   }
00052   
00053 }

void SimQieElectronics::ReadoutPmt ( SimPmt pmt  )  [virtual]

Definition at line 55 of file SimQieElectronics.cxx.

References SimElectronics::AddAdcsAfterFETrigger(), SimElectronics::AddAdcsAfterSpars(), SimElectronics::AddDigit(), SimElectronics::AddDigitsAfterFETrigger(), SimElectronics::AddDigitsAfterSpars(), SimElectronics::AddSignal(), SimDigit::AsString(), PlexPixelSpotId::AsString(), SimPmtBucketIterator::Bucket(), SimPmtBucketIterator::BucketId(), SimPixelTimeBucket::CreateSignal(), SimPmtBucketIterator::End(), Munits::fC, SimElectronics::fContext, fQieDacCharge, fQieSparsifyThresh, GenSimulatedADC(), SimDigit::GetADC(), SimPixelTimeBucket::GetCharge(), RawChannelId::GetEncoded(), SimPmt::GetNumberOfPixels(), SimPmtTimeBucket::GetPixelBucket(), SimPmt::GetPixelSpotId(), PlexHandle::GetRawChannelId(), SimPmt::GetTotalCharge(), SimPmt::GetTotalHitPixels(), SimPmt::GetTubeId(), SimPmt::GetType(), RawChannelId::IsNull(), Msg::kDebug, Msg::kError, Msg::kVerbose, DigiSignal::Merge(), MSG, SimPmtBucketIterator::Next(), and SimPmt::Print().

Referenced by ReadoutDetector().

00056 {
00057   // Reads out a single PMT.
00058   // Adds all readout to the list of SimDigits.
00059   
00060   // This vaugely simulates the real ND,
00061   // which reads out all buckets from a channel before
00062   // moving to the next one. This is only incorrect in that
00063   // this uses pixel order instead of master/minder address order. 
00064   // Shouldn't matter.
00065 
00066   // Also, this assumes a fast extraction mode, such that no 
00067   // hits are out of the readout window.  For resonant extraction
00068   // or cosmics, you need to look for a dynode trigger, find latch the
00069   // dynode trigger time, and put a validity window around the dynode
00070   // trigger QIE tick.  It's irrelevant for neutrino physics (at the moment)
00071   // so I'm ignoring it.  --N
00072 
00073   // This does NOT correctly deal with multiplexing!  Must fix!
00074 
00075   MSG("DetSim",Msg::kDebug) << "SimQieElectronics::ReadoutPmt " 
00076                             << pmt->GetTubeId().AsString() 
00077                             << " type " << pmt->GetType()
00078                             << endl;
00079 
00080   PlexHandle plex(fContext);
00081 
00082   // No trigger, so add up all hits
00083   AddDigitsAfterFETrigger( pmt->GetTotalHitPixels(true) );
00084   AddAdcsAfterFETrigger( pmt->GetTotalCharge() * fQieDacCharge );
00085     
00086   // Build a list of channels we can read out.
00087   std::map<UInt_t,std::vector<UInt_t> > channels;
00088   std::map<UInt_t,std::vector<UInt_t> >::iterator chItr;
00089   
00090   for(int pixel = 1; pixel<= pmt->GetNumberOfPixels(); pixel++) {
00091     PlexPixelSpotId psid = pmt->GetPixelSpotId(pixel);
00092     RawChannelId    rcid = plex.GetRawChannelId(psid);
00093     channels[rcid.GetEncoded()].push_back(pixel);
00094   }
00095   
00096   // Loop through buckets.
00097   SimPmtBucketIterator bIt( *pmt );
00098   for( ; !bIt.End(); bIt.Next() ) {
00099     
00100     Int_t bucketID = bIt.BucketId();
00101     SimPmtTimeBucket& bucket = bIt.Bucket();
00102 
00103     for( chItr = channels.begin(); chItr != channels.end(); chItr++) {
00104       Float_t totalCharge = 0;
00105       DigiSignal* totalSignal = new DigiSignal();
00106       AddSignal(totalSignal);
00107       RawChannelId    rcid(chItr->first);
00108       PlexPixelSpotId psid;
00109 
00110       for(UInt_t ipix = 0; ipix < chItr->second.size(); ipix++) {
00111         Int_t pixel = chItr->second[ipix];
00112         psid = pmt->GetPixelSpotId(pixel);
00113         SimPixelTimeBucket& pixBucket = bucket.GetPixelBucket(pixel);
00114 
00115         DigiSignal* signal = pixBucket.CreateSignal();
00116         Float_t     charge = pixBucket.GetCharge();
00117 
00118         totalSignal->Merge(*signal);
00119         totalCharge+=charge;
00120 
00121         delete signal;
00122       }
00123 
00124       // Protect against invalid channels on tubes that have some valid pixels.
00125       if(!(rcid.IsNull())) {            
00126         if((totalCharge<-1000*Munits::fC)||(totalCharge>1e6*Munits::fC)) {
00127           MSG("DetSim",Msg::kError) << "Abnormal charge " << totalCharge/Munits::fC 
00128                                     << " fC in pmt " << pmt->GetTubeId().AsString() << endl;
00129           pmt->Print();
00130         } 
00131         SimDigit d(  psid,                        // Pixel, or one of them
00132                      rcid,                        // raw channel
00133                      GenSimulatedADC( rcid, psid, totalCharge, bucketID ), // ADC
00134                      bucketID,                        // The TDC _is_ the bucket ID.
00135                      totalSignal,                     // Truth
00136                      0                                // Error bits.
00137                      );
00138         MSG("DetSim",Msg::kVerbose) << "SimQieElectronics::ReadoutPmt: " << d.AsString() << std::endl;
00139         
00140         // Sparsify and record.
00141         if(d.GetADC() > fQieSparsifyThresh) {
00142           AddDigit(d);
00143           
00144           // Stats:
00145           AddDigitsAfterSpars(1);
00146           AddAdcsAfterSpars(d.GetADC());
00147         }
00148       }
00149     }
00150   }
00151 }

void SimQieElectronics::Reset ( const VldContext newContext  )  [virtual]

Reimplemented from SimElectronics.

Definition at line 31 of file SimQieElectronics.cxx.

References fClock, SimElectronics::Reset(), and SimQieClock::Reset().

00032 {
00033   fClock.Reset(newContext);
00034   SimElectronics::Reset(newContext);
00035 }

void SimQieElectronics::SetupTables ( void   ) 

Definition at line 162 of file SimQieElectronics.cxx.

References fAdcDacSlope, fFlipHighAdc, fFlipLowAdc, fFlipPoint, and fQieDacPerRangeZeroAdc.

Referenced by Config().

00163 {
00164   // These are the slopes (ADC/DAC) of each range.
00165   fAdcDacSlope[0] = 1./fQieDacPerRangeZeroAdc; // By definition.
00166   // Each higher range has double the gain of the last one.
00167   // These values could be improved still; I believe they are just approximate.
00168   fAdcDacSlope[1] = fAdcDacSlope[0]*0.5;
00169   fAdcDacSlope[2] = fAdcDacSlope[1]*0.5;
00170   fAdcDacSlope[3] = fAdcDacSlope[2]*0.5;
00171   fAdcDacSlope[4] = fAdcDacSlope[3]*0.5;
00172   fAdcDacSlope[5] = fAdcDacSlope[4]*0.5;
00173   fAdcDacSlope[6] = fAdcDacSlope[5]*0.5;
00174   fAdcDacSlope[7] = fAdcDacSlope[6]*0.5;
00175 
00176   // These values are taken from a plot from Charlie Nelson. See
00177   // MENUswitchpoints.pdf in the doc directory.
00178   // These need not be terribly accurate, since they very from channel-to-channel
00179   // by 4 or 6 counts RMS.
00180   fFlipLowAdc[0] = 0;     // Min
00181   fFlipLowAdc[1] = 23.7;
00182   fFlipLowAdc[2] = 25.6;
00183   fFlipLowAdc[3] = 26.5;
00184   fFlipLowAdc[4] = 27.1;
00185   fFlipLowAdc[5] = 27.0;
00186   fFlipLowAdc[6] = 27.2;
00187   fFlipLowAdc[7] = 29;
00188 
00189   fFlipHighAdc[0] = 185;
00190   fFlipHighAdc[1] = 190;
00191   fFlipHighAdc[2] = 196;
00192   fFlipHighAdc[3] = 199;
00193   fFlipHighAdc[4] = 192;
00194   fFlipHighAdc[5] = 200;
00195   fFlipHighAdc[6] = 177;
00196   fFlipHighAdc[7] = 255; // Max
00197 
00198   // This is the point, in DAC counts, where the range flips.
00199   // i.e. fFlipPoint[1] is the charge where the QIE flips from range 0 to 1
00200   // This is determined entirely from the above tables.
00201   fFlipPoint[0] = 0;
00202   for(int i=1;i<9;i++)
00203     fFlipPoint[i] = fFlipPoint[i-1] + (fFlipHighAdc[i-1]-fFlipLowAdc[i-1])/fAdcDacSlope[i-1];
00204 }


Member Data Documentation

Double_t SimQieElectronics::fAdcDacSlope[8]

Definition at line 52 of file SimQieElectronics.h.

Referenced by GenSimulatedADC(), and SetupTables().

SimQieClock SimQieElectronics::fClock

Definition at line 48 of file SimQieElectronics.h.

Referenced by Reset().

Int_t SimQieElectronics::fDoLookupNonlinearity

Definition at line 64 of file SimQieElectronics.h.

Referenced by Config(), SimQiePerfectElectronics::GenSimulatedADC(), GenSimulatedADC(), and Print().

Double_t SimQieElectronics::fFlipHighAdc[8]

Definition at line 54 of file SimQieElectronics.h.

Referenced by SetupTables().

Double_t SimQieElectronics::fFlipLowAdc[8]

Definition at line 53 of file SimQieElectronics.h.

Referenced by GenSimulatedADC(), and SetupTables().

Double_t SimQieElectronics::fFlipPoint[9]

Definition at line 51 of file SimQieElectronics.h.

Referenced by GenSimulatedADC(), and SetupTables().

Double_t SimQieElectronics::fQieAdcRms

Definition at line 61 of file SimQieElectronics.h.

Referenced by Config(), and GenSimulatedADC().

Double_t SimQieElectronics::fQieDacCharge

Definition at line 58 of file SimQieElectronics.h.

Referenced by Config(), SimQiePerfectElectronics::GenSimulatedADC(), GenSimulatedADC(), SimQiePerfectElectronics::Print(), Print(), and ReadoutPmt().

Double_t SimQieElectronics::fQieDacPerRangeZeroAdc

Definition at line 59 of file SimQieElectronics.h.

Referenced by Config(), GenSimulatedADC(), Print(), and SetupTables().

Int_t SimQieElectronics::fQieDoLookup

Definition at line 57 of file SimQieElectronics.h.

Referenced by Config(), GenSimulatedADC(), and Print().

Int_t SimQieElectronics::fQiePedestalDac

Definition at line 62 of file SimQieElectronics.h.

Referenced by Config(), SimQiePerfectElectronics::GenSimulatedADC(), GenSimulatedADC(), SimQiePerfectElectronics::Print(), and Print().

Double_t SimQieElectronics::fQiePedestalWidthAdc

Definition at line 60 of file SimQieElectronics.h.

Referenced by Config(), GenSimulatedADC(), and Print().

Int_t SimQieElectronics::fQieSparsifyThresh

Definition at line 63 of file SimQieElectronics.h.

Referenced by Config(), SimQiePerfectElectronics::Print(), Print(), and ReadoutPmt().


The documentation for this class was generated from the following files:
Generated on Wed Sep 10 22:52:08 2014 for loon by  doxygen 1.4.7