diff --git a/config/#esb_module.conf# b/config/#esb_module.conf# deleted file mode 100644 index 8c3cbeaef893cf04aa1a8e481615826776ad0180..0000000000000000000000000000000000000000 --- a/config/#esb_module.conf# +++ /dev/null @@ -1,208 +0,0 @@ -# configuration of DAQ modules -# Module { crate, slot, mod_type, Channels { id, name, ch_type } } - -Module -{ - crate = 1 - slot = 3 - type = FADC250 - Channels - { - 0, Cer14_5, Signal - 1, Cer13_4, Signal - 2, Cer13_3, Signal - 3, Cer13_2, Signal - 4, Cer13_1, Signal - 5, Cer13_5, Signal - 6, Cer12_4, Signal - 7, Cer12_3, Signal - 8, Cer12_2, Signal - 9, Cer12_1, Signal - 10, Cer12_5, Signal - 11, Cer11_4, Signal - 12, Cer11_3, Signal - 13, Cer11_2, Signal - 14, Cer11_1, Signal - 15, Cer11_5, Signal - } -} - -Module -{ - crate = 1 - slot = 4 - type = FADC250 - Channels - { - 0, Cer33_1, Signal - 1, Cer33_5, Signal - 2, Cer23_4, Signal - 3, Cer23_3, Signal - 4, Cer23_2, Signal - 5, Cer23_1, Signal - 6, Cer23_5, Signal - 7, Cer24_4, Signal - 8, Cer24_3, Signal - 9, Cer24_2, Signal - 10, Cer24_1, Signal - 11, Cer24_5, Signal - 12, Cer14_4, Signal - 13, Cer14_3, Signal - 14, Cer14_2, Signal - 15, Cer14_1, Signal - } -} - -Module -{ - crate = 1 - slot = 5 - type = FADC250 - Channels - { - 0, Cer43_2, Signal - 1, Cer43_1, Signal - 2, Cer43_5, Signal - 3, Cer44_4, Signal - 4, Cer44_3, Signal - 5, Cer44_2, Signal - 6, Cer44_1, Signal - 7, Cer44_5, Signal - 8, Cer34_4, Signal - 9, Cer34_3, Signal - 10, Cer34_2, Signal - 11, Cer34_1, Signal - 12, Cer34_5, Signal - 13, Cer33_4, Signal - 14, Cer33_3, Signal - 15, Cer33_2, Signal - } -} - -Module -{ - crate = 1 - slot = 6 - type = FADC250 - Channels - { - 0, Cer31_3, Signal - 1, Cer31_2, Signal - 2, Cer31_1, Signal - 3, Cer31_5, Signal - 4, Cer41_4, Signal - 5, Cer41_3, Signal - 6, Cer41_2, Signal - 7, Cer41_1, Signal - 8, Cer41_5, Signal - 9, Cer42_4, Signal - 10, Cer42_3, Signal - 11, Cer42_2, Signal - 12, Cer42_1, Signal - 13, Cer42_5, Signal - 14, Cer43_4, Signal - 15, Cer43_3, Signal - } -} - -Module -{ - crate = 1 - slot = 7 - type = FADC250 - Channels - { - 0, C7_4, Trigger - 1, C7_3, Trigger - 2, C7_2, Trigger - 3, C7_1, Trigger - 4, C6_4, Trigger - 5, C6_3, Trigger - 6, C6_2, Trigger - 7, C6_1, Trigger - 8, C5_4, Trigger - 9, C5_3, Trigger - 10, C5_2, Trigger - 11, C5_1, Trigger - 12, C4, Trigger - 13, C3, Trigger - 14, C2, Trigger - 15, C1, Trigger - } -} - -Module -{ - crate = 1 - slot = 8 - type = FADC250 - Channels - { - 0, Cer22_1, Signal - 1, Cer22_5, Signal - 2, Cer32_4, Signal - 3, Cer32_3, Signal - 4, Cer32_2, Signal - 5, Cer32_1, Signal - 6, Cer32_5, Signal - 7, Cer31_4, Signal - 8, C9_4, Trigger - 9, C9_3, Trigger - 10, C9_2, Trigger - 11, C9_1, Trigger - 12, C8_4, Trigger - 13, C8_3, Trigger - 14, C8_2, Trigger - 15, C8_1, Trigger - } -} - -Module -{ - crate = 1 - slot = 9 - type = FADC250 - Channels - { - 2, Cer21_4, Signal - 3, Cer21_3, Signal - 4, Cer21_2, Signal - 5, Cer21_1, Signal - 6, Cer21_5, Signal - 7, Cer22_4, Signal - 8, Cer22_3, Signal - 9, Cer22_2, Signal - 10, S2_11, Trigger - 11, S2_10, Trigger - 12, S2_9, Trigger - 13, S2_8, Trigger - 14, S2_7, Trigger - 15, S2_6, Trigger - } -} - -Module -{ - crate = 1 - slot = 10 - type = FADC250 - Channels - { - 0, S2_5, Trigger - 1, S2_4, Trigger - 2, S2_3, Trigger - 3, S2_2, Trigger - 4, S2_1, Trigger - 5, S1_11, Trigger - 6, S1_10, Trigger - 7, S1_9, Trigger - 8, S1_8, Trigger - 9, S1_7, Trigger - 10, S1_6, Trigger - 11, S1_5, Trigger - 12, S1_4, Trigger - 13, S1_3, Trigger - 14, S1_2, Trigger - 15, S1_1, Trigger - } -} diff --git a/config/esb_module.conf.bkp b/config/esb_module_old.conf similarity index 100% rename from config/esb_module.conf.bkp rename to config/esb_module_old.conf diff --git a/config/json/esb_module.json b/config/json/esb_module.json new file mode 100644 index 0000000000000000000000000000000000000000..ef72db1c557ce50552854961f498c9014480ce5b --- /dev/null +++ b/config/json/esb_module.json @@ -0,0 +1,688 @@ +{ + "module_1_10": { + "channels": [ + { + "channel": 0, + "name": "S2_5", + "type": "Trigger" + }, + { + "channel": 1, + "name": "S2_4", + "type": "Trigger" + }, + { + "channel": 2, + "name": "S2_3", + "type": "Trigger" + }, + { + "channel": 3, + "name": "S2_2", + "type": "Trigger" + }, + { + "channel": 4, + "name": "S2_1", + "type": "Trigger" + }, + { + "channel": 5, + "name": "S1_11", + "type": "Trigger" + }, + { + "channel": 6, + "name": "S1_10", + "type": "Trigger" + }, + { + "channel": 7, + "name": "S1_9", + "type": "Trigger" + }, + { + "channel": 8, + "name": "S1_8", + "type": "Trigger" + }, + { + "channel": 9, + "name": "S1_7", + "type": "Trigger" + }, + { + "channel": 10, + "name": "S1_6", + "type": "Trigger" + }, + { + "channel": 11, + "name": "S1_5", + "type": "Trigger" + }, + { + "channel": 12, + "name": "S1_4", + "type": "Trigger" + }, + { + "channel": 13, + "name": "S1_3", + "type": "Trigger" + }, + { + "channel": 14, + "name": "S1_2", + "type": "Trigger" + }, + { + "channel": 15, + "name": "S1_1", + "type": "Trigger" + } + ], + "crate": 1, + "slot": 10, + "type": "FADC250" + }, + "module_1_3": { + "channels": [ + { + "channel": 0, + "name": "Cer14_5", + "type": "Signal" + }, + { + "channel": 1, + "name": "Cer13_4", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer13_3", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer13_2", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer13_1", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer13_5", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer12_4", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer12_3", + "type": "Signal" + }, + { + "channel": 8, + "name": "Cer12_2", + "type": "Signal" + }, + { + "channel": 9, + "name": "Cer12_1", + "type": "Signal" + }, + { + "channel": 10, + "name": "Cer12_5", + "type": "Signal" + }, + { + "channel": 11, + "name": "Cer11_4", + "type": "Signal" + }, + { + "channel": 12, + "name": "Cer11_3", + "type": "Signal" + }, + { + "channel": 13, + "name": "Cer11_2", + "type": "Signal" + }, + { + "channel": 14, + "name": "Cer11_1", + "type": "Signal" + }, + { + "channel": 15, + "name": "Cer11_5", + "type": "Signal" + } + ], + "crate": 1, + "slot": 3, + "type": "FADC250" + }, + "module_1_4": { + "channels": [ + { + "channel": 0, + "name": "Cer33_1", + "type": "Signal" + }, + { + "channel": 1, + "name": "Cer33_5", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer23_4", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer23_3", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer23_2", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer23_1", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer23_5", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer24_4", + "type": "Signal" + }, + { + "channel": 8, + "name": "Cer24_3", + "type": "Signal" + }, + { + "channel": 9, + "name": "Cer24_2", + "type": "Signal" + }, + { + "channel": 10, + "name": "Cer24_1", + "type": "Signal" + }, + { + "channel": 11, + "name": "Cer24_5", + "type": "Signal" + }, + { + "channel": 12, + "name": "Cer14_4", + "type": "Signal" + }, + { + "channel": 13, + "name": "Cer14_3", + "type": "Signal" + }, + { + "channel": 14, + "name": "Cer14_2", + "type": "Signal" + }, + { + "channel": 15, + "name": "Cer14_1", + "type": "Signal" + } + ], + "crate": 1, + "slot": 4, + "type": "FADC250" + }, + "module_1_5": { + "channels": [ + { + "channel": 1, + "name": "Cer43_1", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer43_5", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer44_4", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer44_3", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer44_2", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer44_1", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer44_5", + "type": "Signal" + }, + { + "channel": 8, + "name": "Cer34_4", + "type": "Signal" + }, + { + "channel": 9, + "name": "Cer34_3", + "type": "Signal" + }, + { + "channel": 10, + "name": "Cer34_2", + "type": "Signal" + }, + { + "channel": 11, + "name": "Cer34_1", + "type": "Signal" + }, + { + "channel": 12, + "name": "Cer34_5", + "type": "Signal" + }, + { + "channel": 13, + "name": "Cer33_4", + "type": "Signal" + }, + { + "channel": 14, + "name": "Cer33_3", + "type": "Signal" + }, + { + "channel": 15, + "name": "Cer33_2", + "type": "Signal" + } + ], + "crate": 1, + "slot": 5, + "type": "FADC250" + }, + "module_1_6": { + "channels": [ + { + "channel": 0, + "name": "Cer31_3", + "type": "Signal" + }, + { + "channel": 1, + "name": "Cer31_2", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer31_1", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer31_5", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer41_4", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer41_3", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer41_2", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer41_1", + "type": "Signal" + }, + { + "channel": 8, + "name": "Cer41_5", + "type": "Signal" + }, + { + "channel": 9, + "name": "Cer42_4", + "type": "Signal" + }, + { + "channel": 10, + "name": "Cer42_3", + "type": "Signal" + }, + { + "channel": 11, + "name": "Cer42_2", + "type": "Signal" + }, + { + "channel": 12, + "name": "Cer42_1", + "type": "Signal" + }, + { + "channel": 13, + "name": "Cer42_5", + "type": "Signal" + }, + { + "channel": 14, + "name": "Cer43_3", + "type": "Signal" + }, + { + "channel": 15, + "name": "Cer43_2", + "type": "Signal" + } + ], + "crate": 1, + "slot": 6, + "type": "FADC250" + }, + "module_1_7": { + "channels": [ + { + "channel": 0, + "name": "C7_4", + "type": "Trigger" + }, + { + "channel": 1, + "name": "C7_3", + "type": "Trigger" + }, + { + "channel": 2, + "name": "C7_2", + "type": "Trigger" + }, + { + "channel": 3, + "name": "C7_1", + "type": "Trigger" + }, + { + "channel": 4, + "name": "C6_4", + "type": "Trigger" + }, + { + "channel": 5, + "name": "C6_3", + "type": "Trigger" + }, + { + "channel": 6, + "name": "C6_2", + "type": "Trigger" + }, + { + "channel": 7, + "name": "C6_1", + "type": "Trigger" + }, + { + "channel": 8, + "name": "C5_4", + "type": "Trigger" + }, + { + "channel": 9, + "name": "C5_3", + "type": "Trigger" + }, + { + "channel": 10, + "name": "C5_2", + "type": "Trigger" + }, + { + "channel": 11, + "name": "C5_1", + "type": "Trigger" + }, + { + "channel": 12, + "name": "C4", + "type": "Trigger" + }, + { + "channel": 13, + "name": "C3", + "type": "Trigger" + }, + { + "channel": 14, + "name": "C2", + "type": "Trigger" + }, + { + "channel": 15, + "name": "C1", + "type": "Trigger" + } + ], + "crate": 1, + "slot": 7, + "type": "FADC250" + }, + "module_1_8": { + "channels": [ + { + "channel": 0, + "name": "Cer22_1", + "type": "Signal" + }, + { + "channel": 1, + "name": "Cer22_5", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer32_4", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer32_3", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer32_2", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer32_1", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer32_5", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer31_4", + "type": "Signal" + }, + { + "channel": 8, + "name": "C9_4", + "type": "Trigger" + }, + { + "channel": 9, + "name": "C9_3", + "type": "Trigger" + }, + { + "channel": 10, + "name": "C9_2", + "type": "Trigger" + }, + { + "channel": 11, + "name": "C9_1", + "type": "Trigger" + }, + { + "channel": 12, + "name": "C8_4", + "type": "Trigger" + }, + { + "channel": 13, + "name": "C8_3", + "type": "Trigger" + }, + { + "channel": 14, + "name": "C8_2", + "type": "Trigger" + }, + { + "channel": 15, + "name": "C8_1", + "type": "Trigger" + } + ], + "crate": 1, + "slot": 8, + "type": "FADC250" + }, + "module_1_9": { + "channels": [ + { + "channel": 0, + "name": "Cer43_4", + "type": "Signal" + }, + { + "channel": 2, + "name": "Cer21_4", + "type": "Signal" + }, + { + "channel": 3, + "name": "Cer21_3", + "type": "Signal" + }, + { + "channel": 4, + "name": "Cer21_2", + "type": "Signal" + }, + { + "channel": 5, + "name": "Cer21_1", + "type": "Signal" + }, + { + "channel": 6, + "name": "Cer21_5", + "type": "Signal" + }, + { + "channel": 7, + "name": "Cer22_4", + "type": "Signal" + }, + { + "channel": 8, + "name": "Cer22_3", + "type": "Signal" + }, + { + "channel": 9, + "name": "Cer22_2", + "type": "Signal" + }, + { + "channel": 10, + "name": "S2_11", + "type": "Trigger" + }, + { + "channel": 11, + "name": "S2_10", + "type": "Trigger" + }, + { + "channel": 12, + "name": "S2_9", + "type": "Trigger" + }, + { + "channel": 13, + "name": "S2_8", + "type": "Trigger" + }, + { + "channel": 14, + "name": "S2_7", + "type": "Trigger" + }, + { + "channel": 15, + "name": "S2_6", + "type": "Trigger" + } + ], + "crate": 1, + "slot": 9, + "type": "FADC250" + } +} diff --git a/include/WfAnalyzer.h b/include/WfAnalyzer.h new file mode 100644 index 0000000000000000000000000000000000000000..c6f5b7f4a0c902138288d3523dbce6b5f04c215b --- /dev/null +++ b/include/WfAnalyzer.h @@ -0,0 +1,242 @@ +#pragma once + +// A waveform analyzer class for the Fadc250 raw waveform data +// It finds the local maxima (peaks) over the spectrum, and detemines the peak properties +// It is intended to use simple algorithms since we do not expect heavily convoluted spectra +// +// History: +// v1.0.0: a working version with basic functionalities, Chao Peng, 2020/08/04 + +#include <vector> +#include <algorithm> + +// calculate the mean and standard deviation for an array +namespace wfa { + +// data structures +struct Pedestal { + double mean, err; +}; + +struct Peak { + size_t pos, left, right; + double height, integral; + + bool Inside(size_t i) { + return (i >= pos - left) && (i <= pos + right); + } +}; + +// calculate mean and standard deviation of an array +template<typename T> +inline void _calc_mean_err(double &mean, double &err, T *source, size_t npts) +{ + if (npts == 0) { return; } + + mean = 0.; + err = 0.; + + for (size_t i = 0; i < npts; ++i) { + mean += source[i]; + } + mean /= static_cast<double>(npts); + + for (size_t i = 0; i < npts; ++i) { + err += (source[i] - mean ) * (source[i] - mean); + } + err = std::sqrt(err/static_cast<double>(npts)); +} + +template<typename T> +inline void _linear_regr(double &p0, double &p1, double &err, T *x, T *y, size_t npts) +{ + // no data points + if (npts == 0) { + return; + // too few data points + } else if (npts < 3) { + p1 = 0.; + _calc_mean_err(p0, err, y, npts); + return; + } + + double x_mean, x_err; + _calc_mean_err(x_mean, x_err, x, npts); + double y_mean, y_err; + _calc_mean_err(y_mean, y_err, y, npts); + + double xysum = 0.; + for (size_t i = 0; i < npts; ++i) { + xysum += (x[i] - x_mean) * (y[i] - y_mean); + } + + double r = xysum/(x_err*y_err*npts); + + p1 = r*y_err/x_err; + p0 = y_mean - p1*x_mean; + + err = 0.; + for (size_t i = 0; i < npts; ++i) { + double diff = (p0 + p1*x[i] - y[i]); + err += diff*diff; + } + err = std::sqrt(err/static_cast<double>(npts)); +} + +// analyzer class +class Analyzer +{ +public: + Analyzer(size_t resolution = 2, double threshold = 10.0) + : thres(threshold), res(resolution) {} + ~Analyzer() {} + + void Analyze(uint32_t *samples, size_t nsamples) + { + peaks.clear(); + if (!nsamples) { return; } + + auto buffer = ResSpectrum(samples, nsamples, res); + + // search local maxima + std::vector<Peak> candidates; + candidates.reserve(nsamples/2); + // get trend + auto trend = [] (double v1, double v2, double thr = 0.1) { + return std::abs(v1 - v2) < thr ? 0 : (v1 > v2 ? 1 : -1); + }; + for (size_t i = 1; i < nsamples - 1; ++i) { + int tr1 = trend(buffer[i], buffer[i - 1]); + int tr2 = trend(buffer[i], buffer[i + 1]); + // peak at the rising (declining) edge + if ((tr1 * tr2 >= 0) && (std::abs(tr1) > 0) && std::abs(buffer[i]) > ped.err*3.0) { + size_t left = 1, right = 1; + // search the peak range + while ((i > left + 1) && (trend(buffer[i - left], buffer[i - left - 1]) == tr1)) { + left ++; + } + while ((i + right < nsamples - 1) && (trend(buffer[i + right], buffer[i + right + 1])*tr1 >= 0)) { + right ++; + } + + double base = buffer[i - left] * right / static_cast<double>(left + right) + + buffer[i + right] * left / static_cast<double>(left + right); + double height = std::abs(buffer[i] - base); + if (height > thres) { + candidates.push_back(Peak{i, left, right, buffer[i] - base, 0}); + } + } + } + + auto in_peaks = [] (const std::vector<Peak> &peaks, size_t pos) { + for (auto &peak : peaks) { + size_t width = std::min(peak.left, peak.right); + if (std::abs(peak.pos - static_cast<double>(pos)) <= width) { return true; } + } + return false; + }; + + int nped = 0; + auto ybuf = buffer; + for (size_t i = res + 1; i < nsamples - res - 1; ++i) { + if (!in_peaks(candidates, i)) { + ybuf[nped] = buffer[i]; + nped ++; + } + } + + // calculate pedestal + if (nped <= nsamples/4) { + ped = CalcPedestal(&buffer[0], nsamples, 1.5, 3); + } else { + ped = CalcPedestal(&ybuf[0], nped, 1.2, 3); + } + + for (auto &peak : candidates) { + // real sample height + double sample_height = samples[peak.pos] - ped.mean; + if ((sample_height * peak.height < 0.) || + (std::abs(sample_height) < thres) || + (std::abs(sample_height) < 3.0*ped.err)) { + continue; + } + + // integrate it over the peak range + peak.height = sample_height; + peak.integral = buffer[peak.pos] - ped.mean; + for (size_t i = 1; i <= peak.left; ++i) { + double val = buffer[peak.pos - 1] - ped.mean; + if (std::abs(val) < ped.err) { break; } + peak.integral += val; + } + for (size_t i = 1; i <= peak.right; ++i) { + double val = buffer[peak.pos + i] - ped.mean; + if (std::abs(val) < ped.err) { break; } + peak.integral += val; + } + peaks.emplace_back(peak); + } + + /* + std::sort(peaks.begin(), peaks.end(), + [] (const Peak &p1, const Peak &p2) { return p1.height > p2.height; }); + */ + + } + + const Pedestal &GetPedestal() const { return ped; } + const std::vector<Peak> &GetPeaks() const { return peaks; } + +private: + double thres; + size_t res; + Pedestal ped; + std::vector<Peak> peaks; + + +public: + // static methods + template<typename T> + static std::vector<double> ResSpectrum(T *samples, size_t nsamples, size_t res) + { + std::vector<double> buffer(nsamples); + for (size_t i = 0; i < nsamples; ++i) { + double val = samples[i]; + double weights = 1.0; + for (size_t j = 0; j < res; ++j) { + if (j >= i || j + i >= nsamples) { continue; } + double weight = j/static_cast<double>(res + 1); + val += weight*(samples[i - j] + samples[i + j]); + weights += 2.*weight; + } + buffer[i] = val/weights; + } + return buffer; + } + + template<typename T> + static Pedestal CalcPedestal(T *ybuf, size_t npts, double thres = 1.0, int max_iters = 3) + { + Pedestal res; + _calc_mean_err(res.mean, res.err, ybuf, npts); + // interatively fit + while (max_iters-- > 0) { + int count = 0; + for (size_t i = 0; i < npts; ++i) { + if (std::abs(ybuf[i] - res.mean) < res.err*thres) { + ybuf[count] = ybuf[i]; + count++; + } + } + if (count == npts) { break; } + npts = count; + _calc_mean_err(res.mean, res.err, ybuf, npts); + } + + return res; + } + +}; + +}; // namespace wfa + diff --git a/src/esb_analyze_online.cpp b/src/esb_analyze_online.cpp deleted file mode 100644 index f7a896264a78ac536f2c11e468ec183ce417df22..0000000000000000000000000000000000000000 --- a/src/esb_analyze_online.cpp +++ /dev/null @@ -1,433 +0,0 @@ -#include <iostream> -#include <iomanip> -#include <fstream> -#include <csignal> -#include "utils.h" -#include "ConfigParser.h" -#include "ConfigObject.h" -#include "ConfigOption.h" -#include "TSpectrum.h" -#include "TTree.h" -#include "TFile.h" -#include "TH1.h" -#include "simpleLib.h" -#include "Fadc250Decoder.h" -#include "ETChannel.h" - - -#define FADC_BANK 3 -#define PROGRESS_COUNT 100 - - -volatile sig_atomic_t terminate = 0; - -void handle_sig(int signum) -{ - terminate = 1; -} - - - -void monitor(const std::string &addr, int port, const std::string &etfile, - const std::string &opath, const std::string &modules_conf, int nev); - - -uint32_t swap_endian32(uint32_t num) -{ - uint32_t b0 = (num & 0x000000ff) << 24u; - uint32_t b1 = (num & 0x0000ff00) << 8u; - uint32_t b2 = (num & 0x00ff0000) >> 8u; - uint32_t b3 = (num & 0xff000000) >> 24u; - return b0 | b1 | b2 | b3; -} - - -uint32_t parseBlock(const uint32_t *buf) -{ - auto header = (ETChannel::CodaEvHeader*) buf; - const uint32_t buf_size = header->length + 1; - std::cout << "ROC header: " << std::dec << buf_size << "\n" - << (int) header->etype << ", " << (int) header->dtype << ", " << (int) header->num - << std::endl; - std::cout << std::hex; - for (uint32_t i = 0; i < buf_size; ++i) { - std::cout << "0x" << std::setw(8) << std::setfill('0') << buf[i] << "\n"; - } - return buf_size; -} - -// parse an evio event -bool parseEvent(const uint32_t *buf, bool verbose = false) -{ - auto header = (ETChannel::CodaEvHeader*)buf; - const uint32_t buf_size = header->length + 1; - if (verbose) { - std::cout << "Event header: " << std::dec << buf_size << "\n" - << (int) header->etype << ", " << (int) header->dtype << ", " << (int) header->num - << std::endl; - std::cout << std::hex; - for (uint32_t i = 0; i < 2; ++i) { - std::cout << "0x" << std::setw(8) << std::setfill('0') << buf[i] << "\n"; - } - } - - switch(header->etype) { - case ETChannel::CODA_PHY1: - case ETChannel::CODA_PHY2: - break; - case ETChannel::CODA_PRST: - case ETChannel::CODA_GO: - case ETChannel::CODA_END: - default: - return false; - } - - simpleScan((volatile uint32_t*)buf, buf_size); - return true; - - /* - // parse ROC data - uint32_t index = 2; - while(index < buf_size) { - // skip header size and data size 2 + (length - 1) - index += parseBlock(&buf[index]); - } - - // return parsed event type - return buf_size; - */ -} - - -int main(int argc, char* argv[]) -{ - // setup input arguments - ConfigOption conf_opt; - conf_opt.AddOpts(ConfigOption::help_message, 'h', "help"); - conf_opt.AddOpt(ConfigOption::arg_require, 'n'); - conf_opt.AddOpt(ConfigOption::arg_require, 'p'); - conf_opt.AddOpt(ConfigOption::arg_require, 'f'); - conf_opt.AddLongOpt(ConfigOption::arg_require, "config-module", 'm'); - conf_opt.AddLongOpt(ConfigOption::arg_require, "host", 'o'); - - conf_opt.SetDesc("usage: %0 <data_file> <out_file>"); - conf_opt.SetDesc('n', "number of events to process (< 0 means all)."); - conf_opt.SetDesc('m', "configuration file for modules to be read-in, default \"config/esb_module.conf\"."); - conf_opt.SetDesc('p', "port to et system, default 11111."); - conf_opt.SetDesc('f', "path to et file, default \"/tmp/et_sys\""); - conf_opt.SetDesc('o', "host address of et syste, default localhost"); - - if (!conf_opt.ParseArgs(argc, argv) || conf_opt.NbofArgs() != 1) { - std::cout << conf_opt.GetInstruction() << std::endl; - return -1; - } - - int nev = -1; - std::string mconf = "config/esb_module.conf"; - std::string host = "localhost"; - int port = 11111; - std::string etfile = "/tmp/et_sys"; - - for (auto &opt : conf_opt.GetOptions()) { - switch (opt.mark) { - case 'n': - nev = opt.var.Int(); - break; - case 'm': - mconf = opt.var.String(); - break; - case 'o': - host = opt.var.String(); - break; - case 'p': - port = opt.var.Int(); - break; - case 'f': - etfile = opt.var.String(); - break; - default : - std::cout << conf_opt.GetInstruction() << std::endl; - return -1; - } - } - - monitor(host, port, etfile, conf_opt.GetArgument(0), mconf, nev); -} - - -#define MAX_NPEAKS 20 -#define MAX_RAW 300 -struct BranchData -{ - int npul, nraw; - float integral[MAX_NPEAKS], peak[MAX_NPEAKS], time[MAX_NPEAKS]; - int raw[MAX_RAW]; - float ped_mean, ped_err; -}; - -#define BUF_SIZE 1000 -static double buffer[BUF_SIZE], wfbuf[BUF_SIZE], bkbuf[BUF_SIZE]; -void refine_pedestal(const std::vector<uint32_t> &raw, float &ped_mean, float &ped_err) -{ - int count = 0; - float mean = 0.; - for (auto &val : raw) { - if (std::abs(val - ped_mean) < 2.0 * ped_err) { - buffer[count] = val; - mean += val; - count ++; - } - } - if (count == 0) { - return; - } - - mean /= count; - float change = std::abs(ped_mean - mean); - - // no outliers - if (change < 0.05 * ped_err) { - return; - } - - // recursively refine - float err = 0.; - for (int i = 0; i < count; ++i) { - err += (buffer[i] - mean)*(buffer[i] - mean); - } - ped_mean = mean; - ped_err = std::sqrt(err/count); - refine_pedestal(raw, ped_mean, ped_err); -} - -// a function for a simple constant baseline fit -void find_pedestal(const std::vector<uint32_t> &raw, float &ped_mean, float &ped_err) -{ - ped_mean = 0; - ped_err = 0; - - for (auto &val : raw) { - ped_mean += val; - } - ped_mean /= raw.size(); - - for (auto &val : raw) { - ped_err += (val - ped_mean)*(val - ped_mean); - } - ped_err = std::sqrt(ped_err/raw.size()); - - refine_pedestal(raw, ped_mean, ped_err); -} - -// analyze the waveform data and fill the result in a branch data -void waveform_analysis(const std::vector<uint32_t> &raw, BranchData &res) -{ - // no need to analyze - if (raw.empty()) { - return; - } - - // fill in the raw data - res.nraw = raw.size(); - for (size_t i = 0; i < raw.size(); ++i) { - res.raw[i] = raw[i]; - } - - // get pedestals - find_pedestal(raw, res.ped_mean, res.ped_err); - - // fill in spectrum buffer - for (size_t i = 0; i < raw.size(); ++i) { - wfbuf[i] = raw[i] - res.ped_mean; - } - - // find peaks - TSpectrum s; - s.SetResolution(0.5); - int npeaks = s.SearchHighRes(wfbuf, bkbuf, res.nraw, 3.0, 20, false, 5, true, 3); - - // fill branch data - double *pos = s.GetPositionX(); - res.npul = 0; - for (int i = 0; i < npeaks; ++i) { - int j = pos[i]; - if (wfbuf[j] < 5.*res.ped_err) { continue; } - res.time[res.npul] = j; - res.peak[res.npul] = wfbuf[j]; - /* - res.integral[res.npul] = wfbuf[j]; - j = pos[i] - 1; - while ( (j > 0) && (wfbuf[j] - wfbuf[j - 1])*wfbuf[j] > 0. ) { - res.integral[res.npul] += wfbuf[j--]; - } - j = pos[i] + 1; - while ( (j < res.nraw - 1) && (wfbuf[j] - wfbuf[j + 1])*wfbuf[j] > 0. ) { - res.integral[res.npul] += wfbuf[j++]; - } - */ - res.npul ++; - } -} - - -// fill decoded FADC250 data into the container (branch data) -void fill_branch(const Fadc250Data &slot_data, const Module &mod, std::unordered_map<std::string, BranchData> &brdata) -{ - for (auto &event : slot_data.events) { - for (auto &ch : mod.channels) { - auto &channel = event.channels[ch.id]; - auto &bd = brdata[ch.name]; - bd.npul = channel.integral.size(); - for (uint32_t i = 0; i < channel.integral.size(); ++i) { - bd.integral[i] = channel.integral[i]; - bd.time[i] = channel.time[i]; - } - waveform_analysis(channel.raw, bd); - } - } -} - -// fill branch data into the root tree -void fill_tree(TTree *tree, std::unordered_map<std::string, BranchData> &brdata, bool &init, int mode) -{ - if ((mode != 1) && (mode != 3)) { - std::cout << "Warning: unsupported mode " << mode << ", data won't be recorded." << std::endl; - return; - } - - // initialize - if (!init) { - for (auto &it : brdata) { - auto n = it.first; - tree->Branch((n + "_Npulse").c_str(), &brdata[n].npul, (n + "_N/I").c_str()); - tree->Branch((n + "_Pint").c_str(), &brdata[n].integral[0], (n + "_Pint[" + n + "_N]/F").c_str()); - tree->Branch((n + "_Ptime").c_str(), &brdata[n].time[0], (n + "_Ptime[" + n + "_N]/F").c_str()); - // raw waveform provides more information - if (mode == 1) { - tree->Branch((n + "_Ppeak").c_str(), &brdata[n].peak[0], (n + "_Ppeak[" + n + "_N]/F").c_str()); - tree->Branch((n + "_Nraw").c_str(), &brdata[n].nraw, (n + "_Nraw/I").c_str()); - tree->Branch((n + "_raw").c_str(), &brdata[n].raw[0], (n + "_raw[" + n + "_Nraw]/I").c_str()); - tree->Branch((n + "_ped_mean").c_str(), &brdata[n].ped_mean, (n + "_ped_mean/F").c_str()); - tree->Branch((n + "_ped_err").c_str(), &brdata[n].ped_err, (n + "_ped_err/F").c_str()); - } - } - init = true; - std::cout << "Initialized root file for mode " << mode << " data." << std::endl; - } - - tree->Fill(); -} - - -void processEvent(const uint32_t *buf, int &count, TTree *tree, bool &init_tree, int &data_mode, - const std::vector<Module> &modules, std::unordered_map<std::string, BranchData> &brdata) -{ - if (!parseEvent(buf, false)) { - return; - } - - // get block level - int blvl = 1; - simpleGetRocBlockLevel(modules.front().crate, FADC_BANK, &blvl); - - for (int ii = 0; ii < blvl; ++ii) { - // clear data buffer - for (auto &br : brdata) { - br.second.npul = 0; - br.second.nraw = 0; - } - - // parse module data - for (auto &mod : modules) { - uint32_t header = 0; - auto status = simpleGetSlotBlockHeader(mod.crate, FADC_BANK, mod.slot, &header); - if (status <= 0) { - std::cout << "Error getting header for crate = " - << mod.crate << ", slot = " << mod.slot << std::endl; - continue; - } - - uint32_t *dbuf; - auto len = simpleGetSlotEventData(mod.crate, FADC_BANK, mod.slot, ii, &dbuf); - if (len <= 0) { - std::cout << "No data for crate = " << mod.crate << ", slot = " << mod.slot - << ", block_level = " << ii << std::endl; - continue; - } - auto slot_data = fadc250_decoder(header, dbuf, len); - - // check data mode - if (data_mode < 0 && slot_data.GetMode() > 0) { - data_mode = slot_data.GetMode(); - } - // fill branch data - fill_branch(slot_data, mod, brdata); - } - - // fill event - fill_tree(tree, brdata, init_tree, data_mode); - count ++; - } -} - - -void monitor(const std::string &addr, int port, const std::string &etfile, - const std::string &opath, const std::string &mconf, int nev) -{ - ETChannel et_chan(100, 100); - if (et_chan.Connect(addr.c_str(), port, etfile.c_str(), "TCD_MONITOR") != ET_OK) { - return; - } - - auto modules = read_modules(mconf); - - auto *hfile = new TFile(opath.c_str(), "RECREATE", "MAPMT online monitor"); - auto tree = new TTree("EvTree", "Cherenkov Test Events"); - // set up branches and a container to be combined with the branches - std::unordered_map<std::string, BranchData> brdata; - for (auto &mod : modules) { - for (auto &ch : mod.channels) { - auto n = ch.name; - if (brdata.find(n) != brdata.end()) { - std::cout << "WARNING: Duplicated channel names found! -- " << n << std::endl; - } - brdata[n] = BranchData(); - } - } - - int count = 0; - bool init_tree = false; - int data_mode = -1; - int status = ETChannel::READ_EMPTY; - et_chan.Open(); - signal (SIGINT, handle_sig); - - while (true) { - if (terminate > 0 || (nev > 0 && nev < count)) { break; } - if (count % PROGRESS_COUNT == 0) { - std::cout << "Read and processed events - " << count << std::endl; - } - - status = et_chan.ReadEvent(); - - switch (status) { - case ETChannel::READ_ERROR: - case ETChannel::READ_EOF: - terminate = 1; - break; - case ETChannel::READ_EMPTY: - std::cout << "ET station is empty, wait 2 secs..." << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(2)); - break; - case ETChannel::READ_OK: - processEvent(et_chan.GetEvBuffer(), count, tree, init_tree, data_mode, modules, brdata); - break; - } - } - - std::cout << "Read and processed events - " << count << std::endl; - - hfile->Write(); - hfile->Close(); -} - diff --git a/tools/test_wfanalyzer.cxx b/tools/test_wfanalyzer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..046ee8279a87668728871d017a0499f66b61fb4e --- /dev/null +++ b/tools/test_wfanalyzer.cxx @@ -0,0 +1,95 @@ +#include "WfAnalyzer.h" + + +void test(size_t res = 3, double thres = 10.0) +{ + gStyle->SetOptStat(0); + std::vector<std::vector<uint32_t>> tests = { + { + 129, 132, 131, 128, 128, 127, 130, 130, 126, 126, 128, 126, 126, + 127, 128, 125, 130, 130, 131, 143, 146, 149, 143, 142, 139, 136, +// 127, 128, 125, 123, 120, 121, 113, 109, 102, 109, 110, 119, 126, + 134, 135, 132, 132, 132, 128, 139, 167, 188, 189, 180, 171, 164, + 156, 150, 145, 143, 140, 136, 137, 136, 132, 131, 132, 132, 132, + 130, 129, 131, 130, 131, 131, 128, 130, 129, 127, 128, 127 + }, + { + 567, 484, 414, 359, 320, 291, 271, 275, 279, 278, 271, 271, 277, + 277, 265, 252, 237, 228, 213, 207, 201, 195, 188, 183, 179, 176, + 173, 191, 217, 231, 298, 392, 436, 423, 383, 341, 302, 265, 237, + 215, 198, 181, 171, 160, 151, 152, 144, 137, 136, 134, 133, 130, + 125, 125, 124, 123, 120, 122, 117, 117, 116, 115, 116, 113 + }, + }; + + wfa::Analyzer ana(res, thres); + + auto c = new TCanvas("test", "test", 1280, 720); + c->DivideSquare(tests.size()); + + int count = 0; + for (auto &samples : tests) { + count ++; + c->cd(count); + // waveform + auto wf = new TGraph(samples.size()); + for (size_t i = 0; i < samples.size(); ++i) { + wf->SetPoint(i, i, samples[i]); + } + wf->SetLineColor(kBlue + 1); + wf->SetLineWidth(1); + wf->SetLineStyle(2); + wf->Draw("AL"); + + // waveform resolution + auto wf2 = new TGraph(samples.size()); + auto buf = wfa::Analyzer::ResSpectrum(&samples[0], samples.size(), res); + for (size_t i = 0; i < buf.size(); ++i) { + wf2->SetPoint(i, i, buf[i]); + } + wf2->SetLineColor(kBlue + 1); + wf2->SetLineWidth(3); + wf2->Draw("L same"); + + // peak finding + ana.Analyze(&samples[0], samples.size()); + auto ped = ana.GetPedestal(); + auto gr = new TGraph(samples.size()); + gr->SetMarkerStyle(23); + for (auto &peak : ana.GetPeaks()) { + gr->SetPoint(gr->GetN(), peak.pos, peak.height + ped.mean); + // gr->SetPoint(gr->GetN(), peak.pos - peak.left, peak.height + peak.base); + // gr->SetPoint(gr->GetN(), peak.pos + peak.right, peak.height + peak.base); + std::cout << peak.pos << ", " << peak.pos - peak.left << ", " << peak.pos + peak.right + << ", " << peak.height << ", " << peak.integral << std::endl; + } + gr->Draw("P same"); + + // pedestal line + /* + std::vector<double> tped(samples.size()); + tped.assign(samples.begin(), samples.end()); + TSpectrum s; + s.Background(&tped[0], samples.size(), samples.size()/4, TSpectrum::kBackDecreasingWindow, + TSpectrum::kBackOrder2, false, TSpectrum::kBackSmoothing3, false); + */ + auto grp = new TGraph(samples.size()); + auto gre = new TGraph(2*samples.size()); + for (size_t i = 0; i < samples.size(); ++i) { + double pedy = ped.mean; + grp->SetPoint(i, i, pedy); + // grp->SetPoint(i, i, tped[i]); + gre->SetPoint(i, i, pedy + ped.err); + size_t j = samples.size() - i - 1; + double pedy2 = ped.mean; // p0 + ped.p1*j; + gre->SetPoint(i + samples.size(), j, pedy2 - ped.err); + } + gre->SetFillStyle(3001); + gre->SetFillColor(kRed); + grp->SetLineStyle(0); + grp->SetLineWidth(2); + grp->SetLineColor(kRed); + gre->Draw("f same"); + grp->Draw("L same"); + } +}