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