LDMX Software
PedestalCalculator.cxx
1#include "Tracking/Reco/PedestalCalculator.h"
2
3#include <cmath>
4#include <fstream>
5#include <nlohmann/json.hpp>
6
7#include "Tracking/Event/RawSiStripHit.h"
8#include "Tracking/Reco/SiStripChannelMap.h"
9
10namespace tracking::reco {
11
13 input_collection_ =
14 ps.get<std::string>("input_collection", input_collection_);
15 input_pass_name_ = ps.get<std::string>("input_pass_name", input_pass_name_);
16 output_file_ = ps.get<std::string>("output_file", output_file_);
17 output_format_ = ps.get<std::string>("output_format", output_format_);
18}
19
21 const auto& hits = event.getCollection<ldmx::RawSiStripHit>(input_collection_,
22 input_pass_name_);
23
24 for (const auto& hit : hits) {
25 const auto key = channelmap::channelKey(hit.getFebId(), hit.getHybridId(),
26 hit.getApvId(), hit.getChannel());
27 auto& acc = accumulators_[key];
28 acc.n_++;
29 const auto& samples = hit.getSamples();
30 for (int s = 0; s < channelmap::K_SAMPLES_PER_APV_TRIGGER &&
31 s < static_cast<int>(samples.size());
32 ++s) {
33 // Welford's online algorithm: numerically stable incremental
34 // mean+variance.
35 double v = samples[s];
36 double delta = v - acc.mean_[s];
37 acc.mean_[s] += delta / acc.n_;
38 acc.m2_[s] += delta * (v - acc.mean_[s]);
39 }
40 }
41 ++n_events_;
42}
43
45 // Dispatch on the configured storage backend. Only JSON is supported today;
46 // additional backends (e.g. SQLite) can be added as new write*() methods.
47 if (output_format_ == "json") {
49 } else {
50 ldmx_log(error) << "Unknown output_format '" << output_format_
51 << "' (supported: 'json')";
52 }
53}
54
56 nlohmann::json channels = nlohmann::json::object();
57 for (const auto& [key, acc] : accumulators_) {
58 std::array<double, channelmap::K_SAMPLES_PER_APV_TRIGGER> noise{};
59 for (int s = 0; s < channelmap::K_SAMPLES_PER_APV_TRIGGER; ++s) {
60 // Welford: M2/(n-1) is the sample variance; M2/n is population variance.
61 // Use population variance (divide by n) since we want noise of the
62 // distribution.
63 noise[s] = acc.n_ > 1 ? std::sqrt(acc.m2_[s] / acc.n_) : 0.0;
64 }
65 channels[key] = {{"mean", acc.mean_}, {"noise", noise}};
66 }
67
68 nlohmann::json doc = {{"n_events", n_events_}, {"channels", channels}};
69
70 std::ofstream out(output_file_);
71 if (!out) {
72 ldmx_log(error) << "Cannot write to '" << output_file_ << "'";
73 return;
74 }
75 out << doc.dump(2) << std::endl;
76
77 ldmx_log(info) << "Wrote " << accumulators_.size() << " channels from "
78 << n_events_ << " events to '" << output_file_ << "'";
79}
80
81} // namespace tracking::reco
82
#define DECLARE_ANALYZER(CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
Implements an event buffer system for storing event data.
Definition Event.h:42
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
Implementation of a raw digitized hit from a silicon strip detector.
Compute per-channel, per-sample pedestal mean and noise from a baseline run.
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
std::string output_format_
Storage backend for the pedestals ("json"; future: "sqlite", ...).
void writePedestalsJson()
Write the accumulated pedestals to a JSON file (output_file_).
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
void analyze(const framework::Event &event) override
Process the event and make histograms or summaries.
std::string channelKey(uint8_t feb, uint8_t hybrid, uint8_t apv, uint8_t channel)
Build the per-channel pedestal-map key "feb:hybrid:apv:channel".
constexpr int K_SAMPLES_PER_APV_TRIGGER
Number of ADC samples the APV25 reads out per channel per trigger.