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

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