00001 #include "Event.hh"
00002 #include "BaselineFinder.hh"
00003 #include "ConvertData.hh"
00004 #include "SumChannels.hh"
00005 #include "intarray.hh"
00006 #include "RootWriter.hh"
00007 #include "TGraph.h"
00008 #include <vector>
00009 #include <cmath>
00010 #include <string>
00011 #include <iomanip>
00012 #include <iostream>
00013 #include <functional>
00014 #include <algorithm>
00015
00016 BaselineFinder::BaselineFinder():
00017 ChannelModule(GetDefaultName(), "Find the baseline (zero) of the channel in the samples read before the trigger")
00018 {
00019 AddDependency<ConvertData>();
00020
00021
00022 RegisterParameter("fixed_baseline", fixed_baseline = false,
00023 "Search for a flat baseline in pre-trigger window, otherwise search for a drifting baseline");
00024 RegisterParameter("signal_begin_time", signal_begin_time = 0,
00025 "Search for baseline before this time [us] ");
00026
00027
00028 RegisterParameter("segment_samps", segment_samps = 15,
00029 "Samples in each baseline segment");
00030 RegisterParameter("min_valid_samps", min_valid_samps = 50,
00031 "Minimum samples for a baseline to be valid");
00032 RegisterParameter("max_sigma", max_sigma = 1.2,
00033 "Maximum standard deviation for a baseline segment to be accepted");
00034 RegisterParameter("max_sigma_diff", max_sigma_diff = 1,
00035 "Maximum difference between baseline sigma and the sigma of a new valid segment");
00036 RegisterParameter("max_mean_diff", max_mean_diff = 1,
00037 "Maximum difference between baseline mean and the mean of a new valid segment");
00038
00039
00040 RegisterParameter("linear_interpolation", linear_interpolation = false,
00041 "Compute further baseline estimates throughout trigger window and perform interpolation");
00042 RegisterParameter("avg_samps", avg_samps = 1000,
00043 "Number of contiguous samples to use to perform new baseline estimate");
00044 RegisterParameter("max_sigma_factor", max_sigma_factor = 3,
00045 "Samples withing this number of flat baseline sigmas will be considered for baseline estimate");
00046 RegisterParameter("pulse_threshold", pulse_threshold = 4,
00047 "Threshold (in number of max_sigmas) to consider a pulse and ignore cooldown samples from baseline estimate");
00048 RegisterParameter("cooldown", cooldown = 2050,
00049 "Total number of samples around pulses to ignore for baseline estimate");
00050 RegisterParameter("pre_cooldown", pre_cooldown = 50,
00051 "Number of samples before pulse to ignore for baseline estimate");
00052
00053
00054 RegisterParameter("max_amplitude", max_amplitude = 5,
00055 "Max amplitude for sample to be considered in baseline");
00056 RegisterParameter("max_sum_amplitude", max_sum_amplitude = 0.2,
00057 "max_amplitude for sum channel");
00058 RegisterParameter("pre_samps", pre_samps = 5,
00059 "Samples before to include in moving average");
00060 RegisterParameter("post_samps", post_samps = 5,
00061 "Samples after to include in average");
00062 RegisterParameter("laserwindow_begin_time", laserwindow_begin_time = -999,
00063 "Specify the beginning time of a laser window.");
00064
00065 RegisterParameter("laserwindow_end_time", laserwindow_end_time = -999,
00066 "Specify the ending time of a laser window.");
00067 RegisterParameter("laserwindow_freeze", laserwindow_freeze = true,
00068 "Specify whether to always interpolate the baseline in the laser window.");
00069 RegisterParameter("save_interpolations", save_interpolations = false, "Save identified interpolation regions as spe");
00070 }
00071
00072 BaselineFinder::~BaselineFinder()
00073 {
00074 Finalize();
00075 }
00076
00077 int BaselineFinder::Initialize()
00078 {
00079 return 0;
00080 }
00081
00082 int BaselineFinder::Finalize()
00083 {
00084 return 0;
00085 }
00086
00087 int BaselineFinder::Process(ChannelData* chdata)
00088 {
00089 if(fixed_baseline) return FixedBaseline(chdata);
00090 else return DriftingBaseline(chdata);
00091 }
00092
00093 int BaselineFinder::DriftingBaseline(ChannelData* chdata)
00094 {
00095 Baseline& baseline = chdata->baseline;
00096 double* wave = chdata->GetWaveform();
00097 std::vector<double>& baseform = chdata->subtracted_waveform;
00098 const int nsamps = chdata->nsamps;
00099 baseform.resize(nsamps);
00100
00101
00102 int pre_trig_samp = chdata->TimeToSample(signal_begin_time);
00103 if(pre_trig_samp < 0) pre_trig_samp = pre_samps+post_samps;
00104 if(pre_trig_samp >= nsamps) pre_trig_samp = nsamps-1;
00105 double max_pre_trig = *std::max_element(wave,wave+pre_trig_samp);
00106 if( std::abs(chdata->GetVerticalRange() - max_pre_trig ) < 0.01)
00107 baseline.saturated = true;
00108
00109
00110
00111 double var = max_amplitude;
00112 if(chdata->channel_id == ChannelData::CH_SUM)
00113 var = max_sum_amplitude;
00114
00115 double sum = 0;
00116 int sum_samps = 0;
00117 int samp = -1;
00118 int window_samps = pre_samps + post_samps + 1;
00119 int last_good_samp = -1;
00120 double moving_base = -1;
00121 baseline.found_baseline = false;
00122 int laserwindow_begin_samp = chdata->TimeToSample(laserwindow_begin_time);
00123 int laserwindow_end_samp = chdata->TimeToSample(laserwindow_end_time);
00124 while(++samp < chdata->nsamps){
00125 bool pass_amp = false;
00126 if(!baseline.found_baseline && max_pre_trig - wave[samp] < 2*var)
00127 pass_amp = true;
00128 else if(baseline.found_baseline && std::abs(wave[samp]-moving_base)<var)
00129 pass_amp = true;
00130 else if(samp>=laserwindow_begin_samp && samp <= laserwindow_end_samp)
00131 baseline.laserskip = true;
00132 if(laserwindow_freeze && samp>=laserwindow_begin_samp && samp <= laserwindow_end_samp ){
00133 pass_amp = false;
00134 }
00135
00136 if(pass_amp){
00137
00138 sum += wave[samp];
00139 sum_samps++;
00140 if(sum_samps > window_samps){
00141
00142 sum -= wave[samp-window_samps];
00143 sum_samps--;
00144 }
00145 if(sum_samps == window_samps){
00146
00147 double mean = sum/sum_samps;
00148 moving_base = mean;
00149 baseform[samp - post_samps] = mean;
00150 if(last_good_samp < samp-post_samps-1){
00151
00152 double preval = mean;
00153 if(last_good_samp >=0)
00154 preval = baseform[last_good_samp];
00155 double slope = (mean-preval)/((samp-post_samps)-last_good_samp);
00156 for(int backsamp = last_good_samp+1; backsamp < samp; backsamp++){
00157 baseform[backsamp] = preval + slope*(backsamp-last_good_samp);
00158 }
00159 if(save_interpolations && last_good_samp >=0){
00160
00161 Spe pe;
00162 pe.start_time = chdata->SampleToTime(last_good_samp);
00163 pe.length = chdata->SampleToTime(samp-post_samps)-pe.start_time;
00164 int peak_samp = std::min_element(wave+last_good_samp, wave+samp-post_samps)-wave;
00165 pe.peak_time = chdata->SampleToTime(peak_samp);
00166 pe.amplitude = baseform[peak_samp]-wave[peak_samp];
00167 baseline.interpolations.push_back(pe);
00168 baseline.ninterpolations++;
00169 }
00170 }
00171 last_good_samp = samp-post_samps;
00172 if(!baseline.found_baseline){
00173 baseline.found_baseline = true;
00174 baseline.mean = mean;
00175 baseline.search_start_index = samp - window_samps;
00176 baseline.length = window_samps;
00177
00178 double sum2 = 0;
00179 for(int backsamp = samp-window_samps+1; backsamp<=samp; backsamp++)
00180 sum2 += wave[backsamp]*wave[backsamp];
00181 baseline.variance = sum2/window_samps - mean*mean;
00182 }
00183 }
00184 }
00185 else{
00186
00187 sum = 0;
00188 sum_samps = 0;
00189 if(!baseline.found_baseline && samp > pre_trig_samp){
00190
00191 return 0;
00192 }
00193
00194 }
00195 }
00196
00197 for(samp = last_good_samp+1; samp<nsamps; samp++){
00198 baseform[samp] = baseform[last_good_samp];
00199 }
00200
00201 for(samp=0; samp<nsamps; samp++){
00202 baseform[samp] = wave[samp]-baseform[samp];
00203 }
00204
00205 return 0;
00206 }
00207
00208
00209 int BaselineFinder::FixedBaseline(ChannelData* chdata){
00210
00211 Baseline & baseline = chdata->baseline;
00212 double * wave = chdata->GetWaveform();
00213 const int nsamps = chdata->nsamps;
00214
00215
00216 int pre_trig_samp = chdata->TimeToSample(signal_begin_time);
00217 if(pre_trig_samp <= 0 || pre_trig_samp >= nsamps) return 0;
00218 double max_pre_trig = *std::max_element(wave,wave+pre_trig_samp);
00219 double min_pre_trig = *std::min_element(wave,wave+pre_trig_samp);
00220 if( std::abs(chdata->GetVerticalRange() - max_pre_trig ) < 0.01
00221 || min_pre_trig < 0.01)
00222 baseline.saturated = true;
00223
00224 double sum=0, sum2=0, mean=0, sigma=0;
00225 double seg_sum=0, seg_sum2=0, seg_mean=0, seg_sigma=0;
00226 int sum_samps = 0;
00227
00228 baseline.found_baseline = false;
00229 int samp = -1;
00230 while(++samp < chdata->nsamps){
00231 if(samp>=pre_trig_samp) break;
00232
00233 if(!(samp % segment_samps) && samp){
00234 seg_mean = seg_sum/segment_samps;
00235 seg_sigma = std::sqrt(seg_sum2/segment_samps-seg_mean*seg_mean);
00236
00237 if(seg_sigma>max_sigma){
00238
00239 }
00240 else if(sum<1e-6 && sum2<1e-6) {
00241 sum = seg_sum;
00242 sum2 = seg_sum2;
00243 mean = seg_mean;
00244 sigma = seg_sigma;
00245 sum_samps = segment_samps;
00246 baseline.search_start_index = samp - segment_samps;
00247 }
00248 else if(std::fabs(sigma-seg_sigma)<max_sigma_diff && std::fabs(mean-seg_mean)<max_mean_diff){
00249
00250 sum += seg_sum;
00251 sum2 += seg_sum2;
00252 sum_samps += segment_samps;
00253 mean = sum/sum_samps;
00254 sigma = sqrt(sum2/sum_samps-mean*mean);
00255 }
00256 else if(sum_samps>=min_valid_samps) break;
00257 else if(sigma>seg_sigma){
00258 sum = seg_sum;
00259 sum2 = seg_sum2;
00260 mean = seg_mean;
00261 sigma = seg_sigma;
00262 sum_samps = segment_samps;
00263 baseline.search_start_index = samp - segment_samps;
00264 }
00265 else{
00266 sum = 0;
00267 sum2 = 0;
00268 mean = 0;
00269 sigma = 0;
00270 sum_samps = 0;
00271 }
00272 seg_sum = 0;
00273 seg_sum2 = 0;
00274 }
00275 seg_sum += wave[samp];
00276 seg_sum2 += wave[samp]*wave[samp];
00277 }
00278
00279 if(sum_samps>=min_valid_samps){
00280 baseline.found_baseline = true;
00281 baseline.mean = mean;
00282 baseline.variance = sigma*sigma;
00283 baseline.length = sum_samps;
00284
00285 std::vector<double>& baseform = chdata->subtracted_waveform;
00286 baseform.resize(nsamps);
00287
00288 if(linear_interpolation){
00289
00290 double max_sigma_lin = max_sigma_factor*1.4142*sigma;
00291 int cooldown_timer = 0;
00292
00293 std::vector<double> vx;
00294 std::vector<double> vy;
00295 double totx=0, toty=0, asamps=0;
00296
00297
00298 for(samp=0; samp<nsamps-1; samp++){
00299
00300 bool reset = false;
00301
00302 if(std::fabs(wave[samp]-wave[samp+1]) < max_sigma_lin && cooldown_timer==0){
00303 asamps++;
00304 totx+=samp;
00305 toty+=wave[samp];
00306 }
00307
00308 if(asamps>=avg_samps){
00309 vx.push_back(totx/asamps);
00310 vy.push_back(toty/asamps);
00311 reset = true;
00312 }
00313
00314 if(samp<nsamps-pre_cooldown && std::fabs(wave[samp+pre_cooldown]-mean)>pulse_threshold*max_sigma_lin){
00315 cooldown_timer = cooldown;
00316 reset = true;
00317 }
00318 else if(cooldown_timer>0) cooldown_timer--;
00319
00320 if(reset){
00321 asamps=0;
00322 totx=0;
00323 toty=0;
00324 }
00325 }
00326
00327 TGraph* gbase = new TGraph( vx.size(), &vx[0], &vy[0]);
00328
00329 for(samp=0; samp<nsamps; samp++){
00330
00331 if(samp<nsamps-pre_cooldown && std::fabs(wave[samp+pre_cooldown]-mean)>pulse_threshold*max_sigma_lin) cooldown_timer = cooldown;
00332 else if(cooldown_timer>0) cooldown_timer--;
00333
00334 double meanp = mean;
00335 if(gbase->GetN()>1) meanp = gbase->Eval(samp);
00336
00337 if(std::fabs(wave[samp]-meanp) < max_sigma_lin && cooldown_timer == 0) baseform[samp] = 0;
00338 else {
00339
00340 baseform[samp] = wave[samp]-meanp;
00341
00342 if(samp>0 && std::fabs(wave[samp-1]-meanp) < max_sigma_lin) baseform[samp-1] = wave[samp-1]-meanp;
00343 if(samp<nsamps-1 && std::fabs(wave[samp+1]-meanp) < max_sigma_lin){
00344 baseform[samp+1] = wave[samp+1]-meanp;
00345 samp++;
00346 if(cooldown_timer>0) cooldown_timer--;
00347 }
00348 }
00349 }
00350
00351 gbase->Delete();
00352 }
00353
00354 else{
00355
00356 for(samp=0; samp<nsamps; samp++){
00357 baseform[samp] = wave[samp]-mean;
00358 }
00359 }
00360
00361 return 0;
00362 }
00363 else return 0;
00364 }
00365