CFEL - ASG Software Suite  2.5.0
CASS
helperfunctionsforstdc.hpp
Go to the documentation of this file.
1 // Copyright (C) 2009,2010 Lutz Foucar
2 
3 /**
4  * @file helperfunctionsforstdc.hpp file contains functions that help analysing
5  * an acqiris waveform
6  *
7  * @author Lutz Foucar
8  */
9 
10 #ifndef _HELPERFUNCTIONS_H_
11 #define _HELPERFUNCTIONS_H_
12 
13 
14 #include <iostream>
15 #include <cmath>
16 #include <cstdlib>
17 #include <sstream>
18 
19 #include "channel.hpp"
20 #include "cass_event.h"
21 #include "acqiris_device.hpp"
22 #include "signal_producer.h"
23 
24 namespace cass
25 {
26 namespace ACQIRIS
27 {
28 /** extracts the requested channel from the data
29  *
30  * @note this function is just a template function because the compiler
31  * will give errors when its a regular function. This can be avoided
32  * by making this a functor struct or class.
33  *
34  * retrieve the Acqiris device from the CASSEvent. Then check if the device
35  * contains the requested instruemnt. If not throw an invalid_argument
36  * exception.\n
37  * If the requested instruement exists, check if it contains the requested
38  * channelnumber by checking how many channels it has. If it contains the
39  * channel return a pointer to it. If the channel number is bigger than the
40  * number of channels in the instrument, throw an invalid_argument exception.
41  *
42  * @return const pointer to the channel we need to extract
43  * @param evt the CASSEvent wich contains the channel we want to extract
44  * @param instrument the instrument that contains the channel
45  * @param ChannelNumber the channel number of the requested channel
46  *
47  * @author Lutz Foucar
48  */
49 template <typename T>
51  const uint32_t instrument,
52  const size_t& ChannelNumber)
53 {
54  using namespace std;
55  const Device &device
56  (dynamic_cast<const ACQIRIS::Device&>(*(evt.devices().find(CASSEvent::Acqiris)->second)));
57  ACQIRIS::Device::instruments_t::const_iterator instrumentIt
58  (device.instruments().find(instrument));
59  if (instrumentIt == device.instruments().end())
60  throw invalid_argument("extactRightChannel(): The requested Instrument '" +
61  toString(instrument) + "' is not in the datastream");
62  const ACQIRIS::Instrument::channels_t &instrumentChannels
63  (instrumentIt->second.channels());
64  if ((ChannelNumber >= instrumentChannels.size()))
65  throw invalid_argument("extactRightChannel(): The requested channel '" +
66  toString(ChannelNumber) +"' does not exist in Instrument '" +
67  toString(instrument) + "'");
68  return &(instrumentChannels[ChannelNumber]);
69 }
70 
71 /** linear Regression
72  *
73  * this function creates a linear regression through a given amount of points
74  * getting a line that follows the form: \f$y(x) = m*x + c\f$
75  * it will calculate the slope m and the constant c of the line
76  *
77  * @param[in] nbrPoints the number of points for the regression
78  * @param[in] x array of the x-values of the points
79  * @param[in] y array of the y-values of the points
80  * @param[out] m the slope of the line
81  * @param[out] c the constant of the line (y value where it crosses the x-axis)
82  *
83  * @author Lutz Foucar
84  */
85 template <typename T>
86 void linearRegression(const size_t nbrPoints, const double x[], const double y[], double &m, double &c)
87 {
88  double SumXsq=0.,SumX=0.,SumY=0.,SumXY=0.;
89  for (size_t i=0;i<nbrPoints;++i)
90  {
91  SumX += x[i];
92  SumY += y[i];
93  SumXY += (x[i]*y[i]);
94  SumXsq += (x[i]*x[i]);
95  }
96 
97  double a1 = ((SumX*SumX) - (nbrPoints*SumXsq));
98 
99  m = ((SumX*SumY) - (nbrPoints*SumXY)) / a1;
100  c = ((SumX*SumXY) - (SumY*SumXsq)) / a1;
101 }
102 
103 /** A weighted linear Regression
104  *
105  * this function creates a weighted linear regression through a given amount of points
106  * where we give a weight to the points that are farther away from the wanted x point
107  * We will be getting a line that follows the form: \f$y(x) = m*x + c\f$
108  * it will calculate the slope m and the constant c of the line
109  *
110  * @param[in] nbrPoints the number of points for the regression
111  * @param[in] x array of the x-values of the points
112  * @param[in] y array of the y-values of the points
113  * @param[in] correctX the point where we calculate the distance from
114  * @param[out] m the slope of the line
115  * @param[out] c the constant of the line (y value where it crosses the x-axis)
116  *
117  * @author Lutz Foucar
118  */
119 template<typename T>
120 void gewichtetlinearRegression(const size_t nbrPoints, const double x[], const double y[], const double correctX, double &m, double &c)
121 {
122  double SumXsq=0.,SumX=0.,SumY=0.,SumXY=0.,SumWeight=0.;
123  for (size_t i=0;i<nbrPoints;++i)
124  {
125  double weight = (fabs(x[i]-correctX) > 1e-10) ? 1./fabs(x[i]-correctX): 100.;
126  SumWeight += weight;
127  SumX += (x[i]*weight);
128  SumY += (y[i]*weight);
129  SumXY += (x[i]*y[i]*weight);
130  SumXsq += (x[i]*x[i]*weight);
131  }
132 
133  double a1 = ((SumX*SumX) - (SumWeight*SumXsq));
134 
135  m = ((SumX*SumY) - (SumWeight*SumXY)) / a1;
136  c = ((SumX*SumXY) - (SumY*SumXsq)) / a1;
137 }
138 
139 
140 
141 /** create Newton Polynomial
142  *
143  * This function creates the coefficients for Newton interpolating Polynomials.
144  * Newton Polynomials are created from n Points and have the form
145  * \f$p(x) = c_0 + c_1(x-x_0) + c_2(x-x_0)(x-x_1)+...+c_{n-1}(x-x_0)(x-x_1)...(x-x_{n-2})\f$
146  * given that you have n Points
147  * \f$(x_0,y_0), (x_1,y_1), ..., (x_{n-1},y_{n-1})\f$
148  * Here we do it for 4 Points.
149  *
150  * @param[in] x the x-values of the points
151  * @param[in] y the y-values of the points
152  * @param[out] coeff the coefficients of the newton polynomial
153  * @return void
154  *
155  * @author Lutz Foucar
156  */
157 template <typename T>
158 void createNewtonPolynomial(const double * x, const double * y, double * coeff)
159 {
160  double f_x0_x1 = (y[1]-y[0]) / (x[1]-x[0]);
161  double f_x1_x2 = (y[2]-y[1]) / (x[2]-x[1]);
162  double f_x2_x3 = (y[3]-y[2]) / (x[3]-x[2]);
163 
164  double f_x0_x1_x2 = (f_x1_x2 - f_x0_x1) / (x[2]-x[0]);
165  double f_x1_x2_x3 = (f_x2_x3 - f_x1_x2) / (x[3]-x[1]);
166 
167  double f_x0_x1_x2_x3 = (f_x1_x2_x3 - f_x0_x1_x2) / (x[3]-x[0]);
168 
169  coeff[0] = y[0];
170  coeff[1] = f_x0_x1;
171  coeff[2] = f_x0_x1_x2;
172  coeff[3] = f_x0_x1_x2_x3;
173 }
174 
175 /** evaluate Newton Polynomial
176  *
177  * this function evaluates the Newton Polynomial that was created from n Points
178  * \f$(x_0,y_0),..., (x_{n-1},y_{n-1}) with coefficients (c_0,...,c_{n-1})\f$
179  * using Horner's Rule. This is done for an polynomial with 4 entries
180  *
181  * @param[in] x array of x values
182  * @param[in] coeff array of coefficients
183  * @param[in] X
184  * @return the newton polynomial
185  *
186  * @author Lutz Foucar
187  */
188 template <typename T>
189 double evalNewtonPolynomial(const double * x, const double * coeff, double X)
190 {
191  double returnValue = coeff[3];
192  returnValue = returnValue * (X - x[2]) + coeff[2];
193  returnValue = returnValue * (X - x[1]) + coeff[1];
194  returnValue = returnValue * (X - x[0]) + coeff[0];
195 
196  return returnValue;
197 }
198 
199 /** Achims Numerical Approximation
200  *
201  * this function should find x value corrosponding to a given y value
202  * in a newton polynomial. It does it the following way:
203  * -# create a lower and upper boundary point
204  * -# create an interating x-value and initialize it with the Start value
205  * -# evaluate the y-value at the x-value
206  * -# if the y value is bigger than the requested value the start point
207  * is defines the new upper or lower boundary depending on the slope.
208  * -# the new x-point is defined by the arithmetic mean between the tow
209  * boundary points.
210  * -# do points 3-5 until the new x-value does not differ more than 0.005
211  * from the old one.
212  *
213  *@param[in] x two points describing upper and lower boundaries
214  *@param[in] coeff the newton polynomial coefficents
215  *@param[in] Y the requested y-values to find the x-value for
216  *@param[in] Start the x-value we start the search with
217  *
218  *@author Lutz Foucar
219  */
220 template <typename T>
221 double findXForGivenY(const double * x, const double * coeff, const double Y, const double Start)
222 {
223  //a point is a pair of doubles//
224  typedef std::pair<double,double> punkt_t;
225  //initialisiere die Grenzen//
226  punkt_t Low(x[1], evalNewtonPolynomial<T>(x,coeff,x[1]));
227  punkt_t Up (x[2], evalNewtonPolynomial<T>(x,coeff,x[2]));
228 
229  //initialisiere den iterierenden Punkt mit dem Startwert//
230  punkt_t p (Start, evalNewtonPolynomial<T>(x,coeff,Start));
231 
232  //ist der Startpunkt schon der richtige Punkt//
233  //liefere den dazugehoerigen x-Wert zurueck//
234  if (p.second == Y)
235  return p.first;
236 
237  //finde heraus ob es ein positiver oder ein negativer Durchgang ist//
238  bool Neg = (Low.second > Up.second)?true:false;
239 
240  //der Startpunkt soll die richtige neue Grenze bilden//
241  if (Neg) //wenn es ein negativer Druchgang ist
242  {
243  if (p.second > Y) //ist der y-Wert groesser als der gewollte
244  Low = p; //bildet der Punkt die neue untere Grenze
245  else if (p.second < Y) //ist der y-Wert ist kleiner als der gewollte
246  Up = p; //bildet der Punkt die neue obere Grenze
247  else //ist der Punkt genau getroffen
248  return p.first; //liefer den dazugehoerigen x-Wert zurueck
249  }
250  else //wenn es ein positiver Druchgang ist
251  {
252  if (p.second > Y) //und der y-Wert groesser als der gewollte
253  Up = p; //bildet der Punkt die neue obere Grenze
254  else if (p.second < Y) //und y-Wert ist kleiner als der gewollte
255  Low = p; //bildet der Punkt die neue untere Grenze
256  else //ist der Punkt genau getroffen
257  return p.first; //liefer den dazugehoerigen x-Wert zurueck
258  }
259 
260  //iteriere solange bis der Abstand zwischen den x-Werten kleiner als 0.005
261  while((Up.first-Low.first) > 0.005)
262  {
263  //bilde das arithmetische Mittel zwischen beiden Grenzen//
264  //das ist der neue x-Wert unseres Punktes//
265  p.first = 0.5 * (Up.first+Low.first);
266  //finde den dazugehoerigen y-Wert//
267  p.second = evalNewtonPolynomial<T>(x,coeff,p.first);
268 
269  if (Neg) //wenn es ein negativer Druchgang ist
270  {
271  if (p.second > Y) //und der y-Wert groesser als der gewollte
272  Low = p; //bildet der Punkt die neue untere Grenze
273  else if (p.second < Y) //und der y-Wert ist kleiner als der gewollte
274  Up = p; //bildet der Punkt die neue obere Grenze
275  else //ist der Punkt genau getroffen
276  return p.first; //liefer den dazugehoerigen x-Wert zurueck
277  }
278  else //wenn es ein positiver Druchgang ist
279  {
280  if (p.second > Y) //und der y-Wert groesser als der gewollte
281  Up = p; //bildet der Punkt die neue obere Grenze
282  else if (p.second < Y) //und y-Wert ist kleiner als der gewollte
283  Low = p; //bildet der Punkt die neue untere Grenze
284  else //ist der Punkt genau getroffen
285  return p.first; //liefer den dazugehoerigen x-Wert zurueck
286  }
287  // std::cout<<"("<<Low.x<<","<<Low.y<<") ("<<p.x<<","<<p.y<<") ("<<Up.x<<","<<Up.y<<") "<<Y<<std::endl;
288  }
289  //ist der gewuenschte Abstand zwischen den x-Werten erreicht
290  //liefere das arithmetische mittel zwischen beiden zurueck
291  return ((Up.first + Low.first)*0.5);
292 }
293 
294 /** extract full width at half maximum (fwhm)
295  *
296  * @param[in] c the channel that the peak is found in
297  * @param[in,out] s the peak that we found
298  * @param thresh unused
299  *
300  * @author Lutz Foucar
301  */
302 template <typename T>
303 void getfwhm(const Channel &c, SignalProducer::signal_t &s, const double& /*thresh*/)
304 {
305  const Channel::waveform_t Data (c.waveform());
306  const double vGain (c.gain());
307  const int32_t vOff (static_cast<int32_t>(c.offset() / vGain)); //mV -> adc bytes
308  const size_t wLength (c.waveform().size());
309  const int maxposval (static_cast<int>(s[maxpos]+0.1));
310 
311  //--get peak fwhm--//
312  size_t fwhm_l = 0;
313  size_t fwhm_r = 0;
314  const double HalfMax = 0.5*s[maximum];
315 
316  //--go from middle to left until 0.5*height find first point that is above 0.5 height--//
317  for (int i(maxposval); i>=0; --i)
318  {
319  if (abs(Data[i]-vOff) < HalfMax)
320  {
321  fwhm_l = i+1;
322  break;
323  }
324  }
325 
326  //--go from middle to right until 0.5*height (find last point that is still above 0.5 Height--//
327  for (size_t i(maxposval); i<wLength;++i)
328  {
329  if (abs(Data[i]-vOff) < HalfMax)
330  {
331  fwhm_r = i-1;
332  break;
333  }
334  }
335 
336  //--if we found a right side and a left side, then--//
337  //--compute the fwhm with a linear interpolation--//
338  //--between the points that are left and right from--//
339  //--where the fwhm is, else return here--//
340  if (!fwhm_r || !fwhm_l)
341  return;
342 
343  double lx[4];
344  double ly[4];
345  lx[0] = fwhm_l-2; ly[0] = abs(Data[fwhm_l-2]-vOff);
346  lx[1] = fwhm_l-1; ly[1] = abs(Data[fwhm_l-1]-vOff);
347  lx[2] = fwhm_l-0; ly[2] = abs(Data[fwhm_l-0]-vOff);
348  lx[3] = fwhm_l+1; ly[3] = abs(Data[fwhm_l+1]-vOff);
349 
350  double rx[4];
351  double ry[4];
352  rx[0] = fwhm_r-1; ry[0] = abs(Data[fwhm_r-1]-vOff);
353  rx[1] = fwhm_r-0; ry[1] = abs(Data[fwhm_r-0]-vOff);
354  rx[2] = fwhm_r+1; ry[2] = abs(Data[fwhm_r+1]-vOff);
355  rx[3] = fwhm_r+2; ry[3] = abs(Data[fwhm_r+2]-vOff);
356 
357  double mLeft,cLeft,mRight,cRight;
358  linearRegression<T>(4,lx,ly,mLeft,cLeft);
359  linearRegression<T>(4,rx,ry,mRight,cRight);
360 
361  //y = m*x+c => x = (y-c)/m;
362  const double fwhm_L = (HalfMax-cLeft)/mLeft;
363  const double fwhm_R = (HalfMax-cRight)/mRight;
364 
365  //--set all found parameters--//
366  s[fwhm] = fwhm_R-fwhm_L;
367  /** @todo make the below an own function*/
368  s[width] = s[stoppos] - s[startpos];
369 }
370 
371 
372 // //_________________extract the voltage of a channel______________________________________________________________________________________________________________
373 // template <typename T>
374 // void extractVoltage(const MyOriginalChannel &oc, const MyPuls &p, const MyChannelSection &cs, MySignalAnalyzedChannel &sac)
375 // {
376 // double volt = 0;
377 // int count = 0;
378 // const double gain = oc.GetVertGain();
379 // const double offset = oc.GetOffset();
380 // const T *d = static_cast<const T*>(oc.GetDataPointerForPuls(p));
381 //
382 // for (int j=10;j<p.GetLength()-10;++j)
383 // {
384 // volt += (d[j]*gain)-offset;
385 // ++count;
386 // }
387 // volt /= count;
388 //
389 // sac.AddVoltage(volt,cs.GetChannelSectionNbr());
390 // }
391 
392 /** Center of Mass
393  *
394  * find the center of mass of the peak by calculating also the integral of the
395  * peak.
396  *
397  * @param[in] c the channel the peak was found in
398  * @param[in,out] s the peak
399  * @param[in] thresh the threshold that we used to identify the signal in V
400  *
401  * @author Lutz Foucar
402  */
403 template <typename T>
404 void CoM(const Channel &c, SignalProducer::signal_t &s, const double& thresh)
405 {
406  //get informations from the event and the channel//
407  const Channel::waveform_t Data (c.waveform());
408  const double vGain (c.gain());
409  const int32_t vOff (static_cast<int32_t>(c.offset() / vGain));
410  const double horpos (c.horpos()*1.e9); //s -> ns
411  const double sampleInterval (c.sampleInterval()*1e9); //s -> ns
412  const int32_t threshold (static_cast<int32_t>(thresh/vGain));
413 
414  //--this function goes through the puls from start to stop and finds the center of mass--//
415  double &integralval (s[integral]);
416  double wichtung (0);
417  const size_t start (static_cast<size_t>(s[startpos]+0.1));
418  const size_t stop (static_cast<size_t>(s[stoppos]+0.1));
419 
420  for (size_t i = start; i<=stop;++i)
421  {
422  integralval += (abs(Data[i]-vOff)-threshold); //calc integral
423  wichtung += ((abs(Data[i]-vOff)-threshold)*i); //calc weight
424  }
425  s[com] = (wichtung/integralval + horpos)*sampleInterval;
426 }
427 
428 
429 
430 /** find start and stop of pulse
431  *
432  * this function will find the start and the stop of the signal
433  *
434  * @param[in] c the channel the signal was found in
435  * @param[in,out] s the signal
436  * @param[in] thresh the threshold that we used to identify the signal in V
437  * @author Lutz Foucar
438  */
439 template <typename T>
440 void startstop(const Channel &c, SignalProducer::signal_t &s, const double& thresh)
441 {
442  const Channel::waveform_t Data (c.waveform());
443  const double vGain (c.gain());
444  const int32_t vOff (static_cast<int32_t>(c.offset()/vGain));
445  const int32_t wLength (c.waveform().size());
446  const double sampInt (c.sampleInterval()*1e9);
447  const double horpos (c.horpos()*1e9);
448  const int32_t threshold (static_cast<int32_t>(thresh/vGain));
449 
450 
451  //calculate the center of peak is in the waveform coodinates//
452  const int32_t center (static_cast<int32_t>((s[time]/sampInt - horpos)+0.1));
453 
454  //go left from center until either i == 0, or the datapoint is inside the noise
455  //or we go from the previous one (i+1) to the actual one (i) through the baseline
456  int i=0;
457  for (i = center; i>=0; --i)
458  if ((abs(Data[i]-vOff) < threshold) || (((Data[i]-vOff) * (Data[i+1]-vOff)) < 0) )
459  break;
460  s[startpos] = i;
461 
462  //go right form center until either i < pulslength, or the datapoint is inside the noise
463  //or we go from the previous one (i-1) to the actual one (i) through the baseline
464  for (i = center; i< wLength; ++i)
465  if ((abs(Data[i]-vOff) < threshold) || (((Data[i]-vOff) * (Data[i-1]-vOff)) < 0) )
466  break;
467  s[stoppos] = i;
468 }
469 
470 
471 /** find Maximum of puls and calcs the height
472  *
473  * this function will find the maximum of the peak and its position
474  *
475  * @param[in] c the channel the peak was found in
476  * @param[in,out] s the peak
477  * @param thresh unused
478  *
479  * @author Lutz Foucar
480  */
481 template <typename T>
482 void getmaximum(const Channel &c, SignalProducer::signal_t &s, const double& /*thresh*/)
483 {
484  const Channel::waveform_t Data (c.waveform());
485  const double vGain (c.gain());
486  const int32_t vOff (static_cast<int32_t>(c.offset()/vGain));
487 
488  const size_t start (static_cast<size_t>(s[startpos]+0.1));
489  const size_t stop (static_cast<size_t>(s[stoppos]+0.1));
490  double& maximumval (s[maximum]);
491  double& maxposval (s[maxpos]);
492 
493  maximumval = 0;
494  for (size_t i(start); i<=stop;++i)
495  {
496  if (abs(Data[i]-vOff) > maximumval)
497  {
498  maximumval = abs(Data[i]-vOff);
499  maxposval = i;
500  }
501  }
502  /** @todo make the below an own function */
503  s[height] = maximumval * vGain; //this will set the height in mV
504 }
505 
506 
507 
508 
509 }//end namespace acqiris
510 }//end namespace cass
511 
512 #endif
std::vector< int16_t > waveform_t
define the waveform
Definition: channel.hpp:35
Event to store all LCLS Data.
Definition: cass_event.h:32
double findXForGivenY(const double *x, const double *coeff, const double Y, const double Start)
Achims Numerical Approximation.
file contains the classes that describe how to analyze the waveform and stores the result...
waveform_t & waveform()
setter
Definition: channel.hpp:105
void gewichtetlinearRegression(const size_t nbrPoints, const double x[], const double y[], const double correctX, double &m, double &c)
A weighted linear Regression.
void startstop(const Channel &c, SignalProducer::signal_t &s, const double &thresh)
find start and stop of pulse
const Channel * extactRightChannel(const CASSEvent &evt, const uint32_t instrument, const size_t &ChannelNumber)
extracts the requested channel from the data
file contains declaration of the CASSEvent
file contains the classes that describe an acqiris channel
STL namespace.
double & sampleInterval()
setter
Definition: channel.hpp:103
void createNewtonPolynomial(const double *x, const double *y, double *coeff)
create Newton Polynomial
The Acqiris device.
std::vector< double > signal_t
devices_t & devices()
setters
Definition: cass_event.h:66
Binary function for thresholding.
double evalNewtonPolynomial(const double *x, const double *coeff, double X)
evaluate Newton Polynomial
void linearRegression(const size_t nbrPoints, const double x[], const double y[], double &m, double &c)
linear Regression
double & horpos()
setter
Definition: channel.hpp:101
file contains the declaration of the acqiris part of the CASSEvent
std::string toString(const Type &t)
convert any type to a string
Definition: cass.h:63
double & offset()
setter
Definition: channel.hpp:102
void getmaximum(const Channel &c, SignalProducer::signal_t &s, const double &)
find Maximum of puls and calcs the height
A Channel of an Acqiris Instrument.
Definition: channel.hpp:31
void getfwhm(const Channel &c, SignalProducer::signal_t &s, const double &)
extract full width at half maximum (fwhm)
std::vector< Channel > channels_t
a vector of Channels
double & gain()
setter
Definition: channel.hpp:104
void CoM(const Channel &c, SignalProducer::signal_t &s, const double &thresh)
Center of Mass.