11 #ifndef ICARUSCODE_PMT_ALGORITHMS_SAMPLEDWAVEFORMFUNCTION_H
12 #define ICARUSCODE_PMT_ALGORITHMS_SAMPLEDWAVEFORMFUNCTION_H
32 namespace icarus::opdet {
33 using namespace util::quantities::time_literals;
64 std::string
name {
"<unknown>" };
66 std::string date {
"n/a" };
95 float gain()
const {
return fGain; }
122 virtual ADCcount doEvaluateAt(Time time)
const override;
126 {
return fRefTime + fPeakSample * sampleDuration(); }
130 {
return fSamples[fPeakSample]; }
140 std::string
const& indent, std::string
const& firstIndent
148 {
return (index >= 0) && (std::size_t(index) < fSamples.size()); }
152 ADCcount integral()
const;
164 std::vector<ADCcount> buildSamples(
float targetGain)
const;
167 static std::size_t findPeak(std::vector<ADCcount>
const& samples);
175 template <
typename T>
178 : fSource { std::move(waveformSpecs) }
179 , fSamples { buildSamples(gain) }
181 , fPeakSample{ findPeak(fSamples) }
182 , fRefTime { peakTime - fPeakSample * sampleDuration() }
187 template <
typename T>
191 std::ptrdiff_t
const iSample =
static_cast<std::ptrdiff_t
>
192 (std::floor((time - fRefTime)/sampleDuration()));
193 return hasSample(iSample)? fSamples[iSample]:
ADCcount{ 0 };
198 template <
typename T>
201 std::string
const& indent, std::string
const& firstIndent
206 <<
"Pulse '" << fSource.name <<
"' (v. " << fSource.version
207 <<
", " << fSource.date <<
"):"
208 <<
"\n" << indent <<
" " << fSource.description
210 <<
" from " << fSamples.size() <<
"x " << sampleDuration() <<
" samples"
211 <<
", peak at " << Base_t::peakTime()
212 <<
" with amplitude " << Base_t::peakAmplitude()
214 <<
" start at " << fRefTime <<
", gain " << fGain
215 <<
" (integral: " << integral() <<
")"
223 template <
typename T>
225 {
return std::reduce(fSamples.begin(), fSamples.end()); }
229 template <
typename T>
231 (
float targetGain)
const -> std::vector<ADCcount>
244 constexpr
float VoltageRange = 2
'000.0; // millivolt
245 constexpr unsigned short int ADCbits = 14;
247 // 2 V in 14 bits (=> 8.192):
248 constexpr float mVtoADC = (1 << ADCbits) / VoltageRange;
250 // if either the starting gain is unknown or the target gain is not specified,
251 // do not scale the gain
252 float const gainFactor = (fSource.gain != 0.0 && targetGain != 0.0)
253 ? (targetGain / fSource.gain): 1.0;
254 float const factor = gainFactor * mVtoADC;
256 auto voltageToADC = [factor](float mV)
257 { return static_cast<ADCcount>(factor * mV); };
259 std::vector<ADCcount> samples;
260 samples.reserve(fSource.samples.size());
261 std::transform(fSource.samples.begin(), fSource.samples.end(),
262 back_inserter(samples), voltageToADC);
266 } // icarus::opdet::SampledWaveformFunction<>::buildSamples()
269 // -----------------------------------------------------------------------------
270 template <typename T>
271 std::size_t icarus::opdet::SampledWaveformFunction<T>::findPeak
272 (std::vector<ADCcount> const& samples)
274 assert(!samples.empty());
275 auto const sbegin = samples.begin();
276 auto const [ min, max ] = std::minmax_element(sbegin, samples.end());
277 // assume baseline 0:
278 return ((min->abs() > max->abs())? min: max) - sbegin;
279 } // icarus::opdet::SampledWaveformFunction<T>::findPeak()
282 // -----------------------------------------------------------------------------
284 #endif // ICARUSCODE_PMT_ALGORITHMS_SAMPLEDWAVEFORMFUNCTION_H
T Time
Type of time being used.
Abstract interface of shape of a pulse from one photoelectron.
A value measured in the specified unit.
Interface for a function describing a pulse from a photoelectron.
Dimensioned variables representing space or time quantities.