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

Last change on this file since 5807 was 5795, checked in by gaug, 20 years ago
*** empty log message ***
File size: 31.3 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 = 1.5;
158const Float_t MExtractTimeAndChargeSpline::fgFallTimeHiGain = 4.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.), fRandomIter(0)
177{
178
179 fName = name ? name : "MExtractTimeAndChargeSpline";
180 fTitle = title ? title : "Calculate photons arrival time using a fast spline";
181
182 SetResolution();
183
184 SetRiseTimeHiGain();
185 SetFallTimeHiGain();
186
187 SetRange(fgHiGainFirst, fgHiGainLast, fgLoGainFirst, fgLoGainLast);
188
189 SetChargeType();
190 SetLoGainStretch();
191
192 SetOffsetLoGain(fgOffsetLoGain);
193}
194
195
196//-------------------------------------------------------------------
197//
198// Set the ranges
199// In order to set the fNum...Samples variables correctly for the case,
200// the integral is computed, have to overwrite this function and make an
201// explicit call to SetChargeType().
202//
203void MExtractTimeAndChargeSpline::SetRange(Byte_t hifirst, Byte_t hilast, Byte_t lofirst, Byte_t lolast)
204{
205
206 MExtractor::SetRange(hifirst, hilast, lofirst, lolast);
207
208 if (IsExtractionType(kIntegral))
209 SetChargeType(kIntegral);
210 if (IsExtractionType(kAmplitude))
211 SetChargeType(kAmplitude);
212
213}
214
215//-------------------------------------------------------------------
216//
217// Set the Charge Extraction type. Possible are:
218// - kAmplitude: Search the value of the spline at the maximum
219// - kIntegral: Integral the spline from fHiGainFirst to fHiGainLast,
220// by counting the edge bins only half and setting the
221// second derivative to zero, there.
222//
223void MExtractTimeAndChargeSpline::SetChargeType( ExtractionType_t typ )
224{
225
226 CLRBIT(fFlags,kAmplitude);
227 CLRBIT(fFlags,kIntegral );
228
229 SETBIT(fFlags,typ);
230
231}
232
233// --------------------------------------------------------------------------
234//
235// InitArrays
236//
237// Gets called in the ReInit() and initialized the arrays
238//
239Bool_t MExtractTimeAndChargeSpline::InitArrays()
240{
241
242 Int_t range = fHiGainLast - fHiGainFirst + 1 + fHiLoLast;
243
244 fHiGainSignal .Set(range);
245 fHiGainFirstDeriv .Set(range);
246 fHiGainSecondDeriv.Set(range);
247
248 range = fLoGainLast - fLoGainFirst + 1;
249
250 fLoGainSignal .Set(range);
251 fLoGainFirstDeriv .Set(range);
252 fLoGainSecondDeriv.Set(range);
253
254 fHiGainSignal .Reset();
255 fHiGainFirstDeriv .Reset();
256 fHiGainSecondDeriv.Reset();
257
258 fLoGainSignal .Reset();
259 fLoGainFirstDeriv .Reset();
260 fLoGainSecondDeriv.Reset();
261
262 if (IsExtractionType(kAmplitude))
263 {
264 fNumHiGainSamples = 1.;
265 fNumLoGainSamples = fLoGainLast ? 1. : 0.;
266 fSqrtHiGainSamples = 1.;
267 fSqrtLoGainSamples = 1.;
268 fWindowSizeHiGain = 1;
269 fWindowSizeLoGain = 1;
270 }
271
272 if (IsExtractionType(kIntegral))
273 {
274
275 fRiseTimeLoGain = fRiseTimeHiGain * fLoGainStretch;
276 fFallTimeLoGain = fFallTimeHiGain * fLoGainStretch;
277
278 fNumHiGainSamples = fRiseTimeHiGain + fFallTimeHiGain;
279 fNumLoGainSamples = fLoGainLast ? fRiseTimeLoGain + fFallTimeLoGain : 0.;
280 // fNumLoGainSamples *= 0.75;
281
282 fSqrtHiGainSamples = TMath::Sqrt(fNumHiGainSamples);
283 fSqrtLoGainSamples = TMath::Sqrt(fNumLoGainSamples);
284 fWindowSizeHiGain = (Int_t)(fRiseTimeHiGain + fFallTimeHiGain);
285 fWindowSizeLoGain = (Int_t)(fRiseTimeLoGain + fFallTimeLoGain);
286 }
287
288 return kTRUE;
289
290}
291
292// --------------------------------------------------------------------------
293//
294// Calculates the arrival time and charge for each pixel
295//
296void MExtractTimeAndChargeSpline::FindTimeAndChargeHiGain(Byte_t *first, Byte_t *logain, Float_t &sum, Float_t &dsum,
297 Float_t &time, Float_t &dtime,
298 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
299{
300
301 Int_t range = fHiGainLast - fHiGainFirst + 1;
302 const Byte_t *end = first + range;
303 Byte_t *p = first;
304
305 sat = 0;
306
307 const Float_t pedes = ped.GetPedestal();
308 const Float_t ABoffs = ped.GetPedestalABoffset();
309
310 const Float_t pedmean[2] = { pedes + ABoffs, pedes - ABoffs };
311
312 fAbMax = 0.;
313 fAbMaxPos = 0.;
314 fHalfMax = 0.;
315 Int_t maxpos = 0;
316 Int_t max = 0;
317
318 //
319 // Check for saturation in all other slices
320 //
321 Int_t ids = fHiGainFirst;
322 Float_t *sample = fHiGainSignal.GetArray();
323 while (p<end)
324 {
325
326 *sample++ = (Float_t)*p - pedmean[(ids++ + abflag) & 0x1];
327
328 if (*p > max)
329 {
330 maxpos = ids-fHiGainFirst-1;
331 max = *p;
332 }
333
334 if (*p++ >= fSaturationLimit)
335 if (!sat)
336 sat = ids-3;
337
338 }
339
340 if (fHiLoLast != 0)
341 {
342
343 end = logain + fHiLoLast;
344
345 while (logain<end)
346 {
347
348 *sample++ = (Float_t)*logain - pedmean[(ids++ + abflag) & 0x1];
349
350 if (*logain > max)
351 {
352 maxpos = ids-fHiGainFirst-1;
353 max = *logain;
354 }
355
356 if (*logain++ >= fSaturationLimit)
357 if (!sat)
358 sat = ids-3;
359
360 range++;
361 }
362 }
363
364 fAbMax = fHiGainSignal[maxpos];
365
366 Float_t pp;
367
368 fHiGainSecondDeriv[0] = 0.;
369 fHiGainFirstDeriv[0] = 0.;
370
371 for (Int_t i=1;i<range-1;i++)
372 {
373 pp = fHiGainSecondDeriv[i-1] + 4.;
374 fHiGainSecondDeriv[i] = -1.0/pp;
375 fHiGainFirstDeriv [i] = fHiGainSignal[i+1] - fHiGainSignal[i] - fHiGainSignal[i] + fHiGainSignal[i-1];
376 fHiGainFirstDeriv [i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
377 }
378
379 fHiGainSecondDeriv[range-1] = 0.;
380
381 for (Int_t k=range-2;k>=0;k--)
382 fHiGainSecondDeriv[k] = fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k];
383 for (Int_t k=range-2;k>=0;k--)
384 fHiGainSecondDeriv[k] /= 6.;
385
386 if (IsNoiseCalculation())
387 {
388
389 if (fRandomIter == int(1./fResolution))
390 fRandomIter = 0;
391
392 const Float_t nsx = fRandomIter * fResolution;
393
394 if (IsExtractionType(kAmplitude))
395 {
396 const Float_t b = nsx;
397 const Float_t a = 1. - nsx;
398
399 sum = a*fHiGainSignal[1]
400 + b*fHiGainSignal[2]
401 + (a*a*a-a)*fHiGainSecondDeriv[1]
402 + (b*b*b-b)*fHiGainSecondDeriv[2];
403 }
404 else
405 {
406 Float_t start = 2. + nsx;
407 Float_t last = start + fRiseTimeHiGain + fFallTimeHiGain;
408
409 if (int(last) > range)
410 {
411 const Int_t diff = range - int(last);
412 last -= diff;
413 start -= diff;
414 }
415
416 CalcIntegralHiGain(sum, start, last);
417 }
418 fRandomIter++;
419 return;
420 }
421
422 //
423 // Allow no saturated slice
424 // and
425 // Don't start if the maxpos is too close to the limits.
426 //
427 if (sat || maxpos < 1 || maxpos > range-2)
428 {
429 dtime = 0.5;
430 if (IsExtractionType(kAmplitude))
431 {
432 sum = fAbMax;
433 time = (Float_t)(fHiGainFirst + maxpos);
434 return;
435 }
436
437 if (maxpos > range - 2)
438 CalcIntegralHiGain(sum, (Float_t)range - fRiseTimeHiGain - fFallTimeHiGain, (Float_t)range - 0.001);
439 else
440 CalcIntegralHiGain(sum, 0.001, fRiseTimeHiGain + fFallTimeHiGain);
441
442 time = (Float_t)(fHiGainFirst + maxpos - 1);
443 return;
444 }
445
446 dtime = fResolution;
447
448 //
449 // Now find the maximum
450 //
451 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
452 Float_t lower = -1. + maxpos;
453 Float_t upper = (Float_t)maxpos;
454 fAbMaxPos = upper;
455 Float_t x = lower;
456 Float_t y = 0.;
457 Float_t a = 1.;
458 Float_t b = 0.;
459 Int_t klo = maxpos-1;
460 Int_t khi = maxpos;
461
462 //
463 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
464 // If no maximum is found, go to interval maxpos+1.
465 //
466 while ( x < upper - 0.3 )
467 {
468
469 x += step;
470 a -= step;
471 b += step;
472
473 y = a*fHiGainSignal[klo]
474 + b*fHiGainSignal[khi]
475 + (a*a*a-a)*fHiGainSecondDeriv[klo]
476 + (b*b*b-b)*fHiGainSecondDeriv[khi];
477
478 if (y > fAbMax)
479 {
480 fAbMax = y;
481 fAbMaxPos = x;
482 }
483
484 }
485
486 //
487 // Search for the absolute maximum from maxpos to maxpos+1 in steps of 0.2
488 //
489 if (fAbMaxPos > upper-0.1)
490 {
491
492 upper = 1. + maxpos;
493 lower = (Float_t)maxpos;
494 x = lower;
495 a = 1.;
496 b = 0.;
497 khi = maxpos+1;
498 klo = maxpos;
499
500 while (x<upper-0.3)
501 {
502
503 x += step;
504 a -= step;
505 b += step;
506
507 y = a*fHiGainSignal[klo]
508 + b*fHiGainSignal[khi]
509 + (a*a*a-a)*fHiGainSecondDeriv[klo]
510 + (b*b*b-b)*fHiGainSecondDeriv[khi];
511
512 if (y > fAbMax)
513 {
514 fAbMax = y;
515 fAbMaxPos = x;
516 }
517 }
518 }
519 //
520 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
521 // Try a better precision.
522 //
523 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
524 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
525 const Float_t maxpossave = fAbMaxPos;
526
527 x = fAbMaxPos;
528 a = upper - x;
529 b = x - lower;
530
531 step = 2.*fResolution; // step size of 0.1 FADC slices
532
533 while (x<up)
534 {
535
536 x += step;
537 a -= step;
538 b += step;
539
540 y = a*fHiGainSignal[klo]
541 + b*fHiGainSignal[khi]
542 + (a*a*a-a)*fHiGainSecondDeriv[klo]
543 + (b*b*b-b)*fHiGainSecondDeriv[khi];
544
545 if (y > fAbMax)
546 {
547 fAbMax = y;
548 fAbMaxPos = x;
549 }
550 }
551
552 //
553 // Second, try from time down to time-0.2 in steps of fResolution.
554 //
555 x = maxpossave;
556
557 //
558 // Test the possibility that the absolute maximum has not been found between
559 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
560 // which requires new setting of klocont and khicont
561 //
562 if (x < lower + fResolution)
563 {
564 klo--;
565 khi--;
566 upper -= 1.;
567 lower -= 1.;
568 }
569
570 a = upper - x;
571 b = x - lower;
572
573 while (x>lo)
574 {
575
576 x -= step;
577 a += step;
578 b -= step;
579
580 y = a*fHiGainSignal[klo]
581 + b*fHiGainSignal[khi]
582 + (a*a*a-a)*fHiGainSecondDeriv[klo]
583 + (b*b*b-b)*fHiGainSecondDeriv[khi];
584
585 if (y > fAbMax)
586 {
587 fAbMax = y;
588 fAbMaxPos = x;
589 }
590 }
591
592 if (IsExtractionType(kAmplitude))
593 {
594 time = fAbMaxPos + (Int_t)fHiGainFirst;
595 sum = fAbMax;
596 return;
597 }
598
599 fHalfMax = fAbMax/2.;
600
601 //
602 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
603 // First, find the right FADC slice:
604 //
605 klo = maxpos;
606 while (klo >= 0)
607 {
608 klo--;
609 if (fHiGainSignal[klo] < fHalfMax)
610 break;
611 }
612
613 khi = klo+1;
614 //
615 // Loop from the beginning of the slice upwards to reach the fHalfMax:
616 // With means of bisection:
617 //
618 x = (Float_t)klo;
619 a = 1.;
620 b = 0.;
621
622 step = 0.5;
623 Bool_t back = kFALSE;
624
625 Int_t maxcnt = 20;
626 Int_t cnt = 0;
627
628 while (TMath::Abs(y-fHalfMax) > fResolution)
629 {
630
631 if (back)
632 {
633 x -= step;
634 a += step;
635 b -= step;
636 }
637 else
638 {
639 x += step;
640 a -= step;
641 b += step;
642 }
643
644 y = a*fHiGainSignal[klo]
645 + b*fHiGainSignal[khi]
646 + (a*a*a-a)*fHiGainSecondDeriv[klo]
647 + (b*b*b-b)*fHiGainSecondDeriv[khi];
648
649 if (y > fHalfMax)
650 back = kTRUE;
651 else
652 back = kFALSE;
653
654 if (++cnt > maxcnt)
655 break;
656
657 step /= 2.;
658 }
659
660 time = (Float_t)fHiGainFirst + x;
661 //
662 // Now integrate the whole thing!
663 //
664
665 Float_t start = fAbMaxPos - fRiseTimeHiGain;
666 Float_t last = fAbMaxPos + fFallTimeHiGain;
667
668 const Int_t diff = int(last) - range;
669
670 if (diff > 0)
671 {
672 last -= diff;
673 start -= diff;
674 }
675
676 CalcIntegralHiGain(sum, start, last);
677}
678
679
680// --------------------------------------------------------------------------
681//
682// Calculates the arrival time and charge for each pixel
683//
684void MExtractTimeAndChargeSpline::FindTimeAndChargeLoGain(Byte_t *first, Float_t &sum, Float_t &dsum,
685 Float_t &time, Float_t &dtime,
686 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
687{
688
689 Int_t range = fLoGainLast - fLoGainFirst + 1;
690 const Byte_t *end = first + range;
691 Byte_t *p = first;
692
693 const Float_t pedes = ped.GetPedestal();
694 const Float_t ABoffs = ped.GetPedestalABoffset();
695
696 const Float_t pedmean[2] = { pedes + ABoffs, pedes - ABoffs };
697
698 fAbMax = 0.;
699 fAbMaxPos = 0.;
700 Int_t maxpos = 0;
701 Int_t max = 0;
702
703 //
704 // Check for saturation in all other slices
705 //
706 Int_t ids = fLoGainFirst;
707 Float_t *sample = fLoGainSignal.GetArray();
708 while (p<end)
709 {
710
711 *sample++ = (Float_t)*p - pedmean[(ids++ + abflag) & 0x1];
712
713 if (*p > max)
714 {
715 maxpos = ids-fLoGainFirst-1;
716 max = *p;
717 }
718
719 if (*p++ >= fSaturationLimit)
720 sat++;
721 }
722
723 fAbMax = fLoGainSignal[maxpos];
724
725 Float_t pp;
726
727 fLoGainSecondDeriv[0] = 0.;
728 fLoGainFirstDeriv[0] = 0.;
729
730 for (Int_t i=1;i<range-1;i++)
731 {
732 pp = fLoGainSecondDeriv[i-1] + 4.;
733 fLoGainSecondDeriv[i] = -1.0/pp;
734 fLoGainFirstDeriv [i] = fLoGainSignal[i+1] - fLoGainSignal[i] - fLoGainSignal[i] + fLoGainSignal[i-1];
735 fLoGainFirstDeriv [i] = (6.0*fLoGainFirstDeriv[i]-fLoGainFirstDeriv[i-1])/pp;
736 }
737
738 fLoGainSecondDeriv[range-1] = 0.;
739
740 for (Int_t k=range-2;k>=0;k--)
741 fLoGainSecondDeriv[k] = fLoGainSecondDeriv[k]*fLoGainSecondDeriv[k+1] + fLoGainFirstDeriv[k];
742 for (Int_t k=range-2;k>=0;k--)
743 fLoGainSecondDeriv[k] /= 6.;
744
745 if (IsNoiseCalculation())
746 {
747 if (fRandomIter == int(1./fResolution))
748 fRandomIter = 0;
749
750 const Float_t nsx = fRandomIter * fResolution;
751
752 if (IsExtractionType(kAmplitude))
753 {
754 const Float_t b = nsx;
755 const Float_t a = 1. - nsx;
756
757 sum = a*fLoGainSignal[1]
758 + b*fLoGainSignal[2]
759 + (a*a*a-a)*fLoGainSecondDeriv[1]
760 + (b*b*b-b)*fLoGainSecondDeriv[2];
761 }
762 else
763 {
764 Float_t start = 2. + nsx;
765 Float_t last = start + fRiseTimeLoGain + fFallTimeLoGain;
766
767 if (int(last) > range)
768 {
769 const Int_t diff = range - int(last);
770 last -= diff;
771 start -= diff;
772 }
773
774 CalcIntegralLoGain(sum, start, last);
775 }
776 fRandomIter++;
777 return;
778 }
779 //
780 // Allow no saturated slice
781 // and
782 // Don't start if the maxpos is too close to the limits.
783 //
784 if (sat || maxpos < TMath::Ceil(fRiseTimeLoGain) || maxpos > range-2)
785 {
786 dtime = 0.5;
787 if (IsExtractionType(kAmplitude))
788 {
789 time = (Float_t)(fLoGainFirst + maxpos);
790 sum = fAbMax;
791 return;
792 }
793
794 if (maxpos > range-2)
795 CalcIntegralLoGain(sum, (Float_t)range - fRiseTimeLoGain - fFallTimeLoGain -1., (Float_t)range - 0.001);
796 else
797 CalcIntegralLoGain(sum, 0.001, fRiseTimeLoGain + fFallTimeLoGain + 1.);
798
799 time = (Float_t)(fLoGainFirst + maxpos - 1);
800 return;
801 }
802
803 dtime = fResolution;
804
805 //
806 // Now find the maximum
807 //
808 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
809 Float_t lower = -1. + maxpos;
810 Float_t upper = (Float_t)maxpos;
811 fAbMaxPos = upper;
812 Float_t x = lower;
813 Float_t y = 0.;
814 Float_t a = 1.;
815 Float_t b = 0.;
816 Int_t klo = maxpos-1;
817 Int_t khi = maxpos;
818
819 //
820 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
821 // If no maximum is found, go to interval maxpos+1.
822 //
823 while ( x < upper - 0.3 )
824 {
825
826 x += step;
827 a -= step;
828 b += step;
829
830 y = a*fLoGainSignal[klo]
831 + b*fLoGainSignal[khi]
832 + (a*a*a-a)*fLoGainSecondDeriv[klo]
833 + (b*b*b-b)*fLoGainSecondDeriv[khi];
834
835 if (y > fAbMax)
836 {
837 fAbMax = y;
838 fAbMaxPos = x;
839 }
840
841 }
842
843 //
844 // Test the possibility that the absolute maximum has not been found before the
845 // maxpos and search from maxpos to maxpos+1 in steps of 0.2
846 //
847 if (fAbMaxPos > upper-0.1)
848 {
849
850 upper = 1. + maxpos;
851 lower = (Float_t)maxpos;
852 x = lower;
853 a = 1.;
854 b = 0.;
855 khi = maxpos+1;
856 klo = maxpos;
857
858 while (x<upper-0.3)
859 {
860
861 x += step;
862 a -= step;
863 b += step;
864
865 y = a*fLoGainSignal[klo]
866 + b*fLoGainSignal[khi]
867 + (a*a*a-a)*fLoGainSecondDeriv[klo]
868 + (b*b*b-b)*fLoGainSecondDeriv[khi];
869
870 if (y > fAbMax)
871 {
872 fAbMax = y;
873 fAbMaxPos = x;
874 }
875 }
876 }
877
878
879 //
880 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
881 // Try a better precision.
882 //
883 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
884 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
885 const Float_t maxpossave = fAbMaxPos;
886
887 x = fAbMaxPos;
888 a = upper - x;
889 b = x - lower;
890
891 step = 2.*fResolution; // step size of 0.1 FADC slice
892
893 while (x<up)
894 {
895
896 x += step;
897 a -= step;
898 b += step;
899
900 y = a*fLoGainSignal[klo]
901 + b*fLoGainSignal[khi]
902 + (a*a*a-a)*fLoGainSecondDeriv[klo]
903 + (b*b*b-b)*fLoGainSecondDeriv[khi];
904
905 if (y > fAbMax)
906 {
907 fAbMax = y;
908 fAbMaxPos = x;
909 }
910 }
911
912 //
913 // Second, try from time down to time-0.2 in steps of 0.025.
914 //
915 x = maxpossave;
916
917 //
918 // Test the possibility that the absolute maximum has not been found between
919 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
920 // which requires new setting of klocont and khicont
921 //
922 if (x < lower + fResolution)
923 {
924 klo--;
925 khi--;
926 upper -= 1.;
927 lower -= 1.;
928 }
929
930 a = upper - x;
931 b = x - lower;
932
933 while (x>lo)
934 {
935
936 x -= step;
937 a += step;
938 b -= step;
939
940 y = a*fLoGainSignal[klo]
941 + b*fLoGainSignal[khi]
942 + (a*a*a-a)*fLoGainSecondDeriv[klo]
943 + (b*b*b-b)*fLoGainSecondDeriv[khi];
944
945 if (y > fAbMax)
946 {
947 fAbMax = y;
948 fAbMaxPos = x;
949 }
950 }
951
952 if (IsExtractionType(kAmplitude))
953 {
954 time = fAbMaxPos + (Int_t)fLoGainFirst;
955 sum = fAbMax;
956 return;
957 }
958
959 fHalfMax = fAbMax/2.;
960
961 //
962 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
963 // First, find the right FADC slice:
964 //
965 klo = maxpos;
966 while (klo > 0)
967 {
968 klo--;
969 if (fLoGainSignal[klo] < fHalfMax)
970 break;
971 }
972
973 khi = klo+1;
974 //
975 // Loop from the beginning of the slice upwards to reach the fHalfMax:
976 // With means of bisection:
977 //
978 x = (Float_t)klo;
979 a = 1.;
980 b = 0.;
981
982 step = 0.5;
983 Bool_t back = kFALSE;
984
985 Int_t maxcnt = 20;
986 Int_t cnt = 0;
987
988 while (TMath::Abs(y-fHalfMax) > fResolution)
989 {
990
991 if (back)
992 {
993 x -= step;
994 a += step;
995 b -= step;
996 }
997 else
998 {
999 x += step;
1000 a -= step;
1001 b += step;
1002 }
1003
1004 y = a*fLoGainSignal[klo]
1005 + b*fLoGainSignal[khi]
1006 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1007 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1008
1009 if (y > fHalfMax)
1010 back = kTRUE;
1011 else
1012 back = kFALSE;
1013
1014 if (++cnt > maxcnt)
1015 break;
1016
1017 step /= 2.;
1018 }
1019
1020 time = x + (Int_t)fLoGainFirst;
1021
1022 //
1023 // Now integrate the whole thing!
1024 //
1025 Float_t start = fAbMaxPos - fRiseTimeLoGain;
1026 Float_t last = fAbMaxPos + fFallTimeLoGain;
1027
1028 const Int_t diff = int(last) - range;
1029
1030 if (diff > 0)
1031 {
1032 last -= diff;
1033 start -= diff;
1034 }
1035 CalcIntegralLoGain(sum, start, last);
1036}
1037
1038void MExtractTimeAndChargeSpline::CalcIntegralHiGain(Float_t &sum, Float_t start, Float_t last)
1039{
1040
1041 const Float_t step = 0.1;
1042
1043 if (start < 0)
1044 {
1045 last -= start;
1046 start = 0.;
1047 }
1048
1049 Int_t klo = int(start);
1050 Int_t khi = klo+1;
1051
1052 Float_t lo = TMath::Floor(start);
1053 Float_t up = lo + 1.;
1054
1055 const Int_t m = int((start-klo)/step);
1056 start = step*m + klo; // Correct start for the digitization due to resolution
1057
1058 Float_t x = start;
1059 Float_t a = up-start;
1060 Float_t b = start-lo;
1061
1062 while (1)
1063 {
1064
1065 while (x<up)
1066 {
1067 x += step;
1068
1069 if (x > last)
1070 {
1071 sum *= step;
1072 return;
1073 }
1074
1075 a -= step;
1076 b += step;
1077
1078 sum += a*fHiGainSignal[klo]
1079 + b*fHiGainSignal[khi]
1080 + (a*a*a-a)*fHiGainSecondDeriv[klo]
1081 + (b*b*b-b)*fHiGainSecondDeriv[khi];
1082 }
1083
1084 up += 1.;
1085 lo += 1.;
1086 klo++;
1087 khi++;
1088 start += 1.;
1089 a = 1.;
1090 b = 0.;
1091 }
1092
1093}
1094void MExtractTimeAndChargeSpline::CalcIntegralLoGain(Float_t &sum, Float_t start, Float_t last)
1095{
1096
1097 const Float_t step = 0.1;
1098
1099 if (start < 0)
1100 {
1101 last -= start;
1102 start = 0.;
1103 }
1104
1105 Int_t klo = int(start);
1106 Int_t khi = klo+1;
1107
1108 Float_t lo = TMath::Floor(start);
1109 Float_t up = lo + 1.;
1110
1111 const Int_t m = int((start-klo)/step);
1112 start = step*m + klo; // Correct start for the digitization due to resolution
1113
1114 Float_t x = start;
1115 Float_t a = up-start;
1116 Float_t b = start-lo;
1117
1118 while (1)
1119 {
1120
1121 while (x<up)
1122 {
1123 x += step;
1124
1125 if (x > last)
1126 {
1127 sum *= step;
1128 return;
1129 }
1130
1131 a -= step;
1132 b += step;
1133
1134 sum += a*fLoGainSignal[klo]
1135 + b*fLoGainSignal[khi]
1136 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1137 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1138
1139 }
1140
1141 up += 1.;
1142 lo += 1.;
1143 klo++;
1144 khi++;
1145 start += 1.;
1146 a = 1.;
1147 b = 0.;
1148 }
1149
1150}
1151
1152
1153
1154
1155// --------------------------------------------------------------------------
1156//
1157// In addition to the resources of the base-class MExtractor:
1158// MJPedestal.MExtractor.WindowSizeHiGain: 6
1159// MJPedestal.MExtractor.WindowSizeLoGain: 6
1160//
1161Int_t MExtractTimeAndChargeSpline::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1162{
1163
1164 Bool_t rc = kFALSE;
1165
1166 if (IsEnvDefined(env, prefix, "Resolution", print))
1167 {
1168 SetResolution(GetEnvValue(env, prefix, "Resolution",fResolution));
1169 rc = kTRUE;
1170 }
1171 if (IsEnvDefined(env, prefix, "RiseTimeHiGain", print))
1172 {
1173 SetRiseTimeHiGain(GetEnvValue(env, prefix, "RiseTimeHiGain", fRiseTimeHiGain));
1174 rc = kTRUE;
1175 }
1176 if (IsEnvDefined(env, prefix, "FallTimeHiGain", print))
1177 {
1178 SetFallTimeHiGain(GetEnvValue(env, prefix, "FallTimeHiGain", fFallTimeHiGain));
1179 rc = kTRUE;
1180 }
1181 if (IsEnvDefined(env, prefix, "LoGainStretch", print))
1182 {
1183 SetLoGainStretch(GetEnvValue(env, prefix, "LoGainStretch", fLoGainStretch));
1184 rc = kTRUE;
1185 }
1186
1187 Bool_t b = kFALSE;
1188
1189 if (IsEnvDefined(env, prefix, "Amplitude", print))
1190 {
1191 b = GetEnvValue(env, prefix, "Amplitude", IsExtractionType(kAmplitude));
1192 if (b)
1193 SetChargeType(kAmplitude);
1194 rc = kTRUE;
1195 }
1196 if (IsEnvDefined(env, prefix, "Integral", print))
1197 {
1198 b = GetEnvValue(env, prefix, "Integral", IsExtractionType(kIntegral));
1199 if (b)
1200 SetChargeType(kIntegral);
1201 rc = kTRUE;
1202 }
1203
1204 return MExtractTimeAndCharge::ReadEnv(env, prefix, print) ? kTRUE : rc;
1205
1206}
1207
1208
Note: See TracBrowser for help on using the repository browser.