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

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