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

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