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

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