Belle II Software development
CsIDigitizerModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9// Own header
10#include <beast/csi/modules/CsIDigitizerModule.h>
11
12// Beast headers
13#include <beast/csi/geometry/CsiGeometryPar.h>
14
15// Basf2 headers
16#include <framework/dataobjects/EventMetaData.h>
17#include <framework/datastore/StoreObjPtr.h>
18
19// ROOT headers
20#include <TGraph.h>
21#include <TH1.h>
22#include <TH1I.h>
23#include <TRandom.h>
24#include <Math/Vector3D.h>
25
26// C++ headers
27#include <vector>
28
29using namespace std;
30using namespace Belle2;
31using namespace csi;
32//-----------------------------------------------------------------
33// Register the Module
34//-----------------------------------------------------------------
35REG_MODULE(CsIDigitizer);
36
37//-----------------------------------------------------------------
38// Implementation
39//-----------------------------------------------------------------
40
41//Calibration constants (hard-coded for now, put in the xml file for later)
43 m_TrueEdep(0.0),
44 m_nWFcounter(0),
45 m_aDigiHit("CsiDigiHits"),
46 m_calibConstants(16, 5),
47 m_noiseLevels(16, 0.25e-3),
48 m_LY(16, 40e6),
49 m_tRatio(16, 0),
50 m_tFast(16, 1),
51 m_tSlow(16, 1),
52 m_LCE(16, 0.1),
53 m_PmtQE(16, 0.05),
54 m_PmtGain(16, 1e5)
55{
56 // Set module properties
57 setDescription("Digitizer for the BEAST CsI system");
58
59 // Parameter definitions
60 addParam("Resolution", m_Resolution, "Resolution (in mV) of the ACD", 4.8828e-4);
61 addParam("SampleRate", m_SampleRate, "Sample rate (in samples/sec) of the ADC", 250e6);
62 addParam("nWaveforms", m_nWaveforms, "Number of waveforms to save. 0: none, -1: all ", 0);
63}
64
66{
67}
68
70{
71
72 B2DEBUG(100, "Initializing ");
73
74 m_aSimHit.isRequired();
75 m_aDigiHit.registerInDataStore();
76
77 //Calculation of the derived parameters
78 m_dt = 1e9 / m_SampleRate;
79 setnSamples(8192);
80
81 //Get crystal and PMT constants from xml files
83 for (uint i = 0; i != m_LY.size(); ++i) {
84 csip->Print(i, 80);
85
86 m_LY.at(i) = 1;//1e3 * csip->GetMaterialProperty(i, "SCINTILLATIONYIELD");
87 m_tFast.at(i) = 1;//csip->GetMaterialProperty(i, "FASTTIMECONSTANT");
88 m_tSlow.at(i) = 1;//csip->GetMaterialProperty(i, "SLOWTIMECONSTANT");
89 m_tRatio.at(i) = 1;//csip->GetMaterialProperty(i, "YIELDRATIO");
90 }
91
92 //Operate the pure CsI at higher gain to compensate for lower light yield
93 for (int i = 8; i < 16; i++) {
94 m_PmtGain[i] = 35e5;
95 }
96
97}
98
100{
101 //Signal tempo = genTimeSignal(10, 10, 2, 0, 1);
102}
103
105{
106 StoreObjPtr<EventMetaData> eventMetaDataPtr;
107 int m_currentEventNumber = eventMetaDataPtr->getEvent();
108
109 B2DEBUG(80, "Digitingevent " << m_currentEventNumber);
110
111 //Loop over CsiSimHits
112 if (m_aSimHit.getEntries() > 0) {
113 int hitNum = m_aSimHit.getEntries();
115 // double E_tmp[16] = {0}; /**< Sum energy deposited in each cell */
116 // double edepSum = 0; /**< Sum energy deposited in all cells */
117
118 for (int i = 0 ; i < 16 ; i++) {
119 m_SimHitTimes[i].clear();
120 m_SimHitEdeps[i].clear();
121 }
122
123
124 B2DEBUG(150, "Looping over CsISimHits");
125 for (int i = 0; i < hitNum; i++) { // Loop over CsISimHits
126 CsiSimHit* aCsISimHit = m_aSimHit[i];
127 int m_cellID = aCsISimHit->getCellId();
128 double edep = aCsISimHit->getEnergyDep();
129 double tof = aCsISimHit->getFlightTime();
130 // double hitTime = aCsISimHit->getTimeAve(); /**< Time average of the hit*/
131 // double hitTimeRMS = sqrt( aCsISimHit->getTimeVar()/aCsISimHit->getEnergyDep()); /**< Time rms of the hit*/
133
134 ROOT::Math::XYZVector hitPos = aCsISimHit->getPosition();
135 ROOT::Math::XYZVector cellPos = csip->GetPosition(m_cellID);
136 ROOT::Math::XYZVector cellAngle = csip->GetOrientation(m_cellID);
137
138 double localPos = (15. - (hitPos - cellPos).Dot(
139 cellAngle));
141 // 0.06 is the speed of light in CsI(Tl)
142 double propagTime = m_SampleRate *
143 (0.0600 * localPos + (tof / CLHEP::ns)) * 1E-9;
146 m_SimHitTimes[m_cellID].push_back(propagTime);
147 m_SimHitEdeps[m_cellID].push_back(edep);
148
149 /*
150 if (i<10){
151 B2INFO("Hit No = : " << i );
152 B2INFO("Deposited energy = : " << edep );
153 B2INFO("Average time = : " << hitTime );
154 B2INFO("Time RMS = : " << hitTimeRMS );
155
156 csip->Print(m_cellID);
157 }
158 */
159
160 }
161
162 for (int iCh = 0; iCh < 16; iCh++) {
163
164 int n = m_SimHitTimes[iCh].size();
165
166 if (n > 0) {
167
168 B2DEBUG(140, "Generating Time signal");
169 Signal tempSignal;
170 m_TrueEdep = genTimeSignal(&tempSignal, m_SimHitEdeps[iCh], m_SimHitTimes[iCh], iCh, m_dt, m_nSamples, false);
171
172
173 B2DEBUG(140, "Launching Charge integration");
174 bool recordWaveform = false;
175 if ((m_nWaveforms == -1) || (m_nWFcounter < m_nWaveforms)) {
176 m_nWFcounter++;
177 recordWaveform = true;
178 B2DEBUG(80, "Recording WF");
179 }
180 uint16_t max = doChargeIntegration(tempSignal, 128, &m_Baseline, &m_Charge, &m_Time, &m_Waveform,
181 &m_DPPCIBits, 5, 1.2e4, 1e4, 1e3, recordWaveform);
182
183 if (m_Charge > 0) {
184 m_aDigiHit.appendNew();
185 m_hitNum = m_aDigiHit.getEntries() - 1;
186 m_aDigiHit[m_hitNum]->setCellId(iCh);
187 m_aDigiHit[m_hitNum]->setCharge(m_Charge);
188 m_aDigiHit[m_hitNum]->setTime(m_Time);
189 m_aDigiHit[m_hitNum]->setBaseline(m_Baseline);
190 m_aDigiHit[m_hitNum]->setTrueEdep(m_TrueEdep);
191
192 m_aDigiHit[m_hitNum]->setMaxVal(max);
193
194 m_aDigiHit[m_hitNum]->setWaveform(&m_Waveform);
195 m_aDigiHit[m_hitNum]->setStatusBits(&m_DPPCIBits);
196 }
197 }
198 }
199 }
200}
201
202
204{
205}
206
208{
209}
210
211uint16_t CsIDigitizerModule::doChargeIntegration(Signal _u, int _NsamBL, uint16_t* _BSL, uint32_t* _Q,
212 uint32_t* _t, vector<uint16_t>* _Waveform,
213 vector<uint8_t>* _DPPCIBits, int _Treshold,
214 double _TriggerHoldoff, double _GateWidth,
215 double _GateOffset, bool _recordTraces)
216{
217
218 B2DEBUG(80, "Arguments: " << &_u << ", " << _NsamBL << ", " << _BSL << ", " << _Q << ", " << _t
219 << ", " << _Waveform << ", " << _Treshold << ", " << _TriggerHoldoff << ", " << _GateWidth
220 << ", " << _GateOffset << ", " << _recordTraces);
221
222 vector<int> x = doDigitization(_u, m_Resolution);
223 int nSam = x.size();
224
225 // Plots for debugging (see CAEN DPP-CI figs 2.2,2.3
226 TH1I h_trigger("h_trigger", "Trigger", nSam, 0, nSam - 1);
227 TH1I h_gate("h_gate", "Gate", nSam, 0, nSam - 1);
228 TH1I h_holdoff("h_holdoff", "Holdoff", nSam, 0, nSam - 1);
229 TH1I h_baseline("h_baseline", "Baseline", nSam, 0, nSam - 1);
230 TH1I h_charge("h_charge", "Charge", nSam, 0, nSam - 1);
231 TH1F h_signal("h_signal", "Continuous signal", nSam, 0, nSam - 1);
232 TH1I h_digsig("h_digsig", "Digital signal", nSam, 0, nSam - 1);
233
234
235 int max_gated = (int) floor(_GateWidth / m_dt);
236 int gate_offset = (int) floor(_GateOffset / m_dt);
237 int max_holdoff = (int) floor(_TriggerHoldoff / m_dt);
238
239 int baseline = 0;
240 int charge = 0;
241 int n_holdoff = 0;
242 int n_gated = 0;
243
244 bool gate = false;
245 bool holdoff = false;
246 bool stop = false;
247 bool trigger = false;
248
249 // Find trigger position
250 int i = 0;
251 int iFirstTrigger = 0;
252 list<int> baselineBuffer;
253 vector<int>::iterator it;
254 float tempBaseline;
255
256 // Saving inverse number of samples used for baseline averaging (avoid division)
257 const double invMaxNavgBL = 1.0 / _NsamBL;
258 double invNavgBL;
260 _Waveform->resize(nSam, 0);
261 _DPPCIBits->resize(nSam, 0);
262
263 B2DEBUG(140, "Scanning vector: all should have nSam=" << nSam);
264
265 uint16_t maxval = 0;
266
267 for (it = x.begin(); (it != x.end()); ++it, ++i) {
268
269 if (*it > maxval)
270 maxval = *it;
271
272 _Waveform->at(i) = *it;
273 _DPPCIBits->at(i) = trigger + (gate << 1) + (holdoff << 2) + (stop << 3);
274
275 if (_recordTraces) {
276
277 h_trigger.Fill(i, (int) trigger) ;
278 h_gate.Fill(i, (int) gate) ;
279 h_holdoff.Fill(i, (int) holdoff) ;
280 h_baseline.Fill(i, baseline) ;
281 h_charge.Fill(i, charge) ;
282 h_digsig.Fill(i, *it) ;
283 h_signal.Fill(i, _u.at(i)) ;
284 }
285
286 if (!gate && !holdoff) {
287
288 baselineBuffer.push_back(*it);
289
290
291 if ((i + 1) > _NsamBL) {
292 baselineBuffer.pop_front();
293 invNavgBL = invMaxNavgBL;
294 } else {
295 invNavgBL = (1.0 / i);
296 }
297
298 tempBaseline = 0;
299 for (list<int>::iterator itbl = baselineBuffer.begin(); itbl != baselineBuffer.end(); ++itbl)
300 tempBaseline += (float) * itbl;
301
302 tempBaseline *= invNavgBL;
303
304 baseline = (int) round(tempBaseline);
305
306 trigger = (*it - baseline) > _Treshold;
307
308 //first time we see a trigger
309 if (trigger && !iFirstTrigger)
310 iFirstTrigger = i;
311
312 } else {
313
314 if (gate) {
315 charge += (*(it - gate_offset) - baseline);
316 *_BSL = baseline;
317 n_gated++;
318 }
319
320 if (holdoff) {
321 n_holdoff++;
322 }
323
324 trigger = false;
325 }
326
327 holdoff = trigger || (holdoff && (n_holdoff < max_holdoff));
328 gate = trigger || (gate && (n_gated < max_gated));
329
330 stop = iFirstTrigger && !gate && !holdoff;
331 }
332
333 *_Q = charge;
334 // from the doc: 2 sample uncertainty.
335 *_t = (uint)(iFirstTrigger + 2.0 * (gRandom->Rndm() - 0.5));
336
337 if (not(_recordTraces)) {
338 _Waveform->clear();
339 _DPPCIBits->clear();
340 }
341
342 return maxval;
343}
344
345vector<int> CsIDigitizerModule::doDigitization(Signal _v, double _LSB)
346{
347 vector<int> output(_v.size(), 0);
348 double invLSB = 1.0 / _LSB;
349
350 int i = 0;
351 for (Signal::iterator it = _v.begin() ; it != _v.end(); ++it, ++i) {
352 output.at(i) = (int) round(*it * invLSB);
353 }
354
355 return output;
356}
357
358double CsIDigitizerModule::genTimeSignal(Signal* _output, Signal _energies, Signal _times, int _iChannel, int _dt, int _nsam,
359 bool _save)
360{
361
362 double invdt = 1.0 / _dt;
363
364 double tf = 0;
365 double t0 = 1e9;
366 double sumEnergies = 0.0;
367
368 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it) {
369 if (*it < t0)
370 t0 = *it;
371
372 if (*it > tf)
373 tf = *it;
374 }
375
376 Signal edepos(_nsam, 0.0);
377
378 int i = 0;
379 int ioffset = floor(_nsam * 0.25);
380 B2DEBUG(150, "Filling edepos vector. Container length is " << _nsam);
381
382 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it, ++i) {
383 sumEnergies += _energies.at(i);
384 // time index +/- 1 time bin
385 int timeIndex = ((int)(*it - t0) * invdt + ioffset);
386 if ((timeIndex - 1) > (int) edepos.size()) {
387 B2WARNING(" genTimeSignal: TimeIndex greater than length of signal container. Skipping deposit of " << _energies.at(i) << "GeV");
388 } else {
389 edepos.at(timeIndex) += _energies.at(i);
390 }
391 }
392
393 B2DEBUG(80, "Generating time responses for channel " << _iChannel);
394 B2DEBUG(80, " Fast time constant " << m_tFast[_iChannel]);
395 B2DEBUG(80, " Slow time constant " << m_tSlow[_iChannel]);
396 /*
397 Signal Qcathode = firstOrderResponse(m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel],
398 edepos, 0, _dt, m_tSlow[_iChannel], 0.0, m_tRatio[_iChannel], m_tFast[_iChannel]);
399 */
400
401 Signal Qcathode = firstOrderResponse((1 - m_tRatio[_iChannel]) * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0,
402 _dt, m_tSlow[_iChannel], 0.0);
403
404
405 if (m_tRatio[_iChannel]) {
406 Signal QcathodeF = firstOrderResponse(m_tRatio[_iChannel] * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0, _dt,
407 m_tFast[_iChannel], 0.0);
408
409 int j = 0;
410 for (Signal::iterator it = Qcathode.begin() ; it != Qcathode.end(); ++it, ++j)
411 *it += QcathodeF.at(j);
412 }
413
414 Signal Vanode = firstOrderResponse(1.602e-10 * m_Zl * invdt * m_PmtGain[_iChannel], Qcathode, 0, _dt, m_tRisePMT, m_tTransitPMT);
415
416 B2DEBUG(150, "Adding noise. Container length is " << Vanode.size());
417 addNoise(&Vanode, m_noiseLevels[_iChannel], 5e-3 * gRandom->Rndm() + 1e-2);
418
419 if (_save) {
420 Signal t(_nsam, 0);
421 t.at(0) = t0;
422
423 for (i = 1; i < _nsam; i++)
424 t.at(i) = t.at(i - 1) + _dt;
425
426 TGraph gPlot1(_nsam, &t[0], &edepos[0]);
427 gPlot1.SaveAs("EdeposOut.root");
428
429 TGraph gPlot2(_nsam, &t[0], &Qcathode[0]);
430 gPlot2.SaveAs("QOut.root");
431
432 TGraph gPlot3(_nsam, &t[0], &Vanode[0]);
433 gPlot3.SaveAs("VOut.root");
434 }
435
436 *_output = Vanode;
437
438 return sumEnergies;
439}
440
441
442int CsIDigitizerModule::addNoise(Signal* y, double _rms, double _offset)
443{
444 for (Signal::iterator it = y->begin() ; it != y->end(); ++it)
445 *it += _offset + gRandom->Gaus(0, _rms);
446
447 return y->size();
448}
449
450/*
451Signal CsIDigitizerModule::firstOrderResponse(double _gain, Signal _u, double _y0, double _dt, double _tSlow, double _delay, double _tRatio, double _tFast)
452{
453
454 Signal slowLight = firstOrderResponse(_gain*(1-_tRatio), _u, _y0, _dt, _tFast, _delay);
455
456 if (_tRatio>0) {
457 Signal fastLight = firstOrderResponse(_gain* _tRatio , _u, _y0, _dt, _tFast, _delay);
458 int i=0;
459 for (Signal::iterator it = slowLight.begin() ; it != slowLight.end(); ++it, ++i)
460 *it += fastLight.at(i);
461 }
462 B2WARNING("You shouldn't see this!");
463 return slowLight;
464
465}
466*/
467
468Signal CsIDigitizerModule::firstOrderResponse(double _gain, Signal _u, double _y0, double _dt, double _tau, double _delay)
469{
470
471 B2DEBUG(80, "Generating 1st order response with arguments");
472 B2DEBUG(80, " _gain: " << _gain);
473 B2DEBUG(80, " length(_u): " << _u.size());
474 B2DEBUG(80, " _y0: " << _y0);
475 B2DEBUG(80, " _dt: " << _dt);
476 B2DEBUG(80, " _tau: " << _tau);
477 B2DEBUG(80, " _delay: " << _delay);
478
479
480 // First skip everything if the time constant in infinitely short.
481 if (_tau == 0)
482 return _u;
483
484 int n = _u.size();
485 Signal y;
486 double k[4] = {0};
487
488 static const double invSix = 1.0 / 6.0;
489 double invtau = 1.0 / _tau;
490 y.push_back(_y0);
491
492 // Apply delay to input
493 int n_delay = (int) round(_delay / _dt);
494 Signal::iterator it = _u.begin();
495 double _u_0 = _u.front();
496 _u.insert(it, n_delay, _u_0);
497 _u.resize(n);
498
499 // Apply that input to the good old Runge-Kutta 4 routine.
500 for (int i = 0, j = 0; i < (n - 1); i++) {
501 j = i + 1;
502 k[0] = f(i, _u[i], _u[j], y[i], invtau);
503 k[1] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[0], invtau);
504 k[2] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[1], invtau);
505 k[3] = f(j, _u[i], _u[j], y[i] + _dt * k[2], invtau);
506
507 y.push_back(y[i] + _dt * invSix * (k[0] + 2 * k[1] + 2 * k[2] + k[3]));
508 }
509
510
511 // Apply gain
512 if (_gain != 1) {
513 for (Signal::iterator it2 = y.begin() ; it2 != y.end(); ++it2)
514 *it2 *= _gain;
515 }
516
517 return y;
518}
519
520
521double CsIDigitizerModule::f(double fi, double u_i, double u_j, double y, double invtau)
522{
523 //linear interpolation of the input at fractional index fi
524 double u = u_i * (fi - floor(fi)) + u_j * (ceil(fi) - fi);
525
526 return u - invtau * y;
527}
528
R E
internal precision of FFTW codelets
ClassCsiSimHit - Geant4 simulated hits in CsI crystals in BEAST.
Definition: CsiSimHit.h:31
int getCellId() const
Get Cell ID.
Definition: CsiSimHit.h:87
double getFlightTime() const
Get Flight time from IP.
Definition: CsiSimHit.h:102
double getEnergyDep() const
Get Deposit energy.
Definition: CsiSimHit.h:107
ROOT::Math::XYZVector getPosition() const
Get Position.
Definition: CsiSimHit.h:122
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
uint16_t m_Baseline
Baseline (pedestal) frozen during charge integration.
int addNoise(Signal *y, double _rms, double _offset)
Adds noise to the signal.
Signal m_SimHitEdeps[16]
Array of signals (each corresponding to one channel)
double m_Resolution
Parameter: Resolution (in mV) of the ACD.
DigitalSignal doDigitization(Signal _v, double _LSB)
Digitizes the signal the signal.
double m_TrueEdep
Sum of the MC (true) deposited energies in the event-channel.
std::vector< double > m_noiseLevels
Noise level for each channel (in V)
std::vector< uint16_t > m_Waveform
Saved waveform.
virtual void initialize() override
Register input and output data.
double f(double fi, double u_i, double u_j, double y, double invtau)
This returns the RHS of first order differential equation.
const double m_Zl
Line impedance of the analog chain (to get voltage from anode current)
virtual void event() override
Each event This is where the actual digitization is done, and the hits are written to the DataStore.
Signal firstOrderResponse(double _gain, Signal _u, double _y0, double _dt, double _tSlow, double _delay)
Calculates the time response of a first order system (such as crystal, PMT, etc)
virtual void endRun() override
Clean up.
Signal genTimeSignal(double _energy, double _timeAvg, double _timeRMS, int iChannel, bool _save=0)
Generates a time signal for a mean energy deposit The energy deposit is modelled at a Gaussian whose ...
StoreArray< CsiSimHit > m_aSimHit
Each simulated particle in the crystal.
int m_nWFcounter
Counter for the number of waveforms to save.
virtual void terminate() override
Final clean up.
double m_dt
Time interval (in ns) (calculated from m_SampleRate.
std::vector< double > m_LCE
Light collection efficiency for each channel.
void setnSamples(int nsamples)
Sets the number of points in the waveforms arrays.
const double m_tTransitPMT
48Mean transit time of the PMT signal (in ns)
std::vector< double > m_LY
Light yield for each channel (gamma per GeV)
int m_nSamples
Number of points requested in the waveform arrays.
virtual ~CsIDigitizerModule()
Default destructor.
virtual void beginRun() override
To do before each runs.
std::vector< double > m_PmtGain
PMT gain for each channel.
std::vector< double > m_PmtQE
PMT quantum efficiency for each channel.
std::vector< uint8_t > m_DPPCIBits
status of the DPP-CI
const double m_tRisePMT
2.6 Rise time of the PMT signal (in ns)
std::vector< double > m_tSlow
Slow time constant for each channel (ns)
std::vector< double > m_tRatio
Ratio fast light / slow light for each channel.
StoreArray< CsiDigiHit > m_aDigiHit
Output: a digitized hit.
uint16_t doChargeIntegration(Signal _u, int _NsamBL, uint16_t *BSL, uint32_t *Q, uint32_t *t, std::vector< uint16_t > *_Waveform, std::vector< uint8_t > *_DPPCIBits, int _Treshold, double _TriggerHoldoff=0.0, double _GateWidth=320.0, double _GateOffset=40.0, bool _recordTraces=false)
Realizes the charge integration of the input signal.
double m_SampleRate
Parameter: Sample rate (in samples/sec) of the ADC.
int m_nWaveforms
Number of waveforms to save.
Signal m_SimHitTimes[16]
Array of signals (each corresponding to one channel)
CsIDigitizerModule()
Constructor: Sets the description, the properties and the parameters of the module.
uint32_t m_Charge
Integrated Charge.
std::vector< double > m_tFast
Fast time constant for each channel (ns)
The Class for CSI Geometry Parameters.
ROOT::Math::XYZVector GetOrientation(int cid)
Get the orientation of the crystal.
void Print(const int cid, int debuglevel=80)
Print crystal information.
ROOT::Math::XYZVector GetPosition(int cid)
Get the position of the crystal.
static CsiGeometryPar * Instance()
Static method to get a reference to the CsiGeometryPar instance.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:649
std::vector< double > Signal
Designed to hold a "continuous" (in time and amplitude) signal
Abstract base class for different kinds of events.
STL namespace.