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

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