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

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