CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/RecoLocalMuon/CSCRecHitD/src/CSCFindPeakTime.cc

Go to the documentation of this file.
00001 // This is CSCFindPeakTime
00002 
00003 #include <RecoLocalMuon/CSCRecHitD/src/CSCFindPeakTime.h>
00004 #include <FWCore/MessageLogger/interface/MessageLogger.h>
00005 
00006 #include <cmath>
00007 
00008 CSCFindPeakTime::CSCFindPeakTime( const edm::ParameterSet& ps ): 
00009   useAverageTime(false), useParabolaFit(false), useFivePoleFit(false) {
00010 
00011   useAverageTime = ps.getParameter<bool>("UseAverageTime");
00012   useParabolaFit = ps.getParameter<bool>("UseParabolaFit");
00013   useFivePoleFit = ps.getParameter<bool>("UseFivePoleFit");
00014   LogTrace("CSCRecHit") << "[CSCFindPeakTime] useAverageTime=" << useAverageTime <<
00015     ", useParabolaFit=" << useParabolaFit << ", useFivePoleFit=" << useFivePoleFit;
00016 }
00017 
00018 float CSCFindPeakTime::peakTime( int tmax, const float* adc, float t_peak){
00019   if ( useAverageTime ) {
00020     return averageTime( tmax, adc );
00021   }
00022   else if ( useParabolaFit ) {
00023     return parabolaFitTime( tmax, adc );
00024   }
00025   else if ( useFivePoleFit ) {
00026      return fivePoleFitTime( tmax, adc, t_peak);
00027   }
00028   else {
00029   // return something, anyway.. may as well be average
00030     return averageTime( tmax, adc );
00031   }
00032 }
00033 
00034 float CSCFindPeakTime::averageTime( int tmax, const float* adc ) {
00035    float sum  = 0.;
00036    float sumt = 0.;
00037    for (size_t i=0; i<4; ++i){
00038      sum  += adc[i];
00039      sumt += adc[i] * ( tmax - 1 + i );
00040 
00041    }
00042    return sumt/sum * 50.; //@@ in ns. May be some bin width offset things to handle here?
00043 }
00044 
00045 float CSCFindPeakTime::parabolaFitTime( int tmax, const float* adc ) {
00046   // 3-point parabolic fit, from Andy Kubik
00047  
00048   // We calculate offset to tmax by finding the peak of a parabola through three points
00049    float tpeak = tmax;
00050    float tcorr = 0;
00051 
00052    // By construction, input array adc is for bins tmax-1 to tmax+2
00053    float y1 = adc[0];
00054    float y2 = adc[1];
00055    float y3 = adc[2];
00056 
00057    // Checked and simplified... Tim Cox 08-Apr-2009
00058    // Denominator is not zero unless we fed in nonsense values with y2 not the peak!
00059    if ( (y1+y3) < 2.*y2 ) tcorr =  0.5 * ( y1 - y3 ) / ( y1 - 2.*y2 + y3 );
00060    tpeak += tcorr;
00061 
00062    LogTrace("CSCFindPeakTime") << "[CSCFindPeakTime] tmax=" << tmax 
00063      << ", parabolic peak time is tmax+" << tcorr <<" bins, or " << tpeak*50. << " ns";
00064    
00065    return tpeak * 50.; // convert to ns.
00066 }
00067 
00068 float CSCFindPeakTime::fivePoleFitTime( int tmax, const float* adc, float t_peak ) {
00069 
00070   // Input is 
00071   // tmax   = bin# 0-7 containing max SCA pulse height  
00072   // adc    = 4-dim array containing SCA pulse heights in bins tmax-1 to tmax+2
00073   // t_peak = input estimate for SCA peak time
00074 
00075   // Returned value is improved (we hope) estimate for SCA peak time
00076 
00077   // Algorithm is to fit five-pole Semi-Gaussian function for start time of SCA pulse, t0
00078   // (The SCA peak is assumed to be 133 ns from t0.)
00079   // Note that t^4 in time domain corresponds to 1/t^5 in frequency domain (that's the 5 poles).
00080 
00081   // Initialize parameters to sensible (?) values
00082 
00083   float t0       = 0.;
00084   float t0peak   = 133.;   // this is offset of peak from start time t0
00085   float p0       = 4./t0peak;
00086 
00087   // Require that tmax is in range 2-6 of bins the eight SCA time bins 0-7
00088   // (Bins 0, 1 used for dynamic ped)
00089 
00090   if ( tmax < 2 || tmax > 6 ) return t_peak; //@@ Just return the input value
00091 
00092   // Set up time bins to match adc[4] input
00093 
00094   float tb[4];
00095   for ( int time=0; time<4; ++time ){
00096     tb[time] = (tmax + time -1) * 50.;
00097   }
00098 
00099   // How many time bins are we fitting?
00100 
00101   int n_fit  = 4;
00102   if ( tmax == 6 ) n_fit = 3;
00103 
00104   float chi_min  = 1.e10;
00105   float chi_last = 1.e10;
00106   float tt0      = 0.;
00107   float chi2     = 0.;
00108   float del_t    = 100.;
00109 
00110   float x[4];
00111   float sx2 = 0.;
00112   float sxy = 0.;
00113   float fN  = 0.;
00114 
00115   while ( del_t > 1. ) {
00116     sx2 = 0.;
00117     sxy = 0.;
00118         
00119     for ( int j=0; j < n_fit; ++j ) {
00120       float tdif = tb[j] - tt0;
00121       x[j] = tdif * tdif * tdif * tdif * exp( -p0 * tdif );
00122       sx2 += x[j] * x[j];
00123       sxy += x[j] * adc[j];
00124     }
00125     fN = sxy / sx2; // least squares fit over time bins i to adc[i] = fN * fivePoleFunction[i]
00126     
00127     // Compute chi^2
00128     chi2 = 0.0;
00129     for (int j=0; j < n_fit; ++j) chi2 += (adc[j] - fN * x[j]) * (adc[j] - fN * x[j]);
00130 
00131     // Test on chi^2 to decide what to do    
00132     if ( chi_last > chi2 ) {
00133       if (chi2 < chi_min ){
00134         t0      = tt0;
00135       }
00136       chi_last  = chi2;
00137       tt0       = tt0 + del_t;
00138     } else {
00139       tt0      = tt0 - 2. * del_t;
00140       del_t    = del_t / 2.;
00141       tt0      = tt0 + del_t;
00142       chi_last = 1.0e10;
00143     }
00144   }
00145 
00146   return t0 + t0peak;
00147 }
00148 
00149 
00150 
00151 void CSCFindPeakTime::fivePoleFitCharge( int tmax, const float* adc, const float& t_zero, const float& t_peak, std::vector<float>& adcsFit ) {
00152 
00153   //@@ This code can certainly be replaced by fivePoleFitTime above, but I haven't time to do that now (Tim).
00154 
00155   float p0  = 4./t_peak;
00156   float tt0 = t_zero;
00157   int n_fit = 4;
00158   if ( tmax == 6 ) n_fit=3;
00159   
00160   float tb[4], y[4];
00161   for ( int t = 0; t < 4; ++t ){
00162     tb[t] = (tmax + t - 1) * 50.;
00163     y[t] = adc[t];
00164   }
00165 
00166   // Find the normalization factor for the function
00167   float x[4];    
00168   float sx2 = 0.;
00169   float sxy = 0.;
00170   for ( int j=0; j < n_fit; ++j ) {
00171     float t = tb[j];
00172     x[j] = (t-tt0)*(t-tt0)*(t-tt0)*(t-tt0) * exp( -p0 * (t-tt0) );
00173     sx2  = sx2 + x[j] * x[j];
00174     sxy  = sxy + x[j] * y[j];
00175   }
00176   float N = sxy / sx2;
00177     
00178 
00179   // Now compute charge for a given t  --> only need charges at: t_peak-50, t_peak and t_peak+50
00180   for ( int i = 0; i < 3; ++i ) {
00181     float t = t_peak + (i - 1) * 50.;
00182     float q_fitted = N * (t-tt0)*(t-tt0)*(t-tt0)*(t-tt0) * exp( -p0 * (t-tt0) );
00183     adcsFit.push_back(q_fitted);
00184   }
00185   return;
00186 }
00187 
00188