LDMX Software
SiStripWaveform.cxx
1#include "Tracking/Event/SiStripWaveform.h"
2
3#include <algorithm>
4#include <iomanip>
5#include <string>
6
7namespace ldmx {
8
9SiStripWaveform::SiStripWaveform(std::vector<short> samples, int16_t pchannel,
10 uint8_t hybrid_id, uint8_t feb_id,
11 uint8_t n_triggers)
12 : samples_(std::move(samples)),
13 pchannel_(pchannel),
14 hybrid_id_(hybrid_id),
15 feb_id_(feb_id),
16 n_triggers_(n_triggers) {}
17
18void SiStripWaveform::clear() {
19 samples_.clear();
20 pchannel_ = 0;
21 hybrid_id_ = 0;
22 feb_id_ = 0;
23 n_triggers_ = 0;
24 fit_amplitude_ = 0;
25 fit_t0_ = 0;
26 fit_chi2_ = 0;
27 fit_ndf_ = 0;
28 fit_converged_ = false;
29}
30
31std::ostream& operator<<(std::ostream& output, const SiStripWaveform& w) {
32 // Header.
33 output << "[ SiStripWaveform ] FEB=" << static_cast<int>(w.feb_id_)
34 << " Hybrid=" << static_cast<int>(w.hybrid_id_)
35 << " PCh=" << w.pchannel_
36 << " NTrig=" << static_cast<int>(w.n_triggers_)
37 << " PeakAmp=" << w.peakAmplitude();
38 if (w.fit_converged_) {
39 output << " | fit amp=" << w.fit_amplitude_ << " t0=" << w.fit_t0_ << "ns"
40 << " chi2/ndf=" << w.fit_chi2_ << "/" << w.fit_ndf_;
41 }
42 output << "\n";
43
44 if (w.samples_.empty()) return output;
45
46 // Determine scale — always include zero so the baseline is visible.
47 short s_min = *std::min_element(w.samples_.begin(), w.samples_.end());
48 short s_max = *std::max_element(w.samples_.begin(), w.samples_.end());
49 s_min = std::min(s_min, static_cast<short>(0));
50 s_max = std::max(s_max, static_cast<short>(0));
51
52 const int bar_width = 50;
53 const float range = static_cast<float>(s_max - s_min);
54
55 output << " Idx ADC |\n";
56
57 for (int i = 0; i < static_cast<int>(w.samples_.size()); ++i) {
58 short val = w.samples_[i];
59 int t = i / 3, s = i % 3;
60
61 const std::string label = "T" + std::to_string(t) + "." + std::to_string(s);
62
63 // Column positions for zero and this sample.
64 int zero_pos =
65 (range > 0) ? static_cast<int>((0.f - s_min) / range * (bar_width - 1))
66 : bar_width / 2;
67 int val_pos = (range > 0)
68 ? static_cast<int>((static_cast<float>(val) - s_min) /
69 range * (bar_width - 1))
70 : zero_pos;
71 val_pos = std::max(0, std::min(bar_width - 1, val_pos));
72
73 std::string bar(bar_width, ' ');
74 // Fill between zero and sample.
75 int lo = std::min(zero_pos, val_pos);
76 int hi = std::max(zero_pos, val_pos);
77 for (int k = lo; k <= hi; ++k) bar[k] = (val >= 0) ? '+' : '-';
78 // Tip marker.
79 bar[val_pos] = (val > 0) ? '>' : (val < 0) ? '<' : '|';
80 // Zero marker (only when sample is non-zero).
81 if (val != 0 && bar[zero_pos] == ' ') bar[zero_pos] = '|';
82
83 output << " " << std::left << std::setw(4) << label << " " << std::right
84 << std::setw(5) << static_cast<int>(val) << " |" << bar << "|\n";
85 }
86 return output;
87}
88
89} // namespace ldmx
constexpr int16_t pchannel(uint8_t apv_id, uint8_t channel)
Convert an (APV id, APV channel) pair into the physical strip number (pchannel) within a hybrid,...