CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/RecoLocalCalo/HcalRecAlgos/src/HcalSimpleRecAlgo.cc

Go to the documentation of this file.
00001 #include "RecoLocalCalo/HcalRecAlgos/interface/HcalSimpleRecAlgo.h"
00002 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00003 #include "CalibCalorimetry/HcalAlgos/interface/HcalTimeSlew.h"
00004 #include "RecoLocalCalo/HcalRecAlgos/src/HcalTDCReco.h"
00005 #include <algorithm> // for "max"
00006 #include <math.h>
00007 //--- temporary for printouts
00008 #include<iostream>
00009 
00010 constexpr double MaximumFractionalError = 0.002; // 0.2% error allowed from this source
00011 
00012 HcalSimpleRecAlgo::HcalSimpleRecAlgo(bool correctForTimeslew, bool correctForPulse, float phaseNS) : 
00013   correctForTimeslew_(correctForTimeslew),
00014   correctForPulse_(correctForPulse),
00015   phaseNS_(phaseNS), setForData_(false), setLeakCorrection_(false)
00016 { 
00017   
00018   pulseCorr_ = std::auto_ptr<HcalPulseContainmentManager>(
00019                new HcalPulseContainmentManager(MaximumFractionalError)
00020                                                           );
00021 }
00022   
00023 
00024 HcalSimpleRecAlgo::HcalSimpleRecAlgo() : 
00025   correctForTimeslew_(false), setForData_(false) { }
00026 
00027 
00028 void HcalSimpleRecAlgo::beginRun(edm::EventSetup const & es)
00029 {
00030   pulseCorr_->beginRun(es);
00031 }
00032 
00033 
00034 void HcalSimpleRecAlgo::endRun()
00035 {
00036   pulseCorr_->endRun();
00037 }
00038 
00039 
00040 void HcalSimpleRecAlgo::initPulseCorr(int toadd) {
00041 }
00042 
00043 void HcalSimpleRecAlgo::setRecoParams(bool correctForTimeslew, bool correctForPulse, bool setLeakCorrection, int pileupCleaningID, float phaseNS){
00044    correctForTimeslew_=correctForTimeslew;
00045    correctForPulse_=correctForPulse;
00046    phaseNS_=phaseNS;
00047    setLeakCorrection_=setLeakCorrection;
00048    pileupCleaningID_=pileupCleaningID;
00049 }
00050 
00051 void HcalSimpleRecAlgo::setForData () { setForData_ = true;}
00052 
00053 void HcalSimpleRecAlgo::setLeakCorrection () { setLeakCorrection_ = true;}
00054 
00060 static float timeshift_ns_hbheho(float wpksamp);
00061 
00063 static float timeshift_ns_hf(float wpksamp);
00064 
00066 static float eCorr(int ieta, int iphi, double ampl);
00067 
00069 static float leakCorr(double energy);
00070 
00071 namespace HcalSimpleRecAlgoImpl {
00072   template<class Digi, class RecHit>
00073   inline RecHit reco(const Digi& digi, const HcalCoder& coder, const HcalCalibrations& calibs, 
00074                      int ifirst, int n, bool slewCorrect, bool pulseCorrect, const HcalPulseContainmentCorrection* corr,
00075                      HcalTimeSlew::BiasSetting slewFlavor, bool forData, bool useLeak) {
00076     CaloSamples tool;
00077     coder.adc2fC(digi,tool);
00078 
00079     double ampl=0; int maxI = -1; double maxA = -1e10; float ta=0;
00080     double fc_ampl=0;
00081     for (int i=ifirst; i<tool.size() && i<n+ifirst; i++) {
00082       int capid=digi[i].capid();
00083       ta = (tool[i]-calibs.pedestal(capid)); // pedestal subtraction
00084       fc_ampl+=ta; 
00085       ta*= calibs.respcorrgain(capid) ; // fC --> GeV
00086       ampl+=ta;
00087       if(ta>maxA){
00088         maxA=ta;
00089         maxI=i;
00090       }
00091     }
00092 
00093     float time = -9999;
00095     if(maxI==0 || maxI==(tool.size()-1)) {      
00096       LogDebug("HCAL Pulse") << "HcalSimpleRecAlgo::reconstruct :" 
00097                                                << " Invalid max amplitude position, " 
00098                                                << " max Amplitude: "<< maxI
00099                                                << " first: "<<ifirst
00100                                                << " last: "<<(tool.size()-1)
00101                                                << std::endl;
00102     } else {
00103       int capid=digi[maxI-1].capid();
00104       float t0 = ((tool[maxI-1]-calibs.pedestal(capid))*calibs.respcorrgain(capid) );
00105       capid=digi[maxI+1].capid();
00106       float t2 = ((tool[maxI+1]-calibs.pedestal(capid))*calibs.respcorrgain(capid) );
00107 
00108       // Handle negative excursions by moving "zero":
00109       float minA=t0;
00110       if (maxA<minA) minA=maxA;
00111       if (t2<minA)   minA=t2;
00112       if (minA<0) { maxA-=minA; t0-=minA; t2-=minA; } // positivizes all samples
00113 
00114       float wpksamp = (t0 + maxA + t2);
00115       if (wpksamp!=0) wpksamp=(maxA + 2.0*t2) / wpksamp; 
00116       time = (maxI - digi.presamples())*25.0 + timeshift_ns_hbheho(wpksamp);
00117       if (corr!=0 && pulseCorrect ) {
00118         // Apply phase-based amplitude correction:
00119 
00120         /*
00121         HcalDetId cell(digi.id());
00122         int ieta  = cell.ieta();
00123         int iphi  = cell.iphi();
00124         int depth = cell.depth();
00125         std::cout << "HcalSimpleRecAlgo::reco  cell:  ieta, iphi, depth =  " 
00126                   << ieta << ", " << iphi
00127                   << ", " << depth 
00128                   << "    first, toadd = " << ifirst << ", " << n << std::endl
00129                   << "    ampl,  corr,  ampl_after_corr = "
00130                   << ampl << ",   " << corr->getCorrection(fc_ampl)
00131                   << ",   "
00132                   << ampl * corr->getCorrection(fc_ampl) << std::endl;
00133         */
00134 
00135         ampl *= corr->getCorrection(fc_ampl);
00136 
00137       }
00138       if (slewCorrect) time-=HcalTimeSlew::delay(std::max(1.0,fc_ampl),slewFlavor);
00139 
00140       time=time-calibs.timecorr(); // time calibration
00141     }
00142 
00143 
00144     // Temoprary hack to apply energy-dependent corrections to some HB- cells
00145     if(forData) {
00146       HcalDetId cell(digi.id());
00147       int ieta  = cell.ieta();
00148       int iphi  = cell.iphi();
00149       ampl *= eCorr(ieta,iphi,ampl);
00150     }
00151 
00152     // Correction for a leak to pre-sample
00153     if(useLeak) {
00154       ampl *= leakCorr(ampl); 
00155     }
00156 
00157 
00158     return RecHit(digi.id(),ampl,time);    
00159   }
00160 }
00161 
00162 HBHERecHit HcalSimpleRecAlgo::reconstruct(const HBHEDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00163   return HcalSimpleRecAlgoImpl::reco<HBHEDataFrame,HBHERecHit>(digi,coder,calibs,
00164                                                                first,toadd,correctForTimeslew_, correctForPulse_,
00165                                                                pulseCorr_->get(digi.id(), toadd, phaseNS_),
00166                                                                HcalTimeSlew::Medium,
00167                                                                setForData_, setLeakCorrection_);
00168 }
00169 
00170 HORecHit HcalSimpleRecAlgo::reconstruct(const HODataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00171   return HcalSimpleRecAlgoImpl::reco<HODataFrame,HORecHit>(digi,coder,calibs,
00172                                                            first,toadd,correctForTimeslew_,correctForPulse_,
00173                                                            pulseCorr_->get(digi.id(), toadd, phaseNS_),
00174                                                            HcalTimeSlew::Slow,
00175                                                            setForData_, false);
00176 }
00177 
00178 HcalCalibRecHit HcalSimpleRecAlgo::reconstruct(const HcalCalibDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00179   return HcalSimpleRecAlgoImpl::reco<HcalCalibDataFrame,HcalCalibRecHit>(digi,coder,calibs,
00180                                                                          first,toadd,correctForTimeslew_,correctForPulse_,
00181                                                                          pulseCorr_->get(digi.id(), toadd, phaseNS_),
00182                                                                          HcalTimeSlew::Fast,
00183                                                                          setForData_, false );
00184 }
00185 
00186 /*
00187 HBHERecHit HcalSimpleRecAlgo::reconstruct(const HBHEDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00188   return HcalSimpleRecAlgoImpl::reco<HBHEDataFrame,HBHERecHit>(digi,coder,calibs,
00189                                                                first,toadd,correctForTimeslew_, correctForPulse_,
00190                                                                pulseCorr_->get(digi.id(), toadd, phaseNS_),
00191                                                                HcalTimeSlew::Medium,
00192                                                                setForData_, setLeakCorrection_);
00193 }
00194 */
00195 
00196 
00197 HBHERecHit HcalSimpleRecAlgo::reconstructHBHEUpgrade(const HcalUpgradeDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00198   HBHERecHit result = HcalSimpleRecAlgoImpl::reco<HcalUpgradeDataFrame,HBHERecHit>( digi, coder, calibs, first, toadd, correctForTimeslew_, correctForPulse_, pulseCorr_->get(digi.id(), toadd, phaseNS_), HcalTimeSlew::Medium, false, false);
00199   HcalTDCReco tdcReco;
00200   tdcReco.reconstruct(digi, result);
00201   return result;
00202 }
00203 
00204 
00205 HFRecHit HcalSimpleRecAlgo::reconstruct(const HFDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00206 
00207   const HcalPulseContainmentCorrection* corr = pulseCorr_->get(digi.id(), toadd, phaseNS_);
00208 
00209   CaloSamples tool;
00210   coder.adc2fC(digi,tool);
00211   
00212   double ampl=0; int maxI = -1; double maxA = -1e10; float ta=0; float amp_fC=0;
00213   for (int i=first; i<tool.size() && i<first+toadd; i++) {
00214     int capid=digi[i].capid();
00215     ta = (tool[i]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00216     ampl+=ta;
00217     amp_fC += tool[i]-calibs.pedestal(capid);
00218     if(ta>maxA){
00219       maxA=ta;
00220       maxI=i;
00221     }
00222   }
00223 
00224   float time=-9999.0;
00226   if(maxI==0 || maxI==(tool.size()-1)) {
00227       LogDebug("HCAL Pulse") << "HcalSimpleRecAlgo::reconstruct :" 
00228                                                << " Invalid max amplitude position, " 
00229                                                << " max Amplitude: "<< maxI
00230                                                << " first: "<< first
00231                                                << " last: "<<(tool.size()-1)
00232                                                << std::endl;
00233   } else {
00234     int capid=digi[maxI-1].capid();
00235     float t0 = (tool[maxI-1]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00236     capid=digi[maxI+1].capid();
00237     float t2 = (tool[maxI+1]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00238 
00239     // Handle negative excursions by moving "zero":
00240     float zerocorr=std::min(t0,t2);
00241     if (zerocorr<0.f) {
00242       t0   -= zerocorr;
00243       t2   -= zerocorr;
00244       maxA -= zerocorr;
00245     }
00246     
00247     // pair the peak with the larger of the two neighboring time samples
00248     float wpksamp=0.f;
00249     if (t0>t2) {
00250       wpksamp = t0+maxA;
00251       if (wpksamp != 0.f) wpksamp = maxA/wpksamp;
00252     } else {
00253       wpksamp = maxA+t2;
00254       if (wpksamp != 0.f) wpksamp = 1.+(t2/wpksamp);
00255     }
00256 
00257     time = (maxI - digi.presamples())*25.0 + timeshift_ns_hf(wpksamp);
00258 
00259     if (corr!=0 && correctForPulse_) { 
00260       
00261       // Apply phase-based amplitude correction:
00262       
00263       /*
00264         HcalDetId cell(digi.id());
00265         int ieta  = cell.ieta();
00266         int iphi  = cell.iphi();
00267         int depth = cell.depth();
00268         std::cout << "*** ieta, iphi, depth =  " << ieta << ", " << iphi
00269         << ", " << depth 
00270                   << "    first, toadd = " << ifirst << ", " << n << std::endl
00271                   << "    ampl,  corr,  ampl_after_corr = "
00272                   << ampl << ",   " << corr->getCorrection(fc_ampl)
00273                   << ",   "
00274                   << ampl * corr->getCorrection(fc_ampl) << std::endl;
00275         */
00276       
00277       ampl *= corr->getCorrection(amp_fC);
00278     }
00279 
00280     if (correctForTimeslew_ && (amp_fC>0)) {
00281       // -5.12327 - put in calibs.timecorr()
00282       double tslew=exp(0.337681-5.94689e-4*amp_fC)+exp(2.44628-1.34888e-2*amp_fC);
00283       time -= (float)tslew;
00284     }
00285 
00286     time=time-calibs.timecorr();
00287   }
00288 
00289   return HFRecHit(digi.id(),ampl,time); 
00290 }
00291 
00292 // NB: Upgrade HFRecHit method content is just the same as regular  HFRecHit
00293 //     with one exclusion: double time (second is dummy) in constructor 
00294 HFRecHit HcalSimpleRecAlgo::reconstructHFUpgrade(const HcalUpgradeDataFrame& digi, int first, int toadd, const HcalCoder& coder, const HcalCalibrations& calibs) const {
00295 
00296   const HcalPulseContainmentCorrection* corr = pulseCorr_->get(digi.id(), toadd, phaseNS_);
00297 
00298   CaloSamples tool;
00299   coder.adc2fC(digi,tool);
00300   
00301   double ampl=0; int maxI = -1; double maxA = -1e10; float ta=0; float amp_fC=0;
00302   for (int i=first; i<tool.size() && i<first+toadd; i++) {
00303     int capid=digi[i].capid(); 
00304     ta = (tool[i]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00305     ampl+=ta;
00306     amp_fC += tool[i]-calibs.pedestal(capid);
00307     if(ta>maxA){
00308       maxA=ta;
00309       maxI=i;
00310     }
00311   }
00312 
00313   float time=-9999.0;
00315   if(maxI==0 || maxI==(tool.size()-1)) {
00316       LogDebug("HCAL Pulse") << "HcalSimpleRecAlgo::reconstruct :" 
00317                                                << " Invalid max amplitude position, " 
00318                                                << " max Amplitude: "<< maxI
00319                                                << " first: "<< first
00320                                                << " last: "<<(tool.size()-1)
00321                                                << std::endl;
00322   } else {
00323     int capid=digi[maxI-1].capid(); 
00324     float t0 = (tool[maxI-1]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00325     capid=digi[maxI+1].capid();    
00326     float t2 = (tool[maxI+1]-calibs.pedestal(capid))*calibs.respcorrgain(capid);
00327 
00328     // Handle negative excursions by moving "zero":
00329     float zerocorr=std::min(t0,t2);
00330     if (zerocorr<0.f) {
00331       t0   -= zerocorr;
00332       t2   -= zerocorr;
00333       maxA -= zerocorr;
00334     }
00335     
00336     // pair the peak with the larger of the two neighboring time samples
00337     float wpksamp=0.f;
00338     if (t0>t2) {
00339       wpksamp = t0+maxA;
00340       if (wpksamp != 0.f) wpksamp = maxA/wpksamp;
00341     } else {
00342       wpksamp = maxA+t2;
00343       if (wpksamp != 0.f) wpksamp = 1.+(t2/wpksamp);
00344     }
00345 
00346     time = (maxI - digi.presamples())*25.0 + timeshift_ns_hf(wpksamp);
00347 
00348     if (corr!=0 && correctForPulse_) { 
00349       
00350       // Apply phase-based amplitude correction:
00351       
00352       /*
00353         HcalDetId cell(digi.id());
00354         int ieta  = cell.ieta();
00355         int iphi  = cell.iphi();
00356         int depth = cell.depth();
00357         std::cout << "*** ieta, iphi, depth =  " << ieta << ", " << iphi
00358         << ", " << depth 
00359                   << "    first, toadd = " << ifirst << ", " << n << std::endl
00360                   << "    ampl,  corr,  ampl_after_corr = "
00361                   << ampl << ",   " << corr->getCorrection(fc_ampl)
00362                   << ",   "
00363                   << ampl * corr->getCorrection(fc_ampl) << std::endl;
00364         */
00365       
00366       ampl *= corr->getCorrection(amp_fC);
00367     }
00368 
00369     if (correctForTimeslew_ && (amp_fC>0)) {
00370       // -5.12327 - put in calibs.timecorr()
00371       double tslew=exp(0.337681-5.94689e-4*amp_fC)+exp(2.44628-1.34888e-2*amp_fC);
00372       time -= (float)tslew;
00373     }
00374 
00375     time=time-calibs.timecorr();
00376   }
00377 
00378   return HFRecHit(digi.id(),ampl,time); // new RecHit gets second time = 0.
00379 
00380 }
00381 
00382 
00384 float eCorr(int ieta, int iphi, double energy) {
00385 // return energy correction factor for HBM channels 
00386 // iphi=6 ieta=(-1,-15) and iphi=32 ieta=(-1,-7)
00387 // I.Vodopianov 28 Feb. 2011
00388   static const float low32[7]  = {0.741,0.721,0.730,0.698,0.708,0.751,0.861};
00389   static const float high32[7] = {0.973,0.925,0.900,0.897,0.950,0.935,1};
00390   static const float low6[15]  = {0.635,0.623,0.670,0.633,0.644,0.648,0.600,
00391                                   0.570,0.595,0.554,0.505,0.513,0.515,0.561,0.579};
00392   static const float high6[15] = {0.875,0.937,0.942,0.900,0.922,0.925,0.901,
00393                                   0.850,0.852,0.818,0.731,0.717,0.782,0.853,0.778};
00394 
00395   
00396   double slope, mid, en;
00397   double corr = 1.0;
00398 
00399   if (!(iphi==6 && ieta<0 && ieta>-16) && !(iphi==32 && ieta<0 && ieta>-8)) 
00400     return corr;
00401 
00402   int jeta = -ieta-1;
00403   double xeta = (double) ieta;
00404   if (energy > 0.) en=energy;
00405   else en = 0.;
00406 
00407   if (iphi == 32) {
00408     slope = 0.2272;
00409     mid = 17.14 + 0.7147*xeta;
00410     if (en > 100.) corr = high32[jeta];
00411     else corr = low32[jeta]+(high32[jeta]-low32[jeta])/(1.0+exp(-(en-mid)*slope));
00412   }
00413   else if (iphi == 6) {
00414     slope = 0.1956;
00415     mid = 15.96 + 0.3075*xeta;
00416     if (en > 100.0) corr = high6[jeta];
00417     else corr = low6[jeta]+(high6[jeta]-low6[jeta])/(1.0+exp(-(en-mid)*slope));
00418   }
00419 
00420   //  std::cout << "HBHE cell:  ieta, iphi = " << ieta << "  " << iphi 
00421   //        << "  ->  energy = " << en << "   corr = " << corr << std::endl;
00422 
00423   return corr;
00424 }
00425 
00426 
00427 // Actual leakage (to pre-sample) correction 
00428 float leakCorr(double energy) {
00429   double corr = 1.0;
00430   return corr;
00431 }
00432 
00433 
00434 // timeshift implementation
00435 
00436 static const float wpksamp0_hbheho = 0.5;
00437 static const int   num_bins_hbheho = 61;
00438 
00439 static const float actual_ns_hbheho[num_bins_hbheho] = {
00440 -5.44000, // 0.500, 0.000-0.017
00441 -4.84250, // 0.517, 0.017-0.033
00442 -4.26500, // 0.533, 0.033-0.050
00443 -3.71000, // 0.550, 0.050-0.067
00444 -3.18000, // 0.567, 0.067-0.083
00445 -2.66250, // 0.583, 0.083-0.100
00446 -2.17250, // 0.600, 0.100-0.117
00447 -1.69000, // 0.617, 0.117-0.133
00448 -1.23000, // 0.633, 0.133-0.150
00449 -0.78000, // 0.650, 0.150-0.167
00450 -0.34250, // 0.667, 0.167-0.183
00451  0.08250, // 0.683, 0.183-0.200
00452  0.50250, // 0.700, 0.200-0.217
00453  0.90500, // 0.717, 0.217-0.233
00454  1.30500, // 0.733, 0.233-0.250
00455  1.69500, // 0.750, 0.250-0.267
00456  2.07750, // 0.767, 0.267-0.283
00457  2.45750, // 0.783, 0.283-0.300
00458  2.82500, // 0.800, 0.300-0.317
00459  3.19250, // 0.817, 0.317-0.333
00460  3.55750, // 0.833, 0.333-0.350
00461  3.91750, // 0.850, 0.350-0.367
00462  4.27500, // 0.867, 0.367-0.383
00463  4.63000, // 0.883, 0.383-0.400
00464  4.98500, // 0.900, 0.400-0.417
00465  5.33750, // 0.917, 0.417-0.433
00466  5.69500, // 0.933, 0.433-0.450
00467  6.05000, // 0.950, 0.450-0.467
00468  6.40500, // 0.967, 0.467-0.483
00469  6.77000, // 0.983, 0.483-0.500
00470  7.13500, // 1.000, 0.500-0.517
00471  7.50000, // 1.017, 0.517-0.533
00472  7.88250, // 1.033, 0.533-0.550
00473  8.26500, // 1.050, 0.550-0.567
00474  8.66000, // 1.067, 0.567-0.583
00475  9.07000, // 1.083, 0.583-0.600
00476  9.48250, // 1.100, 0.600-0.617
00477  9.92750, // 1.117, 0.617-0.633
00478 10.37750, // 1.133, 0.633-0.650
00479 10.87500, // 1.150, 0.650-0.667
00480 11.38000, // 1.167, 0.667-0.683
00481 11.95250, // 1.183, 0.683-0.700
00482 12.55000, // 1.200, 0.700-0.717
00483 13.22750, // 1.217, 0.717-0.733
00484 13.98500, // 1.233, 0.733-0.750
00485 14.81500, // 1.250, 0.750-0.767
00486 15.71500, // 1.267, 0.767-0.783
00487 16.63750, // 1.283, 0.783-0.800
00488 17.53750, // 1.300, 0.800-0.817
00489 18.38500, // 1.317, 0.817-0.833
00490 19.16500, // 1.333, 0.833-0.850
00491 19.89750, // 1.350, 0.850-0.867
00492 20.59250, // 1.367, 0.867-0.883
00493 21.24250, // 1.383, 0.883-0.900
00494 21.85250, // 1.400, 0.900-0.917
00495 22.44500, // 1.417, 0.917-0.933
00496 22.99500, // 1.433, 0.933-0.950
00497 23.53250, // 1.450, 0.950-0.967
00498 24.03750, // 1.467, 0.967-0.983
00499 24.53250, // 1.483, 0.983-1.000
00500 25.00000  // 1.500, 1.000-1.017 - keep for interpolation
00501 };
00502 
00503 float timeshift_ns_hbheho(float wpksamp) {
00504   float flx = (num_bins_hbheho-1)*(wpksamp - wpksamp0_hbheho);
00505   int index = (int)flx;
00506   float yval;
00507 
00508   if      (index <    0)               return actual_ns_hbheho[0];
00509   else if (index >= num_bins_hbheho-1) return actual_ns_hbheho[num_bins_hbheho-1];
00510 
00511   // else interpolate:
00512   float y1 = actual_ns_hbheho[index];
00513   float y2 = actual_ns_hbheho[index+1];
00514 
00515   yval = y1 + (y2-y1)*(flx-(float)index);
00516 
00517   return yval;
00518 }
00519 
00520 static const int   num_bins_hf = 101;
00521 static const float wpksamp0_hf = 0.5;
00522 
00523 static const float actual_ns_hf[num_bins_hf] = {
00524  0.00250, // 0.000-0.010
00525  0.04500, // 0.010-0.020
00526  0.08750, // 0.020-0.030
00527  0.13000, // 0.030-0.040
00528  0.17250, // 0.040-0.050
00529  0.21500, // 0.050-0.060
00530  0.26000, // 0.060-0.070
00531  0.30250, // 0.070-0.080
00532  0.34500, // 0.080-0.090
00533  0.38750, // 0.090-0.100
00534  0.42750, // 0.100-0.110
00535  0.46000, // 0.110-0.120
00536  0.49250, // 0.120-0.130
00537  0.52500, // 0.130-0.140
00538  0.55750, // 0.140-0.150
00539  0.59000, // 0.150-0.160
00540  0.62250, // 0.160-0.170
00541  0.65500, // 0.170-0.180
00542  0.68750, // 0.180-0.190
00543  0.72000, // 0.190-0.200
00544  0.75250, // 0.200-0.210
00545  0.78500, // 0.210-0.220
00546  0.81750, // 0.220-0.230
00547  0.85000, // 0.230-0.240
00548  0.88250, // 0.240-0.250
00549  0.91500, // 0.250-0.260
00550  0.95500, // 0.260-0.270
00551  0.99250, // 0.270-0.280
00552  1.03250, // 0.280-0.290
00553  1.07000, // 0.290-0.300
00554  1.10750, // 0.300-0.310
00555  1.14750, // 0.310-0.320
00556  1.18500, // 0.320-0.330
00557  1.22500, // 0.330-0.340
00558  1.26250, // 0.340-0.350
00559  1.30000, // 0.350-0.360
00560  1.34000, // 0.360-0.370
00561  1.37750, // 0.370-0.380
00562  1.41750, // 0.380-0.390
00563  1.48750, // 0.390-0.400
00564  1.55750, // 0.400-0.410
00565  1.62750, // 0.410-0.420
00566  1.69750, // 0.420-0.430
00567  1.76750, // 0.430-0.440
00568  1.83750, // 0.440-0.450
00569  1.90750, // 0.450-0.460
00570  2.06750, // 0.460-0.470
00571  2.23250, // 0.470-0.480
00572  2.40000, // 0.480-0.490
00573  2.82250, // 0.490-0.500
00574  3.81000, // 0.500-0.510
00575  6.90500, // 0.510-0.520
00576  8.99250, // 0.520-0.530
00577 10.50000, // 0.530-0.540
00578 11.68250, // 0.540-0.550
00579 12.66250, // 0.550-0.560
00580 13.50250, // 0.560-0.570
00581 14.23750, // 0.570-0.580
00582 14.89750, // 0.580-0.590
00583 15.49000, // 0.590-0.600
00584 16.03250, // 0.600-0.610
00585 16.53250, // 0.610-0.620
00586 17.00000, // 0.620-0.630
00587 17.44000, // 0.630-0.640
00588 17.85250, // 0.640-0.650
00589 18.24000, // 0.650-0.660
00590 18.61000, // 0.660-0.670
00591 18.96750, // 0.670-0.680
00592 19.30500, // 0.680-0.690
00593 19.63000, // 0.690-0.700
00594 19.94500, // 0.700-0.710
00595 20.24500, // 0.710-0.720
00596 20.54000, // 0.720-0.730
00597 20.82250, // 0.730-0.740
00598 21.09750, // 0.740-0.750
00599 21.37000, // 0.750-0.760
00600 21.62750, // 0.760-0.770
00601 21.88500, // 0.770-0.780
00602 22.13000, // 0.780-0.790
00603 22.37250, // 0.790-0.800
00604 22.60250, // 0.800-0.810
00605 22.83000, // 0.810-0.820
00606 23.04250, // 0.820-0.830
00607 23.24500, // 0.830-0.840
00608 23.44250, // 0.840-0.850
00609 23.61000, // 0.850-0.860
00610 23.77750, // 0.860-0.870
00611 23.93500, // 0.870-0.880
00612 24.05500, // 0.880-0.890
00613 24.17250, // 0.890-0.900
00614 24.29000, // 0.900-0.910
00615 24.40750, // 0.910-0.920
00616 24.48250, // 0.920-0.930
00617 24.55500, // 0.930-0.940
00618 24.62500, // 0.940-0.950
00619 24.69750, // 0.950-0.960
00620 24.77000, // 0.960-0.970
00621 24.84000, // 0.970-0.980
00622 24.91250, // 0.980-0.990
00623 24.95500, // 0.990-1.000
00624 24.99750, // 1.000-1.010 - keep for interpolation
00625 };
00626 
00627 float timeshift_ns_hf(float wpksamp) {
00628   float flx = (num_bins_hf-1)*(wpksamp-wpksamp0_hf);
00629   int index = (int)flx;
00630   float yval;
00631   
00632   if      (index <  0)             return actual_ns_hf[0];
00633   else if (index >= num_bins_hf-1) return actual_ns_hf[num_bins_hf-1];
00634 
00635   // else interpolate:
00636   float y1       = actual_ns_hf[index];
00637   float y2       = actual_ns_hf[index+1];
00638 
00639   // float delta_x  = 1/(float)num_bins_hf;
00640   // yval = y1 + (y2-y1)*(flx-(float)index)/delta_x;
00641 
00642   yval = y1 + (y2-y1)*(flx-(float)index);
00643   return yval;
00644 }