CbmRoot
Loading...
Searching...
No Matches
CbmStsSimModule.cxx
Go to the documentation of this file.
1/* Copyright (C) 2013-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese [committer], Florian Uhlig */
4
10#include "CbmStsSimModule.h"
11
12#include "CbmStsDigitize.h"
13#include "CbmStsElement.h"
14
15
16using namespace std;
17
19
20
21 // ----- Default constructor -------------------------------------------
23 : fElement(element)
24 , fDigitizer(digitizer)
25 , fParams(params)
26{
27}
28// -------------------------------------------------------------------------
29
30
31// --- Destructor --------------------------------------------------------
33{
34
35 // --- Clean analog buffer
36 for (auto chanIt = fAnalogBuffer.begin(); chanIt != fAnalogBuffer.end(); chanIt++) {
37 for (auto sigIt = (chanIt->second).begin(); sigIt != (chanIt->second).end(); sigIt++) {
38 delete (*sigIt);
39 }
40 }
41}
42// -------------------------------------------------------------------------
43
44
45// ----- Add a signal to the buffer ------------------------------------
46void CbmStsSimModule::AddSignal(UShort_t channel, Double_t time, Double_t charge, Int_t index, Int_t entry, Int_t file)
47{
48
49 // --- Check channel number
50 assert(channel < GetNofChannels());
51
52 // --- Discard charge if the channel is dead
53 if (!fParams->IsChannelActive(channel)) return;
54
55 // --- If the channel is not yet active: create a new set and insert
56 // --- new signal into it.
57 if (fAnalogBuffer.find(channel) == fAnalogBuffer.end()) {
58 CbmStsSignal* signal = new CbmStsSignal(time, charge, index, entry, file);
59 fAnalogBuffer[channel].insert(signal);
60 return;
61 } //? Channel not yet active
62
63 // --- The channel is active: there are already signals in.
64 // --- Loop over all signals in the channels and compare their time.
65 //TODO: Loop over all signals is not needed, since they are time-ordered.
66 Bool_t isMerged = kFALSE;
67 sigset::iterator it;
68 Double_t deadTime = fParams->GetParAsic(channel).GetDeadTime();
69 for (it = fAnalogBuffer[channel].begin(); it != fAnalogBuffer[channel].end(); it++) {
70
71 // Time between new and old signal smaller than dead time: merge signals
72 if (TMath::Abs((*it)->GetTime() - time) < deadTime) {
73
74 // Current implementation of merging signals:
75 // Add charges, keep first signal time
76 // TODO: Check with STS electronics people on more realistic behaviour.
77 (*it)->SetTime(TMath::Min((*it)->GetTime(), time));
78 (*it)->AddLink(charge, index, entry, file);
79 isMerged = kTRUE; // mark new signal as merged
80 break; // Merging should be necessary only for one buffer signal
81
82 } //? Time difference smaller than dead time
83
84 } // Loop over signals in buffer for this channel
85
86 // --- If signal was merged: no further action
87 if (isMerged) return;
88
89 // --- Arriving here, the signal did not interfere with existing ones.
90 // --- So, it is added to the analog buffer.
91 CbmStsSignal* signal = new CbmStsSignal(time, charge, index, entry, file);
92 fAnalogBuffer[channel].insert(signal);
93}
94// -------------------------------------------------------------------------
95
96
97// ----- Status of analogue buffer -------------------------------------
98void CbmStsSimModule::BufferStatus(Int_t& nofSignals, Double_t& timeFirst, Double_t& timeLast)
99{
100
101
102 Int_t nSignals = 0;
103 Double_t tFirst = -1.;
104 Double_t tLast = -1.;
105 Double_t tSignal = -1.;
106
107 // --- Loop over active channels
108 for (auto chanIt = fAnalogBuffer.begin(); chanIt != fAnalogBuffer.end(); chanIt++) {
109
110 // --- Loop over signals in channel
111 for (auto sigIt = (chanIt->second).begin(); sigIt != (chanIt->second).end(); sigIt++) {
112
113 tSignal = (*sigIt)->GetTime();
114 nSignals++;
115 tFirst = tFirst < 0. ? tSignal : TMath::Min(tFirst, tSignal);
116 tLast = TMath::Max(tLast, tSignal);
117
118 } // signals in channel
119
120 } // channels in module
121
122 nofSignals = nSignals;
123 timeFirst = tFirst;
124 timeLast = tLast;
125}
126// -------------------------------------------------------------------------
127
128
129// ----- Digitise an analogue charge signal ----------------------------
130void CbmStsSimModule::Digitize(UShort_t channel, CbmStsSignal* signal)
131{
132
133 // --- Check channel number
134 assert(channel < GetNofChannels());
135
136 auto& asic = fParams->GetParAsic(channel);
137
138 // --- No action if charge is below threshold
139 Double_t charge = signal->GetCharge();
140
141 // --- Digitise charge
142 Short_t adc = asic.ChargeToAdc(charge);
143 if (adc < 1) return; // Charge below threshold
144
145 // --- Digitise time
146 Double_t deltaT = 0.;
147 if (!(asic.GetTimeResol() < 0.)) deltaT = gRandom->Gaus(0., asic.GetTimeResol());
148 Long64_t dTime = Long64_t(round(signal->GetTime() + deltaT));
149
150 // --- Send the message to the digitiser task
151 UInt_t address = fElement->GetAddress();
152 if (fDigitizer) fDigitizer->CreateDigi(address, channel, dTime, adc, signal->GetMatch());
153
154 // --- If no digitiser task is present (debug mode): create a digi and
155 // --- add it to the digi buffer.
156 else
157 return;
158}
159// -------------------------------------------------------------------------
160
161
162// ----- Generate noise ------------------------------------------------
163Int_t CbmStsSimModule::GenerateNoise(Double_t t1, Double_t t2)
164{
165
166 if (!(t2 > t1)) return 0;
167 Int_t nNoiseAll = 0;
168 UInt_t nAsicChannels = fParams->GetNofAsicChannels();
169
170 for (UInt_t iAsic = 0; iAsic < fParams->GetNofAsics(); iAsic++) {
171 auto& asic = fParams->GetAsicParams().at(iAsic);
172
173 // --- Mean number of noise digis in [t1, t2]
174 Double_t nNoiseMean = asic.GetNoiseRate() * nAsicChannels * (t2 - t1);
175
176 // --- Sample number of noise digis
177 Int_t nNoise = gRandom->Poisson(nNoiseMean);
178
179 // --- Create noise digis
180 for (Int_t iNoise = 0; iNoise < nNoise; iNoise++) {
181
182 // --- Random channel number, time and charge
183 UInt_t channel = UInt_t(gRandom->Uniform(Double_t(nAsicChannels)));
184 Double_t time = gRandom->Uniform(t1, t2);
185 Double_t charge = asic.GetRandomNoiseCharge();
186 UInt_t moduleChannel = iAsic * nAsicChannels + channel;
187
188 // --- Insert a signal object (without link index, entry and file)
189 // --- into the analogue buffer.
190 AddSignal(moduleChannel, time, charge, -1, -1, -1);
191 } //# noise digis
192
193 nNoiseAll += nNoise;
194 }
195
196 return nNoiseAll;
197}
198// -------------------------------------------------------------------------
199
200
201// ----- Get the unique address from the sensor name (static) ----------
203{
204
205 Bool_t isValid = kTRUE;
206 if (name.Length() != 16) isValid = kFALSE;
207 if (isValid) {
208 if (!name.BeginsWith("STS")) isValid = kFALSE;
209 if (name[4] != 'U') isValid = kFALSE;
210 if (name[8] != 'L') isValid = kFALSE;
211 if (name[13] != 'M') isValid = kFALSE;
212 }
213 assert(isValid);
214
215 Int_t unit = 10 * (name[5] - '0') + name[6] - '0' - 1;
216 Int_t ladder = 10 * (name[9] - '0') + name[10] - '0' - 1;
217 Int_t hLadder = (name[11] == 'U' ? 0 : 1);
218 Int_t module = 10 * (name[14] - '0') + name[15] - '0' - 1;
219
220 return CbmStsAddress::GetAddress(unit, ladder, hLadder, module);
221}
222// -------------------------------------------------------------------------
223
224
225// ----- Initialise the analogue buffer ---------------------------------
227{
228
229 for (UShort_t channel = 0; channel < fParams->GetNofChannels(); channel++) {
230 multiset<CbmStsSignal*, CbmStsSignal::Before> mset;
231 fAnalogBuffer[channel] = mset;
232 } //# channels
233}
234// -------------------------------------------------------------------------
235
236
237// ----- Process the analogue buffer -----------------------------------
238Int_t CbmStsSimModule::ProcessAnalogBuffer(Double_t readoutTime)
239{
240
241 // --- Counter
242 Int_t nDigis = 0;
243
244 // Create iterators needed for inner loop
245 sigset::iterator sigIt;
246 ;
247 sigset::iterator oldIt;
248 sigset::iterator endIt;
249
250 // --- Iterate over active channels
251 for (auto& chanIt : fAnalogBuffer) {
252
253 // Only do something if there are signals for the channel
254 if (!(chanIt.second).empty()) {
255 auto& asic = fParams->GetParAsic(chanIt.first);
256
257 // --- Time limit up to which signals are digitised and sent to DAQ.
258 // --- Up to that limit, it is guaranteed that future signals do not
259 // --- interfere with the buffered ones. The readoutTime is the time
260 // --- of the last processed StsPoint. All coming points will be later
261 // --- in time. So, the time limit is defined by this time minus
262 // --- 5 times the time resolution (maximal deviation of signal time
263 // --- from StsPoint time) minus the dead time, within which
264 // --- interference of signals can happen.
265 Double_t timeLimit = readoutTime - 5. * asic.GetTimeResol() - asic.GetDeadTime();
266
267 // --- Digitise all signals up to the specified time limit
268 sigIt = (chanIt.second).begin();
269 oldIt = sigIt;
270 endIt = (chanIt.second).end();
271 while (sigIt != endIt) {
272
273 // --- Exit loop if signal time is larger than time limit
274 // --- N.b.: Readout time < 0 means digitise everything
275 if (readoutTime >= 0. && (*sigIt)->GetTime() > timeLimit) break;
276
277 // --- Digitise signal
278 Digitize(chanIt.first, (*sigIt));
279 nDigis++;
280
281 // --- Increment iterator before it becomes invalid
282 oldIt = sigIt;
283 sigIt++;
284
285 // --- Delete digitised signal
286 delete (*oldIt);
287 (chanIt.second).erase(oldIt);
288 } // Iterate over signals in channel
289 } // if there are signals
290 } // Iterate over channels
291
292 return nDigis;
293}
294// -------------------------------------------------------------------------
295
296
297// ----- String output -------------------------------------------------
299{
300 stringstream ss;
301 auto& asic = fParams->GetParAsic(0);
302 ss << "Module " << fElement->GetName() << ": dynRange " << asic.GetDynRange() << "e, thresh. " << asic.GetThreshold()
303 << "e, nAdc " << asic.GetNofAdc() << ", time res. " << asic.GetTimeResol() << "ns, dead time "
304 << asic.GetDeadTime() << "ns, noise " << asic.GetNoise() << "e, zero noise rate " << asic.GetZeroNoiseRate()
305 << "/ns";
306 return ss.str();
307}
308// -------------------------------------------------------------------------
ClassImp(CbmStsSimModule) CbmStsSimModule
Task class for simulating the detector response of the STS.
void CreateDigi(Int_t address, UShort_t channel, Long64_t time, UShort_t adc, const CbmMatch &match)
Class representing an element of the STS setup.
Int_t GetAddress() const
double GetTimeResol() const
Time resolution.
double GetDeadTime() const
Single-channel dead time.
Parameters for one STS module.
uint32_t GetNofChannels() const
Number of channels.
uint32_t GetNofAsics() const
Number of ASICs.
uint32_t GetNofAsicChannels() const
Number of channels per ASIC.
bool IsChannelActive(uint32_t channel) const
Check for a channel being active.
const std::vector< CbmStsParAsic > & GetAsicParams() const
All ASIC parameters.
const CbmStsParAsic & GetParAsic(uint32_t channel) const
ASIC parameters for a given channel.
Data class for an analog signal in the STS.
const CbmMatch & GetMatch() const
Double_t GetCharge() const
Double_t GetTime() const
Class for the simulation of a readout unit in the CBM-STS.
Int_t ProcessAnalogBuffer(Double_t readoutTime)
CbmStsSimModule(CbmStsElement *setupModule=nullptr, const CbmStsParModule *modulePar=nullptr, CbmStsDigitize *digitizer=nullptr)
Standard constructor.
const CbmStsParModule * fParams
Digitizer.
void AddSignal(UShort_t channel, Double_t time, Double_t charge, Int_t index=0, Int_t entry=0, Int_t file=0)
static Int_t GetAddressFromName(TString name)
Get the address from the module name (static)
void Digitize(UShort_t channel, CbmStsSignal *signal)
UShort_t GetNofChannels() const
Number of electronic channels @value Number of ADC channels.
std::map< UShort_t, sigset > fAnalogBuffer
std::string ToString() const
CbmStsElement * fElement
virtual ~CbmStsSimModule()
Destructor.
Int_t GenerateNoise(Double_t t1, Double_t t2)
Generate noise.
void BufferStatus(Int_t &nofSignals, Double_t &timeFirst, Double_t &timeLast)
CbmStsDigitize * fDigitizer
Element in geometry setup.
int32_t GetAddress(uint32_t unit=0, uint32_t ladder=0, uint32_t halfladder=0, uint32_t module=0, uint32_t sensor=0, uint32_t side=0, uint32_t version=kCurrentVersion)
Construct address.
Hash for CbmL1LinkKey.