00001 #include "PulseFinder.hh"
00002 #include "BaselineFinder.hh"
00003 #include "SumChannels.hh"
00004 #include "Integrator.hh"
00005 #include "ConvertData.hh"
00006 #include "RootWriter.hh"
00007 #include "intarray.hh"
00008 #include "TMath.h"
00009 #include <algorithm>
00010 #include <numeric>
00011 #include <stdexcept>
00012 #include <cmath>
00013
00014 std::ostream& operator<<(std::ostream& out, const PulseFinder::SEARCH_MODE& m)
00015 {
00016 switch(m){
00017 case PulseFinder::VARIANCE:
00018 out<<"VARIANCE";
00019 break;
00020 case PulseFinder::DISCRIMINATOR:
00021 out<<"DISCRIMINATOR";
00022 break;
00023 case PulseFinder::INTEGRAL:
00024 out<<"INTEGRAL";
00025 break;
00026 case PulseFinder::CURVATURE:
00027 out<<"CURVATURE";
00028 break;
00029 }
00030 return out;
00031 }
00032
00033 std::istream& operator>>(std::istream& in, PulseFinder::SEARCH_MODE& m)
00034 {
00035 std::string dummy;
00036 in>>dummy;
00037 if(dummy == "VARIANCE" || dummy == "variance")
00038 m = PulseFinder::VARIANCE;
00039 else if (dummy == "DISCRIMINATOR" || dummy == "discriminator")
00040 m = PulseFinder::DISCRIMINATOR;
00041 else if (dummy == "INTEGRAL" || dummy == "integral")
00042 m = PulseFinder::INTEGRAL;
00043 else if (dummy == "CURVATURE" || dummy == "curvature")
00044 m = PulseFinder::CURVATURE;
00045 else{
00046 throw std::invalid_argument(dummy+"is not a valid value for search_mode!");
00047 }
00048 return in;
00049 }
00050
00051
00052 PulseFinder::PulseFinder() :
00053 BaseModule(GetDefaultName(), "Search for individual physical scintillation pulses within the hardware trigger")
00054 {
00055 AddDependency<ConvertData>();
00056 AddDependency<BaselineFinder>();
00057 AddDependency<Integrator>();
00058
00060 RegisterParameter("align_pulses", align_pulses = true,
00061 "Have one set of pulse edges for all channels ? (Search done on sum channel in case of multiple channels)");
00062 RegisterParameter("search_mode", mode=INTEGRAL);
00063 RegisterParameter("normalize", normalize=true,
00064 "normalize amplitude to spe before searching?");
00065 RegisterParameter("start_window", start_window = 5);
00066 RegisterParameter("min_start_variance", min_start_variance = 100);
00067 RegisterParameter("min_resolution", min_resolution = 300);
00068 RegisterParameter("min_start_peak_sep", min_start_peak_sep = 5);
00069 RegisterParameter("discriminator_relative", discriminator_relative = false,
00070 "Is the discriminator value relative to the baseline?");
00071 RegisterParameter("discriminator_value", discriminator_value = 0,
00072 "Value sample must cross to mark the start of the pulse");
00073 RegisterParameter("discriminator_start_add", discriminator_start_add = 2,
00074 "Number of samples to add before the detected start of the pulse");
00075 RegisterParameter("discriminator_end_add", discriminator_end_add = 2,
00076 "Number of samples to add after the detected end of the pulse");
00077
00078 RegisterParameter("integral_start_time", integral_start_time = 3,
00079 "time in us over which photons arrive");
00080 RegisterParameter("integral_end_time", integral_end_time = 3,
00081 "time over which to evaluate end of pulse to return to 0");
00082 RegisterParameter("integral_start_threshold", integral_start_threshold = 5,
00083 "amount in npe integral must fall");
00084 RegisterParameter("integral_end_threshold", integral_end_threshold = 3,
00085 "amount in npe integral must fall");
00086 RegisterParameter("min_sep_time", min_sep_time = 2,
00087 "minimum time between starts of two pulses");
00088 RegisterParameter("multipulse_thresh_value", multipulse_thresh_value = 2,
00089 "secondary must be > this*previous integral+start_thresh");
00090 RegisterParameter("amplitude_start_threshold",amplitude_start_threshold = 0.3,
00091 "Raw signal must go below this at actual pulse start");
00092 RegisterParameter("amplitude_end_threshold", amplitude_end_threshold = 0.3,
00093 "Amplitude must fall below this to end pulse");
00094 RegisterParameter("min_pulse_time", min_pulse_time = 7,
00095 "Minimum pulse width before it can be considered over");
00096 RegisterParameter("lookback_time", lookback_time = 0.5,
00097 "Time to compare against for pileup");
00098
00099
00100 RegisterParameter("down_sample_factor", down_sample_factor = 250,
00101 "Reduce the integral vector size by this factor");
00102 RegisterParameter("pulse_start_curvature", pulse_start_curvature = -4,
00103 "Curvature threshold to start a new pulse");
00104 RegisterParameter("pile_up_curvature", pile_up_curvature = -20,
00105 "Curvature threshold to start a pile up pulse");
00106 RegisterParameter("pulse_end_slope", pulse_end_slope = -0.25,
00107 "Slope threshold to end a pulse");
00108
00109
00110 RegisterParameter("fixed_time1", fixed_time1 = 7.,
00111 "Fixed time at which to evaluate integral for s1 pulses");
00112 RegisterParameter("fixed_time2", fixed_time2 = 30.,
00113 "Fixed time at which to evaluate integral for s2 pulses");
00114
00115 }
00116
00117 PulseFinder::~PulseFinder()
00118 {
00119 }
00120
00121 int PulseFinder::Initialize()
00122 {
00123 return 0;
00124 }
00125
00126 int PulseFinder::Finalize()
00127 {
00128 return 0;
00129 }
00130
00131 int PulseFinder::Process(EventPtr evt)
00132 {
00133 EventDataPtr event = evt->GetEventData();
00134 ChannelData* sum_ch = event->GetChannelByID(ChannelData::CH_SUM);
00135
00136
00137 std::map<int, std::vector<int> > start_index;
00138 std::map<int, std::vector<int> > end_index;
00139
00140 if (align_pulses == true
00141 && event->channels.size() > 1)
00142 {
00143 if (! sum_ch)
00144 {
00145 Message(ERROR)<<"PulseFinder.cc: Request to align pulses across channels but sum channels disabled"<<std::endl;
00146 return 0;
00147 }
00148
00149 event->pulses_aligned = true;
00150
00151
00152 if(! sum_ch->baseline.found_baseline)
00153 return 0;
00154
00155 start_index[ChannelData::CH_SUM].clear();
00156 end_index[ChannelData::CH_SUM].clear();
00157
00158 if(mode == DISCRIMINATOR)
00159 DiscriminatorSearch(sum_ch, start_index[ChannelData::CH_SUM], end_index[ChannelData::CH_SUM]);
00160 else if (mode == VARIANCE)
00161 VarianceSearch(sum_ch, start_index[ChannelData::CH_SUM], end_index[ChannelData::CH_SUM]);
00162 else if (mode == INTEGRAL)
00163 IntegralSearch(sum_ch, start_index[ChannelData::CH_SUM], end_index[ChannelData::CH_SUM]);
00164 else if (mode == CURVATURE)
00165 CurvatureSearch(sum_ch, start_index[ChannelData::CH_SUM], end_index[ChannelData::CH_SUM]);
00166
00167
00168
00169 double* subtracted = sum_ch->GetBaselineSubtractedWaveform();
00170 double* integral = sum_ch->GetIntegralWaveform();
00171 int ratio_samps = (int)(0.02*sum_ch->sample_rate);
00172 for (size_t i = 0; i < start_index[ChannelData::CH_SUM].size(); i++)
00173 {
00174 double pulse_integral = (sum_ch->integral[end_index[ChannelData::CH_SUM][i]]
00175 - sum_ch->integral[start_index[ChannelData::CH_SUM][i]]);
00176 int peak_index = std::min_element(subtracted + start_index[ChannelData::CH_SUM][i],
00177 subtracted + end_index[ChannelData::CH_SUM][i]) - subtracted;
00178
00179 double ratio1 = 0, ratio2 = 0;
00180 if (peak_index >= ratio_samps &&
00181 peak_index < sum_ch->nsamps - ratio_samps)
00182 {
00183 ratio1 = ((integral[peak_index+ratio_samps] -
00184 integral[peak_index-ratio_samps]) /
00185 pulse_integral);
00186 ratio2 = ((integral[peak_index-ratio_samps] -
00187 integral[start_index[ChannelData::CH_SUM][i]]) /
00188 pulse_integral);
00189 }
00190
00191 if (ratio1 > 0.05 && ratio2 < 0.02)
00192 {
00193 double max_s1_peak_sep_time = 0.04;
00194 int max_sep_samps = (int)(max_s1_peak_sep_time*sum_ch->sample_rate);
00195 double default_peak_sep_time = 0.02;
00196 int default_sep_samps =
00197 (int)(default_peak_sep_time*sum_ch->sample_rate);
00198 if (std::abs(start_index[ChannelData::CH_SUM][i] - peak_index) > max_sep_samps)
00199 {
00200
00201 start_index[ChannelData::CH_SUM][i] = peak_index - default_sep_samps;
00202 }
00203 }
00204 }
00205
00206
00207
00208 for (size_t ch = 0; ch < event->channels.size(); ch++)
00209 {
00210 ChannelData& chdata = event->channels[ch];
00211
00212 if(_skip_channels.find(chdata.channel_id) != _skip_channels.end())
00213 continue;
00214 if (chdata.channel_id == ChannelData::CH_SUM)
00215 continue;
00216
00217 start_index[chdata.channel_id] = start_index[ChannelData::CH_SUM];
00218 end_index[chdata.channel_id] = end_index[ChannelData::CH_SUM];
00219 }
00220 }
00221
00222 else
00223 {
00224
00225 for (size_t ch = 0; ch < event->channels.size(); ch++)
00226 {
00227 ChannelData& chdata = event->channels[ch];
00228
00229 if(_skip_channels.find(chdata.channel_id) != _skip_channels.end())
00230 continue;
00231 if(! chdata.baseline.found_baseline)
00232 continue;
00233
00234 start_index[chdata.channel_id].clear();
00235 end_index[chdata.channel_id].clear();
00236
00237 if(mode == DISCRIMINATOR)
00238 DiscriminatorSearch(&chdata, start_index[chdata.channel_id], end_index[chdata.channel_id]);
00239 else if (mode == VARIANCE)
00240 VarianceSearch(&chdata, start_index[chdata.channel_id], end_index[chdata.channel_id]);
00241 else if (mode == INTEGRAL)
00242 IntegralSearch(&chdata, start_index[chdata.channel_id], end_index[chdata.channel_id]);
00243 else if (mode == CURVATURE)
00244 CurvatureSearch(&chdata, start_index[chdata.channel_id], end_index[chdata.channel_id]);
00245
00246
00247
00248 double* subtracted = chdata.GetBaselineSubtractedWaveform();
00249 double* integral = chdata.GetIntegralWaveform();
00250 int ratio_samps = (int)(0.02*chdata.sample_rate);
00251 for (size_t i = 0; i < start_index[chdata.channel_id].size(); i++)
00252 {
00253 double pulse_integral = (chdata.integral[end_index[chdata.channel_id][i]]
00254 - chdata.integral[start_index[chdata.channel_id][i]]);
00255 int peak_index = std::min_element(subtracted + start_index[chdata.channel_id][i],
00256 subtracted + end_index[chdata.channel_id][i]) - subtracted;
00257
00258 double ratio1 = 0, ratio2 = 0;
00259 if (peak_index >= ratio_samps &&
00260 peak_index < chdata.nsamps - ratio_samps)
00261 {
00262 ratio1 = ((integral[peak_index+ratio_samps] -
00263 integral[peak_index-ratio_samps]) /
00264 pulse_integral);
00265 ratio2 = ((integral[peak_index-ratio_samps] -
00266 integral[start_index[chdata.channel_id][i]]) /
00267 pulse_integral);
00268 }
00269
00270 if (ratio1 > 0.05 && ratio2 < 0.02)
00271 {
00272 double max_s1_peak_sep_time = 0.04;
00273 int max_sep_samps = (int)(max_s1_peak_sep_time*chdata.sample_rate);
00274 double default_peak_sep_time = 0.02;
00275 int default_sep_samps =
00276 (int)(default_peak_sep_time*chdata.sample_rate);
00277 if (std::abs(start_index[chdata.channel_id][i] - peak_index) > max_sep_samps)
00278 {
00279
00280 start_index[chdata.channel_id][i] = peak_index - default_sep_samps;
00281 }
00282 }
00283 }
00284
00285 }
00286 }
00287
00288
00289
00290 for (size_t ch = 0; ch < event->channels.size(); ch++)
00291 {
00292 ChannelData& chdata = event->channels[ch];
00293
00294 if(_skip_channels.find(chdata.channel_id) != _skip_channels.end())
00295 continue;
00296
00297 int ch_id = chdata.channel_id;
00298
00299 for (size_t i = 0; i < start_index[ch_id].size(); i++)
00300 {
00301 if (start_index[ch_id][i] >= end_index[ch_id][i])
00302 return -1;
00303 Pulse pulse;
00304 EvaluatePulse(pulse, &chdata, start_index[ch_id][i], end_index[ch_id][i]);
00305
00306 if( !chdata.integral.empty())
00307 {
00308
00309
00310 if (i > 0)
00311 {
00312 pulse.start_clean = (start_index[ch_id][i] > end_index[ch_id][i-1]);
00313 }
00314 else
00315 {
00316
00317 pulse.start_clean = true;
00318 }
00319
00320
00321 if (i < start_index[ch_id].size() - 1)
00322 {
00323 pulse.dt = (start_index[ch_id][i+1] - start_index[ch_id][i])/chdata.sample_rate;
00324 pulse.end_clean = (end_index[ch_id][i] < start_index[ch_id][i+1]);
00325 }
00326 else
00327 {
00328 pulse.dt = (chdata.nsamps - 1 - start_index[ch_id][i])/chdata.sample_rate;
00329 pulse.end_clean = (end_index[ch_id][i] < chdata.nsamps-1);
00330 }
00331
00332 pulse.fixed_int1_valid = (pulse.start_clean &&
00333 fixed_time1 < pulse.dt);
00334 pulse.fixed_int2_valid = (pulse.start_clean &&
00335 fixed_time2 < pulse.dt);
00336
00337 pulse.is_clean = pulse.start_clean && pulse.end_clean;
00338 }
00339 chdata.pulses.push_back(pulse);
00340
00341 }
00342 chdata.npulses = chdata.pulses.size();
00343 }
00344
00345 return 0;
00346 }
00347
00348 int PulseFinder::EvaluatePulse(Pulse& pulse, ChannelData* chdata,
00349 int start_index, int end_index) const
00350 {
00351 if(!chdata->baseline.found_baseline)
00352 return 1;
00353 double* subtracted = chdata->GetBaselineSubtractedWaveform();
00354 int min_index = std::min_element(subtracted + start_index,
00355 subtracted + end_index) - subtracted;
00356 pulse.found_start = true;
00357 pulse.start_index = start_index;
00358 pulse.start_time = chdata->SampleToTime(pulse.start_index);
00359 pulse.found_end = (subtracted[end_index] > 0.);
00360 pulse.end_index = end_index;
00361 pulse.end_time = chdata->SampleToTime(pulse.end_index);
00362 pulse.found_peak = true;
00363 pulse.peak_index = min_index;
00364 pulse.peak_time = chdata->SampleToTime(pulse.peak_index);
00365 pulse.peak_amplitude = -subtracted[min_index];
00366 if(!chdata->integral.empty()){
00367 pulse.integral = chdata->integral[pulse.end_index] -
00368 chdata->integral[pulse.start_index];
00369
00370
00371
00372
00373 pulse.f_param.clear();
00374 for(int ft=10; ft <=100; ft+=10)
00375 {
00376 int fsamp = (int)(pulse.start_index+0.001*ft*chdata->sample_rate);
00377 if(fsamp >= chdata->nsamps)
00378 break;
00379 double fp =
00380 ( chdata->integral[fsamp] - chdata->integral[pulse.start_index] ) /
00381 pulse.integral;
00382 pulse.f_param.push_back(fp);
00383 if(ft == 90)
00384 pulse.f90 = fp;
00385 }
00386
00387
00388 int samp = pulse.start_index;
00389 while( samp<pulse.end_index &&
00390 std::abs(chdata->integral[samp]-chdata->integral[pulse.start_index])<
00391 std::abs(pulse.integral)*0.05 ) samp++;
00392 pulse.t05 = chdata->SampleToTime(samp)-pulse.start_time;
00393 while( samp<pulse.end_index &&
00394 std::abs(chdata->integral[samp]-chdata->integral[pulse.start_index])<
00395 std::abs(pulse.integral)*0.10 ) samp++;
00396 pulse.t10 = chdata->SampleToTime(samp)-pulse.start_time;
00397 samp = pulse.end_index-1;
00398 while( samp>=pulse.start_index &&
00399 std::abs(chdata->integral[samp]-chdata->integral[pulse.start_index])>
00400 std::abs(pulse.integral)*0.95 ) samp--;
00401 pulse.t95 = chdata->SampleToTime(++samp)-pulse.start_time;
00402 while( samp>=pulse.start_index &&
00403 std::abs(chdata->integral[samp]-chdata->integral[pulse.start_index])>
00404 std::abs(pulse.integral)*0.90 ) samp--;
00405 pulse.t90 = chdata->SampleToTime(++samp)-pulse.start_time;
00406
00407
00408 samp = chdata->TimeToSample(pulse.start_time+fixed_time1,true);
00409 pulse.fixed_int1 = chdata->integral[samp] -
00410 chdata->integral[pulse.start_index];
00411 samp = chdata->TimeToSample(pulse.start_time+fixed_time2,true);
00412 pulse.fixed_int2 = chdata->integral[samp] -
00413 chdata->integral[pulse.start_index];
00414
00415 }
00416 pulse.npe = -pulse.integral/chdata->spe_mean;
00417
00418 double* wave = chdata->GetWaveform();
00419 if(wave[min_index] == 0){
00420 pulse.peak_saturated = true;
00421 int min_end_index = min_index + 1;
00422 while (wave[min_end_index] == 0 && min_end_index < end_index)
00423 {
00424 min_end_index++;
00425 }
00426 pulse.peak_index = (int)(min_index + min_end_index)/2;
00427 }
00428 return 0;
00429 }
00430
00431
00432 void PulseFinder::VarianceSearch(ChannelData* chdata,
00433 std::vector<int>& start_index,
00434 std::vector<int>& end_index)
00435 {
00436 Baseline& baseline = chdata->baseline;
00437 int index=start_window;
00438 double* wave = chdata->GetWaveform();
00439 double start_baseline;
00440 bool found_start;
00441 for(index = start_window; index < chdata->nsamps; index++)
00442 {
00443 if(start_index.size() > 5)
00444 {
00445 break;
00446 }
00447
00448
00449
00450
00451 found_start = true;
00452 for(int samp=index-start_window; samp < index; samp++)
00453 {
00454 if( wave[samp]-wave[samp+1] < baseline.variance )
00455 {
00456 found_start = false;
00457 break;
00458 }
00459 }
00460 if (start_index.size() == 0)
00461 start_baseline = baseline.mean;
00462 else
00463 start_baseline = wave[index-start_window];
00464
00465 if(!found_start ||
00466 wave[index] > start_baseline-min_start_variance * baseline.variance )
00467 continue;
00468
00469 start_index.push_back(index-start_window);
00470 index = index + min_resolution;
00471 }
00472
00473
00474
00475 for (size_t i = 0; i < start_index.size(); i++)
00476 {
00477 int limit_index;
00478 if (i == start_index.size() - 1)
00479 limit_index = chdata->nsamps;
00480 else
00481 limit_index = start_index[i+1];
00482
00483 int min_index = std::min_element(wave + start_index[i], wave + limit_index) - wave;
00484 if(wave[min_index] > baseline.mean)
00485 end_index.push_back(min_index);
00486 else
00487 end_index.push_back(limit_index - 1);
00488 }
00489
00490 }
00491
00492 void PulseFinder::DiscriminatorSearch( ChannelData* chdata,
00493 std::vector<int>& start_index,
00494 std::vector<int>& end_index)
00495 {
00496 double* wave = chdata->GetWaveform();
00497 double check_val = discriminator_value;
00498 if(discriminator_relative)
00499 wave = chdata->GetBaselineSubtractedWaveform();
00500
00501 for(int index = discriminator_start_add;
00502 index < chdata->nsamps - discriminator_end_add ; index++){
00503 if(wave[index] < check_val){
00504 start_index.push_back( index - discriminator_start_add );
00505 while(++index < chdata->nsamps-discriminator_end_add-1 &&
00506 wave[index] < check_val &&
00507 wave[index + discriminator_end_add] < check_val) {}
00508 index += discriminator_end_add;
00509 end_index.push_back( index );
00510 index += discriminator_start_add;
00511 }
00512 }
00513
00514 }
00515
00516 void LinearRegression(double* start, double* end,
00517 double& slope, double& intercept)
00518 {
00519
00520 int N = (end - start);
00521 double delta = 1.*N*N/12. * (N*N-1);
00522 double sumx=0, sumy=0, sumxy=0, sumx2=0;
00523 for(int x=0; x<N; x++){
00524 sumx += x;
00525 sumx2 += x*x;
00526 sumy += *(start+x);
00527 sumxy += *(start+x)*x;
00528 }
00529 slope = 1./delta * (N*sumxy - sumx*sumy);
00530 intercept = 1./delta * (sumx2*sumy - sumx*sumxy);
00531 }
00532
00533 void PulseFinder::IntegralSearch( ChannelData* chdata,
00534 std::vector<int>& start_index,
00535 std::vector<int>& end_index)
00536 {
00537 double scale_factor = normalize ? chdata->spe_mean : 1;
00538
00539 double* integral = chdata->GetIntegralWaveform();
00540 double* wave = chdata->GetBaselineSubtractedWaveform();
00541 int start_samps = (int)(integral_start_time * chdata->sample_rate);
00542 int end_samps = (int)(integral_end_time * chdata->sample_rate);
00543 int min_pulse_samps = (int)(min_pulse_time * chdata->sample_rate);
00544 if(start_samps <= 0) start_samps = 1;
00545 int samp = -1;
00546
00547
00548 bool in_pulse = false;
00549 while ( ++samp < chdata->nsamps){
00550 int lookback_samps = std::min(samp,
00551 (int)(lookback_time*chdata->sample_rate));
00552 double int_thresh = integral_start_threshold;
00553 double amp_thresh = amplitude_start_threshold;
00554
00555 if(in_pulse){
00556
00557 if(samp - start_index.back() >= min_pulse_samps){
00558 int test_samp = std::min(chdata->nsamps-1, samp+end_samps);
00559 if( (integral[samp] - integral[test_samp] )/scale_factor <
00560 integral_end_threshold &&
00561 (*std::min_element(wave+samp,wave+test_samp))/scale_factor >
00562 -amplitude_end_threshold ){
00563
00564 in_pulse = false;
00565 end_index.push_back(samp);
00566 continue;
00567 }
00568 }
00569
00570
00571
00572
00573 if(integral[samp-lookback_samps] - integral[samp] >
00574 (integral[samp-2*lookback_samps] - integral[samp-lookback_samps]) *
00575 multipulse_thresh_value)
00576 continue;
00577
00578
00579 double prev_max = -(*std::min_element(wave+samp-lookback_samps,
00580 wave+samp)) / scale_factor;
00581
00582 double halfback = (integral[samp-lookback_samps/2] - integral[samp] );
00583 double ratio = halfback /
00584 (integral[samp-lookback_samps] -
00585 integral[samp-lookback_samps/2] ) ;
00586
00587 double integral_est = halfback*ratio*
00588 (2*start_samps/lookback_samps ) / scale_factor;
00589 amp_thresh += prev_max*multipulse_thresh_value;
00590 int_thresh += integral_est*multipulse_thresh_value;
00591 }
00592
00593
00594 if(wave[samp]/scale_factor > -amp_thresh) continue;
00595
00596 int test_samp = std::min(chdata->nsamps-1, samp+start_samps);
00597 if((integral[samp]-integral[test_samp])/scale_factor >
00598 int_thresh){
00599
00600 int good_samp = std::max(0,samp-2);
00601 if(in_pulse)
00602 end_index.push_back(good_samp);
00603 in_pulse = true;
00604 start_index.push_back(good_samp);
00605 samp += (int)(min_sep_time * chdata->sample_rate);
00606 continue;
00607 }
00608
00609
00610 }
00611 if(in_pulse)
00612 end_index.push_back(chdata->nsamps-1);
00613
00614 }
00615
00616 void PulseFinder::CurvatureSearch( ChannelData* chdata,
00617 std::vector<int>& start_index,
00618 std::vector<int>& end_index) {
00619 double* integral = chdata->GetIntegralWaveform();
00620
00621 int df = down_sample_factor;
00622 int n = chdata->nsamps/df;
00623 std::vector<double> sm(n);
00624 for(int i=0; i<n; i++){
00625 sm[i] = integral[i*df];
00626 }
00627
00628 std::vector<double> diff(n);
00629 diff[0]= sm[1];
00630 for (int i=1; i<n-1; i++){
00631 diff[i] = sm[i+1]-sm[i-1];
00632 }
00633
00634 std::vector<double> curve(n);
00635 curve[0] = diff[1];
00636 for (int i=1; i<n-1; i++){
00637 curve[i] = diff[i+1]-diff[i-1];
00638 }
00639
00640 bool in_pulse = false;
00641 bool before_peak = true;
00642 int last = -1;
00643 for (int i=0; i<n-1; i++){
00644 if (!in_pulse){
00645 if (curve[i] < pulse_start_curvature){
00646 in_pulse = true;
00647 int start = i*df;
00648
00649
00650
00651 int loopcount=0;
00652 int maxloop = df;
00653 if(i<n-2) maxloop+= df;
00654 double* sub = chdata->GetBaselineSubtractedWaveform();
00655 while( ++loopcount<maxloop && -sub[start] < amplitude_start_threshold)
00656 start++;
00657 start_index.push_back(start-2 > 0 ? start-2 : 0);
00658 }
00659 }
00660 else{
00661 if (before_peak){
00662 if (curve[i] > 0){
00663 before_peak = false;
00664 }
00665 }
00666 else {
00667 if (curve[i] < 0 && last < 0){
00668 last = i;
00669 }
00670 if (curve[i] > 0 && last > 0){
00671 last = -1;
00672 }
00673
00674 if (curve[i] < pile_up_curvature){
00675 end_index.push_back(last*df);
00676 start_index.push_back(last*df);
00677 before_peak = true;
00678 last = -1;
00679 }
00680 else if (diff[i] > pulse_end_slope){
00681 end_index.push_back(i*df);
00682 in_pulse = false;
00683 before_peak = true;
00684 last = -1;
00685 }
00686 }
00687 }
00688 }
00689 if (in_pulse){
00690 end_index.push_back(chdata->nsamps-1);
00691 }
00692 }