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

Last change on this file since 5542 was 5511, checked in by gaug, 20 years ago
*** empty log message ***
File size: 32.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analyzing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17! Author(s): Markus Gaug 09/2004 <mailto:markus@ifae.es>
18!
19! Copyright: MAGIC Software Development, 2002-2004
20!
21!
22\* ======================================================================== */
23//////////////////////////////////////////////////////////////////////////////
24//
25// MExtractTimeAndChargeSpline
26//
27// Fast Spline extractor using a cubic spline algorithm, adapted from
28// Numerical Recipes in C++, 2nd edition, pp. 116-119.
29//
30// The coefficients "ya" are here denoted as "fHiGainSignal" and "fLoGainSignal"
31// which means the FADC value subtracted by the clock-noise corrected pedestal.
32//
33// The coefficients "y2a" get immediately divided 6. and are called here
34// "fHiGainSecondDeriv" and "fLoGainSecondDeriv" although they are now not exactly
35// the second derivative coefficients any more.
36//
37// The calculation of the cubic-spline interpolated value "y" on a point
38// "x" along the FADC-slices axis becomes:
39//
40// y = a*fHiGainSignal[klo] + b*fHiGainSignal[khi]
41// + (a*a*a-a)*fHiGainSecondDeriv[klo] + (b*b*b-b)*fHiGainSecondDeriv[khi]
42//
43// with:
44// a = (khi - x)
45// b = (x - klo)
46//
47// and "klo" being the lower bin edge FADC index and "khi" the upper bin edge FADC index.
48// fHiGainSignal[klo] and fHiGainSignal[khi] are the FADC values at "klo" and "khi".
49//
50// An analogues formula is used for the low-gain values.
51//
52// The coefficients fHiGainSecondDeriv and fLoGainSecondDeriv are calculated with the
53// following simplified algorithm:
54//
55// for (Int_t i=1;i<range-1;i++) {
56// pp = fHiGainSecondDeriv[i-1] + 4.;
57// fHiGainFirstDeriv[i] = fHiGainSignal[i+1] - 2.*fHiGainSignal[i] + fHiGainSignal[i-1]
58// fHiGainFirstDeriv[i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
59// }
60//
61// for (Int_t k=range-2;k>=0;k--)
62// fHiGainSecondDeriv[k] = (fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k])/6.;
63//
64//
65// This algorithm takes advantage of the fact that the x-values are all separated by exactly 1
66// which simplifies the Numerical Recipes algorithm.
67// (Note that the variables "fHiGainFirstDeriv" are not real first derivative coefficients.)
68//
69//
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.01;
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.)
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// ReInit
254//
255// Calls:
256// - MExtractTimeAndCharge::ReInit(pList);
257// - Deletes all arrays, if not NULL
258// - Creates new arrays according to the extraction range
259//
260Bool_t MExtractTimeAndChargeSpline::ReInit(MParList *pList)
261{
262
263 if (IsExtractionType(kAmplitude))
264 {
265 fNumHiGainSamples = 1.;
266 fNumLoGainSamples = fLoGainLast ? 1. : 0.;
267 fSqrtHiGainSamples = 1.;
268 fSqrtLoGainSamples = 1.;
269 fWindowSizeHiGain = 1;
270 fWindowSizeLoGain = 1;
271 }
272
273 if (IsExtractionType(kIntegral))
274 {
275 fNumHiGainSamples = fRiseTime + fFallTime;
276 fNumLoGainSamples = fLoGainLast ? fNumHiGainSamples + 1. : 0.;
277 fSqrtHiGainSamples = TMath::Sqrt(fNumHiGainSamples);
278 fSqrtLoGainSamples = TMath::Sqrt(fNumLoGainSamples);
279 fWindowSizeHiGain = (Int_t)(fRiseTime + fFallTime);
280 fWindowSizeLoGain = (Int_t)(fRiseTime + fFallTime+1);
281 }
282
283 if (!MExtractTimeAndCharge::ReInit(pList))
284 return kFALSE;
285
286 return kTRUE;
287}
288
289// --------------------------------------------------------------------------
290//
291// InitArrays
292//
293// Gets called in the ReInit() and initialized the arrays
294//
295Bool_t MExtractTimeAndChargeSpline::InitArrays()
296{
297
298 Int_t range = fHiGainLast - fHiGainFirst + 1 + fHiLoLast;
299
300 fHiGainSignal .Set(range);
301 fHiGainFirstDeriv .Set(range);
302 fHiGainSecondDeriv.Set(range);
303
304 range = fLoGainLast - fLoGainFirst + 1;
305
306 fLoGainSignal .Set(range);
307 fLoGainFirstDeriv .Set(range);
308 fLoGainSecondDeriv.Set(range);
309
310 fHiGainSignal .Reset();
311 fHiGainFirstDeriv .Reset();
312 fHiGainSecondDeriv.Reset();
313
314 fLoGainSignal .Reset();
315 fLoGainFirstDeriv .Reset();
316 fLoGainSecondDeriv.Reset();
317
318 return kTRUE;
319
320}
321
322// --------------------------------------------------------------------------
323//
324// Calculates the arrival time and charge for each pixel
325//
326void MExtractTimeAndChargeSpline::FindTimeAndChargeHiGain(Byte_t *first, Byte_t *logain, Float_t &sum, Float_t &dsum,
327 Float_t &time, Float_t &dtime,
328 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
329{
330
331 Int_t range = fHiGainLast - fHiGainFirst + 1;
332 const Byte_t *end = first + range;
333 Byte_t *p = first;
334 Int_t count = 0;
335
336 const Float_t pedes = ped.GetPedestal();
337 const Float_t ABoffs = ped.GetPedestalABoffset();
338
339 Float_t pedmean[2];
340 pedmean[0] = pedes + ABoffs;
341 pedmean[1] = pedes - ABoffs;
342
343 fAbMax = 0.;
344 fAbMaxPos = 0.;
345 Byte_t maxpos = 0;
346
347 //
348 // Check for saturation in all other slices
349 //
350 while (p<end)
351 {
352
353 const Int_t ids = fHiGainFirst + count ;
354 const Float_t signal = (Float_t)*p - pedmean[(ids+abflag) & 0x1];
355 fHiGainSignal[count] = signal;
356
357 if (signal > fAbMax + 0.1) /* the 0.1 is necessary for the ultra-high enery events saturating many slices */
358 {
359 fAbMax = signal;
360 maxpos = p-first;
361 }
362
363 if (*p++ >= fSaturationLimit)
364 sat++;
365
366 count++;
367 }
368
369 if (fHiLoLast != 0)
370 {
371
372 end = logain + fHiLoLast;
373
374 while (logain<end)
375 {
376
377 const Int_t ids = fHiGainFirst + range ;
378 const Float_t signal = (Float_t)*logain - pedmean[(ids+abflag) & 0x1];
379 fHiGainSignal[range] = signal;
380 range++;
381
382 if (signal > fAbMax)
383 {
384 fAbMax = signal;
385 maxpos = logain-first;
386 }
387
388 if (*logain >= fSaturationLimit)
389 sat++;
390
391 logain++;
392 }
393 }
394
395 Float_t pp;
396
397 fHiGainSecondDeriv[0] = 0.;
398 fHiGainFirstDeriv[0] = 0.;
399
400 for (Int_t i=1;i<range-1;i++)
401 {
402 pp = fHiGainSecondDeriv[i-1] + 4.;
403 fHiGainSecondDeriv[i] = -1.0/pp;
404 fHiGainFirstDeriv [i] = fHiGainSignal[i+1] - fHiGainSignal[i] - fHiGainSignal[i] + fHiGainSignal[i-1];
405 fHiGainFirstDeriv [i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
406 }
407
408 fHiGainSecondDeriv[range-1] = 0.;
409
410 for (Int_t k=range-2;k>=0;k--)
411 fHiGainSecondDeriv[k] = fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k];
412 for (Int_t k=range-2;k>=0;k--)
413 fHiGainSecondDeriv[k] /= 6.;
414
415 if (IsNoiseCalculation() && IsExtractionType(kAmplitude))
416 {
417 //
418 // Take the spline value at the middle of the third slice (to avoid egde effects)
419 //
420 sum = 0.5*fHiGainSignal[2]
421 + 0.5*fHiGainSignal[3]
422 + (-0.375)*fHiGainSecondDeriv[2]
423 + (-0.375)*fHiGainSecondDeriv[3];
424 return;
425 }
426
427 if (IsNoiseCalculation() && IsExtractionType(kIntegral))
428 {
429 //
430 // Take the spline value at the middle of the third slice (to avoid egde effects)
431 //
432 Int_t first = 2;
433 Int_t last = first + (Int_t)(fRiseTime+fFallTime);
434 CalcIntegralHiGain(sum,first,last);
435 return;
436 }
437
438 //
439 // Allow no saturated slice
440 // and
441 // Don't start if the maxpos is too close to the left limit.
442 //
443 if ((sat || maxpos < 2))
444 {
445 time = IsExtractionType(kMaximum)
446 ? (Float_t)(fHiGainFirst + maxpos)
447 : (Float_t)(fHiGainFirst + maxpos - 1);
448 sum = IsExtractionType(kAmplitude)
449 ? fAbMax : 0.;
450 return;
451 }
452
453 //
454 // Now find the maximum
455 //
456 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
457 Float_t lower = (Float_t)maxpos-1.;
458 Float_t upper = (Float_t)maxpos;
459 fAbMaxPos = upper;
460 Float_t x = lower;
461 Float_t y = 0.;
462 Float_t a = 1.;
463 Float_t b = 0.;
464 Int_t klo = maxpos-1;
465 Int_t khi = maxpos;
466
467 //
468 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
469 // If no maximum is found, go to interval maxpos+1.
470 //
471 while ( x < upper - 0.3 )
472 {
473
474 x += step;
475 a -= step;
476 b += step;
477
478 y = a*fHiGainSignal[klo]
479 + b*fHiGainSignal[khi]
480 + (a*a*a-a)*fHiGainSecondDeriv[klo]
481 + (b*b*b-b)*fHiGainSecondDeriv[khi];
482
483 if (y > fAbMax)
484 {
485 fAbMax = y;
486 fAbMaxPos = x;
487 }
488
489 // *fLog << err << x << " " << y << " " << fAbMaxPos<< endl;
490 }
491
492 //
493 // Search for the absolute maximum from maxpos to maxpos+1 in steps of 0.2
494 //
495 if (fAbMaxPos > upper-0.1)
496 {
497
498 upper = (Float_t)maxpos+1.;
499 lower = (Float_t)maxpos;
500 x = lower;
501 a = 1.;
502 b = 0.;
503 khi = maxpos+1;
504 klo = maxpos;
505
506 while (x<upper-0.3)
507 {
508
509 x += step;
510 a -= step;
511 b += step;
512
513 y = a*fHiGainSignal[klo]
514 + b*fHiGainSignal[khi]
515 + (a*a*a-a)*fHiGainSecondDeriv[klo]
516 + (b*b*b-b)*fHiGainSecondDeriv[khi];
517
518 if (y > fAbMax)
519 {
520 fAbMax = y;
521 fAbMaxPos = x;
522 }
523 // *fLog << inf << x << " " << y << " " << fAbMaxPos << endl;
524
525 }
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-0.035;
534 const Float_t lo = fAbMaxPos-step+0.035;
535 const Float_t maxpossave = fAbMaxPos;
536
537 x = fAbMaxPos;
538 a = upper - x;
539 b = x - lower;
540
541 step = 0.025; // 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 // *fLog << inf << x << " " << y << " " << fAbMaxPos << endl;
561 }
562
563 //
564 // Second, try from time down to time-0.2 in steps of 0.025.
565 //
566 x = maxpossave;
567
568 //
569 // Test the possibility that the absolute maximum has not been found between
570 // maxpos and maxpos+0.025, then we have to look between maxpos-0.025 and maxpos
571 // which requires new setting of klocont and khicont
572 //
573 if (x < klo + 0.02)
574 {
575 klo--;
576 khi--;
577 upper--;
578 lower--;
579 }
580
581 a = upper - x;
582 b = x - lower;
583
584 while (x>lo)
585 {
586
587 x -= step;
588 a += step;
589 b -= step;
590
591 y = a*fHiGainSignal[klo]
592 + b*fHiGainSignal[khi]
593 + (a*a*a-a)*fHiGainSecondDeriv[klo]
594 + (b*b*b-b)*fHiGainSecondDeriv[khi];
595
596 if (y > fAbMax)
597 {
598 fAbMax = y;
599 fAbMaxPos = x;
600 }
601 // *fLog << warn << x << " " << y << " " << fAbMaxPos << endl;
602 }
603
604 if (IsExtractionType(kMaximum))
605 {
606 time = (Float_t)fHiGainFirst + fAbMaxPos;
607 dtime = 0.025;
608 }
609 else
610 {
611 fHalfMax = fAbMax/2.;
612
613 //
614 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
615 // First, find the right FADC slice:
616 //
617 klo = maxpos - 1;
618 while (klo >= 0)
619 {
620 if (fHiGainSignal[klo] < fHalfMax)
621 break;
622 klo--;
623 }
624
625 //
626 // Loop from the beginning of the slice upwards to reach the fHalfMax:
627 // With means of bisection:
628 //
629 x = (Float_t)klo;
630 a = 1.;
631 b = 0.;
632
633 step = 0.5;
634 Bool_t back = kFALSE;
635
636 Int_t maxcnt = 50;
637 Int_t cnt = 0;
638
639 while (TMath::Abs(y-fHalfMax) > fResolution)
640 {
641
642 if (back)
643 {
644 x -= step;
645 a += step;
646 b -= step;
647 }
648 else
649 {
650 x += step;
651 a -= step;
652 b += step;
653 }
654
655 y = a*fHiGainSignal[klo]
656 + b*fHiGainSignal[khi]
657 + (a*a*a-a)*fHiGainSecondDeriv[klo]
658 + (b*b*b-b)*fHiGainSecondDeriv[khi];
659
660 if (y > fHalfMax)
661 back = kTRUE;
662 else
663 back = kFALSE;
664
665 if (++cnt > maxcnt)
666 {
667 // *fLog << inf << x << " " << y << " " << fHalfMax << endl;
668 break;
669 }
670
671 step /= 2.;
672 }
673
674 time = (Float_t)fHiGainFirst + x;
675 dtime = fResolution;
676 }
677
678 if (IsExtractionType(kAmplitude))
679 {
680 sum = fAbMax;
681 return;
682 }
683
684 if (IsExtractionType(kIntegral))
685 {
686 //
687 // Now integrate the whole thing!
688 //
689 Int_t startslice = (Int_t)(fAbMaxPos - fRiseTime);
690 Int_t lastslice = (Int_t)(fAbMaxPos + fFallTime);
691
692 if (lastslice > range)
693 {
694 lastslice = range;
695 startslice += (lastslice - range);
696 }
697
698 CalcIntegralHiGain(sum, startslice, lastslice);
699 }
700
701}
702
703
704// --------------------------------------------------------------------------
705//
706// Calculates the arrival time and charge for each pixel
707//
708void MExtractTimeAndChargeSpline::FindTimeAndChargeLoGain(Byte_t *first, Float_t &sum, Float_t &dsum,
709 Float_t &time, Float_t &dtime,
710 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
711{
712
713 Int_t range = fLoGainLast - fLoGainFirst + 1;
714 const Byte_t *end = first + range;
715 Byte_t *p = first;
716 Int_t count = 0;
717
718 Float_t pedes = ped.GetPedestal();
719 const Float_t ABoffs = ped.GetPedestalABoffset();
720
721 Float_t pedmean[2];
722 pedmean[0] = pedes + ABoffs;
723 pedmean[1] = pedes - ABoffs;
724
725 fAbMax = 0.;
726 fAbMaxPos = 0.;
727 Byte_t maxpos = 0;
728
729 //
730 // Check for saturation in all other slices
731 //
732 while (p<end)
733 {
734
735 const Int_t ids = fLoGainFirst + count ;
736 const Float_t signal = (Float_t)*p - pedmean[(ids+abflag) & 0x1];
737 fLoGainSignal[count] = signal;
738
739 if (signal > fAbMax)
740 {
741 fAbMax = signal;
742 maxpos = p-first;
743 }
744
745 if (*p >= fSaturationLimit)
746 sat++;
747
748 p++;
749 count++;
750 }
751
752 Float_t pp;
753
754 fLoGainSecondDeriv[0] = 0.;
755 fLoGainFirstDeriv[0] = 0.;
756
757 for (Int_t i=1;i<range-1;i++)
758 {
759 pp = fLoGainSecondDeriv[i-1] + 4.;
760 fLoGainSecondDeriv[i] = -1.0/pp;
761 fLoGainFirstDeriv [i] = fLoGainSignal[i+1] - fLoGainSignal[i] - fLoGainSignal[i] + fLoGainSignal[i-1];
762 fLoGainFirstDeriv [i] = (6.0*fLoGainFirstDeriv[i]-fLoGainFirstDeriv[i-1])/pp;
763 }
764
765 fLoGainSecondDeriv[range-1] = 0.;
766 for (Int_t k=range-2;k>=0;k--)
767 fLoGainSecondDeriv[k] = fLoGainSecondDeriv[k]*fLoGainSecondDeriv[k+1] + fLoGainFirstDeriv[k];
768 for (Int_t k=range-2;k>=0;k--)
769 fLoGainSecondDeriv[k] /= 6.;
770
771 if (IsNoiseCalculation() && IsExtractionType(kAmplitude))
772 {
773 //
774 // Take the spline value at the middle of the third slice (to avoid egde effects)
775 //
776 sum = 0.5*fLoGainSignal[2]
777 + 0.5*fLoGainSignal[3]
778 + (-0.375)*fLoGainSecondDeriv[2]
779 + (-0.375)*fLoGainSecondDeriv[3];
780 return;
781 }
782
783 if (IsNoiseCalculation() && IsExtractionType(kIntegral))
784 {
785 //
786 // Take the spline value at the middle of the third slice (to avoid egde effects)
787 //
788 Int_t first = 2;
789 Int_t last = first + (Int_t)(fRiseTime+fFallTime);
790 CalcIntegralLoGain(sum,first,last);
791 return;
792 }
793
794 //
795 // Allow no saturated slice
796 // and
797 // Don't start if the maxpos is too close to the left limit.
798 //
799 if (sat || maxpos < 1)
800 {
801 time = IsExtractionType(kMaximum)
802 ? (Float_t)(fLoGainFirst + maxpos)
803 : (Float_t)(fLoGainFirst + maxpos - 1);
804 return;
805 }
806
807 if (maxpos < 2 && IsExtractionType(kHalfMaximum))
808 {
809 time = (Float_t)(fLoGainFirst + maxpos - 1);
810 return;
811 }
812
813 //
814 // Now find the maximum
815 //
816 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
817 Float_t lower = (Float_t)maxpos-1.;
818 Float_t upper = (Float_t)maxpos;
819 fAbMaxPos = upper;
820 Float_t x = lower;
821 Float_t y = 0.;
822 Float_t a = 1.;
823 Float_t b = 0.;
824 Int_t klo = maxpos-1;
825 Int_t khi = maxpos;
826
827 //
828 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
829 // If no maximum is found, go to interval maxpos+1.
830 //
831 while ( x < upper - 0.3 )
832 {
833
834 x += step;
835 a -= step;
836 b += step;
837
838 y = a*fLoGainSignal[klo]
839 + b*fLoGainSignal[khi]
840 + (a*a*a-a)*fLoGainSecondDeriv[klo]
841 + (b*b*b-b)*fLoGainSecondDeriv[khi];
842
843 if (y > fAbMax)
844 {
845 fAbMax = y;
846 fAbMaxPos = x;
847 }
848
849 // *fLog << err << x << " " << y << " " << fAbMaxPos<< endl;
850 }
851
852 //
853 // Test the possibility that the absolute maximum has not been found before the
854 // maxpos and search from maxpos to maxpos+1 in steps of 0.2
855 //
856 if (fAbMaxPos > upper-0.1)
857 {
858
859 upper = (Float_t)maxpos+1.;
860 lower = (Float_t)maxpos;
861 x = lower;
862 a = 1.;
863 b = 0.;
864 khi = maxpos+1;
865 klo = maxpos;
866
867 while (x<upper-0.3)
868 {
869
870 x += step;
871 a -= step;
872 b += step;
873
874 y = a*fLoGainSignal[klo]
875 + b*fLoGainSignal[khi]
876 + (a*a*a-a)*fLoGainSecondDeriv[klo]
877 + (b*b*b-b)*fLoGainSecondDeriv[khi];
878
879 if (y > fAbMax)
880 {
881 fAbMax = y;
882 fAbMaxPos = x;
883 }
884 // *fLog << inf << x << " " << y << " " << fAbMaxPos << endl;
885
886 }
887 }
888
889
890 //
891 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
892 // Try a better precision.
893 //
894 const Float_t up = fAbMaxPos+step-0.035;
895 const Float_t lo = fAbMaxPos-step+0.035;
896 const Float_t maxpossave = fAbMaxPos;
897
898 x = fAbMaxPos;
899 a = upper - x;
900 b = x - lower;
901
902 step = 0.025; // step size of 83 ps
903
904 while (x<up)
905 {
906
907 x += step;
908 a -= step;
909 b += step;
910
911 y = a*fLoGainSignal[klo]
912 + b*fLoGainSignal[khi]
913 + (a*a*a-a)*fLoGainSecondDeriv[klo]
914 + (b*b*b-b)*fLoGainSecondDeriv[khi];
915
916 if (y > fAbMax)
917 {
918 fAbMax = y;
919 fAbMaxPos = x;
920 }
921 // *fLog << inf << x << " " << y << " " << fAbMaxPos << endl;
922 }
923
924 //
925 // Second, try from time down to time-0.2 in steps of 0.025.
926 //
927 x = maxpossave;
928
929 //
930 // Test the possibility that the absolute maximum has not been found between
931 // maxpos and maxpos+0.02, then we have to look between maxpos-0.02 and maxpos
932 // which requires new setting of klocont and khicont
933 //
934 if (x < klo + 0.02)
935 {
936 klo--;
937 khi--;
938 upper--;
939 lower--;
940 }
941
942 a = upper - x;
943 b = x - lower;
944
945 while (x>lo)
946 {
947
948 x -= step;
949 a += step;
950 b -= step;
951
952 y = a*fLoGainSignal[klo]
953 + b*fLoGainSignal[khi]
954 + (a*a*a-a)*fLoGainSecondDeriv[klo]
955 + (b*b*b-b)*fLoGainSecondDeriv[khi];
956
957 if (y > fAbMax)
958 {
959 fAbMax = y;
960 fAbMaxPos = x;
961 }
962 // *fLog << warn << x << " " << y << " " << fAbMaxPos << endl;
963 }
964
965 if (IsExtractionType(kMaximum))
966 {
967 time = (Float_t)fLoGainFirst + fAbMaxPos;
968 dtime = 0.02;
969 }
970 else
971 {
972 fHalfMax = fAbMax/2.;
973
974 //
975 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
976 // First, find the right FADC slice:
977 //
978 klo = maxpos - 1;
979 while (klo >= 0)
980 {
981 if (fLoGainSignal[klo] < fHalfMax)
982 break;
983 klo--;
984 }
985
986 //
987 // Loop from the beginning of the slice upwards to reach the fHalfMax:
988 // With means of bisection:
989 //
990 x = (Float_t)klo;
991 a = 1.;
992 b = 0.;
993
994 step = 0.5;
995 Bool_t back = kFALSE;
996
997 Int_t maxcnt = 50;
998 Int_t cnt = 0;
999
1000 while (TMath::Abs(y-fHalfMax) > fResolution)
1001 {
1002
1003 if (back)
1004 {
1005 x -= step;
1006 a += step;
1007 b -= step;
1008 }
1009 else
1010 {
1011 x += step;
1012 a -= step;
1013 b += step;
1014 }
1015
1016 y = a*fLoGainSignal[klo]
1017 + b*fLoGainSignal[khi]
1018 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1019 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1020
1021 if (y > fHalfMax)
1022 back = kTRUE;
1023 else
1024 back = kFALSE;
1025
1026 if (++cnt > maxcnt)
1027 {
1028 // *fLog << inf << x << " " << y << " " << fHalfMax << endl;
1029 break;
1030 }
1031
1032 step /= 2.;
1033 }
1034
1035 time = (Float_t)fLoGainFirst + x;
1036 dtime = fResolution;
1037 }
1038
1039 if (IsExtractionType(kAmplitude))
1040 {
1041 sum = fAbMax;
1042 return;
1043 }
1044
1045 if (IsExtractionType(kIntegral))
1046 {
1047 //
1048 // Now integrate the whole thing!
1049 //
1050 Int_t startslice = (Int_t)(fAbMaxPos - fRiseTime);
1051 Int_t lastslice = (Int_t)(fAbMaxPos + fFallTime + 1);
1052
1053 if (lastslice > range)
1054 {
1055 lastslice = range;
1056 startslice += (lastslice - range);
1057 }
1058 CalcIntegralLoGain(sum, startslice, lastslice);
1059 }
1060}
1061
1062void MExtractTimeAndChargeSpline::CalcIntegralHiGain(Float_t &sum, Int_t startslice, Int_t lastslice)
1063{
1064
1065 if (startslice < 0)
1066 {
1067 lastslice -= startslice;
1068 startslice = 0;
1069 }
1070
1071 Int_t i = startslice;
1072 sum = 0.5*fHiGainSignal[i];
1073
1074 //
1075 // We sum 1.5 times the second deriv. coefficients because these had been
1076 // divided by 6. already. Usually, 0.25*fHiGainSecondDeriv should be added.
1077 //
1078 for (i=startslice+1; i<lastslice; i++)
1079 sum += fHiGainSignal[i] + 1.5*fHiGainSecondDeriv[i];
1080
1081 sum += 0.5*fHiGainSignal[lastslice];
1082
1083}
1084
1085void MExtractTimeAndChargeSpline::CalcIntegralLoGain(Float_t &sum, Int_t startslice, Int_t lastslice)
1086{
1087
1088 if (startslice < 0)
1089 {
1090 lastslice -= startslice;
1091 startslice = 0;
1092 }
1093
1094 Int_t i = startslice;
1095 sum = 0.5*fLoGainSignal[i];
1096
1097 //
1098 // We sum 1.5 times the second deriv. coefficients because these had been
1099 // divided by 6. already. Usually, 0.25*fLoGainSecondDeriv should be added.
1100 //
1101 for (i=startslice+1; i<lastslice; i++)
1102 sum += fLoGainSignal[i] + 1.5*fLoGainSecondDeriv[i];
1103
1104 sum += 0.5*fLoGainSignal[lastslice];
1105
1106}
1107
1108
1109
1110// --------------------------------------------------------------------------
1111//
1112// In addition to the resources of the base-class MExtractor:
1113// MJPedestal.MExtractor.WindowSizeHiGain: 6
1114// MJPedestal.MExtractor.WindowSizeLoGain: 6
1115//
1116Int_t MExtractTimeAndChargeSpline::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1117{
1118
1119 Bool_t rc = kFALSE;
1120
1121 if (IsEnvDefined(env, prefix, "Resolution", print))
1122 {
1123 SetResolution(GetEnvValue(env, prefix, "Resolution",fResolution));
1124 rc = kTRUE;
1125 }
1126 if (IsEnvDefined(env, prefix, "RiseTime", print))
1127 {
1128 SetRiseTime(GetEnvValue(env, prefix, "RiseTime", fRiseTime));
1129 rc = kTRUE;
1130 }
1131 if (IsEnvDefined(env, prefix, "FallTime", print))
1132 {
1133 SetFallTime(GetEnvValue(env, prefix, "FallTime", fFallTime));
1134 rc = kTRUE;
1135 }
1136
1137 Bool_t b = kFALSE;
1138
1139 if (IsEnvDefined(env, prefix, "Amplitude", print))
1140 {
1141 b = GetEnvValue(env, prefix, "Amplitude", IsExtractionType(kAmplitude));
1142 if (b)
1143 SetChargeType(kAmplitude);
1144 rc = kTRUE;
1145 }
1146 if (IsEnvDefined(env, prefix, "Integral", print))
1147 {
1148 b = GetEnvValue(env, prefix, "Integral", IsExtractionType(kIntegral));
1149 if (b)
1150 SetChargeType(kIntegral);
1151 rc = kTRUE;
1152 }
1153 if (IsEnvDefined(env, prefix, "Maximum", print))
1154 {
1155 b = GetEnvValue(env, prefix, "Maximum", IsExtractionType(kMaximum));
1156 if (b)
1157 SetTimeType(kMaximum);
1158 rc = kTRUE;
1159 }
1160 if (IsEnvDefined(env, prefix, "HalfMaximum", print))
1161 {
1162 b = GetEnvValue(env, prefix, "HalfMaximum", IsExtractionType(kHalfMaximum));
1163 if (b)
1164 SetTimeType(kHalfMaximum);
1165 rc = kTRUE;
1166 }
1167
1168 return MExtractTimeAndCharge::ReadEnv(env, prefix, print) ? kTRUE : rc;
1169
1170}
1171
1172
Note: See TracBrowser for help on using the repository browser.