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

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