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

Last change on this file since 8955 was 8795, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 8.4 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-2007
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#include "../mbase/MArrayF.h"
56
57using namespace std;
58
59// --------------------------------------------------------------------------
60//
61// Calculate the first and second derivative for the splie.
62//
63// The coefficients are calculated such that
64// 1) fVal[i] = Eval(i, 0)
65// 2) Eval(i-1, 1)==Eval(i, 0)
66//
67// In other words: The values with the index i describe the spline
68// between fVal[i] and fVal[i+1]
69//
70void MExtralgoSpline::InitDerivatives() const
71{
72 if (fNum<2)
73 return;
74
75 // Look up table for coefficients
76 static MArrayF lut;
77
78 // If the lut is not yet large enough: resize and reclaculate
79 if (fNum>(Int_t)lut.GetSize())
80 {
81 lut.Set(fNum);
82
83 lut[0] = 0.;
84 for (Int_t i=1; i<fNum-1; i++)
85 lut[i] = -1.0/(lut[i-1] + 4);
86 }
87
88 // Calculate the coefficients used to get reproduce the first and
89 // second derivative.
90 fDer1[0] = 0.;
91 for (Int_t i=1; i<fNum-1; i++)
92 {
93 const Float_t d1 = fVal[i+1] - 2*fVal[i] + fVal[i-1];
94 fDer1[i] = (fDer1[i-1]-d1)*lut[i];
95 }
96
97 fDer2[fNum-1] = 0.;
98 for (Int_t k=fNum-2; k>=0; k--)
99 fDer2[k] = lut[k]*fDer2[k+1] + fDer1[k];
100}
101
102// --------------------------------------------------------------------------
103//
104// Return the two results x1 and x2 of f'(x)=0 for the third order
105// polynomial (spline) in the interval i. Return the number of results.
106// (0 if the fist derivative does not have a null-point)
107//
108Int_t MExtralgoSpline::EvalDerivEq0(const Int_t i, Double_t &x1, Double_t &x2) const
109{
110 const Double_t difder = fDer2[i+1]-fDer2[i];
111 const Double_t difval = fVal[i+1] -fVal[i];
112
113 return MMath::SolvePol2(3*difder, 6*fDer2[i], difval-2*fDer2[i]-fDer2[i+1], x1, x2);
114}
115
116// --------------------------------------------------------------------------
117//
118// Returns the highest x value in [min;max[ at which the spline in
119// the bin i is equal to y
120//
121// min and max are defined to be [0;1]
122//
123// The default for min is 0, the default for max is 1
124// The defaule for y is 0
125//
126Double_t MExtralgoSpline::FindY(Int_t i, Bool_t downwards, Double_t y, Double_t min, Double_t max) const
127{
128 // y = a*x^3 + b*x^2 + c*x + d'
129 // 0 = a*x^3 + b*x^2 + c*x + d' - y
130
131 // Calculate coefficients
132 const Double_t a = fDer2[i+1]-fDer2[i];
133 const Double_t b = 3*fDer2[i];
134 const Double_t c = fVal[i+1]-fVal[i] -2*fDer2[i]-fDer2[i+1];
135 const Double_t d = fVal[i] - y;
136
137 // If the first derivative is nowhere==0 and it is increasing
138 // in one point, and the value we search is outside of the
139 // y-interval... it cannot be there
140 // if (c>0 && (d>0 || fVal[i+1]<y) && b*b<3*c*a)
141 // return -2;
142
143 Double_t x1, x2, x3;
144 const Int_t rc = MMath::SolvePol3(a, b, c, d, x1, x2, x3);
145
146 if (downwards==kTRUE)
147 {
148 Double_t x = -1;
149
150 if (rc>0 && x1>=min && x1<max && x1>x)
151 x = x1;
152 if (rc>1 && x2>=min && x2<max && x2>x)
153 x = x2;
154 if (rc>2 && x3>=min && x3<max && x3>x)
155 x = x3;
156
157 return x<0 ? -2 : x+i;
158 }
159 else
160 {
161 Double_t x = 2;
162
163 if (rc>0 && x1>min && x1<=max && x1<x)
164 x = x1;
165 if (rc>1 && x2>min && x2<=max && x2<x)
166 x = x2;
167 if (rc>2 && x3>min && x3<=max && x3<x)
168 x = x3;
169
170 return x>1 ? -2 : x+i;
171 }
172
173 return -2;
174}
175
176// --------------------------------------------------------------------------
177//
178// Search analytically downward for the value y of the spline, starting
179// at x, until x==0. If y is not found -2 is returned.
180//
181Double_t MExtralgoSpline::SearchY(Float_t x, Float_t y) const
182{
183 if (x>=fNum-1)
184 x = fNum-1.0001;
185
186 Int_t i = TMath::FloorNint(x);
187 Double_t rc = FindY(i, kTRUE, y, 0, x-i);
188 while (--i>=0 && rc<0)
189 rc = FindY(i, kTRUE, y);
190
191 return rc;
192}
193
194Double_t MExtralgoSpline::SearchYup(Float_t x, Float_t y) const
195{
196 if (x<0)
197 x = 0.0001;
198
199 Int_t i = TMath::FloorNint(x);
200 Double_t rc = FindY(i, kFALSE, y, x-i, 1.);
201 while (i++<fNum-1 && rc<0)
202 rc = FindY(i, kFALSE, y);
203
204 return rc;
205}
206
207// --------------------------------------------------------------------------
208//
209// Do a range check an then calculate the integral from start-fRiseTime
210// to start+fFallTime. An extrapolation of 0.5 slices is allowed.
211//
212Float_t MExtralgoSpline::CalcIntegral(Float_t pos) const
213{
214 // In the future we will calculate the intgeral analytically.
215 // It has been tested that it gives identical results within
216 // acceptable differences.
217
218 // We allow extrapolation of 1/2 slice.
219 const Float_t min = fRiseTime; //-0.5+fRiseTime;
220 const Float_t max = fNum-1-fFallTime; //fNum-0.5+fFallTime;
221
222 if (pos<min)
223 pos = min;
224 if (pos>max)
225 pos = max;
226
227 return EvalInteg(pos-fRiseTime, pos+fFallTime);
228}
229
230Float_t MExtralgoSpline::ExtractNoise()
231{
232 if (fNum<5)
233 return 0;
234
235 if (fExtractionType == kAmplitude)
236 {
237 const Int_t pos = gRandom->Integer(fNum-1);
238 const Float_t nsx = gRandom->Uniform();
239 return Eval(pos, nsx);
240 }
241 else
242 {
243 const Float_t pos = gRandom->Uniform(fNum-1-fRiseTime-fFallTime)+fRiseTime;
244 return CalcIntegral(pos);
245 }
246}
247
248void MExtralgoSpline::Extract(Int_t maxbin, Bool_t width)
249{
250 fSignal = 0;
251 fTime = 0;
252 fWidth = 0;
253 fSignalDev = -1;
254 fTimeDev = -1;
255 fWidthDev = -1;
256
257 if (fNum<2)
258 return;
259
260 Float_t maxpos;
261 // FIXME: Check the default if no maximum found!!!
262 GetMaxAroundI(maxbin, maxpos, fHeight);
263
264 // --- End NEW ---
265
266 if (fExtractionType == kAmplitude)
267 {
268 fTime = maxpos;
269 fTimeDev = 0;
270 fSignal = fHeight;
271 fSignalDev = 0; // means: is valid
272 return;
273 }
274
275 fSignal = CalcIntegral(maxpos);
276 fSignalDev = 0; // means: is valid
277
278 if (fExtractionType==kIntegralRel && fHeightTm<0)
279 {
280 fTime = maxpos;
281 fTimeDev = 0;
282 return;
283 }
284
285 const Float_t h = fExtractionType==kIntegralAbs ? fHeightTm : fHeight*fHeightTm;
286
287 // Search downwards for fHeight/2
288 // By doing also a search upwards we could extract the pulse width
289 fTime = SearchY(maxpos, h);
290 fTimeDev = 0;
291 if (width)
292 {
293 fWidth = SearchYup(maxpos, h)-fTime;
294 fWidthDev = 0;
295 }
296}
Note: See TracBrowser for help on using the repository browser.