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.