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

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