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

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