9 double sampling_interval_ns,
10 double pedestal_adc,
double noise_sigma_adc,
11 double t_scan_min_ns,
double t_scan_max_ns,
12 double t_scan_step_ns)
14 t0_offset_ns_(t0_offset_ns),
15 sampling_interval_ns_(sampling_interval_ns),
16 pedestal_adc_(pedestal_adc),
17 inv_sigma2_(1.0 / (noise_sigma_adc * noise_sigma_adc)),
18 t_scan_min_ns_(t_scan_min_ns),
19 t_scan_max_ns_(t_scan_max_ns),
20 t_scan_step_ns_(t_scan_step_ns) {}
27 const std::vector<short>& samples,
double T)
const {
28 const int n =
static_cast<int>(samples.size());
35 for (
int i = 0; i < n; ++i) {
36 const double t_arg = t0_offset_ns_ + i * sampling_interval_ns_ - T;
37 const double fi = shape_->
eval(t_arg);
38 const double si =
static_cast<double>(samples[i]) - pedestal_adc_;
44 if (sum_f2 < 1.0e-12) {
45 return {std::numeric_limits<double>::max(), 0.0};
48 const double amplitude = sum_sf / sum_f2;
52 for (
int i = 0; i < n; ++i) {
53 const double t_arg = t0_offset_ns_ + i * sampling_interval_ns_ - T;
54 const double fi = shape_->
eval(t_arg);
55 const double si =
static_cast<double>(samples[i]) - pedestal_adc_;
56 const double resid = si - amplitude * fi;
60 return {chi2, amplitude};
68 const std::vector<short>& samples)
const {
70 result.
ndf =
static_cast<int>(samples.size()) - 2;
73 bool any_signal =
false;
74 for (
auto s : samples) {
75 if (
static_cast<double>(s) > pedestal_adc_) {
87 double best_chi2 = std::numeric_limits<double>::max();
88 double best_T = t_scan_min_ns_;
89 double best_amp = 0.0;
92 double T_lo = t_scan_min_ns_, chi2_lo = std::numeric_limits<double>::max();
93 double T_hi = t_scan_min_ns_, chi2_hi = std::numeric_limits<double>::max();
95 double T_prev = t_scan_min_ns_;
96 double chi2_prev = std::numeric_limits<double>::max();
98 for (
double T = t_scan_min_ns_; T <= t_scan_max_ns_; T += t_scan_step_ns_) {
99 auto [chi2, amp] =
evalAtT(samples, T);
101 if (chi2 < best_chi2) {
108 }
else if (T > best_T && chi2_hi > best_chi2) {
121 if (T_lo < best_T && T_hi > best_T && chi2_lo > best_chi2 &&
122 chi2_hi > best_chi2) {
125 const double d1 = best_T - T_lo;
126 const double d2 = T_hi - best_T;
127 const double dc1 = best_chi2 - chi2_lo;
128 const double dc2 = chi2_hi - best_chi2;
130 const double denom = 2.0 * (d1 * dc2 + d2 * dc1);
131 if (std::abs(denom) > 1.0e-12) {
132 const double delta = (d1 * d1 * dc2 - d2 * d2 * dc1) / denom;
134 if (std::abs(delta) < std::max(d1, d2)) {
135 const double T_refined = best_T + delta;
136 auto [chi2_ref, amp_ref] =
evalAtT(samples, T_refined);
137 if (chi2_ref < best_chi2) {
140 best_chi2 = chi2_ref;
148 result.
chi2 = best_chi2;
StripPulseFitter(const PulseShape &shape, double t0_offset_ns, double sampling_interval_ns, double pedestal_adc, double noise_sigma_adc, double t_scan_min_ns=-50.0, double t_scan_max_ns=150.0, double t_scan_step_ns=1.0)