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

Last change on this file since 7876 was 7876, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 34.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//
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.39; // 5 ns
162const Float_t MExtractTimeAndChargeSpline::fgLoGainStartShift = -2.4;
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 // range-fWindowSizeHiGain+1 == fHiLoLast isn't it?
402 if (maxpos > 1 && maxpos < (range - fWindowSizeHiGain + 1))
403 fMaxBinContent = *p;
404 }
405
406 if (*p++ >= fSaturationLimit)
407 if (!sat)
408 sat = ids-fHiGainFirst;
409
410 }
411
412 if (fHiLoLast != 0)
413 {
414
415 end = logain + fHiLoLast;
416
417 while (logain<end)
418 {
419
420 *sample++ = (Float_t)*logain - pedmean[(ids++ + abflag) & 0x1];
421
422 if (*logain > fMaxBinContent)
423 {
424 maxpos = ids-fHiGainFirst-1;
425 // range-fWindowSizeHiGain+1 == fHiLoLast isn't it?
426 //if (maxpos > 1 && maxpos < (range - fWindowSizeHiGain + 1))
427 // fMaxBinContent = *logain;
428 }
429
430 if (*logain++ >= fSaturationLimit)
431 if (!sat)
432 sat = ids-fHiGainFirst;
433
434 range++;
435 }
436 }
437
438 fAbMax = fHiGainSignal[maxpos];
439
440 fHiGainSecondDeriv[0] = 0.;
441 fHiGainFirstDeriv[0] = 0.;
442
443 for (Int_t i=1;i<range-1;i++)
444 {
445 const Float_t pp = fHiGainSecondDeriv[i-1] + 4.;
446 fHiGainSecondDeriv[i] = -1.0/pp;
447 fHiGainFirstDeriv [i] = fHiGainSignal[i+1] - 2*fHiGainSignal[i] + fHiGainSignal[i-1];
448 fHiGainFirstDeriv [i] = (6.0*fHiGainFirstDeriv[i]-fHiGainFirstDeriv[i-1])/pp;
449 }
450
451 fHiGainSecondDeriv[range-1] = 0.;
452
453 for (Int_t k=range-2;k>=0;k--)
454 fHiGainSecondDeriv[k] = fHiGainSecondDeriv[k]*fHiGainSecondDeriv[k+1] + fHiGainFirstDeriv[k];
455 for (Int_t k=range-2;k>=0;k--)
456 fHiGainSecondDeriv[k] /= 6.;
457
458 if (IsNoiseCalculation())
459 {
460
461 if (fRandomIter == int(1./fResolution))
462 fRandomIter = 0;
463
464 const Float_t nsx = fRandomIter * fResolution;
465
466 if (fExtractionType == kAmplitude)
467 {
468 const Float_t b = nsx;
469 const Float_t a = 1. - nsx;
470
471 sum = a*fHiGainSignal[1]
472 + b*fHiGainSignal[2]
473 + (a*a*a-a)*fHiGainSecondDeriv[1]
474 + (b*b*b-b)*fHiGainSecondDeriv[2];
475 }
476 else
477 sum = CalcIntegralHiGain(2. + nsx, range);
478
479 fRandomIter++;
480 return;
481 }
482
483 //
484 // Allow no saturated slice and
485 // Don't start if the maxpos is too close to the limits.
486 //
487 const Bool_t limlo = maxpos < TMath::Ceil(fRiseTimeHiGain);
488 const Bool_t limup = maxpos > range-TMath::Ceil(fFallTimeHiGain)-1;
489 if (sat || limlo || limup)
490 {
491 dtime = 1.0;
492 if (fExtractionType == kAmplitude)
493 {
494 sum = fAbMax;
495 time = (Float_t)(fHiGainFirst + maxpos);
496 return;
497 }
498
499 sum = CalcIntegralHiGain(limlo ? 0 : range, range);
500 time = (Float_t)(fHiGainFirst + maxpos - 1);
501 return;
502 }
503
504 dtime = fResolution;
505
506 //
507 // Now find the maximum
508 //
509 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
510 Float_t lower = -1. + maxpos;
511 Float_t upper = (Float_t)maxpos;
512 fAbMaxPos = upper;
513 Float_t x = lower;
514 Float_t y = 0.;
515 Float_t a = 1.;
516 Float_t b = 0.;
517 Int_t klo = maxpos-1;
518 Int_t khi = maxpos;
519
520 //
521 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
522 // If no maximum is found, go to interval maxpos+1.
523 //
524 while ( x < upper - 0.3 )
525 {
526
527 x += step;
528 a -= step;
529 b += step;
530
531 y = a*fHiGainSignal[klo]
532 + b*fHiGainSignal[khi]
533 + (a*a*a-a)*fHiGainSecondDeriv[klo]
534 + (b*b*b-b)*fHiGainSecondDeriv[khi];
535
536 if (y > fAbMax)
537 {
538 fAbMax = y;
539 fAbMaxPos = x;
540 }
541
542 }
543
544 //
545 // Search for the absolute maximum from maxpos to maxpos+1 in steps of 0.2
546 //
547 if (fAbMaxPos > upper-0.1)
548 {
549 upper = 1. + maxpos;
550 lower = (Float_t)maxpos;
551 x = lower;
552 a = 1.;
553 b = 0.;
554 khi = maxpos+1;
555 klo = maxpos;
556
557 while (x<upper-0.3)
558 {
559
560 x += step;
561 a -= step;
562 b += step;
563
564 y = a*fHiGainSignal[klo]
565 + b*fHiGainSignal[khi]
566 + (a*a*a-a)*fHiGainSecondDeriv[klo]
567 + (b*b*b-b)*fHiGainSecondDeriv[khi];
568
569 if (y > fAbMax)
570 {
571 fAbMax = y;
572 fAbMaxPos = x;
573 }
574 }
575 }
576 //
577 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
578 // Try a better precision.
579 //
580 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
581 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
582 const Float_t maxpossave = fAbMaxPos;
583
584 x = fAbMaxPos;
585 a = upper - x;
586 b = x - lower;
587
588 step = 2.*fResolution; // step size of 0.1 FADC slices
589
590 while (x<up)
591 {
592
593 x += step;
594 a -= step;
595 b += step;
596
597 y = a*fHiGainSignal[klo]
598 + b*fHiGainSignal[khi]
599 + (a*a*a-a)*fHiGainSecondDeriv[klo]
600 + (b*b*b-b)*fHiGainSecondDeriv[khi];
601
602 if (y > fAbMax)
603 {
604 fAbMax = y;
605 fAbMaxPos = x;
606 }
607 }
608
609 //
610 // Second, try from time down to time-0.2 in steps of fResolution.
611 //
612 x = maxpossave;
613
614 //
615 // Test the possibility that the absolute maximum has not been found between
616 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
617 // which requires new setting of klocont and khicont
618 //
619 if (x < lower + fResolution)
620 {
621 klo--;
622 khi--;
623 upper -= 1.;
624 lower -= 1.;
625 }
626
627 a = upper - x;
628 b = x - lower;
629
630 while (x>lo)
631 {
632
633 x -= step;
634 a += step;
635 b -= step;
636
637 y = a*fHiGainSignal[klo]
638 + b*fHiGainSignal[khi]
639 + (a*a*a-a)*fHiGainSecondDeriv[klo]
640 + (b*b*b-b)*fHiGainSecondDeriv[khi];
641
642 if (y > fAbMax)
643 {
644 fAbMax = y;
645 fAbMaxPos = x;
646 }
647 }
648
649 if (fExtractionType == kAmplitude)
650 {
651 time = fAbMaxPos + (Int_t)fHiGainFirst;
652 sum = fAbMax;
653 return;
654 }
655
656 fHalfMax = fAbMax/2.;
657
658 //
659 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
660 // First, find the right FADC slice:
661 //
662 klo = maxpos;
663 while (klo > 0)
664 {
665 if (fHiGainSignal[--klo] < fHalfMax)
666 break;
667 }
668
669 khi = klo+1;
670 //
671 // Loop from the beginning of the slice upwards to reach the fHalfMax:
672 // With means of bisection:
673 //
674 x = (Float_t)klo;
675 a = 1.;
676 b = 0.;
677
678 step = 0.5;
679 Bool_t back = kFALSE;
680
681 Int_t maxcnt = 20;
682 Int_t cnt = 0;
683
684 while (TMath::Abs(y-fHalfMax) > fResolution)
685 {
686
687 if (back)
688 {
689 x -= step;
690 a += step;
691 b -= step;
692 }
693 else
694 {
695 x += step;
696 a -= step;
697 b += step;
698 }
699
700 y = a*fHiGainSignal[klo]
701 + b*fHiGainSignal[khi]
702 + (a*a*a-a)*fHiGainSecondDeriv[klo]
703 + (b*b*b-b)*fHiGainSecondDeriv[khi];
704
705 back = y > fHalfMax;
706
707 if (++cnt > maxcnt)
708 break;
709
710 step /= 2.;
711 }
712
713 //
714 // Now integrate the whole thing!
715 //
716 time = (Float_t)fHiGainFirst + x;
717 sum = CalcIntegralHiGain(fAbMaxPos - fRiseTimeHiGain, range);
718}
719
720
721// --------------------------------------------------------------------------
722//
723// Calculates the arrival time and charge for each pixel
724//
725void MExtractTimeAndChargeSpline::FindTimeAndChargeLoGain(Byte_t *first, Float_t &sum, Float_t &dsum,
726 Float_t &time, Float_t &dtime,
727 Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
728{
729 Int_t range = fLoGainLast - fLoGainFirst + 1;
730 const Byte_t *end = first + range;
731 Byte_t *p = first;
732
733 const Float_t pedes = ped.GetPedestal();
734 const Float_t ABoffs = ped.GetPedestalABoffset();
735
736 const Float_t pedmean[2] = { pedes + ABoffs, pedes - ABoffs };
737
738 fAbMax = 0.;
739 fAbMaxPos = 0.;
740 Int_t maxpos = 0;
741 Int_t max = -9999;
742
743 //
744 // Check for saturation in all other slices
745 //
746 Int_t ids = fLoGainFirst;
747 Float_t *sample = fLoGainSignal.GetArray();
748 while (p<end)
749 {
750
751 *sample++ = (Float_t)*p - pedmean[(ids++ + abflag) & 0x1];
752
753 if (*p > max)
754 {
755 maxpos = ids-fLoGainFirst-1;
756 max = *p;
757 }
758
759 if (*p++ >= fSaturationLimit)
760 sat++;
761 }
762
763 fAbMax = fLoGainSignal[maxpos];
764
765 fLoGainSecondDeriv[0] = 0.;
766 fLoGainFirstDeriv[0] = 0.;
767
768 for (Int_t i=1;i<range-1;i++)
769 {
770 const Float_t pp = fLoGainSecondDeriv[i-1] + 4.;
771 fLoGainSecondDeriv[i] = -1.0/pp;
772 fLoGainFirstDeriv [i] = fLoGainSignal[i+1] - 2*fLoGainSignal[i] + fLoGainSignal[i-1];
773 fLoGainFirstDeriv [i] = (6.0*fLoGainFirstDeriv[i]-fLoGainFirstDeriv[i-1])/pp;
774 }
775
776 fLoGainSecondDeriv[range-1] = 0.;
777
778 for (Int_t k=range-2;k>=0;k--)
779 fLoGainSecondDeriv[k] = fLoGainSecondDeriv[k]*fLoGainSecondDeriv[k+1] + fLoGainFirstDeriv[k];
780 for (Int_t k=range-2;k>=0;k--)
781 fLoGainSecondDeriv[k] /= 6.;
782
783 if (IsNoiseCalculation())
784 {
785 if (fRandomIter == int(1./fResolution))
786 fRandomIter = 0;
787
788 const Float_t nsx = fRandomIter * fResolution;
789
790 if (fExtractionType == kAmplitude)
791 {
792 const Float_t b = nsx;
793 const Float_t a = 1. - nsx;
794
795 sum = a*fLoGainSignal[1]
796 + b*fLoGainSignal[2]
797 + (a*a*a-a)*fLoGainSecondDeriv[1]
798 + (b*b*b-b)*fLoGainSecondDeriv[2];
799 }
800 else
801 sum = CalcIntegralLoGain(2. + nsx, range);
802
803 fRandomIter++;
804 return;
805 }
806 //
807 // Allow no saturated slice and
808 // Don't start if the maxpos is too close to the limits.
809 //
810 const Bool_t limlo = maxpos < TMath::Ceil(fRiseTimeLoGain);
811 const Bool_t limup = maxpos > range-TMath::Ceil(fFallTimeLoGain)-1;
812 if (sat || limlo || limup)
813 {
814 dtime = 1.0;
815 if (fExtractionType == kAmplitude)
816 {
817 time = (Float_t)(fLoGainFirst + maxpos);
818 sum = fAbMax;
819 return;
820 }
821
822 sum = CalcIntegralLoGain(limlo ? 0 : range, range);
823 time = (Float_t)(fLoGainFirst + maxpos - 1);
824 return;
825 }
826
827 dtime = fResolution;
828
829 //
830 // Now find the maximum
831 //
832 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
833 Float_t lower = -1. + maxpos;
834 Float_t upper = (Float_t)maxpos;
835 fAbMaxPos = upper;
836 Float_t x = lower;
837 Float_t y = 0.;
838 Float_t a = 1.;
839 Float_t b = 0.;
840 Int_t klo = maxpos-1;
841 Int_t khi = maxpos;
842
843 //
844 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
845 // If no maximum is found, go to interval maxpos+1.
846 //
847 while ( x < upper - 0.3 )
848 {
849
850 x += step;
851 a -= step;
852 b += step;
853
854 y = a*fLoGainSignal[klo]
855 + b*fLoGainSignal[khi]
856 + (a*a*a-a)*fLoGainSecondDeriv[klo]
857 + (b*b*b-b)*fLoGainSecondDeriv[khi];
858
859 if (y > fAbMax)
860 {
861 fAbMax = y;
862 fAbMaxPos = x;
863 }
864
865 }
866
867 //
868 // Test the possibility that the absolute maximum has not been found before the
869 // maxpos and search from maxpos to maxpos+1 in steps of 0.2
870 //
871 if (fAbMaxPos > upper-0.1)
872 {
873
874 upper = 1. + maxpos;
875 lower = (Float_t)maxpos;
876 x = lower;
877 a = 1.;
878 b = 0.;
879 khi = maxpos+1;
880 klo = maxpos;
881
882 while (x<upper-0.3)
883 {
884
885 x += step;
886 a -= step;
887 b += step;
888
889 y = a*fLoGainSignal[klo]
890 + b*fLoGainSignal[khi]
891 + (a*a*a-a)*fLoGainSecondDeriv[klo]
892 + (b*b*b-b)*fLoGainSecondDeriv[khi];
893
894 if (y > fAbMax)
895 {
896 fAbMax = y;
897 fAbMaxPos = x;
898 }
899 }
900 }
901
902
903 //
904 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
905 // Try a better precision.
906 //
907 const Float_t up = fAbMaxPos+step - 3.0*fResolution;
908 const Float_t lo = fAbMaxPos-step + 3.0*fResolution;
909 const Float_t maxpossave = fAbMaxPos;
910
911 x = fAbMaxPos;
912 a = upper - x;
913 b = x - lower;
914
915 step = 2.*fResolution; // step size of 0.1 FADC slice
916
917 while (x<up)
918 {
919
920 x += step;
921 a -= step;
922 b += step;
923
924 y = a*fLoGainSignal[klo]
925 + b*fLoGainSignal[khi]
926 + (a*a*a-a)*fLoGainSecondDeriv[klo]
927 + (b*b*b-b)*fLoGainSecondDeriv[khi];
928
929 if (y > fAbMax)
930 {
931 fAbMax = y;
932 fAbMaxPos = x;
933 }
934 }
935
936 //
937 // Second, try from time down to time-0.2 in steps of 0.025.
938 //
939 x = maxpossave;
940
941 //
942 // Test the possibility that the absolute maximum has not been found between
943 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
944 // which requires new setting of klocont and khicont
945 //
946 if (x < lower + fResolution)
947 {
948 klo--;
949 khi--;
950 upper -= 1.;
951 lower -= 1.;
952 }
953
954 a = upper - x;
955 b = x - lower;
956
957 while (x>lo)
958 {
959
960 x -= step;
961 a += step;
962 b -= step;
963
964 y = a*fLoGainSignal[klo]
965 + b*fLoGainSignal[khi]
966 + (a*a*a-a)*fLoGainSecondDeriv[klo]
967 + (b*b*b-b)*fLoGainSecondDeriv[khi];
968
969 if (y > fAbMax)
970 {
971 fAbMax = y;
972 fAbMaxPos = x;
973 }
974 }
975
976 if (fExtractionType == kAmplitude)
977 {
978 time = fAbMaxPos + (Int_t)fLoGainFirst;
979 sum = fAbMax;
980 return;
981 }
982
983 fHalfMax = fAbMax/2.;
984
985 //
986 // Now, loop from the maximum bin leftward down in order to find the position of the half maximum.
987 // First, find the right FADC slice:
988 //
989 klo = maxpos;
990 while (klo > 0)
991 {
992 klo--;
993 if (fLoGainSignal[klo] < fHalfMax)
994 break;
995 }
996
997 khi = klo+1;
998 //
999 // Loop from the beginning of the slice upwards to reach the fHalfMax:
1000 // With means of bisection:
1001 //
1002 x = (Float_t)klo;
1003 a = 1.;
1004 b = 0.;
1005
1006 step = 0.5;
1007 Bool_t back = kFALSE;
1008
1009 Int_t maxcnt = 20;
1010 Int_t cnt = 0;
1011
1012 while (TMath::Abs(y-fHalfMax) > fResolution)
1013 {
1014
1015 if (back)
1016 {
1017 x -= step;
1018 a += step;
1019 b -= step;
1020 }
1021 else
1022 {
1023 x += step;
1024 a -= step;
1025 b += step;
1026 }
1027
1028 y = a*fLoGainSignal[klo]
1029 + b*fLoGainSignal[khi]
1030 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1031 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1032
1033 back = y > fHalfMax;
1034
1035 if (++cnt > maxcnt)
1036 break;
1037
1038 step /= 2.;
1039 }
1040
1041 //
1042 // Now integrate the whole thing!
1043 //
1044 time = x + (Int_t)fLoGainFirst;
1045 sum = CalcIntegralLoGain(fAbMaxPos - fRiseTimeLoGain, range);
1046}
1047
1048Float_t MExtractTimeAndChargeSpline::CalcIntegralHiGain(Float_t start, Float_t range) const
1049{
1050 // The number of steps is calculated directly from the integration
1051 // window. This is the only way to ensure we are not dealing with
1052 // numerical rounding uncertanties, because we always get the same
1053 // value under the same conditions -- it might still be different on
1054 // other machines!
1055 const Float_t step = 0.2;
1056 const Float_t width = fRiseTimeHiGain+fFallTimeHiGain;
1057 const Float_t max = range-1 - (width+step);
1058 const Int_t num = TMath::Nint(width/step);
1059
1060 // The order is important. In some cases (limlo-/limup-check) it can
1061 // happen than max<0. In this case we start at 0
1062 if (start > max)
1063 start = max;
1064 if (start < 0)
1065 start = 0;
1066
1067 start += step/2;
1068
1069 Double_t sum = 0.;
1070 for (Int_t i=0; i<num; i++)
1071 {
1072 const Float_t x = start+i*step;
1073 const Int_t klo = (Int_t)TMath::Floor(x);
1074 const Int_t khi = klo + 1;
1075 // Note: if x is close to one integer number (= a FADC sample)
1076 // we get the same result by using that sample as klo, and the
1077 // next one as khi, or using the sample as khi and the previous
1078 // one as klo (the spline is of course continuous). So we do not
1079 // expect problems from rounding issues in the argument of
1080 // Floor() above (we have noticed differences in roundings
1081 // depending on the compilation options).
1082
1083 const Float_t a = khi - x; // Distance from x to next FADC sample
1084 const Float_t b = x - klo; // Distance from x to previous FADC sample
1085
1086 sum += a*fHiGainSignal[klo]
1087 + b*fHiGainSignal[khi]
1088 + (a*a*a-a)*fHiGainSecondDeriv[klo]
1089 + (b*b*b-b)*fHiGainSecondDeriv[khi];
1090
1091 // FIXME? Perhaps the integral should be done analitically
1092 // between every two FADC slices, instead of numerically
1093 }
1094
1095 sum *= step; // Transform sum in integral
1096 return sum;
1097}
1098
1099Float_t MExtractTimeAndChargeSpline::CalcIntegralLoGain(Float_t start, Float_t range) const
1100{
1101 // The number of steps is calculated directly from the integration
1102 // window. This is the only way to ensure we are not dealing with
1103 // numerical rounding uncertanties, because we always get the same
1104 // value under the same conditions -- it might still be different on
1105 // other machines!
1106 const Float_t step = 0.2;
1107 const Float_t width = fRiseTimeLoGain+fFallTimeLoGain;
1108 const Float_t max = range-1 - (width+step);
1109 const Int_t num = TMath::Nint(width/step);
1110
1111 // The order is important. In some cases (limlo-/limup-check) it can
1112 // happen that max<0. In this case we start at 0
1113 if (start > max)
1114 start = max;
1115 if (start < 0)
1116 start = 0;
1117
1118 start += step/2;
1119
1120 Double_t sum = 0.;
1121 for (Int_t i=0; i<num; i++)
1122 {
1123 const Float_t x = start+i*step;
1124 const Int_t klo = (Int_t)TMath::Floor(x);
1125 const Int_t khi = klo + 1;
1126 // Note: if x is close to one integer number (= a FADC sample)
1127 // we get the same result by using that sample as klo, and the
1128 // next one as khi, or using the sample as khi and the previous
1129 // one as klo (the spline is of course continuous). So we do not
1130 // expect problems from rounding issues in the argument of
1131 // Floor() above (we have noticed differences in roundings
1132 // depending on the compilation options).
1133
1134 const Float_t a = khi - x; // Distance from x to next FADC sample
1135 const Float_t b = x - klo; // Distance from x to previous FADC sample
1136
1137 sum += a*fLoGainSignal[klo]
1138 + b*fLoGainSignal[khi]
1139 + (a*a*a-a)*fLoGainSecondDeriv[klo]
1140 + (b*b*b-b)*fLoGainSecondDeriv[khi];
1141
1142 // FIXME? Perhaps the integral should be done analitically
1143 // between every two FADC slices, instead of numerically
1144 }
1145 sum *= step; // Transform sum in integral
1146 return sum;
1147}
1148
1149// --------------------------------------------------------------------------
1150//
1151// In addition to the resources of the base-class MExtractor:
1152// Resolution
1153// RiseTimeHiGain
1154// FallTimeHiGain
1155// LoGainStretch
1156// ExtractionType: amplitude, integral
1157//
1158Int_t MExtractTimeAndChargeSpline::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1159{
1160
1161 Bool_t rc = kFALSE;
1162
1163 if (IsEnvDefined(env, prefix, "Resolution", print))
1164 {
1165 SetResolution(GetEnvValue(env, prefix, "Resolution",fResolution));
1166 rc = kTRUE;
1167 }
1168 if (IsEnvDefined(env, prefix, "RiseTimeHiGain", print))
1169 {
1170 SetRiseTimeHiGain(GetEnvValue(env, prefix, "RiseTimeHiGain", fRiseTimeHiGain));
1171 rc = kTRUE;
1172 }
1173 if (IsEnvDefined(env, prefix, "FallTimeHiGain", print))
1174 {
1175 SetFallTimeHiGain(GetEnvValue(env, prefix, "FallTimeHiGain", fFallTimeHiGain));
1176 rc = kTRUE;
1177 }
1178 if (IsEnvDefined(env, prefix, "LoGainStretch", print))
1179 {
1180 SetLoGainStretch(GetEnvValue(env, prefix, "LoGainStretch", fLoGainStretch));
1181 rc = kTRUE;
1182 }
1183
1184 if (IsEnvDefined(env, prefix, "ExtractionType", print))
1185 {
1186 TString type = GetEnvValue(env, prefix, "ExtractionType", "");
1187 type.ToLower();
1188 type = type.Strip(TString::kBoth);
1189 if (type==(TString)"amplitude")
1190 SetChargeType(kAmplitude);
1191 if (type==(TString)"integral")
1192 SetChargeType(kIntegral);
1193 rc=kTRUE;
1194 }
1195
1196 return MExtractTimeAndCharge::ReadEnv(env, prefix, print) ? kTRUE : rc;
1197
1198}
1199
1200
Note: See TracBrowser for help on using the repository browser.