source: trunk/MagicSoft/Mars/mextralgo/MExtralgoSpline.cc@ 8500

Last change on this file since 8500 was 8500, checked in by tbretz, 18 years ago
*** empty log message ***
File size: 13.0 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): Thomas Bretz <mailto:tbretz@astro.uni-wuerzbrug.de>
18! Author(s): Markus Gaug 09/2004 <mailto:markus@ifae.es>
19!
20! Copyright: MAGIC Software Development, 2002-2006
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MExtralgoSpline
28//
29// Fast Spline extractor using a cubic spline algorithm, adapted from
30// Numerical Recipes in C++, 2nd edition, pp. 116-119.
31//
32// The coefficients "ya" are here denoted as "fVal" corresponding to
33// the FADC value subtracted by the clock-noise corrected pedestal.
34//
35// The coefficients "y2a" get immediately divided 6. and are called here
36// fDer2 although they are now not exactly the second derivative
37// coefficients any more.
38//
39// The calculation of the cubic-spline interpolated value "y" on a point
40// "x" along the FADC-slices axis becomes: EvalAt(x)
41//
42// The coefficients fDer2 are calculated with the simplified
43// algorithm in InitDerivatives.
44//
45// This algorithm takes advantage of the fact that the x-values are all
46// separated by exactly 1 which simplifies the Numerical Recipes algorithm.
47// (Note that the variables fDer are not real first derivative coefficients.)
48//
49//////////////////////////////////////////////////////////////////////////////
50#include "MExtralgoSpline.h"
51
52#include <TRandom.h>
53
54#include "../mbase/MMath.h"
55
56using namespace std;
57
58// --------------------------------------------------------------------------
59//
60// Calculate the first and second derivative for the splie.
61//
62// The coefficients are calculated such that
63// 1) fVal[i] = Eval(i, 0)
64// 2) Eval(i-1, 1)==Eval(i, 0)
65//
66// In other words: The values with the index i describe the spline
67// between fVal[i] and fVal[i+1]
68//
69void MExtralgoSpline::InitDerivatives() const
70{
71 if (fNum<2)
72 return;
73
74 fDer1[0] = 0.;
75 fDer2[0] = 0.;
76
77 for (Int_t i=1; i<fNum-1; i++)
78 {
79 const Float_t pp = fDer2[i-1] + 4.;
80
81 fDer2[i] = -1.0/pp;
82
83 const Float_t d1 = fVal[i+1] - 2*fVal[i] + fVal[i-1];
84 fDer1[i] = (6.0*d1-fDer1[i-1])/pp;
85 }
86
87 fDer2[fNum-1] = 0.;
88
89 for (Int_t k=fNum-2; k>=0; k--)
90 fDer2[k] = fDer2[k]*fDer2[k+1] + fDer1[k];
91
92 for (Int_t k=fNum-2; k>=0; k--)
93 fDer2[k] /= 6.;
94}
95
96// --------------------------------------------------------------------------
97//
98// Returns the highest x value in [min;max[ at which the spline in
99// the bin i is equal to y
100//
101// min and max are defined to be [0;1]
102//
103// The default for min is 0, the default for max is 1
104// The defaule for y is 0
105//
106Double_t MExtralgoSpline::FindY(Int_t i, Double_t y, Double_t min, Double_t max) const
107{
108 // y = a*x^3 + b*x^2 + c*x + d'
109 // 0 = a*x^3 + b*x^2 + c*x + d' - y
110
111 // Calculate coefficients
112 const Double_t a = fDer2[i+1]-fDer2[i];
113 const Double_t b = 3*fDer2[i];
114 const Double_t c = fVal[i+1]-fVal[i] -2*fDer2[i]-fDer2[i+1];
115 const Double_t d = fVal[i] - y;
116
117 Double_t x1, x2, x3;
118 const Int_t rc = MMath::SolvePol3(a, b, c, d, x1, x2, x3);
119
120 Double_t x = -1;
121 if (rc>0 && x1>=min && x1<max && x1>x)
122 x = x1;
123 if (rc>1 && x2>=min && x2<max && x2>x)
124 x = x2;
125 if (rc>2 && x3>=min && x3<max && x3>x)
126 x = x3;
127
128 return x<0 ? -2 : x+i;
129}
130
131// --------------------------------------------------------------------------
132//
133// Search analytically downward for the value y of the spline, starting
134// at x, until x==0. If y is not found -2 is returned.
135//
136Double_t MExtralgoSpline::SearchY(Float_t x, Float_t y) const
137{
138 if (x>=fNum-1)
139 x = fNum-1.0001;
140
141 Int_t i = TMath::FloorNint(x);
142 Double_t rc = FindY(i, y, 0, x-i);
143 while (--i>=0 && rc<0)
144 rc = FindY(i, y);
145
146 return rc;
147}
148
149Double_t MExtralgoSpline::SearchYup(Float_t x, Float_t y) const
150{
151 if (x<0)
152 x = 0.0001;
153
154 Int_t i = TMath::FloorNint(x);
155 Double_t rc = FindY(i, y, x-i, 1.);
156 while (i++<fNum-1 && rc<0)
157 rc = FindY(i, y);
158
159 return rc;
160}
161
162// --------------------------------------------------------------------------
163//
164// Do a range check an then calculate the integral from start-fRiseTime
165// to start+fFallTime. An extrapolation of 0.5 slices is allowed.
166//
167Float_t MExtralgoSpline::CalcIntegral(Float_t pos) const
168{
169/*
170 // The number of steps is calculated directly from the integration
171 // window. This is the only way to ensure we are not dealing with
172 // numerical rounding uncertanties, because we always get the same
173 // value under the same conditions -- it might still be different on
174 // other machines!
175 const Float_t start = pos-fRiseTime;
176 const Float_t step = 0.2;
177 const Float_t width = fRiseTime+fFallTime;
178 const Float_t max = fNum-1 - (width+step);
179 const Int_t num = TMath::Nint(width/step);
180
181 // The order is important. In some cases (limlo-/limup-check) it can
182 // happen that max<0. In this case we start at 0
183 if (start > max)
184 start = max;
185 if (start < 0)
186 start = 0;
187
188 start += step/2;
189
190 Double_t sum = 0.;
191 for (Int_t i=0; i<num; i++)
192 {
193 // Note: if x is close to one integer number (= a FADC sample)
194 // we get the same result by using that sample as klo, and the
195 // next one as khi, or using the sample as khi and the previous
196 // one as klo (the spline is of course continuous). So we do not
197 // expect problems from rounding issues in the argument of
198 // Floor() above (we have noticed differences in roundings
199 // depending on the compilation options).
200
201 sum += EvalAt(start + i*step);
202
203 // FIXME? Perhaps the integral should be done analitically
204 // between every two FADC slices, instead of numerically
205 }
206 sum *= step; // Transform sum in integral
207
208 return sum;
209 */
210
211 // In the future we will calculate the intgeral analytically.
212 // It has been tested that it gives identical results within
213 // acceptable differences.
214
215 // We allow extrapolation of 1/2 slice.
216 const Float_t min = fRiseTime; //-0.5+fRiseTime;
217 const Float_t max = fNum-1-fFallTime; //fNum-0.5+fFallTime;
218
219 if (pos<min)
220 pos = min;
221 if (pos>max)
222 pos = max;
223
224 return EvalInteg(pos-fRiseTime, pos+fFallTime);
225}
226
227Float_t MExtralgoSpline::ExtractNoise()
228{
229 if (fNum<5)
230 return 0;
231
232 if (fExtractionType == kAmplitude)
233 {
234 const Int_t pos = gRandom->Integer(fNum-1);
235 const Float_t nsx = gRandom->Uniform();
236 return Eval(pos, nsx);
237 }
238 else
239 {
240 const Float_t pos = gRandom->Uniform(fNum-1-fRiseTime-fFallTime)+fRiseTime;
241 return CalcIntegral(pos);
242 }
243}
244
245void MExtralgoSpline::Extract(Byte_t sat, Int_t maxbin, Bool_t width)
246{
247 fSignal = 0;
248 fTime = 0;
249 fWidth = 0;
250 fSignalDev = -1;
251 fTimeDev = -1;
252 fWidthDev = -1;
253
254 if (fNum<2)
255 return;
256/*
257 //
258 // Allow no saturated slice and
259 // Don't start if the maxpos is too close to the limits.
260 //
261
262 const Bool_t limlo = maxbin < TMath::Ceil(fRiseTime);
263 const Bool_t limup = maxbin > fNum-TMath::Ceil(fFallTime)-1;
264 if (sat || limlo || limup)
265 {
266 fTimeDev = 1.0;
267 if (fExtractionType == kAmplitude)
268 {
269 fSignal = fVal[maxbin];
270 fTime = maxbin;
271 fSignalDev = 0; // means: is valid
272 return;
273 }
274
275 fSignal = CalcIntegral(limlo ? 0 : fNum);
276 fTime = maxbin - 1;
277 fSignalDev = 0; // means: is valid
278 return;
279 }
280
281 //
282 // Now find the maximum
283 //
284
285 Float_t step = 0.2; // start with step size of 1ns and loop again with the smaller one
286
287 Int_t klo = maxbin-1;
288
289 Float_t maxpos = maxbin;//! Current position of the maximum of the spline
290 Float_t max = fVal[maxbin];//! Current maximum of the spline
291
292 //
293 // Search for the maximum, starting in interval maxpos-1 in steps of 0.2 till maxpos-0.2.
294 // If no maximum is found, go to interval maxpos+1.
295 //
296 for (Int_t i=0; i<TMath::Nint(TMath::Ceil((1-0.3)/step)); i++)
297 {
298 const Float_t x = klo + step*(i+1);
299 //const Float_t y = Eval(klo, x);
300 const Float_t y = Eval(klo, x-klo);
301 if (y > max)
302 {
303 max = y;
304 maxpos = x;
305 }
306 }
307
308 //
309 // Search for the absolute maximum from maxpos to maxpos+1 in steps of 0.2
310 //
311 if (maxpos > maxbin - 0.1)
312 {
313 klo = maxbin;
314
315 for (Int_t i=0; i<TMath::Nint(TMath::Ceil((1-0.3)/step)); i++)
316 {
317 const Float_t x = klo + step*(i+1);
318 //const Float_t y = Eval(klo, x);
319 const Float_t y = Eval(klo, x-klo);
320 if (y > max)
321 {
322 max = y;
323 maxpos = x;
324 }
325 }
326 }
327
328 //
329 // Now, the time, abmax and khicont and klocont are set correctly within the previous precision.
330 // Try a better precision.
331 //
332 const Float_t up = maxpos+step - 3.0*fResolution;
333 const Float_t lo = maxpos-step + 3.0*fResolution;
334 const Float_t abmaxpos = maxpos;
335
336 step = 2.*fResolution; // step size of 0.1 FADC slices
337
338 for (int i=0; i<TMath::Nint(TMath::Ceil((up-abmaxpos)/step)); i++)
339 {
340 const Float_t x = abmaxpos + (i+1)*step;
341 //const Float_t y = Eval(klo, x);
342 const Float_t y = Eval(klo, x-klo);
343 if (y > max)
344 {
345 max = y;
346 maxpos = x;
347 }
348 }
349
350 //
351 // Second, try from time down to time-0.2 in steps of fResolution.
352 //
353
354 //
355 // Test the possibility that the absolute maximum has not been found between
356 // maxpos and maxpos+0.05, then we have to look between maxpos-0.05 and maxpos
357 // which requires new setting of klocont and khicont
358 //
359 if (abmaxpos < klo + fResolution)
360 klo--;
361
362 for (int i=TMath::Nint(TMath::Ceil((abmaxpos-lo)/step))-1; i>=0; i--)
363 {
364 const Float_t x = abmaxpos - (i+1)*step;
365 //const Float_t y = Eval(klo, x);
366 const Float_t y = Eval(klo, x-klo);
367 if (y > max)
368 {
369 max = y;
370 maxpos = x;
371 }
372 }
373
374 fTime = maxpos;
375 fTimeDev = fResolution;
376 fSignal = CalcIntegral(maxpos);
377 fSignalDev = 0; // means: is valid
378
379 return;
380*/
381 // --- Start NEW ---
382
383 // This block extracts values very similar to the old algorithm...
384 // for max>10
385 /* Most accurate (old identical) version:
386
387 Float_t xmax=maxpos, ymax=Eval(maxpos-1, 1);
388 Int_t rc = GetMaxPos(maxpos-1, xmax, ymax);
389 if (xmax==maxpos)
390 {
391 GetMaxPos(maxpos, xmax, ymax);
392
393 Float_t y = Eval(maxpos, 1);
394 if (y>ymax)
395 {
396 ymax = y;
397 xmax = maxpos+1;
398 }
399 }*/
400
401 Float_t maxpos;
402 // FIXME: Check the default if no maximum found!!!
403 GetMaxAroundI(maxbin, maxpos, fHeight);
404
405 // --- End NEW ---
406
407 if (fExtractionType == kAmplitude)
408 {
409 fTime = maxpos;
410 fTimeDev = 0;
411 fSignal = fHeight;
412 fSignalDev = 0; // means: is valid
413 return;
414 }
415
416 fSignal = CalcIntegral(maxpos);
417 fSignalDev = 0; // means: is valid
418
419 if (fExtractionType==kIntegralRel && fHeightTm<0)
420 {
421 fTime = maxpos;
422 fTimeDev = 0;
423 return;
424 }
425
426 const Float_t h = fExtractionType==kIntegralAbs ? fHeightTm : fHeight*fHeightTm;
427
428 // Search downwards for fHeight/2
429 // By doing also a search upwards we could extract the pulse width
430 fTime = SearchY(maxpos, h);
431 fTimeDev = 0;
432 if (width)
433 {
434 fWidth = SearchYup(maxpos, h)-fTime;
435 fWidthDev = 0;
436 }
437
438 //
439 // Loop from the beginning of the slice upwards to reach the maxhalf:
440 // With means of bisection:
441 //
442 /*
443 static const Float_t sqrt2 = TMath::Sqrt(2.);
444
445 step = sqrt2*3*0.061;//fRiseTime;
446 Float_t x = maxpos-0.86-3*0.061;//fRiseTime*1.25;
447
448// step = sqrt2*0.5;//fRiseTime;
449// Float_t x = maxpos-1.25;//fRiseTime*1.25;
450
451 Int_t cnt =0;
452 while (cnt++<30)
453 {
454 const Float_t y=EvalAt(x);
455
456 if (TMath::Abs(y-maxval/2)<fResolution)
457 break;
458
459 step /= sqrt2; // /2
460 x += y>maxval/2 ? -step : +step;
461 }
462 */
463
464 //
465 // Now integrate the whole thing!
466 //
467 // fTime = cnt==31 ? -1 : x;
468 // fTimeDev = fResolution;
469 // fSignal = cnt==31 ? CalcIntegral(x) : CalcIntegral(maxpos);
470 // fSignalDev = 0; // means: is valid
471}
Note: See TracBrowser for help on using the repository browser.