All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AsymExpPulseFunction.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Algorithms/AsymExpPulseFunction.h
3  * @brief Pulse from one photoelectron as sum of two exponential functions.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 20, 2020
6  *
7  * This library is header only.
8  *
9  */
10 
11 #ifndef ICARUSCODE_PMT_ALGORITHMS_ASYMEXPPULSEFUNCTION_H
12 #define ICARUSCODE_PMT_ALGORITHMS_ASYMEXPPULSEFUNCTION_H
13 
14 // library header
16 
17 // LArSoft libraries
19 
20 // C++ standard library
21 #include <ostream> // std::ostream
22 #include <string>
23 #include <utility> // std::forward()
24 #include <cmath> // std::exp(), std::signbit(), std::isnormal()
25 #include <cassert>
26 
27 
28 // -----------------------------------------------------------------------------
29 namespace icarus::opdet {
30  template <typename T> class AsymExpPulseFunction;
31 }
32 
33 // -----------------------------------------------------------------------------
34 /**
35  * @brief Describes the waveform from a single photoelectron.
36  * @tparam Time type of time unit to be used
37  *
38  * This functor (class behaving like a function) describes the shape of the
39  * response to a single photoelectron as an exponentially raising and then
40  * exponentially falling shape:
41  * @f[ A \left[ exp(-(t - t_{0})/\tau_{s}) - exp(-(t - t_{0})/\tau) \right] @f]
42  * with @f$ \tau_{s} @f$ the rise time and @f$ \tau @f$ the fall time;
43  * @f$ t_{0} @f$ is the start of the signal formation, i.e. the time at which
44  * the signal starts raising.
45  *
46  * Note that @f$ t_{0} @f$ is not the peak time, and @f$ A @f$ is not the peak
47  * amplitude of the signal.
48  */
49 template <typename T>
52 {
54 
55  public:
56  /// Type for ADC counts (floating point).
57  using ADCcount = typename Base_t::ADCcount;
58 
59  using Time = typename Base_t::Time; ///< Type of time being used.
60 
61  /**
62  * @brief Constructor: assigns the parameters of the shape.
63  * @param amplitude the maximum amplitudes of the shape (at transition)
64  * @param peakTime the time of the maximum amplitude of the shape
65  * @param raiseTau the raise time (exponential parameter) of the shape
66  * @param fallTau the decay time (exponential parameter) of the shape
67  *
68  * The time parameters (`peakTime`, `raiseTau` and `fallTau`) must be
69  * measured in same unit. The `peakTime` defines the position of the shape
70  * with respect to time 0.
71  *
72  * @note The construction parameters are *not* the ones described by the
73  * functional form documented in the class,
74  * @f$ A \left[ exp(-(t - t_{0})/\tau_{s}) - exp(-(t - t_{0})/\tau) \right] @f$:
75  * the `amplitude` parameter is the actual maximum of the signal
76  * response, and `peakTime` is the actual time at which the signal
77  * peaks.
78  * These parameters are more easily read from a measured waveform.
79  *
80  */
83  Time peakTime,
84  Time raiseTau,
86  );
87 
88  /// @{
89  /// @name Parameter accessors.
90 
91 // Time peakTime() const { return fPeakTime; } // inherited
92  Time raiseTau() const { return fRaiseTau; }
93  Time fallTau() const { return fFallTau; }
94  ADCcount amplitude() const { return fAmplitude; }
95 
96  /// @}
97 
98  /// Returns the value of an exponential: `exp(-t/tau)`.
99  static double Exponential(Time t, Time tau) { return std::exp(-t/tau); }
100 
101  /// Returns the value of an exponential: `exp(-t/tau)`.
102  static double ExponentialDiff(Time t, Time raise, Time fall)
103  { return Exponential(t, raise) - Exponential(t, fall); }
104 
105  private:
106  ADCcount const fAmplitude; ///< Amplitude at peak (transition).
107  Time const fPeakTime; ///< Time of maximum signal.
108  Time const fRaiseTau; ///< Time constant of signal rise.
109  Time const fFallTau; ///< Time constant of signal fall.
110 
111  Time const fRaiseTime; ///< Time when the signal starts rising above baseline.
112  ADCcount const fA; ///< Normalization factor in the functional form.
113 
114  /// Returns the time of the peak.
115  Time myPeakTime() const { return fPeakTime; }
116 
117  /// Returns the amplitude of the pulse from the baseline, including its sign.
118  ADCcount myAmplitude() const { return fAmplitude; }
119 
120 
121  // --- BEGIN -- Interface implementation -------------------------------------
122  /**
123  * @brief Evaluates the pulse at the given time.
124  * @param time time to evaluate the shape at
125  *
126  * The scale of the time is defined by the transition time passed
127  * at construction.
128  */
129  virtual ADCcount doEvaluateAt(Time time) const override;
130 
131  /// Returns the time at which the first peak is found.
132  virtual Time doPeakTime() const override { return myPeakTime(); }
133 
134  /// Returns the amplitude of the first peak in ADC counts.
135  virtual ADCcount doPeakAmplitude() const override { return myAmplitude(); }
136 
137  /**
138  * @brief Prints on stream the parameters of this shape.
139  * @param out the stream to write into
140  * @param indent indentation string, prepended to all lines except first
141  * @param indentFirst indentation string prepended to the first line
142  */
143  virtual void doDump(
144  std::ostream& out,
145  std::string const& indent, std::string const& firstIndent
146  ) const override;
147 
148  // --- END -- Interface implementation -------------------------------------
149 
150  /// Returns the time value at which `ExponentialDiff()` is maximum.
152 
153 
154  template <typename V>
155  static V round(V value) { return (value.abs() < V{ 1e-6 })? V{ 0.0 }: value; }
156 
157 
158 }; // class icarus::opdet::AsymExpPulseFunction<>
159 
160 
161 // -----------------------------------------------------------------------------
162 // --- template implementation
163 // -----------------------------------------------------------------------------
164 template <typename T>
166  ADCcount amplitude,
167  Time peakTime,
168  Time raiseTau,
169  Time fallTau
170  )
171  : fAmplitude(amplitude)
172  , fPeakTime(peakTime)
173  , fRaiseTau(raiseTau)
174  , fFallTau(fallTau)
175  , fRaiseTime(fPeakTime - expDiffPeak(fRaiseTau, fFallTau))
176  , fA(fAmplitude/ExponentialDiff(fPeakTime - fRaiseTime, fRaiseTau, fFallTau))
177 {
178  // numerical sanity checks (for debugging only)
179  assert(std::isnormal(fA.value()));
180 } // icarus::opdet::AsymExpPulseFunction<>::AsymExpPulseFunction()
181 
182 
183 // -----------------------------------------------------------------------------
184 template <typename T>
186  -> ADCcount
187 {
188  return (time <= fRaiseTime)
189  ? ADCcount{ 0 }
190  : round(fA * ExponentialDiff(time - fRaiseTime, fRaiseTau, fFallTau) );
191 } // icarus::opdet::AsymExpPulseFunction<>::doEvaluateAt()
192 
193 
194 // -----------------------------------------------------------------------------
195 template <typename T>
197  std::ostream& out,
198  std::string const& indent, std::string const& firstIndent
199  ) const
200 {
201  out << firstIndent
202  << "Pulse shape: exponential sum with peak at "
203  << myPeakTime() << " and amplitude " << amplitude()
204  << ", time constants: " << raiseTau()
205  << " (raise) and " << fallTau() << " (fall)"
206  << indent << " start at " << fRaiseTime << ", normalization factor " << fA
207  << '\n';
208 } // icarus::opdet::AsymExpPulseFunction<>::doDump()
209 
210 
211 // -----------------------------------------------------------------------------
212 template <typename T>
214  (Time raiseTau, Time fallTau) -> Time
215 {
216  // the strange order of the operations makes sure that if Time defines
217  // difference (into Time), ratio (into scalar) and multiplication to scalar,
218  // the expression is valid.
219  return
220  raiseTau * (fallTau / (raiseTau - fallTau)) * std::log(raiseTau/fallTau);
221 } // icarus::opdet::AsymExpPulseFunction<T>::expDiffPeak()
222 
223 
224 // -----------------------------------------------------------------------------
225 
226 #endif // ICARUSCODE_PMT_ALGORITHMS_ASYMEXPPULSEFUNCTION_H
Time const fRaiseTime
Time when the signal starts rising above baseline.
Time const fPeakTime
Time of maximum signal.
typename Base_t::ADCcount ADCcount
Type for ADC counts (floating point).
virtual ADCcount doEvaluateAt(Time time) const override
Evaluates the pulse at the given time.
Abstract interface of shape of a pulse from one photoelectron.
BEGIN_PROLOG V
static double Exponential(Time t, Time tau)
Returns the value of an exponential: exp(-t/tau).
Time peakTime() const
Returns the time at which the first peak is found.
virtual void doDump(std::ostream &out, std::string const &indent, std::string const &firstIndent) const override
Prints on stream the parameters of this shape.
virtual Time doPeakTime() const override
Returns the time at which the first peak is found.
Interface for a function describing a pulse from a photoelectron.
ADCcount const fAmplitude
Amplitude at peak (transition).
static double ExponentialDiff(Time t, Time raise, Time fall)
Returns the value of an exponential: exp(-t/tau).
Describes the waveform from a single photoelectron.
ADCcount myAmplitude() const
Returns the amplitude of the pulse from the baseline, including its sign.
Dimensioned variables related to electronics.
typename Base_t::Time Time
Type of time being used.
ADCcount const fA
Normalization factor in the functional form.
do i e
temporary value
Time myPeakTime() const
Returns the time of the peak.
Time const fFallTau
Time constant of signal fall.
virtual ADCcount doPeakAmplitude() const override
Returns the amplitude of the first peak in ADC counts.
AsymExpPulseFunction(ADCcount amplitude, Time peakTime, Time raiseTau, Time fallTau)
Constructor: assigns the parameters of the shape.
util::quantities::counts_f ADCcount
Type for ADC counts (floating point).
static Time expDiffPeak(Time raiseTau, Time fallTau)
Returns the time value at which ExponentialDiff() is maximum.
Time const fRaiseTau
Time constant of signal rise.