source: trunk/MagicSoft/Mars/msignal/MExtractTimeAndChargeSpline.cc@ 6769

Last change on this file since 6769 was 6769, checked in by gaug, 20 years ago
*** empty log message ***
File size: 32.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analyzing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17! Author(s): Markus Gaug 09/2004 <mailto:markus@ifae.es>
18!
19! Copyright: MAGIC Software Development, 2002-2004
20!
21!
22\* ======================================================================== */
23//////////////////////////////////////////////////////////////////////////////
24//
25// MExtractTimeAndChargeSpline
26//
27// Fast Spline extractor using a cubic spline algorithm, adapted from
28// Numerical Recipes in C++, 2nd edition, pp. 116-119.
29//
30// The coefficients "ya" are here denoted as "fHiGainSignal" and "fLoGainSignal"
31// which means the FADC value subtracted by the clock-noise corrected pedestal.
32//
33// The coefficients "y2a" get immediately divided 6. and are called here
34// "fHiGainSecondDeriv" and "fLoGainSecondDeriv" although they are now not exactly
35// the second derivative coefficients any more.
36//
37// The calculation of the cubic-spline interpolated value "y" on a point
38// "x" along the FADC-slices axis becomes:
39//
40// y = a*fHiGainSignal[klo] + b*fHiGainSignal[khi]
41// + (a*a*a-a)*fHiGainSecondDeriv[klo] + (b*b*b-b)*fHiGainSecondDeriv[khi]
42//
43// with:
44// a = (khi - x)
45// b = (x - klo)
46//
47// and "klo" being the lower bin edge FADC index and "khi" the upper bin edge FADC index.
48// fHiGainSignal[klo] and fHiGainSignal[khi] are the FADC values at "klo" and "khi".
49//
50// An analogues formula is used for the low-gain values.
51//
52// The coefficients fHiGainSecondDeriv and fLoGainSecondDeriv are calculated with the
53// following simplified algorithm:
54//
55// for (Int_t i=1;i<range-1;i++) {
56// pp = fHiGainSecondDeriv[i-1] + 4.;
57// fHiGainFirstDeriv[i] = fHiGainSignal[i+1] - 2.*fHiGainSignal[i] + fHiGainSignal[i-1]
58// fHiGainFirstDeriv[i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
59// }
60//
61// for (Int_t k=range-2;k>=0;k--)
62// fHiGainSecondDeriv[k] = (fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k])/6.;
63//
64//
65// This algorithm takes advantage of the fact that the x-values are all separated by exactly 1
66// which simplifies the Numerical Recipes algorithm.
67// (Note that the variables "fHiGainFirstDeriv" are not real first derivative coefficients.)
68//
69// The algorithm to search the time proceeds as follows:
70//
71// 1) Calculate all fHiGainSignal from fHiGainFirst to fHiGainLast
72// (note that an "overlap" to the low-gain arrays is possible: i.e. fHiGainLast>14 in the case of
73// the MAGIC FADCs).
74// 2) Remember the position of the slice with the highest content "fAbMax" at "fAbMaxPos".
75// 3) If one or more slices are saturated or fAbMaxPos is less than 2 slices from fHiGainFirst,
76// return fAbMaxPos as time and fAbMax as charge (note that the pedestal is subtracted here).
77// 4) Calculate all fHiGainSecondDeriv from the fHiGainSignal array
78// 5) Search for the maximum, starting in interval fAbMaxPos-1 in steps of 0.2 till fAbMaxPos-0.2.
79// If no maximum is found, go to interval fAbMaxPos+1.
80// --> 4 function evaluations
81// 6) Search for the absolute maximum from fAbMaxPos to fAbMaxPos+1 in steps of 0.2
82// --> 4 function evaluations
83// 7) Try a better precision searching from new max. position fAbMaxPos-0.2 to fAbMaxPos+0.2
84// in steps of 0.025 (83 psec. in the case of the MAGIC FADCs).
85// --> 14 function evaluations
86// 8) If Time Extraction Type kMaximum has been chosen, the position of the found maximum is
87// returned, else:
88// 9) The Half Maximum is calculated.
89// 10) fHiGainSignal is called beginning from fAbMaxPos-1 backwards until a value smaller than fHalfMax
90// is found at "klo".
91// 11) Then, the spline value between "klo" and "klo"+1 is halfed by means of bisection as long as
92// the difference between fHalfMax and spline evaluation is less than fResolution (default: 0.01).
93// --> maximum 12 interations.
94//
95// The algorithm to search the charge proceeds as follows:
96//
97// 1) If Charge Type: kAmplitude was chosen, return the Maximum of the spline, found during the
98// time search.
99// 2) If Charge Type: kIntegral was chosen, sum the fHiGainSignal between:
100// (Int_t)(fAbMaxPos - fRiseTimeHiGain) and
101// (Int_t)(fAbMaxPos + fFallTimeHiGain)
102// (default: fRiseTime: 1.5, fFallTime: 4.5)
103// sum the fLoGainSignal between:
104// (Int_t)(fAbMaxPos - fRiseTimeHiGain*fLoGainStretch) and
105// (Int_t)(fAbMaxPos + fFallTimeHiGain*fLoGainStretch)
106// (default: fLoGainStretch: 1.5)
107//
108// The values: fNumHiGainSamples and fNumLoGainSamples are set to:
109// 1) If Charge Type: kAmplitude was chosen: 1.
110// 2) If Charge Type: kIntegral was chosen: fRiseTimeHiGain + fFallTimeHiGain
111// or: fNumHiGainSamples*fLoGainStretch in the case of the low-gain
112//
113// Call: SetRange(fHiGainFirst, fHiGainLast, fLoGainFirst, fLoGainLast)
114// to modify the ranges.
115//
116// Defaults:
117// fHiGainFirst = 2
118// fHiGainLast = 14
119// fLoGainFirst = 2
120// fLoGainLast = 14
121//
122// Call: SetResolution() to define the resolution of the half-maximum search.
123// Default: 0.01
124//
125// Call: SetRiseTime() and SetFallTime() to define the integration ranges
126// for the case, the extraction type kIntegral has been chosen.
127//
128// Call: - SetChargeType(MExtractTimeAndChargeSpline::kAmplitude) for the
129// computation of the amplitude at the maximum (default) and extraction
130// the position of the maximum (default)
131// --> no further function evaluation needed
132// - SetChargeType(MExtractTimeAndChargeSpline::kIntegral) for the
133// computation of the integral beneith the spline between fRiseTimeHiGain
134// from the position of the maximum to fFallTimeHiGain after the position of
135// the maximum. The Low Gain is computed with half a slice more at the rising
136// edge and half a slice more at the falling edge.
137// The time of the half maximum is returned.
138// --> needs one function evaluations but is more precise
139//
140//////////////////////////////////////////////////////////////////////////////
141#include "MExtractTimeAndChargeSpline.h"
142
143#include "MPedestalPix.h"
144
145#include "MLog.h"
146#include "MLogManip.h"
147
148ClassImp(MExtractTimeAndChargeSpline);
149
150using namespace std;
151
152const Byte_t MExtractTimeAndChargeSpline::fgHiGainFirst = 2;
153const Byte_t MExtractTimeAndChargeSpline::fgHiGainLast = 14;
154const Byte_t MExtractTimeAndChargeSpline::fgLoGainFirst = 2;
155const Byte_t MExtractTimeAndChargeSpline::fgLoGainLast = 14;
156const Float_t MExtractTimeAndChargeSpline::fgResolution = 0.05;
157const Float_t MExtractTimeAndChargeSpline::fgRiseTimeHiGain = 0.5;
158const Float_t MExtractTimeAndChargeSpline::fgFallTimeHiGain = 1.5;
159const Float_t MExtractTimeAndChargeSpline::fgLoGainStretch = 1.5;
160const Float_t MExtractTimeAndChargeSpline::fgOffsetLoGain = 1.7; // 5 ns
161// --------------------------------------------------------------------------
162//
163// Default constructor.
164//
165// Calls:
166// - SetRange(fgHiGainFirst, fgHiGainLast, fgLoGainFirst, fgLoGainLast)
167//
168// Initializes:
169// - fResolution to fgResolution
170// - fRiseTimeHiGain to fgRiseTimeHiGain
171// - fFallTimeHiGain to fgFallTimeHiGain
172// - Charge Extraction Type to kAmplitude
173// - fLoGainStretch to fgLoGainStretch
174//
175MExtractTimeAndChargeSpline::MExtractTimeAndChargeSpline(const char *name, const char *title)
176 : fAbMax(0.), fAbMaxPos(0.), fHalfMax(0.),
177 fRandomIter(0), fExtractionType(kIntegral)
178{
179
180 fName = name ? name : "MExtractTimeAndChargeSpline";
181 fTitle = title ? title : "Calculate photons arrival time using a fast spline";
182
183 SetResolution();
184 SetLoGainStretch();
185 SetOffsetLoGain(fgOffsetLoGain);
186
187 SetRiseTimeHiGain();
188 SetFallTimeHiGain();
189
190 SetRange(fgHiGainFirst, fgHiGainLast, fgLoGainFirst, fgLoGainLast);
191}
192
193
194//-------------------------------------------------------------------
195//
196// Set the ranges
197// In order to set the fNum...Samples variables correctly for the case,
198// the integral is computed, have to overwrite this function and make an
199// explicit call to SetChargeType().
200//
201void MExtractTimeAndChargeSpline::SetRange(Byte_t hifirst, Byte_t hilast, Byte_t lofirst, Byte_t lolast)
202{
203
204 MExtractor::SetRange(hifirst, hilast, lofirst, lolast);
205
206 SetChargeType(fExtractionType);
207}
208
209//-------------------------------------------------------------------
210//
211// Set the Charge Extraction type. Possible are:
212// - kAmplitude: Search the value of the spline at the maximum
213// - kIntegral: Integral the spline from fHiGainFirst to fHiGainLast,
214// by counting the edge bins only half and setting the
215// second derivative to zero, there.
216//
217void MExtractTimeAndChargeSpline::SetChargeType( ExtractionType_t typ )
218{
219
220 fExtractionType = typ;
221
222 if (fExtractionType == kAmplitude)
223 {
224 fNumHiGainSamples = 1.;
225 fNumLoGainSamples = fLoGainLast ? 1. : 0.;
226 fSqrtHiGainSamples = 1.;
227 fSqrtLoGainSamples = 1.;
228 fWindowSizeHiGain = 1;
229 fWindowSizeLoGain = 1;
230 fRiseTimeHiGain = 0.5;
231
232 return;
233 }
234
235 if (fExtractionType == kIntegral)
236 {
237
238 fNumHiGainSamples = fRiseTimeHiGain + fFallTimeHiGain;
239 fNumLoGainSamples = fLoGainLast ? fRiseTimeLoGain + fFallTimeLoGain : 0.;
240 // fNumLoGainSamples *= 0.75;
241
242 fSqrtHiGainSamples = TMath::Sqrt(fNumHiGainSamples);
243 fSqrtLoGainSamples = TMath::Sqrt(fNumLoGainSamples);
244 fWindowSizeHiGain = (Int_t)(fRiseTimeHiGain + fFallTimeHiGain);
245 fWindowSizeLoGain = (Int_t)((fRiseTimeLoGain + fFallTimeLoGain)*fLoGainStretch);
246 // fNumLoGainSamples *= 0.75;
247 }
248}
249
250// --------------------------------------------------------------------------
251//
252// InitArrays
253//
254// Gets called in the ReInit() and initialized the arrays
255//
256Bool_t MExtractTimeAndChargeSpline::InitArrays()
257{
258
259 Int_t range = fHiGainLast - fHiGainFirst + 1 + fHiLoLast;
260
261 fHiGainSignal .Set(range);
262 fHiGainFirstDeriv .Set(range);
263 fHiGainSecondDeriv.Set(range);
264
265 range = fLoGainLast - fLoGainFirst + 1;
266
267 fLoGainSignal .Set(range);
268 fLoGainFirstDeriv .Set(range);
269 fLoGainSecondDeriv.Set(range);
270
271 fHiGainSignal .Reset();
272 fHiGainFirstDeriv .Reset();
273 fHiGainSecondDeriv.Reset();
274
275 fLoGainSignal .Reset();
276 fLoGainFirstDeriv .Reset();
277 fLoGainSecondDeriv.Reset();
278
279 if (fExtractionType == kAmplitude)
280 {
281 fNumHiGainSamples = 1.;
282 fNumLoGainSamples = fLoGainLast ? 1. : 0.;
283 fSqrtHiGainSamples = 1.;
284 fSqrtLoGainSamples = 1.;
285 fWindowSizeHiGain = 1;
286 fWindowSizeLoGain = 1;
287 fRiseTimeHiGain = 0.5;
288 }
289
290 fRiseTimeLoGain = fRiseTimeHiGain * fLoGainStretch;
291 fFallTimeLoGain = fFallTimeHiGain * fLoGainStretch;
292
293 if (fExtractionType == kIntegral)
294 {
295
296 fNumHiGainSamples = fRiseTimeHiGain + fFallTimeHiGain;
297 fNumLoGainSamples = fLoGainLast ? fRiseTimeLoGain + fFallTimeLoGain : 0.;
298 // fNumLoGainSamples *= 0.75;
299
300 fSqrtHiGainSamples = TMath::Sqrt(fNumHiGainSamples);
301 fSqrtLoGainSamples = TMath::Sqrt(fNumLoGainSamples);
302 fWindowSizeHiGain = (Int_t)(fRiseTimeHiGain + fFallTimeHiGain);
303 fWindowSizeLoGain = (Int_t)(fRiseTimeLoGain + fFallTimeLoGain);
304 }
305
306 return kTRUE;
307
308}
309
310// --------------------------------------------------------------------------
311//
312// Calculates the arrival time and charge for each pixel
313//
314void MExtractTimeAndChargeSpline::FindTimeAndChargeHiGain(Byte_t *first, Byte_t *logain, Float_t &sum, Float_t &dsum,
315 Float_t &time, Float_t &dtime,
316 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
317{
318
319 Int_t range = fHiGainLast - fHiGainFirst + 1;
320 const Byte_t *end = first + range;
321 Byte_t *p = first;
322
323 sat = 0;
324
325 const Float_t pedes = ped.GetPedestal();
326 const Float_t ABoffs = ped.GetPedestalABoffset();
327
328 const Float_t pedmean[2] = { pedes + ABoffs, pedes - ABoffs };
329
330 fAbMax = 0.;
331 fAbMaxPos = 0.;
332 fHalfMax = 0.;
333 fMaxBinContent = 0;
334 Int_t maxpos = 0;
335
336 //
337 // Check for saturation in all other slices
338 //
339 Int_t ids = fHiGainFirst;
340 Float_t *sample = fHiGainSignal.GetArray();
341 while (p<end)
342 {
343
344 *sample++ = (Float_t)*p - pedmean[(ids++ + abflag) & 0x1];
345
346 if (*p > fMaxBinContent)
347 {
348 maxpos = ids-fHiGainFirst-1;
349 fMaxBinContent = *p;
350 }
351
352 if (*p++ >= fSaturationLimit)
353 if (!sat)
354 sat = ids-2;
355
356 }
357
358 if (fHiLoLast != 0)
359 {
360
361 end = logain + fHiLoLast;
362
363 while (logain<end)
364 {
365
366 *sample++ = (Float_t)*logain - pedmean[(ids++ + abflag) & 0x1];
367
368 if (*logain > fMaxBinContent)
369 {
370 maxpos = ids-fHiGainFirst-1;
371 fMaxBinContent = *logain;
372 }
373
374 if (*logain++ >= fSaturationLimit)
375 if (!sat)
376 sat = ids-2;
377
378 range++;
379 }
380 }
381
382 fAbMax = fHiGainSignal[maxpos];
383
384 Float_t pp;
385
386 fHiGainSecondDeriv[0] = 0.;
387 fHiGainFirstDeriv[0] = 0.;
388
389 for (Int_t i=1;i<range-1;i++)
390 {
391 pp = fHiGainSecondDeriv[i-1] + 4.;
392 fHiGainSecondDeriv[i] = -1.0/pp;
393 fHiGainFirstDeriv [i] = fHiGainSignal[i+1] - fHiGainSignal[i] - fHiGainSignal[i] + fHiGainSignal[i-1];
394 fHiGainFirstDeriv [i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
395 }
396
397 fHiGainSecondDeriv[range-1] = 0.;
398
399 for (Int_t k=range-2;k>=0;k--)
400 fHiGainSecondDeriv[k] = fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k];
401 for (Int_t k=range-2;k>=0;k--)
402 fHiGainSecondDeriv[k] /= 6.;
403
404 if (IsNoiseCalculation())
405 {
406
407 if (fRandomIter == int(1./fResolution))
408 fRandomIter = 0;
409
410 const Float_t nsx = fRandomIter * fResolution;
411
412 if (fExtractionType == kAmplitude)
413 {
414 const Float_t b = nsx;
415 const Float_t a = 1. - nsx;
416
417 sum = a*fHiGainSignal[1]
418 + b*fHiGainSignal[2]
419 + (a*a*a-a)*fHiGainSecondDeriv[1]
420 + (b*b*b-b)*fHiGainSecondDeriv[2];
421 }
422 else
423 {
424 Float_t start = 2. + nsx;
425 Float_t last = start + fRiseTimeHiGain + fFallTimeHiGain;
426
427 if (int(last) > range)
428 {
429 const Int_t diff = range - int(last);
430 last -= diff;
431 start -= diff;
432 }
433
434 CalcIntegralHiGain(sum, start, last);
435 }
436 fRandomIter++;
437 return;
438 }
439
440 //
441 // Allow no saturated slice
442 // and
443 // Don't start if the maxpos is too close to the limits.
444 //
445 if (sat || maxpos < TMath::Ceil(fRiseTimeHiGain) || maxpos > range-2)
446 {
447
448 dtime = 1.0;
449 if (fExtractionType == kAmplitude)
450 {
451 sum = fAbMax;
452 time = (Float_t)(fHiGainFirst + maxpos);
453 return;
454 }
455
456 if (maxpos > range - 2)
457 CalcIntegralHiGain(sum, (Float_t)range - fRiseTimeHiGain - fFallTimeHiGain, (Float_t)range - 0.001);
458 else
459 CalcIntegralHiGain(sum, 0.001, fRiseTimeHiGain + fFallTimeHiGain);
460
461 time = (Float_t)(fHiGainFirst + maxpos - 1);
462 return;
463 }
464
465 dtime = fResolution;
466
467 //
468 // Now find the maximum
469 //
470 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
471 Float_t lower = -1. + maxpos;
472 Float_t upper = (Float_t)maxpos;
473 fAbMaxPos = upper;
474 Float_t x = lower;
475 Float_t y = 0.;
476 Float_t a = 1.;
477 Float_t b = 0.;
478 Int_t klo = maxpos-1;
479 Int_t khi = maxpos;
480
481 //
482 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
483 // If no maximum is found, go to interval maxpos+1.
484 //
485 while ( x < upper - 0.3 )
486 {
487
488 x += step;
489 a -= step;
490 b += step;
491
492 y = a*fHiGainSignal[klo]
493 + b*fHiGainSignal[khi]
494 + (a*a*a-a)*fHiGainSecondDeriv[klo]
495 + (b*b*b-b)*fHiGainSecondDeriv[khi];
496
497 if (y > fAbMax)
498 {
499 fAbMax = y;
500 fAbMaxPos = x;
501 }
502
503 }
504
505 //
506 // Search for the absolute maximum from maxpos to maxpos+1 in steps of 0.2
507 //
508 if (fAbMaxPos > upper-0.1)
509 {
510
511 upper = 1. + maxpos;
512 lower = (Float_t)maxpos;
513 x = lower;
514 a = 1.;
515 b = 0.;
516 khi = maxpos+1;
517 klo = maxpos;
518
519 while (x<upper-0.3)
520 {
521
522 x += step;
523 a -= step;
524 b += step;
525
526 y = a*fHiGainSignal[klo]
527 + b*fHiGainSignal[khi]
528 + (a*a*a-a)*fHiGainSecondDeriv[klo]
529 + (b*b*b-b)*fHiGainSecondDeriv[khi];
530
531 if (y > fAbMax)
532 {
533 fAbMax = y;
534 fAbMaxPos = x;
535 }
536 }
537 }
538 //
539 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
540 // Try a better precision.
541 //
542 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
543 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
544 const Float_t maxpossave = fAbMaxPos;
545
546 x = fAbMaxPos;
547 a = upper - x;
548 b = x - lower;
549
550 step = 2.*fResolution; // step size of 0.1 FADC slices
551
552 while (x<up)
553 {
554
555 x += step;
556 a -= step;
557 b += step;
558
559 y = a*fHiGainSignal[klo]
560 + b*fHiGainSignal[khi]
561 + (a*a*a-a)*fHiGainSecondDeriv[klo]
562 + (b*b*b-b)*fHiGainSecondDeriv[khi];
563
564 if (y > fAbMax)
565 {
566 fAbMax = y;
567 fAbMaxPos = x;
568 }
569 }
570
571 //
572 // Second, try from time down to time-0.2 in steps of fResolution.
573 //
574 x = maxpossave;
575
576 //
577 // Test the possibility that the absolute maximum has not been found between
578 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
579 // which requires new setting of klocont and khicont
580 //
581 if (x < lower + fResolution)
582 {
583 klo--;
584 khi--;
585 upper -= 1.;
586 lower -= 1.;
587 }
588
589 a = upper - x;
590 b = x - lower;
591
592 while (x>lo)
593 {
594
595 x -= step;
596 a += step;
597 b -= step;
598
599 y = a*fHiGainSignal[klo]
600 + b*fHiGainSignal[khi]
601 + (a*a*a-a)*fHiGainSecondDeriv[klo]
602 + (b*b*b-b)*fHiGainSecondDeriv[khi];
603
604 if (y > fAbMax)
605 {
606 fAbMax = y;
607 fAbMaxPos = x;
608 }
609 }
610
611 if (fExtractionType == kAmplitude)
612 {
613 time = fAbMaxPos + (Int_t)fHiGainFirst;
614 sum = fAbMax;
615 return;
616 }
617
618 fHalfMax = fAbMax/2.;
619
620 //
621 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
622 // First, find the right FADC slice:
623 //
624 klo = maxpos;
625 while (klo > 0)
626 {
627 klo--;
628 if (fHiGainSignal[klo] < fHalfMax)
629 break;
630 }
631
632 khi = klo+1;
633 //
634 // Loop from the beginning of the slice upwards to reach the fHalfMax:
635 // With means of bisection:
636 //
637 x = (Float_t)klo;
638 a = 1.;
639 b = 0.;
640
641 step = 0.5;
642 Bool_t back = kFALSE;
643
644 Int_t maxcnt = 20;
645 Int_t cnt = 0;
646
647 while (TMath::Abs(y-fHalfMax) > fResolution)
648 {
649
650 if (back)
651 {
652 x -= step;
653 a += step;
654 b -= step;
655 }
656 else
657 {
658 x += step;
659 a -= step;
660 b += step;
661 }
662
663 y = a*fHiGainSignal[klo]
664 + b*fHiGainSignal[khi]
665 + (a*a*a-a)*fHiGainSecondDeriv[klo]
666 + (b*b*b-b)*fHiGainSecondDeriv[khi];
667
668 if (y > fHalfMax)
669 back = kTRUE;
670 else
671 back = kFALSE;
672
673 if (++cnt > maxcnt)
674 break;
675
676 step /= 2.;
677 }
678
679 time = (Float_t)fHiGainFirst + x;
680 //
681 // Now integrate the whole thing!
682 //
683
684 Float_t start = fAbMaxPos - fRiseTimeHiGain;
685 Float_t last = fAbMaxPos + fFallTimeHiGain;
686
687 const Int_t diff = int(last) - range;
688
689 if (diff > 0)
690 {
691 last -= diff;
692 start -= diff;
693 }
694
695 CalcIntegralHiGain(sum, start, last);
696}
697
698
699// --------------------------------------------------------------------------
700//
701// Calculates the arrival time and charge for each pixel
702//
703void MExtractTimeAndChargeSpline::FindTimeAndChargeLoGain(Byte_t *first, Float_t &sum, Float_t &dsum,
704 Float_t &time, Float_t &dtime,
705 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
706{
707
708 Int_t range = fLoGainLast - fLoGainFirst + 1;
709 const Byte_t *end = first + range;
710 Byte_t *p = first;
711
712 const Float_t pedes = ped.GetPedestal();
713 const Float_t ABoffs = ped.GetPedestalABoffset();
714
715 const Float_t pedmean[2] = { pedes + ABoffs, pedes - ABoffs };
716
717 fAbMax = 0.;
718 fAbMaxPos = 0.;
719 Int_t maxpos = 0;
720 Int_t max = 0;
721
722 //
723 // Check for saturation in all other slices
724 //
725 Int_t ids = fLoGainFirst;
726 Float_t *sample = fLoGainSignal.GetArray();
727 while (p<end)
728 {
729
730 *sample++ = (Float_t)*p - pedmean[(ids++ + abflag) & 0x1];
731
732 if (*p > max)
733 {
734 maxpos = ids-fLoGainFirst-1;
735 max = *p;
736 }
737
738 if (*p++ >= fSaturationLimit)
739 sat++;
740 }
741
742 fAbMax = fLoGainSignal[maxpos];
743
744 Float_t pp;
745
746 fLoGainSecondDeriv[0] = 0.;
747 fLoGainFirstDeriv[0] = 0.;
748
749 for (Int_t i=1;i<range-1;i++)
750 {
751 pp = fLoGainSecondDeriv[i-1] + 4.;
752 fLoGainSecondDeriv[i] = -1.0/pp;
753 fLoGainFirstDeriv [i] = fLoGainSignal[i+1] - fLoGainSignal[i] - fLoGainSignal[i] + fLoGainSignal[i-1];
754 fLoGainFirstDeriv [i] = (6.0*fLoGainFirstDeriv[i]-fLoGainFirstDeriv[i-1])/pp;
755 }
756
757 fLoGainSecondDeriv[range-1] = 0.;
758
759 for (Int_t k=range-2;k>=0;k--)
760 fLoGainSecondDeriv[k] = fLoGainSecondDeriv[k]*fLoGainSecondDeriv[k+1] + fLoGainFirstDeriv[k];
761 for (Int_t k=range-2;k>=0;k--)
762 fLoGainSecondDeriv[k] /= 6.;
763
764 if (IsNoiseCalculation())
765 {
766 if (fRandomIter == int(1./fResolution))
767 fRandomIter = 0;
768
769 const Float_t nsx = fRandomIter * fResolution;
770
771 if (fExtractionType == kAmplitude)
772 {
773 const Float_t b = nsx;
774 const Float_t a = 1. - nsx;
775
776 sum = a*fLoGainSignal[1]
777 + b*fLoGainSignal[2]
778 + (a*a*a-a)*fLoGainSecondDeriv[1]
779 + (b*b*b-b)*fLoGainSecondDeriv[2];
780 }
781 else
782 {
783 Float_t start = 2. + nsx;
784 Float_t last = start + fRiseTimeLoGain + fFallTimeLoGain;
785
786 if (int(last) > range)
787 {
788 const Int_t diff = range - int(last);
789 last -= diff;
790 start -= diff;
791 }
792
793 CalcIntegralLoGain(sum, start, last);
794 }
795 fRandomIter++;
796 return;
797 }
798 //
799 // Allow no saturated slice
800 // and
801 // Don't start if the maxpos is too close to the limits.
802 //
803 if (sat || maxpos < TMath::Ceil(fRiseTimeLoGain) || maxpos > range-2)
804 {
805
806 dtime = 1.0;
807 if (fExtractionType == kAmplitude)
808 {
809 time = (Float_t)(fLoGainFirst + maxpos);
810 sum = fAbMax;
811 return;
812 }
813
814 if (maxpos > range-2)
815 CalcIntegralLoGain(sum, (Float_t)range - fRiseTimeLoGain - fFallTimeLoGain -1., (Float_t)range - 0.001);
816 else
817 CalcIntegralLoGain(sum, 0.001, fRiseTimeLoGain + fFallTimeLoGain + 1.);
818
819 time = (Float_t)(fLoGainFirst + maxpos - 1);
820 return;
821 }
822
823 dtime = fResolution;
824
825 //
826 // Now find the maximum
827 //
828 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
829 Float_t lower = -1. + maxpos;
830 Float_t upper = (Float_t)maxpos;
831 fAbMaxPos = upper;
832 Float_t x = lower;
833 Float_t y = 0.;
834 Float_t a = 1.;
835 Float_t b = 0.;
836 Int_t klo = maxpos-1;
837 Int_t khi = maxpos;
838
839 //
840 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
841 // If no maximum is found, go to interval maxpos+1.
842 //
843 while ( x < upper - 0.3 )
844 {
845
846 x += step;
847 a -= step;
848 b += step;
849
850 y = a*fLoGainSignal[klo]
851 + b*fLoGainSignal[khi]
852 + (a*a*a-a)*fLoGainSecondDeriv[klo]
853 + (b*b*b-b)*fLoGainSecondDeriv[khi];
854
855 if (y > fAbMax)
856 {
857 fAbMax = y;
858 fAbMaxPos = x;
859 }
860
861 }
862
863 //
864 // Test the possibility that the absolute maximum has not been found before the
865 // maxpos and search from maxpos to maxpos+1 in steps of 0.2
866 //
867 if (fAbMaxPos > upper-0.1)
868 {
869
870 upper = 1. + maxpos;
871 lower = (Float_t)maxpos;
872 x = lower;
873 a = 1.;
874 b = 0.;
875 khi = maxpos+1;
876 klo = maxpos;
877
878 while (x<upper-0.3)
879 {
880
881 x += step;
882 a -= step;
883 b += step;
884
885 y = a*fLoGainSignal[klo]
886 + b*fLoGainSignal[khi]
887 + (a*a*a-a)*fLoGainSecondDeriv[klo]
888 + (b*b*b-b)*fLoGainSecondDeriv[khi];
889
890 if (y > fAbMax)
891 {
892 fAbMax = y;
893 fAbMaxPos = x;
894 }
895 }
896 }
897
898
899 //
900 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
901 // Try a better precision.
902 //
903 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
904 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
905 const Float_t maxpossave = fAbMaxPos;
906
907 x = fAbMaxPos;
908 a = upper - x;
909 b = x - lower;
910
911 step = 2.*fResolution; // step size of 0.1 FADC slice
912
913 while (x<up)
914 {
915
916 x += step;
917 a -= step;
918 b += step;
919
920 y = a*fLoGainSignal[klo]
921 + b*fLoGainSignal[khi]
922 + (a*a*a-a)*fLoGainSecondDeriv[klo]
923 + (b*b*b-b)*fLoGainSecondDeriv[khi];
924
925 if (y > fAbMax)
926 {
927 fAbMax = y;
928 fAbMaxPos = x;
929 }
930 }
931
932 //
933 // Second, try from time down to time-0.2 in steps of 0.025.
934 //
935 x = maxpossave;
936
937 //
938 // Test the possibility that the absolute maximum has not been found between
939 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
940 // which requires new setting of klocont and khicont
941 //
942 if (x < lower + fResolution)
943 {
944 klo--;
945 khi--;
946 upper -= 1.;
947 lower -= 1.;
948 }
949
950 a = upper - x;
951 b = x - lower;
952
953 while (x>lo)
954 {
955
956 x -= step;
957 a += step;
958 b -= step;
959
960 y = a*fLoGainSignal[klo]
961 + b*fLoGainSignal[khi]
962 + (a*a*a-a)*fLoGainSecondDeriv[klo]
963 + (b*b*b-b)*fLoGainSecondDeriv[khi];
964
965 if (y > fAbMax)
966 {
967 fAbMax = y;
968 fAbMaxPos = x;
969 }
970 }
971
972 if (fExtractionType == kAmplitude)
973 {
974 time = fAbMaxPos + (Int_t)fLoGainFirst;
975 sum = fAbMax;
976 return;
977 }
978
979 fHalfMax = fAbMax/2.;
980
981 //
982 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
983 // First, find the right FADC slice:
984 //
985 klo = maxpos;
986 while (klo > 0)
987 {
988 klo--;
989 if (fLoGainSignal[klo] < fHalfMax)
990 break;
991 }
992
993 khi = klo+1;
994 //
995 // Loop from the beginning of the slice upwards to reach the fHalfMax:
996 // With means of bisection:
997 //
998 x = (Float_t)klo;
999 a = 1.;
1000 b = 0.;
1001
1002 step = 0.5;
1003 Bool_t back = kFALSE;
1004
1005 Int_t maxcnt = 20;
1006 Int_t cnt = 0;
1007
1008 while (TMath::Abs(y-fHalfMax) > fResolution)
1009 {
1010
1011 if (back)
1012 {
1013 x -= step;
1014 a += step;
1015 b -= step;
1016 }
1017 else
1018 {
1019 x += step;
1020 a -= step;
1021 b += step;
1022 }
1023
1024 y = a*fLoGainSignal[klo]
1025 + b*fLoGainSignal[khi]
1026 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1027 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1028
1029 if (y > fHalfMax)
1030 back = kTRUE;
1031 else
1032 back = kFALSE;
1033
1034 if (++cnt > maxcnt)
1035 break;
1036
1037 step /= 2.;
1038 }
1039
1040 time = x + (Int_t)fLoGainFirst;
1041
1042 //
1043 // Now integrate the whole thing!
1044 //
1045 Float_t start = fAbMaxPos - fRiseTimeLoGain;
1046 Float_t last = fAbMaxPos + fFallTimeLoGain;
1047
1048 const Int_t diff = int(last) - range;
1049
1050 if (diff > 0)
1051 {
1052 last -= diff;
1053 start -= diff;
1054 }
1055 CalcIntegralLoGain(sum, start, last);
1056}
1057
1058void MExtractTimeAndChargeSpline::CalcIntegralHiGain(Float_t &sum, Float_t start, Float_t last)
1059{
1060
1061 const Float_t step = 0.2;
1062
1063 if (start < 0)
1064 {
1065 last -= start;
1066 start = 0.;
1067 }
1068
1069 Int_t klo = int(start);
1070 Int_t khi = klo+1;
1071
1072 Float_t lo = TMath::Floor(start);
1073 Float_t up = lo + 1.;
1074
1075 const Int_t m = int((start-klo)/step);
1076 start = step*m + klo; // Correct start for the digitization due to resolution
1077
1078 Float_t x = start;
1079 Float_t a = up-start;
1080 Float_t b = start-lo;
1081
1082 while (1)
1083 {
1084
1085 while (x<up)
1086 {
1087 x += step;
1088
1089 if (x > last)
1090 {
1091 sum *= step;
1092 return;
1093 }
1094
1095 a -= step;
1096 b += step;
1097
1098 sum += a*fHiGainSignal[klo]
1099 + b*fHiGainSignal[khi]
1100 + (a*a*a-a)*fHiGainSecondDeriv[klo]
1101 + (b*b*b-b)*fHiGainSecondDeriv[khi];
1102 }
1103
1104 up += 1.;
1105 lo += 1.;
1106 klo++;
1107 khi++;
1108 start += 1.;
1109 a = 1.;
1110 b = 0.;
1111 }
1112
1113}
1114void MExtractTimeAndChargeSpline::CalcIntegralLoGain(Float_t &sum, Float_t start, Float_t last)
1115{
1116
1117 const Float_t step = 0.1;
1118
1119 if (start < 0)
1120 {
1121 last -= start;
1122 start = 0.;
1123 }
1124
1125 Int_t klo = int(start);
1126 Int_t khi = klo+1;
1127
1128 Float_t lo = TMath::Floor(start);
1129 Float_t up = lo + 1.;
1130
1131 const Int_t m = int((start-klo)/step);
1132 start = step*m + klo; // Correct start for the digitization due to resolution
1133
1134 Float_t x = start;
1135 Float_t a = up-start;
1136 Float_t b = start-lo;
1137
1138 while (1)
1139 {
1140
1141 while (x<up)
1142 {
1143 x += step;
1144
1145 if (x > last)
1146 {
1147 sum *= step;
1148 return;
1149 }
1150
1151 a -= step;
1152 b += step;
1153
1154 sum += a*fLoGainSignal[klo]
1155 + b*fLoGainSignal[khi]
1156 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1157 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1158
1159 }
1160
1161 up += 1.;
1162 lo += 1.;
1163 klo++;
1164 khi++;
1165 start += 1.;
1166 a = 1.;
1167 b = 0.;
1168 }
1169
1170}
1171
1172
1173
1174
1175// --------------------------------------------------------------------------
1176//
1177// In addition to the resources of the base-class MExtractor:
1178// Resolution
1179// RiseTimeHiGain
1180// FallTimeHiGain
1181// LoGainStretch
1182// ExtractionType: amplitude, integral
1183//
1184Int_t MExtractTimeAndChargeSpline::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1185{
1186
1187 Bool_t rc = kFALSE;
1188
1189 if (IsEnvDefined(env, prefix, "Resolution", print))
1190 {
1191 SetResolution(GetEnvValue(env, prefix, "Resolution",fResolution));
1192 rc = kTRUE;
1193 }
1194 if (IsEnvDefined(env, prefix, "RiseTimeHiGain", print))
1195 {
1196 SetRiseTimeHiGain(GetEnvValue(env, prefix, "RiseTimeHiGain", fRiseTimeHiGain));
1197 rc = kTRUE;
1198 }
1199 if (IsEnvDefined(env, prefix, "FallTimeHiGain", print))
1200 {
1201 SetFallTimeHiGain(GetEnvValue(env, prefix, "FallTimeHiGain", fFallTimeHiGain));
1202 rc = kTRUE;
1203 }
1204 if (IsEnvDefined(env, prefix, "LoGainStretch", print))
1205 {
1206 SetLoGainStretch(GetEnvValue(env, prefix, "LoGainStretch", fLoGainStretch));
1207 rc = kTRUE;
1208 }
1209
1210 if (IsEnvDefined(env, prefix, "ExtractionType", print))
1211 {
1212 TString type = GetEnvValue(env, prefix, "ExtractionType", "");
1213 type.ToLower();
1214 type = type.Strip(TString::kBoth);
1215 if (type==(TString)"amplitude")
1216 SetChargeType(kAmplitude);
1217 if (type==(TString)"integral")
1218 SetChargeType(kIntegral);
1219 rc=kTRUE;
1220 }
1221
1222 return MExtractTimeAndCharge::ReadEnv(env, prefix, print) ? kTRUE : rc;
1223
1224}
1225
1226
Note: See TracBrowser for help on using the repository browser.