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

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