ATLAS Offline Software
Loading...
Searching...
No Matches
RPDDataAnalyzer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "TLinearFitter.h"
8#include "TMath.h"
9#include <limits>
10
11namespace ZDC {
12
13float nullPileupFunc(unsigned int /* sample */) {
14 return 0;
15}
16
17void helpResetFuncs(std::span<std::function<float(unsigned int)>> v) {
18 std::function<float(unsigned int)> f (nullPileupFunc);
19 std::fill(v.begin(), v.end(), f);
20}
21
23 ZDCMsg::MessageFunctionPtr messageFunc_p,
24 std::string tag,
25 RPDConfig const& config,
26 std::vector<float> const& calibFactors
27) : m_msgFunc_p(std::move(messageFunc_p)),
28 m_tag(std::move(tag)),
29 m_nSamples(config.nSamples),
30 m_nBaselineSamples(config.nBaselineSamples),
31 m_endSignalSample(config.endSignalSample),
32 m_pulse2ndDerivThresh(config.pulse2ndDerivThresh),
33 m_postPulseFracThresh(config.postPulseFracThresh),
34 m_goodPulseSampleStart(config.goodPulseSampleStart),
35 m_goodPulseSampleStop(config.goodPulseSampleStop),
36 m_nominalBaseline(config.nominalBaseline),
37 m_pileupBaselineSumThresh(config.pileupBaselineSumThresh),
38 m_pileupBaselineStdDevThresh(config.pileupBaselineStdDevThresh),
39 m_nNegativesAllowed(config.nNegativesAllowed),
40 m_AdcOverflow(config.ADCOverflow)
41{
42 if (m_endSignalSample == 0) m_endSignalSample = m_nSamples; // sentinel value 0 -> go to end of waveform
43 if (m_outputCalibFactors.size() != s_nChannels) {
44 (*m_msgFunc_p)(ZDCMsg::Fatal,
45 "RPDDataAnalyzer::RPDDataAnalyzer: received incorrect number of channels in calibration factors ("
46 + std::to_string(m_outputCalibFactors.size()) + " != " + std::to_string(s_nChannels) + ")"
47 );
48 }
49 std::copy(calibFactors.begin(), calibFactors.end(), m_outputCalibFactors.data());
50 m_chFADCData.fill(std::vector<uint16_t>(m_nSamples, 0));
51 m_chCorrectedFadcData.fill(std::vector<float>(m_nSamples, 0));
52 m_chPileupExpFitParams.fill(std::vector<float>(2, 0));
53 m_chPileupStretchedExpFitParams.fill(std::vector<float>(3, 0));
54 m_chPileupExpFitParamErrs.fill(std::vector<float>(2, 0));
55 m_chPileupStretchedExpFitParamErrs.fill(std::vector<float>(3, 0));
59
60 m_sideStatus.reset();
61 m_sideStatus.set(ValidBit, true);
62 for (auto& status : m_chStatus) {
63 status.reset();
64 status.set(ValidBit, true);
65 }
66}
67
71void RPDDataAnalyzer::loadChannelData(unsigned int channel, const std::vector<uint16_t>& FadcData)
72{
73 if (FadcData.size() != m_nSamples) {
74 (*m_msgFunc_p)(ZDCMsg::Fatal,
75 "RPDDataAnalyzer::loadChannelData: received incorrect number of samples "
76 "in FADC data (" + std::to_string(FadcData.size()) + ", expected " + std::to_string(m_nSamples) + ")"
77 );
78 }
79 m_chFADCData.at(channel) = FadcData;
81}
82
119
124bool RPDDataAnalyzer::checkOverflow(unsigned int channel)
125{
126 for (unsigned int sample = 0; sample < m_nSamples; sample++) {
127 if (m_chFADCData.at(channel).at(sample) >= m_AdcOverflow) {
128 m_chStatus.at(channel).set(OverflowBit, true);
129 return false; // overflow - not good
130 }
131 }
132 return true; // all good
133}
134
140bool RPDDataAnalyzer::checkPulses(unsigned int channel) {
141 float prePulseSize = 0;
142 unsigned int prePulseSample = 0;
143 float goodPulseSize = 0;
144 unsigned int goodPulseSample = 0;
145 float postPulseSize = 0;
146 unsigned int postPulseSample = 0;
147 for (unsigned int sample = 1; sample < m_nSamples - 1; sample++) {
148 float const secondDiff = m_chFADCData.at(channel).at(sample + 1) - 2*m_chFADCData.at(channel).at(sample) + m_chFADCData.at(channel).at(sample - 1);
149 if (secondDiff > m_pulse2ndDerivThresh) continue; // no pulse here
150 if (sample < m_goodPulseSampleStart && secondDiff < prePulseSize) {
151 prePulseSize = secondDiff;
152 prePulseSample = sample;
153 } else if (sample >= m_goodPulseSampleStart && sample <= m_goodPulseSampleStop && secondDiff < goodPulseSize) {
154 goodPulseSize = secondDiff;
155 goodPulseSample = sample;
156 } else if (sample > m_goodPulseSampleStop && secondDiff < postPulseSize) {
157 postPulseSize = secondDiff;
158 postPulseSample = sample;
159 }
160 }
161
162 bool hasPrePulse = prePulseSample;
163 bool hasGoodPulse = goodPulseSample;
164 bool hasPostPulse = postPulseSample;
165
166 // we need to accomodate side A, which has dips in second derivative after good pulse range
167 // if post-pulses are sufficiently small, we ignore them
168 // we expect these anomolies at ~ sample 11 or 12
169 if (hasGoodPulse && hasPostPulse && postPulseSize/goodPulseSize <= m_postPulseFracThresh) hasPostPulse = false;
170
171 bool hasNoPulse = !hasPrePulse && !hasGoodPulse && !hasPostPulse;
172
173 if (hasPrePulse) m_chStatus.at(channel).set(PrePulseBit, true);
174 if (hasPostPulse) m_chStatus.at(channel).set(PostPulseBit, true);
175 if (hasNoPulse) m_chStatus.at(channel).set(NoPulseBit, true);
176
177 return !hasPrePulse && !hasPostPulse; // true if there is a only good pulse or if there is no pulse
178}
179
183float RPDDataAnalyzer::calculateBaselineSamplesMSE(unsigned int channel, std::function<float(unsigned int)> const& fit) const
184{
185 float MSE = 0;
186 for (unsigned int sample = 0; sample < m_nBaselineSamples; sample++) {
187 MSE += std::pow(m_chFADCData.at(channel).at(sample) - m_chBaseline.at(channel) - fit(sample), 2);
188 }
189 MSE /= m_nBaselineSamples;
190 return MSE;
191}
192
197bool RPDDataAnalyzer::doPileupExpFit(unsigned int channel, std::vector<std::pair<unsigned int, float>> const& pileupFitPoints)
198{
199 auto pFitter = std::make_unique<TLinearFitter>(1, "1 ++ x");
200 double x {};
201 for (auto const& [sample, y] : pileupFitPoints) {
202 x = sample;
203 pFitter->AddPoint(&x, std::log(y));
204 }
205 if (pFitter->Eval()) {
206 (*m_msgFunc_p)(ZDCMsg::Warn, "RPDDataAnalyzer::doPileupExpFit: there was an error while evaluating TLinearFitter!");
207 m_chStatus.at(channel).set(PileupExpFitFailBit, true);
208 return false;
209 }
210 m_chPileupExpFitParams.at(channel) = {static_cast<float>(pFitter->GetParameter(0)), static_cast<float>(pFitter->GetParameter(1))};
211 m_chPileupExpFitParamErrs.at(channel) = {static_cast<float>(pFitter->GetParError(0)), static_cast<float>(pFitter->GetParError(1))};
212 m_chExpPileupFuncs.at(channel) = [intercept = pFitter->GetParameter(0), slope = pFitter->GetParameter(1)](unsigned int sample) { return std::exp(intercept + slope*sample); };
213 m_chExpPileupMSE.at(channel) = calculateBaselineSamplesMSE(channel, m_chExpPileupFuncs.at(channel));
214
215 // check for exponential growth in parameters - we definitely don't want that for a function that describes pileup
216 if (pFitter->GetParameter(1) >= 0) {
217 (*m_msgFunc_p)(ZDCMsg::Debug, "RPDDataAnalyzer::doPileupExpFit: p1 is " + std::to_string(pFitter->GetParameter(1)) + " > 0 -> there is exponential growth in fit function!");
218 m_chStatus.at(channel).set(PileupExpGrowthBit, true);
219 return false;
220 }
221 return true; // all good
222}
223
228bool RPDDataAnalyzer::doPileupStretchedExpFit(unsigned int channel, std::vector<std::pair<unsigned int, float>> const& pileupFitPoints)
229{
230 auto pFitter = std::make_unique<TLinearFitter>(1, "1 ++ (x + 4)**(0.5) ++ (x + 4)**(-0.5)");
231 double x {};
232 for (auto const& [sample, y] : pileupFitPoints) {
233 x = sample;
234 pFitter->AddPoint(&x, std::log(y));
235 }
236 if (pFitter->Eval()) {
237 (*m_msgFunc_p)(ZDCMsg::Warn, "RPDDataAnalyzer::doPileupStretchedExpFit: there was an error while evaluating TLinearFitter!");
238 m_chStatus.at(channel).set(PileupStretchedExpFitFailBit, true);
239 return false;
240 }
241 auto getFitParam = [&pFitter](int i){return pFitter->GetParameter(i);};
242 auto fGetFitErr = [&pFitter](int i){return static_cast<float>(pFitter->GetParError(i));};
243 auto fGetFitParam = [&pFitter](int i){return static_cast<float>(pFitter->GetParameter(i));};
244 //
245 m_chPileupStretchedExpFitParams.at(channel) = {fGetFitParam(0), fGetFitParam(1), fGetFitParam(2)};
246 m_chPileupStretchedExpFitParamErrs.at(channel) = {fGetFitErr(0), fGetFitErr(1), fGetFitErr(2)};
247 m_ch2ndOrderStretchedExpPileupFuncs.at(channel) = [p0 = getFitParam(0), p1 = getFitParam(1), p2 = getFitParam(2)](unsigned int sample) {
248 return std::exp(p0 + p1*std::pow(sample + 4, 0.5) + p2*std::pow(sample + 4, -0.5));
249 };
251
252 // check for exponential growth in parameters - we definitely don't want that for a function that describes pileup
253 if (getFitParam(1) >= 0) {
254 (*m_msgFunc_p)(ZDCMsg::Debug, "RPDDataAnalyzer::doPileupStretchedExpFit: p1 is " + std::to_string(getFitParam(1)) + " > 0 -> there is exponential growth in fit function!");
255 m_chStatus.at(channel).set(PileupStretchedExpGrowthBit, true);
256 return false;
257 }
258 if (getFitParam(2)/getFitParam(1) - 4 > 0) {
259 (*m_msgFunc_p)(ZDCMsg::Debug, "RPDDataAnalyzer::doPileupStretchedExpFit: 1st deriv max occurs at sample " + std::to_string(getFitParam(1)) + " > 0 -> fit probably looks like a pulse (and not like pileup)");
260 m_chStatus.at(channel).set(PileupStretchedExpPulseLikeBit, true);
261 // analysis remains valid (for now)
262 }
263 return true; // all good
264}
265
269unsigned int RPDDataAnalyzer::countSignalRangeNegatives(std::vector<float> const& values) const
270{
271 unsigned int nNegatives = 0;
272 for (unsigned int sample = m_nBaselineSamples; sample < m_endSignalSample; sample++) {
273 if (values.at(sample) < 0) nNegatives++;
274 }
275 return nNegatives;
276}
277
283 float nominalBaselineSubtrSum = 0;
285 std::vector<std::pair<unsigned int, float>> pileupFitPoints;
286 for (unsigned int sample = 0; sample < m_nBaselineSamples; sample++) {
287 float const& adc = m_chFADCData.at(channel).at(sample);
288 float const adcBaselineSubtr = adc - m_nominalBaseline;
289 nominalBaselineSubtrSum += adcBaselineSubtr;
290 if (adcBaselineSubtr > 0) {
291 // this sample is a candidate for pileup fit
292 pileupFitPoints.emplace_back(sample, adcBaselineSubtr);
293 }
294 }
295 float baselineStdDev = TMath::StdDev(m_chFADCData.at(channel).begin(), std::next(m_chFADCData.at(channel).begin(), m_nBaselineSamples));
296
297 if (nominalBaselineSubtrSum < m_pileupBaselineSumThresh || baselineStdDev < m_pileupBaselineStdDevThresh) {
298 // there is NO pileup, we will trust the average of baseline samples as a good baseline estimate
299 m_chBaseline.at(channel) = TMath::Mean(m_chFADCData.at(channel).begin(), std::next(m_chFADCData.at(channel).begin(), m_nBaselineSamples));
300 // calculate fadc data with baseline subtracted
301 for (unsigned int sample = 0; sample < m_nSamples; sample++) {
302 m_chCorrectedFadcData.at(channel).at(sample) = m_chFADCData.at(channel).at(sample) - m_chBaseline.at(channel);
303 }
305 m_chStatus.at(channel).set(BadAvgBaselineSubtrBit, true);
306 return false;
307 }
308 return true; // all good
309 }
310
311 // we suspect that there is pileup - use nominal baseline
312 m_chBaseline.at(channel) = m_nominalBaseline;
313
314 if (pileupFitPoints.size() < s_minPileupFitPoints) {
315 m_chStatus.at(channel).set(InsufficientPileupFitPointsBit, true);
316 // there are not enough points to do fit, so just use nominal baseline and call it a day
317 for (unsigned int sample = 0; sample < m_nSamples; sample++) {
318 m_chCorrectedFadcData.at(channel).at(sample) = m_chFADCData.at(channel).at(sample) - m_chBaseline.at(channel);
319 }
320 return true; // all good
321 }
322
323 // there is OOT pileup in this channel => expect approx. negative exponential in baseline samples
324 m_chStatus.at(channel).set(OutOfTimePileupBit, true);
325 // fit (approximately) to exponential and stretched exponential in baseline samples
326 bool expFitSuccess = doPileupExpFit(channel, pileupFitPoints);
327 bool stretchedExpFitSuccess = doPileupStretchedExpFit(channel, pileupFitPoints);
328
329 if (stretchedExpFitSuccess) {
330 // calculate fadc data with baseline and pileup contribution subtracted
331 for (unsigned int sample = 0; sample < m_nSamples; sample++) {
332 m_chCorrectedFadcData.at(channel).at(sample) = m_chFADCData.at(channel).at(sample) - m_chBaseline.at(channel) - m_ch2ndOrderStretchedExpPileupFuncs.at(channel)(sample);
333 }
335 m_chStatus.at(channel).set(PileupBadStretchedExpSubtrBit, true);
336 // fallback to exponential fit
337 } else {
339 return true; // all good
340 }
341 }
342
343 if (expFitSuccess) {
344 // calculate fadc data with baseline and pileup contribution subtracted
345 for (unsigned int sample = 0; sample < m_nSamples; sample++) {
346 m_chCorrectedFadcData.at(channel).at(sample) = m_chFADCData.at(channel).at(sample) - m_chBaseline.at(channel) - m_chExpPileupFuncs.at(channel)(sample);
347 }
349 m_chStatus.at(channel).set(PileupBadExpSubtrBit, true);
350 return false;
351 }
353 return true; // all good
354 }
355
356 return false; // both fits are bad...we have no measure of pileup!
357}
358
363{
364 if (m_chStatus.at(channel)[NoPulseBit]) {
365 m_chMaxAdc.at(channel) = 0;
366 m_chMaxAdcCalib.at(channel) = 0;
367 m_chMaxSample.at(channel) = -1;
368 return;
369 }
370 float maxAdc = -std::numeric_limits<float>::infinity();
371 unsigned int maxSample = 0;
372 for (unsigned int sample = m_nBaselineSamples; sample < m_endSignalSample; sample++) {
373 float adc = m_chCorrectedFadcData.at(channel).at(sample);
374 if (adc > maxAdc) {
375 maxAdc = adc;
376 maxSample = sample;
377 }
378 }
379 m_chMaxAdc.at(channel) = maxAdc;
380 m_chMaxAdcCalib.at(channel) = maxAdc*m_outputCalibFactors.at(channel);
381 m_chMaxSample.at(channel) = maxSample;
382}
383
387void RPDDataAnalyzer::calculateSumAdc(unsigned int channel) {
388 if (m_chStatus.at(channel)[NoPulseBit]) {
389 m_chSumAdc.at(channel) = 0;
390 m_chSumAdcCalib.at(channel) = 0;
391 return;
392 }
393 // sum range is after baseline until end of signal
394 float signalRangeAdcSum = 0;
395 for (unsigned int sample = m_nBaselineSamples; sample < m_endSignalSample; sample++) {
396 signalRangeAdcSum += m_chCorrectedFadcData.at(channel).at(sample);
397 }
398 m_chSumAdc.at(channel) = signalRangeAdcSum;
399 m_chSumAdcCalib.at(channel) = signalRangeAdcSum*m_outputCalibFactors.at(channel);
400
401 if (m_chStatus.at(channel)[OutOfTimePileupBit]) {
402 // there is pileup in this channel, calculate fraction of baseline-subtracted raw signal
403 // that is pileup (beginning of window until end of signal)
404 std::function<float(unsigned int)> pileupFunc;
405 switch (m_chPileupFuncType.at(channel)) {
407 pileupFunc = m_ch2ndOrderStretchedExpPileupFuncs.at(channel);
408 break;
410 pileupFunc = m_chExpPileupFuncs.at(channel);
411 break;
412 default:
413 break;
414 }
415
416 float totalAdcSum = 0;
417 float pileupTotalAdcSum = 0;
418 for (unsigned int sample = 0; sample < m_endSignalSample; sample++) {
419 totalAdcSum += m_chFADCData.at(channel).at(sample) - m_nominalBaseline;
420 pileupTotalAdcSum += pileupFunc(sample);
421 }
422 if (totalAdcSum > 0) {
423 m_chPileupFrac.at(channel) = pileupTotalAdcSum/totalAdcSum;
424 } else {
425 // avoid dividing by zero or negative, return sentinel value of -1
426 m_chPileupFrac.at(channel) = -1;
427 }
428 } // else fractional pileup is zero initialized, and this is what we want for no pileup
429}
430
435{
436 for (unsigned int channel = 0; channel < s_nChannels; channel++) {
437 if (!m_chStatus.at(channel)[ValidBit]) m_sideStatus.set(ValidBit, false);
438
440 if (m_chStatus.at(channel)[OverflowBit]) m_sideStatus.set(OverflowBit, true);
441 if (m_chStatus.at(channel)[PrePulseBit]) m_sideStatus.set(PrePulseBit, true);
442 if (m_chStatus.at(channel)[PostPulseBit]) m_sideStatus.set(PostPulseBit, true);
443 if (m_chStatus.at(channel)[NoPulseBit]) m_sideStatus.set(NoPulseBit, true);
453 }
454}
455
460{
462 (*m_msgFunc_p)(ZDCMsg::Warn,
463 "RPDDataAnalyzer::analyzeData: analyzing data with " + std::to_string(m_nChannelsLoaded) + " of "
464 + std::to_string(s_nChannels) + " channels loaded"
465 );
466 }
467 for (unsigned int channel = 0; channel < s_nChannels; channel++) {
468 if (!checkOverflow(channel)) {
469 // there was overflow, stop analysis
470 m_chStatus.at(channel).set(ValidBit, false);
471 continue;
472 }
473 if (!checkPulses(channel)) {
474 // there was a pre-pulse or post-pulse, stop analysis
475 m_chStatus.at(channel).set(ValidBit, false);
476 continue;
477 }
478 // there is either only a good pulse or no pulse
479 // only do baseline and pileup subtraction if there is a pulse!
480 if (!m_chStatus.at(channel)[NoPulseBit] /* there is a pulse -> */ && !doBaselinePileupSubtraction(channel)) {
481 // there was a pulse and a problem with baseline/pileup subtraction, stop analysis
482 m_chStatus.at(channel).set(ValidBit, false);
483 continue;
484 }
486 calculateSumAdc(channel);
487 }
489}
490
494unsigned int RPDDataAnalyzer::getChMaxSample(unsigned int channel) const
495{
496 return m_chMaxSample.at(channel);
497}
498
502float RPDDataAnalyzer::getChSumAdc(unsigned int channel) const
503{
504 return m_chSumAdc.at(channel);
505}
506
510float RPDDataAnalyzer::getChSumAdcCalib(unsigned int channel) const
511{
512 return m_chSumAdcCalib.at(channel);
513}
514
518float RPDDataAnalyzer::getChMaxAdc(unsigned int channel) const
519{
520 return m_chMaxAdc.at(channel);
521}
522
526float RPDDataAnalyzer::getChMaxAdcCalib(unsigned int channel) const
527{
528 return m_chMaxAdcCalib.at(channel);
529}
530
534float RPDDataAnalyzer::getChPileupFrac(unsigned int channel) const
535{
536 return m_chPileupFrac.at(channel);
537}
538
542float RPDDataAnalyzer::getChBaseline(unsigned int channel) const {
543 return m_chBaseline.at(channel);
544}
545
549const std::vector<float>& RPDDataAnalyzer::getChPileupExpFitParams(unsigned int channel) const {
550 return m_chPileupExpFitParams.at(channel);
551}
552
556const std::vector<float>& RPDDataAnalyzer::getChPileupStretchedExpFitParams(unsigned int channel) const {
557 return m_chPileupStretchedExpFitParams.at(channel);
558}
559
563const std::vector<float>& RPDDataAnalyzer::getChPileupExpFitParamErrs(unsigned int channel) const {
564 return m_chPileupExpFitParamErrs.at(channel);
565}
566
570const std::vector<float>& RPDDataAnalyzer::getChPileupStretchedExpFitParamErrs(unsigned int channel) const {
571 return m_chPileupStretchedExpFitParamErrs.at(channel);
572}
573
577float RPDDataAnalyzer::getChPileupExpFitMSE(unsigned int channel) const {
578 return m_chExpPileupMSE.at(channel);
579}
580
584float RPDDataAnalyzer::getChPileupStretchedExpFitMSE(unsigned int channel) const {
585 return m_ch2ndOrderStretchedExpPileupMSE.at(channel);
586}
587
591unsigned int RPDDataAnalyzer::getChStatus(unsigned int channel) const
592{
593 return static_cast<unsigned int>(m_chStatus.at(channel).to_ulong());
594}
595
600{
601 return static_cast<unsigned int>(m_sideStatus.to_ulong());
602}
603
604} // namespace ZDC
#define y
#define x
float m_pulse2ndDerivThresh
Samples before (not including) this sample are the signal region; nSamples goes to end of window.
unsigned int m_goodPulseSampleStop
Pulses before this sample are considered pre-pulses.
unsigned int m_nBaselineSamples
void reset()
Reset all member variables to default values.
std::array< float, s_nChannels > m_chBaseline
OOT pileup sum as a fraction of non-pileup sum in entire window (0 if no OOT pileup,...
bool doPileupStretchedExpFit(unsigned int channel, std::vector< std::pair< unsigned int, float > > const &pileupFitPoints)
Perform a stretched exponential fit in baseline-subtracted baseline samples and set relevant status b...
const std::vector< float > & getChPileupExpFitParams(unsigned int channel) const
Get parameters for pileup exponential fit (if pileup was detected and fit did not fail): exp( [0] + [...
const std::vector< float > & getChPileupStretchedExpFitParams(unsigned int channel) const
Get parameters for pileup stretched exponential fit (if pileup was detected and fit did not fail): ex...
float getChPileupFrac(unsigned int channel) const
Get OOT pileup sum as a fraction of non-pileup sum in entire window (0 if no OOT pileup,...
std::array< float, s_nChannels > m_chSumAdc
sample of max of RPD data in signal range after pileup subtraction; per channel
std::array< std::bitset< N_STATUS_BITS >, s_nChannels > m_chStatus
mean squared error of pileup stretched exponential fit in baseline samples (if pileup was detected an...
std::array< float, s_nChannels > m_ch2ndOrderStretchedExpPileupMSE
mean squared error of pileup exponential fit in baseline samples (if pileup was detected and fit did ...
std::array< float, s_nChannels > m_chSumAdcCalib
sum of RPD data in signal range after baseline and pileup subtraction; per channel
bool checkPulses(unsigned int channel)
Calculate 2nd difference, identify pulses, and set relevant status bits.
float m_pileupBaselineSumThresh
The global nominal baseline; used when pileup is detected.
std::array< float, s_nChannels > m_outputCalibFactors
ADC values greater than or equal to this number are considered overflow.
void analyzeData()
Analyze RPD data.
std::array< std::vector< float >, s_nChannels > m_chPileupStretchedExpFitParams
parameters for pileup exponential fit (if pileup was detected and fit did not fail): exp( [0] + [1]*s...
std::array< std::vector< float >, s_nChannels > m_chCorrectedFadcData
raw RPD data; index channel then sample
const std::vector< float > & getChPileupStretchedExpFitParamErrs(unsigned int channel) const
Get parameter errors for pileup stretched exponential fit (if pileup was detected and fit did not fai...
float getChMaxAdcCalib(unsigned int channel) const
Get max of RPD data in signal range after baseline and pileup subtraction, with output calibration fa...
bool doBaselinePileupSubtraction(unsigned int channel)
Determine if there is pileup, subtract baseline and pileup, and set relevant status bits.
bool checkOverflow(unsigned int channel)
Check for overflow and set relevant status bit.
unsigned int getChMaxSample(unsigned int channel) const
Get sample of max of RPD data in signal range after pileup subtraction.
float m_nominalBaseline
Pulses after this sample are considered post-pulses.
std::array< float, s_nChannels > m_chPileupFrac
max of RPD data in signal range after baseline and pileup subtraction, with output calibration factor...
unsigned int countSignalRangeNegatives(std::vector< float > const &values) const
Calculate the number of negative values in signal range.
ZDCMsg::MessageFunctionPtr m_msgFunc_p
void calculateMaxSampleMaxAdc(unsigned int channel)
Calculate max ADC and max sample.
float getChPileupStretchedExpFitMSE(unsigned int channel) const
Get mean squared error of pileup stretched exponential fit in baseline samples (if pileup was detecte...
static unsigned int constexpr s_minPileupFitPoints
status bits for side
float calculateBaselineSamplesMSE(unsigned int channel, std::function< float(unsigned int)> const &fit) const
Calculate the mean squared error of the fit function in the baseline samples.
void calculateSumAdc(unsigned int channel)
Calculate sum ADC and if there is pileup, calculate fractional pileup.
std::bitset< N_STATUS_BITS > m_sideStatus
status bits per channel
std::array< float, s_nChannels > m_chMaxAdcCalib
max of RPD data in signal range after baseline and pileup subtraction; per channel
bool doPileupExpFit(unsigned int channel, std::vector< std::pair< unsigned int, float > > const &pileupFitPoints)
Perform an exponential fit in baseline-subtracted baseline samples and set relevant status bits.
std::array< float, s_nChannels > m_chExpPileupMSE
pileup stretched exponential fit function (if pileup was detected and fit did not fail); per channel
unsigned int m_nChannelsLoaded
void loadChannelData(unsigned int channel, const std::vector< uint16_t > &FadcData)
Load a single channel's FADC data into member variable.
unsigned int getSideStatus() const
Get status word for side.
unsigned int m_goodPulseSampleStart
If there is a good pulse and post-pulse and size of post-pulse as a fraction of good pulse is less th...
float getChPileupExpFitMSE(unsigned int channel) const
Get mean squared error of pileup exponential fit in baseline samples (if pileup was detected and fit ...
float getChMaxAdc(unsigned int channel) const
Get max of RPD data in signal range after baseline and pileup subtraction.
std::array< std::vector< float >, s_nChannels > m_chPileupExpFitParams
baseline used in baseline subtraction; per channel
const std::vector< float > & getChPileupExpFitParamErrs(unsigned int channel) const
Get parameter errors for pileup exponential fit (if pileup was detected and fit did not fail).
unsigned int m_endSignalSample
Number of baseline samples; the sample equal to this number is the start of signal region.
std::array< float, s_nChannels > m_chMaxAdc
sum of RPD data in signal range after baseline and pileup subtraction, with output calibration factor...
unsigned int m_nNegativesAllowed
Baseline standard deviations less than this number indicate there is not pileup.
std::array< std::vector< uint16_t >, s_nChannels > m_chFADCData
multiplicative calibration factors to apply to output, e.g., max and sum ADC; per channel
RPDDataAnalyzer(ZDCMsg::MessageFunctionPtr messageFunc_p, std::string tag, RPDConfig const &config, std::vector< float > const &calibFactors)
void setSideStatusBits()
Set side status bits according to channel status bits.
float m_pileupBaselineStdDevThresh
Baseline sums less than this number indicate there is not pileup.
static unsigned int constexpr s_nChannels
float getChSumAdcCalib(unsigned int channel) const
Get sum of RPD data in signal range after baseline and pileup subtraction, with output calibration fa...
unsigned int m_AdcOverflow
Maximum number of negative ADC values after baseline and pileup subtraction allowed in signal range.
std::array< std::vector< float >, s_nChannels > m_chPileupExpFitParamErrs
parameters for pileup stretched exponential fit (if pileup was detected and fit did not fail): exp( [...
std::array< std::function< float(unsigned int)>, s_nChannels > m_ch2ndOrderStretchedExpPileupFuncs
pileup exponential fit function (if pileup was detected and fit did not fail); per channel
unsigned int getChStatus(unsigned int channel) const
Get status word for channel.
float getChSumAdc(unsigned int channel) const
Get sum of RPD data in signal range after baseline and pileup subtraction.
std::array< unsigned int, s_nChannels > m_chMaxSample
RPD data with baseline and pileup subtracted; index channel then sample.
float getChBaseline(unsigned int channel) const
Get baseline used in baseline subtraction.
float m_postPulseFracThresh
Second differences less than or equal to this number indicate a pulse.
std::array< std::vector< float >, s_nChannels > m_chPileupStretchedExpFitParamErrs
parameter errors for pileup exponential fit (if pileup was detected and fit did not fail); per channe...
std::array< std::function< float(unsigned int)>, s_nChannels > m_chExpPileupFuncs
enum indicating type of pileup fit function; per channel
std::array< PileupFitFuncType, s_nChannels > m_chPileupFuncType
parameter errors for pileup stretched exponential fit (if pileup was detected and fit did not fail); ...
void helpZero(Range &v)
Definition RPDUtils.h:27
@ Fatal
Definition ZDCMsg.h:23
@ Debug
Definition ZDCMsg.h:19
@ Warn
Definition ZDCMsg.h:21
std::shared_ptr< MessageFunction > MessageFunctionPtr
Definition ZDCMsg.h:14
float nullPileupFunc(unsigned int)
void helpResetFuncs(std::span< std::function< float(unsigned int)> > v)
STL namespace.