CFEL - ASG Software Suite  2.5.0
CASS
cfd.cpp
Go to the documentation of this file.
1 //Copyright (C) 2003-2010 Lutz Foucar
2 
3 /**
4  * @file cfd.cpp file contains definition of class that does a constant fraction
5  * descrimination like analysis of a waveform
6  *
7  * @author Lutz Foucar
8  */
9 
10 #include <typeinfo>
11 #include <cmath>
12 #include <limits>
13 
14 #include "cfd.h"
15 
16 #include "channel.hpp"
17 #include "cass_event.h"
18 #include "cass_settings.h"
20 
21 using namespace cass::ACQIRIS;
22 namespace cass
23 {
24 namespace ACQIRIS
25 {
26 namespace ConstantFraction
27 {
28 /** Implematation of Constant Fraction Method
29  *
30  * The CFD calculates a second trace from the original trace, where two
31  * points of the original create one point of the cfd trace
32  * \f[new_x = -orig_x*fraction + orig_x-delay \f]
33  * It will then find where the new trace will cross the walk value where
34  * this point defines the time.
35  *
36  * @tparam T type of a wavform point
37  * @param[in] c the channel that contains the waveform to analyze
38  * @param[in] param the user defined parameters for extracting signal in the
39  * waveform
40  * @param[out] sig the container with all the found signals
41  *
42  * @author Lutz Foucar
43  */
44 template <typename T>
45 void getcfd(const Channel& c, const CFDParameters &param, SignalProducer::signals_t& sig)
46 {
47  using namespace cass::ACQIRIS;
48  //make sure that we are the right one for the waveform_t//
49  assert(typeid(Channel::waveform_t::value_type) == typeid(T));
50 
51  //now extract information from the Channel
52  const double sampleInterval = c.sampleInterval()*1e9; //convert the s to ns
53  const double horpos = c.horpos()*1.e9;
54  const double vGain = c.gain();
55  const int32_t vOff = static_cast<int32_t>(c.offset() / vGain); //V -> ADC Bytes
56 
57  const int32_t idxToFiPoint = 0;
58  const Channel::waveform_t Data = c.waveform();
59  const size_t wLength = c.waveform().size();
60 
61  //--get the right cfd settings--//
62  const int32_t delay = static_cast<int32_t>(param._delay / sampleInterval); //ns -> sampleinterval units
63  const double walk = param._walk / vGain; //V -> ADC Bytes
64  const double threshold = param._threshold / vGain; //V -> ADC Bytes
65  const double fraction = param._fraction;
66 
67  //--go through the waveform--//
68  for (size_t i=delay+1; i<wLength-2;++i)
69  {
70  const double fx = Data[i] - static_cast<double>(vOff); //the original Point at i
71  const double fxd = Data[i-delay] - static_cast<double>(vOff); //the delayed Point at i
72  const double fsx = -fx*fraction + fxd; //the calculated CFPoint at i
73 
74  const double fx_1 = Data[i+1] - static_cast<double>(vOff); //original Point at i+1
75  const double fxd_1 = Data[i+1-delay] - static_cast<double>(vOff); //delayed Point at i+1
76  const double fsx_1 = -fx_1*fraction + fxd_1; //calculated CFPoint at i+1
77 
78  //check wether the criteria for a Peak are fullfilled
79  if (((fsx-walk) * (fsx_1-walk)) <= 0 ) //one point above one below the walk
80  if (fabs(fx) > threshold) //original point above the threshold
81  {
82  //--it could be that the first criteria is 0 because --//
83  //--one of the Constant Fraction Signal Points or both--//
84  //--are exactly where the walk is --//
85  if (fabs(fsx-fsx_1) < 1e-8) //both points are on the walk
86  {
87  //--go to next loop until at least one is over or under the walk--//
88  continue;
89  }
90  else if ((fsx-walk) == 0) //only first is on walk
91  {
92  //--Only the fist is on the walk, this is what we want--//
93  //--so:do nothing--//
94  }
95  else if ((fsx_1-walk) == 0) //only second is on walk
96  {
97  //--we want that the first point will be on the walk,--//
98  //--so in the next loop this point will be the first.--//
99  continue;
100  }
101  //does the peak have the right polarity?//
102  //if two pulses are close together then the cfsignal goes through the walk//
103  //three times, where only two crossings are good. So we need to check for//
104  //the one where it is not good//
105  if (fsx > fsx_1) //neg polarity
106  if (Data[i] > vOff) //but pos Puls .. skip
107  continue;
108  if (fsx < fsx_1) //pos polarity
109  if (Data[i] < vOff) //but neg Puls .. skip
110  continue;
111 
112 
113  //--later we need two more points, create them here--//
114  const double fx_m1 = Data[i-1] - static_cast<double>(vOff); //the original Point at i-1
115  const double fxd_m1 = Data[i-1-delay] - static_cast<double>(vOff); //the delayed Point at i-1
116  const double fsx_m1 = -fx_m1*fraction + fxd_m1; //the calculated CFPoint at i-1
117 
118  const double fx_2 = Data[i+2] - static_cast<double>(vOff); //original Point at i+2
119  const double fxd_2 = Data[i+2-delay] - static_cast<double>(vOff); //delayed Point at i+2
120  const double fsx_2 = -fx_2*fraction + fxd_2; //calculated CFPoint at i+2
121 
122 
123  //--find x with a linear interpolation between the two points--//
124  const double m = fsx_1-fsx; //(fsx-fsx_1)/(i-(i+1));
125  const double xLin = i + (walk - fsx)/m; //PSF fx = (x - i)*m + cfs[i]
126 
127  //--make a linear regression to find the slope of the leading edge--//
128  double mslope,cslope;
129  const double xslope[3] = {static_cast<double>(i-delay),
130  static_cast<double>(i+1-delay),
131  static_cast<double>(i+2-delay)};
132  const double yslope[3] = {fxd,fxd_1,fxd_2};
133  linearRegression<T>(3,xslope,yslope,mslope,cslope);
134 
135  //--find x with a cubic polynomial interpolation between four points--//
136  //--do this with the Newtons interpolation Polynomial--//
137  const double x[4] = {static_cast<double>(i-1),
138  static_cast<double>(i),
139  static_cast<double>(i+1),
140  static_cast<double>(i+2)}; //x vector
141  const double y[4] = {fsx_m1,fsx,fsx_1,fsx_2}; //y vector
142  double coeff[4] = {0,0,0,0}; //Newton coeff vector
143  createNewtonPolynomial<T>(x,y,coeff);
144 
145  //--numericaly solve the Newton Polynomial--//
146  //--give the lineare approach for x as Start Value--//
147  const double xPoly = cass::ACQIRIS::findXForGivenY<T>(x,coeff,walk,xLin);
148  const double pos = xPoly + static_cast<double>(idxToFiPoint) + horpos;
149 
150  //--create a new signal--//
152 
153  //add the info//
154  signal[time] = pos*sampleInterval;
155  signal[cfd] = pos*sampleInterval;
156  if (fsx > fsx_1) signal[polarity] = Negative;
157  if (fsx < fsx_1) signal[polarity] = Positive;
158  if (fabs(fsx-fsx_1) < std::sqrt(std::numeric_limits<double>::epsilon()))
159  signal[polarity] = Bad;
160 
161  //--start and stop of the puls--//
162  startstop<T>(c,signal,param._threshold);
163 
164  //--height of peak--//
165  getmaximum<T>(c,signal,param._threshold);
166 
167  //--width & fwhm of peak--//
168  getfwhm<T>(c,signal,param._threshold);
169 
170  //--the com and integral--//
171  CoM<T>(c,signal,param._threshold);
172 
173  //--add peak to signal if it fits the conditions--//
174  /** @todo make sure that is works right, since we get back a double */
175  if(fabs(signal[polarity]-param._polarity) < std::sqrt(std::numeric_limits<double>::epsilon())) //if it has the right polarity
176  {
177  for (CFDParameters::timeranges_t::const_iterator it (param._timeranges.begin());
178  it != param._timeranges.end();
179  ++it)
180  {
181  if(signal[time] > it->first && signal[time] < it->second) //if signal is in the right timerange
182  {
183  signal[isUsed] = false;
184  sig.push_back(signal);
185  break;
186  }
187  }
188  }
189  }
190  }
191 }
192 
193 /** implementation of loading settings for both CFD classes
194  *
195  * this function implements the retrieval of the settings for the CFD
196  * signal extractors. For a description on the settings see decription of
197  * CFD8Bit class.\n
198  * It opens the group "ContantFraction" and retrieves the settings for the
199  * CFD algorithm from the CASSSettings object.
200  *
201  * @param[in] s the CASSSettings object we retrieve the information from
202  * @param[out] p the container for the Constant Fraction Parameters
203  * @param [out] instrument the instrument that contains the channel the
204  * constant fraction signal extractor should anlyze.
205  * @param [out] channelNbr the channel number of the channel that conatins
206  * the singals that this extractor should extract.
207  *
208  * @author Lutz Foucar
209  */
210 void loadSettings(CASSSettings &s,CFDParameters &p, uint32_t &instrument, size_t & channelNbr)
211 {
212  s.beginGroup("ConstantFraction");
213  instrument = s.value("AcqirisInstrument",0).toInt();
214  channelNbr = s.value("ChannelNumber",0).toInt();
215  p._polarity = static_cast<Polarity>(s.value("Polarity",Negative).toInt());
216  p._threshold = fabs(s.value("Threshold",0.05).toDouble());
217  p._delay = s.value("Delay",5).toInt();
218  p._fraction = s.value("Fraction",0.6).toDouble();
219  p._walk = s.value("Walk",0.).toDouble();
220  int size = s.beginReadArray("Timeranges");
221  for (int i = 0; i < size; ++i)
222  {
223  s.setArrayIndex(i);
224  p._timeranges.push_back(std::make_pair(s.value("LowerLimit",0.).toDouble(),
225  s.value("UpperLimit",1000).toDouble()));
226  }
227  s.endArray();
228  s.endGroup();
229 }
230 }
231 }
232 }
233 
234 //########################## 8 Bit Version ###########################################################################
235 //______________________________________________________________________________________________________________________
237 {
238  ConstantFraction::getcfd<char>(*_chan,_parameters,sig);
239  return sig;
240 }
241 
243 {
244  ConstantFraction::loadSettings(s,_parameters,_instrument,_chNbr);
245 }
246 
248 {
249  _chan = extactRightChannel<char>(evt,_instrument,_chNbr);
250 }
251 
252 //########################## 16 Bit Version ###########################################################################
253 //______________________________________________________________________________________________________________________
255 {
256  ConstantFraction::getcfd<short>(*_chan,_parameters,sig);
257  return sig;
258 }
259 
261 {
262  ConstantFraction::loadSettings(s,_parameters,_instrument,_chNbr);
263 }
264 
266 {
267  _chan = extactRightChannel<short>(evt,_instrument,_chNbr);
268 }
SignalProducer::signals_t & operator()(SignalProducer::signals_t &sig)
retrieve signals from data
Definition: cfd.cpp:254
std::vector< int16_t > waveform_t
define the waveform
Definition: channel.hpp:35
setArrayIndex(int i)
double _walk
the walk of the cfd (in V)
Definition: cfd.h:48
Event to store all LCLS Data.
Definition: cass_event.h:32
double _threshold
the level above which we think this is a signal (in V)
Definition: cfd.h:39
int32_t _delay
the delay of the cfd
Definition: cfd.h:42
std::vector< signal_t > signals_t
waveform_t & waveform()
setter
Definition: channel.hpp:105
file contains declaration of the CASSEvent
Settings for CASS.
Definition: cass_settings.h:30
file contains the classes that describe an acqiris channel
double _fraction
the fraction of the cfd
Definition: cfd.h:45
double & sampleInterval()
setter
Definition: channel.hpp:103
things written only at end of run H5Dump ProcessorSummary size
void associate(const CASSEvent &evt)
associate the event with this analyzer
Definition: cfd.cpp:265
std::vector< double > signal_t
beginReadArray(const QString &prefix)
void loadSettings(CASSSettings &)
load the settings of the extractor
Definition: cfd.cpp:242
Binary function for thresholding.
timeranges_t _timeranges
the time ranges in which the signals are found
Definition: cfd.h:33
Polarity
the Polarity of a Signal in the waveform (Peak)
file contains functions that help analysing an acqiris waveform
double & horpos()
setter
Definition: channel.hpp:101
double & offset()
setter
Definition: channel.hpp:102
value(const QString &key, const QVariant &defaultValue=QVariant()
A Channel of an Acqiris Instrument.
Definition: channel.hpp:31
void loadSettings(CASSSettings &)
load the settings of the extractor
Definition: cfd.cpp:260
void loadSettings(CASSSettings &s, CFDParameters &p, uint32_t &instrument, size_t &channelNbr)
implementation of loading settings for both CFD classes
Definition: cfd.cpp:210
file contains specialized class that do the settings for cass
double & gain()
setter
Definition: channel.hpp:104
struct to combine the parameters that the Constant Fraction Extractors need
Definition: cfd.h:27
file contains declaration of class that does a constant fraction descrimination like analysis of a wa...
Polarity _polarity
the polarity that the signals have
Definition: cfd.h:36
void getcfd(const Channel &c, const CFDParameters &param, SignalProducer::signals_t &sig)
Implematation of Constant Fraction Method.
Definition: cfd.cpp:45
beginGroup(const QString &prefix)
void associate(const CASSEvent &evt)
associate the event with this analyzer
Definition: cfd.cpp:247
SignalProducer::signals_t & operator()(SignalProducer::signals_t &sig)
extract signals form the CASSEvent
Definition: cfd.cpp:236