Project
Loading...
Searching...
No Matches
TrapSimulator.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13// //
14// TRD MCM (Multi Chip Module) simulator //
15// which simulates the TRAP processing after the AD-conversion. //
16// The relevant parameters (i.e. configuration settings of the TRAP) //
17// are taken from TrapConfig. //
18// //
20
25#include "fairlogger/Logger.h"
29
30#include "TCanvas.h"
31#include "TH1F.h"
32#include "TH2F.h"
33#include "TLine.h"
34#include "TMath.h"
35#include "TRandom.h"
36#include "TFile.h"
37
38#include <iomanip>
39
40using namespace o2::trd;
41using namespace std;
42using namespace o2::trd::constants;
43
44const int TrapSimulator::mgkFormatIndex = std::ios_base::xalloc();
45const std::array<unsigned short, 4> TrapSimulator::mgkFPshifts{11, 14, 17, 21};
46
47void TrapSimulator::init(TrapConfig* trapconfig, int det, int robPos, int mcmPos)
48{
49 //
50 // Initialize the class with new MCM position information
51 //
52 mDetector = det;
53 mRobPos = robPos;
54 mMcmPos = mcmPos;
55
56 uint64_t row = mFeeParam->getPadRowFromMCM(mRobPos, mMcmPos); // need uint64_t type to assemble mTrkltWordEmpty below
57 uint64_t column = mMcmPos % NMCMROBINCOL;
58 // prepare a part of the MCM header, what still is missing are the 3 x 8 bits from the charges
59 // < 1 | padrow (4 bits) | column (2 bits) | 00..0 (8 bit) | 00..0 (8 bit) | 00..0 (8 bit) | 1 >
60 mMcmHeaderEmpty = (1 << 31) | (row << 27) | (column << 25) | 1;
61 // prepare the part of the Tracklet64 which is common to all tracklets of this MCM
62 uint64_t hcid = 2 * mDetector + (mRobPos % 2);
63 uint64_t format = mUseFloatingPointForQ ? 1UL : 0UL;
64 mTrkltWordEmpty = (format << Tracklet64::formatbs) | (hcid << Tracklet64::hcidbs) | (row << Tracklet64::padrowbs) | (column << Tracklet64::colbs);
65
66 if (!mInitialized) {
67 mTrapConfig = trapconfig;
68 mNTimeBin = mTrapConfig->getTrapReg(TrapConfig::kC13CPUA, mDetector, mRobPos, mMcmPos);
69 mZSMap.resize(NADCMCM);
70 mADCR.resize(mNTimeBin * NADCMCM);
71 mADCF.resize(mNTimeBin * NADCMCM);
72 }
73
74 mInitialized = true;
75 reset();
76}
77
79{
80 // Resets the data values and internal filter registers
81 // by re-initialising them
82
83 if (!checkInitialized()) {
84 return;
85 }
86
87 //clear the adc data
88 std::fill(mADCR.begin(), mADCR.end(), 0);
89 std::fill(mADCF.begin(), mADCF.end(), 0);
90 std::fill(mADCDigitIndices.begin(), mADCDigitIndices.end(), -1);
91
92 for (auto filterreg : mInternalFilterRegisters) {
93 filterreg.ClearReg();
94 }
95
96 // Default unread, low active bit mask
97 std::fill(mZSMap.begin(), mZSMap.end(), 0);
98 std::fill(mMCMT.begin(), mMCMT.end(), 0);
99
101 //filterGainInit(); // we do not use the gain filter anyway, so disable it completely
103
104 for (auto& fitreg : mFitReg) {
105 fitreg.ClearReg();
106 }
107 mADCFilled = 0;
108
109 mTrackletArray64.clear();
110 mTrackletDigitCount.clear();
111 mTrackletDigitIndices.clear();
112
113 mDataIsSet = false;
114}
115
116// ----- I/O implementation -----
117
118ostream& TrapSimulator::text(ostream& os)
119{
120 // manipulator to activate output in text format (default)
121
122 os.iword(mgkFormatIndex) = 0;
123 return os;
124}
125
126ostream& TrapSimulator::cfdat(ostream& os)
127{
128 // manipulator to activate output in CFDAT format
129 // to send to the FEE via SCSN
130
131 os.iword(mgkFormatIndex) = 1;
132 return os;
133}
134
135ostream& TrapSimulator::raw(ostream& os)
136{
137 // manipulator to activate output as raw data dump
138
139 os.iword(mgkFormatIndex) = 2;
140 return os;
141}
142
143//std::ostream& operator<<(std::ostream& os, const TrapSimulator& mcm); // data output using ostream (e.g. cout << mcm;)
144std::ostream& o2::trd::operator<<(std::ostream& os, const TrapSimulator& mcm)
145{
146 // output implementation
147
148 // no output for non-initialized MCM
149 if (!mcm.checkInitialized()) {
150 return os;
151 }
152
153 // ----- human-readable output -----
154 if (os.iword(TrapSimulator::mgkFormatIndex) == 0) {
155
156 os << "TRAP " << mcm.getMcmPos() << " on ROB " << mcm.getRobPos() << " in detector " << mcm.getDetector() << std::endl;
157
158 os << "----- Unfiltered ADC data (10 bit) -----" << std::endl;
159 os << "ch ";
160 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
161 os << std::setw(5) << iChannel;
162 }
163 os << std::endl;
164 for (int iTimeBin = 0; iTimeBin < mcm.getNumberOfTimeBins(); iTimeBin++) {
165 os << "tb " << std::setw(2) << iTimeBin << ":";
166 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
167 os << std::setw(5) << (mcm.getDataRaw(iChannel, iTimeBin) >> mcm.mgkAddDigits);
168 }
169 os << std::endl;
170 }
171 os << "----- Filtered ADC data (10+2 bit) -----" << std::endl;
172 os << "ch ";
173 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
174 os << std::setw(4) << iChannel
175 << ((~mcm.getZeroSupressionMap(iChannel) != 0) ? "!" : " ");
176 }
177 os << std::endl;
178 for (int iTimeBin = 0; iTimeBin < mcm.getNumberOfTimeBins(); iTimeBin++) {
179 os << "tb " << std::setw(2) << iTimeBin << ":";
180 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
181 os << std::setw(4) << (mcm.getDataFiltered(iChannel, iTimeBin))
182 << (((mcm.getZeroSupressionMap(iChannel) & (1 << iTimeBin)) == 0) ? "!" : " ");
183 }
184 os << std::endl;
185 }
186 }
187
188 // ----- CFDAT output -----
189 else if (os.iword(TrapSimulator::mgkFormatIndex) == 1) {
190 int dest = 127;
191 int addrOffset = 0x2000;
192 int addrStep = 0x80;
193
194 for (int iTimeBin = 0; iTimeBin < mcm.getNumberOfTimeBins(); iTimeBin++) {
195 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
196 os << std::setw(5) << 10
197 << std::setw(5) << addrOffset + iChannel * addrStep + iTimeBin
198 << std::setw(5) << (mcm.getDataFiltered(iChannel, iTimeBin))
199 << std::setw(5) << dest << std::endl;
200 }
201 os << std::endl;
202 }
203 }
204
205 // ----- raw data ouptut -----
206 else if (os.iword(TrapSimulator::mgkFormatIndex) == 2) {
207 int bufSize = 300;
208 std::vector<uint32_t> buf;
209 buf.reserve(bufSize);
210 int bufLength = mcm.packData(buf, 0);
211
212 for (int i = 0; i < bufLength; i++) {
213 std::cout << "0x" << std::hex << buf[i] << std::dec << std::endl;
214 }
215
216 }
217
218 else {
219 os << "unknown format set" << std::endl;
220 }
221
222 return os;
223}
224
225void TrapSimulator::printFitRegXml(ostream& os) const
226{
227 // print fit registres in XML format
228
229 bool tracklet = false;
230
231 for (int cpu = 0; cpu < 4; cpu++) {
232 if (mFitPtr[cpu] != NOTRACKLETFIT) {
233 tracklet = true;
234 }
235 }
236 const char* const aquote{R"(")"};
237 const char* const cmdid{R"(" cmdid="0">)"};
238 if (tracklet == true) {
239 os << "<nginject>" << std::endl;
240 os << "<ack roc=\"" << mDetector << cmdid << std::endl;
241 os << "<dmem-readout>" << std::endl;
242 os << "<d det=\"" << mDetector << "\">" << std::endl;
243 os << " <ro-board rob=\"" << mRobPos << "\">" << std::endl;
244 os << " <m mcm=\"" << mMcmPos << "\">" << std::endl;
245
246 for (int cpu = 0; cpu < 4; cpu++) {
247 os << " <c cpu=\"" << cpu << "\">" << std::endl;
248 if (mFitPtr[cpu] != NOTRACKLETFIT) {
249 for (int adcch = mFitPtr[cpu]; adcch < mFitPtr[cpu] + 2; adcch++) {
250 if (adcch > 24) {
251 LOG(error) << "adcch going awol : " << adcch << " > 25";
252 }
253 os << " <ch chnr=\"" << adcch << "\">" << std::endl;
254 os << " <hits>" << mFitReg[adcch].nHits << "</hits>" << std::endl;
255 os << " <q0>" << mFitReg[adcch].q0 << "</q0>" << std::endl;
256 os << " <q1>" << mFitReg[adcch].q1 << "</q1>" << std::endl;
257 os << " <sumx>" << mFitReg[adcch].sumX << "</sumx>" << std::endl;
258 os << " <sumxsq>" << mFitReg[adcch].sumX2 << "</sumxsq>" << std::endl;
259 os << " <sumy>" << mFitReg[adcch].sumY << "</sumy>" << std::endl;
260 os << " <sumysq>" << mFitReg[adcch].sumY2 << "</sumysq>" << std::endl;
261 os << " <sumxy>" << mFitReg[adcch].sumXY << "</sumxy>" << std::endl;
262 os << " </ch>" << std::endl;
263 }
264 }
265 os << " </c>" << std::endl;
266 }
267 os << " </m>" << std::endl;
268 os << " </ro-board>" << std::endl;
269 os << "</d>" << std::endl;
270 os << "</dmem-readout>" << std::endl;
271 os << "</ack>" << std::endl;
272 os << "</nginject>" << std::endl;
273 }
274}
275
276void TrapSimulator::printTrackletsXml(ostream& os) const
277{
278 // print tracklets in XML format
279 //TODO FIX this to new format
280 const char* const cmdid{R"(" cmdid="0">)"};
281 os << "<nginject>" << std::endl;
282 os << "<ack roc=\"" << mDetector << cmdid << std::endl;
283 os << "<dmem-readout>" << std::endl;
284 os << "<d det=\"" << mDetector << "\">" << std::endl;
285 os << " <ro-board rob=\"" << mRobPos << "\">" << std::endl;
286 os << " <m mcm=\"" << mMcmPos << "\">" << std::endl;
287
288 int pid, padrow, slope, offset;
289 //TODO take care of the 0th being the header, and cpu1,2,3 being 1 to 3 tracklets.
290 for (int cpu = 0; cpu < 4; cpu++) {
291 if (mMCMT[cpu] == 0x10001000) {
292 pid = -1;
293 padrow = -1;
294 slope = -1;
295 offset = -1;
296 } else {
297 pid = (mMCMT[cpu] & 0xFF000000) >> 24;
298 padrow = (mMCMT[cpu] & 0xF00000) >> 20;
299 slope = (mMCMT[cpu] & 0xFE000) >> 13;
300 offset = (mMCMT[cpu] & 0x1FFF);
301 }
302 os << " <trk> <pid>" << pid << "</pid>"
303 << " <padrow>" << padrow << "</padrow>"
304 << " <slope>" << slope << "</slope>"
305 << " <offset>" << offset << "</offset>"
306 << "</trk>" << std::endl;
307 }
308
309 os << " </m>" << std::endl;
310 os << " </ro-board>" << std::endl;
311 os << "</d>" << std::endl;
312 os << "</dmem-readout>" << std::endl;
313 os << "</ack>" << std::endl;
314 os << "</nginject>" << std::endl;
315}
316
317void TrapSimulator::printAdcDatTxt(ostream& os) const
318{
319 // print ADC data in text format (suitable as Modelsim stimuli)
320
321 os << "# MCM " << mMcmPos << " on ROB " << mRobPos << " in detector " << mDetector << std::endl;
322
323 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
324 for (int iChannel = 0; iChannel < NADCMCM; ++iChannel) {
325 os << std::setw(5) << (getDataRaw(iChannel, iTimeBin) >> mgkAddDigits);
326 }
327 os << std::endl;
328 }
329}
330
331void TrapSimulator::printAdcDatHuman(ostream& os) const
332{
333 // print ADC data in human-readable format
334
335 os << "MCM " << mMcmPos << " on ROB " << mRobPos << " in detector " << mDetector << std::endl;
336
337 os << "----- Unfiltered ADC data (10 bit) -----" << std::endl;
338 os << "ch ";
339 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
340 os << std::setw(5) << iChannel;
341 }
342 os << std::endl;
343 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
344 os << "tb " << std::setw(2) << iTimeBin << ":";
345 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
346 os << std::setw(5) << (getDataRaw(iChannel, iTimeBin));
347 }
348 os << std::endl;
349 }
350
351 os << "----- Filtered ADC data (10+2 bit) -----" << std::endl;
352 os << "ch ";
353 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
354 os << std::setw(4) << iChannel
355 << ((~mZSMap[iChannel] != 0) ? "!" : " ");
356 }
357 os << std::endl;
358 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
359 os << "tb " << std::setw(2) << iTimeBin << ":";
360 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
361 os << std::setw(4) << (getDataFiltered(iChannel, iTimeBin))
362 << (((mZSMap[iChannel] & (1 << iTimeBin)) == 0) ? "!" : " ");
363 }
364 os << std::endl;
365 }
366}
367
368void TrapSimulator::printAdcDatXml(ostream& os) const
369{
370 // print ADC data in XML format
371
372 const char* const cmdid{R"(" cmdid="0">)"};
373 os << "<nginject>" << std::endl;
374 os << "<ack roc=\"" << mDetector << cmdid << std::endl;
375 os << "<dmem-readout>" << std::endl;
376 os << "<d det=\"" << mDetector << "\">" << std::endl;
377 os << " <ro-board rob=\"" << mRobPos << "\">" << std::endl;
378 os << " <m mcm=\"" << mMcmPos << "\">" << std::endl;
379
380 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
381 os << " <ch chnr=\"" << iChannel << "\">" << std::endl;
382 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
383 os << "<tb>" << mADCF[iChannel * mNTimeBin + iTimeBin] / 4 << "</tb>";
384 }
385 os << " </ch>" << std::endl;
386 }
387
388 os << " </m>" << std::endl;
389 os << " </ro-board>" << std::endl;
390 os << "</d>" << std::endl;
391 os << "</dmem-readout>" << std::endl;
392 os << "</ack>" << std::endl;
393 os << "</nginject>" << std::endl;
394}
395
396void TrapSimulator::printAdcDatDatx(ostream& os, bool broadcast, int timeBinOffset) const
397{
398 // print ADC data in datx format (to send to FEE)
399
400 mTrapConfig->printDatx(os, 2602, 1, 0, 127); // command to enable the ADC clock - necessary to write ADC values to MCM
401 os << std::endl;
402
403 int addrOffset = 0x2000;
404 int addrStep = 0x80;
405 int addrOffsetEBSIA = 0x20;
406
407 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
408 for (int iChannel = 0; iChannel < NADCMCM; iChannel++) {
409 if ((iTimeBin < timeBinOffset) || (iTimeBin >= mNTimeBin + timeBinOffset)) {
410 if (broadcast == false) {
411 mTrapConfig->printDatx(os, addrOffset + iChannel * addrStep + addrOffsetEBSIA + iTimeBin, 10, getRobPos(), getMcmPos());
412 } else {
413 mTrapConfig->printDatx(os, addrOffset + iChannel * addrStep + addrOffsetEBSIA + iTimeBin, 10, 0, 127);
414 }
415 } else {
416 if (broadcast == false) {
417 mTrapConfig->printDatx(os, addrOffset + iChannel * addrStep + addrOffsetEBSIA + iTimeBin, (getDataFiltered(iChannel, iTimeBin - timeBinOffset) / 4), getRobPos(), getMcmPos());
418 } else {
419 mTrapConfig->printDatx(os, addrOffset + iChannel * addrStep + addrOffsetEBSIA + iTimeBin, (getDataFiltered(iChannel, iTimeBin - timeBinOffset) / 4), 0, 127);
420 }
421 }
422 }
423 os << std::endl;
424 }
425}
426
427void TrapSimulator::noiseTest(int nsamples, int mean, int sigma, int inputGain, int inputTail)
428{
429 // This function can be used to test the filters.
430 // It feeds nsamples of ADC values with a gaussian distribution specified by mean and sigma.
431 // The filter chain implemented here consists of:
432 // Pedestal -> Gain -> Tail
433 // With inputGain and inputTail the input to the gain and tail filter, respectively,
434 // can be chosen where
435 // 0: noise input
436 // 1: pedestal output
437 // 2: gain output
438 // The input has to be chosen from a stage before.
439 // The filter behaviour is controlled by the TRAP parameters from TrapConfig in the
440 // same way as in normal simulation.
441 // The functions produces four histograms with the values at the different stages.
442
443 if (!checkInitialized()) {
444 return;
445 }
446
447 std::string nameInputGain;
448 std::string nameInputTail;
449
450 switch (inputGain) {
451 case 0:
452 nameInputGain = "Noise";
453 break;
454
455 case 1:
456 nameInputGain = "Pedestal";
457 break;
458
459 default:
460 LOG(error) << "Undefined input to tail cancellation filter";
461 return;
462 }
463
464 switch (inputTail) {
465 case 0:
466 nameInputTail = "Noise";
467 break;
468
469 case 1:
470 nameInputTail = "Pedestal";
471 break;
472
473 case 2:
474 nameInputTail = "Gain";
475 break;
476
477 default:
478 LOG(error) << "Undefined input to tail cancellation filter";
479 return;
480 }
481
482 TH1F* h = new TH1F("noise", "Gaussian Noise;sample;ADC count",
483 nsamples, 0, nsamples);
484 TH1F* hfp = new TH1F("ped", "Noise #rightarrow Pedestal filter;sample;ADC count", nsamples, 0, nsamples);
485 TH1F* hfg = new TH1F("gain",
486 (nameInputGain + "#rightarrow Gain;sample;ADC count").c_str(),
487 nsamples, 0, nsamples);
488 TH1F* hft = new TH1F("tail",
489 (nameInputTail + "#rightarrow Tail;sample;ADC count").c_str(),
490 nsamples, 0, nsamples);
491 h->SetStats(false);
492 hfp->SetStats(false);
493 hfg->SetStats(false);
494 hft->SetStats(false);
495
496 for (int i = 0; i < nsamples; i++) {
497 int value; // ADC count with noise (10 bit)
498 int valuep; // pedestal filter output (12 bit)
499 int valueg; // gain filter output (12 bit)
500 int valuet; // tail filter value (12 bit)
501 value = (int)gRandom->Gaus(mean, sigma); // generate noise with gaussian distribution
502 h->SetBinContent(i, value);
503
504 valuep = filterPedestalNextSample(1, 0, ((int)value) << 2);
505
506 if (inputGain == 0) {
507 valueg = filterGainNextSample(1, ((int)value) << 2);
508 } else {
509 valueg = filterGainNextSample(1, valuep);
510 }
511
512 if (inputTail == 0) {
513 valuet = filterTailNextSample(1, ((int)value) << 2);
514 } else if (inputTail == 1) {
515 valuet = filterTailNextSample(1, valuep);
516 } else {
517 valuet = filterTailNextSample(1, valueg);
518 }
519
520 hfp->SetBinContent(i, valuep >> 2);
521 hfg->SetBinContent(i, valueg >> 2);
522 hft->SetBinContent(i, valuet >> 2);
523 }
524
525 TCanvas* c = new TCanvas;
526 c->Divide(2, 2);
527 c->cd(1);
528 h->Draw();
529 c->cd(2);
530 hfp->Draw();
531 c->cd(3);
532 hfg->Draw();
533 c->cd(4);
534 hft->Draw();
535}
536
537
538void TrapSimulator::print(int choice) const
539{
540 // Prints the data stored and/or calculated for this TRAP
541 // The output is controlled by option which can be any bitpattern defined in the header
542 // PRINTRAW - prints raw ADC data
543 // PRINTFILTERED - prints filtered data
544 // PRINTHITS - prints detected hits
545 // PRINTTRACKLETS - prints found tracklets
546 // The later stages are only meaningful after the corresponding calculations
547 // have been performed.
548 // Codacy wont let us use string choices, as it says we must use string::starts_with() instead of string::find()
549
550 if (!checkInitialized()) {
551 return;
552 }
553
554 LOG(debug) << "MCM " << mMcmPos << " on ROB " << mRobPos << " in detector " << mDetector;
555
556 //std::string opt = option;
557 if ((choice & PRINTRAW) != 0 || (choice & PRINTFILTERED) != 0) {
558 std::cout << *this;
559 }
560
561 if ((choice & PRINTFOUND) != 0) {
562 LOG(debug) << "Found Tracklets:";
563 for (int iTrkl = 0; iTrkl < mTrackletArray64.size(); iTrkl++) {
564 LOG(debug) << "tracklet " << iTrkl << ": 0x" << hex << std::setw(32) << mTrackletArray64[iTrkl].getTrackletWord();
565 LOG(debug) << mTrackletArray64[iTrkl];
566 }
567 }
568}
569
570void TrapSimulator::draw(int choice, int index)
571{
572 // Plots the data stored in a 2-dim. timebin vs. ADC channel plot.
573 // The choice selects what data is plotted and is enumated in the header.
574 // PLOTRAW - plot raw data (default)
575 // PLOTFILTERED - plot filtered data (meaningless if R is specified)
576 // In addition to the ADC values:
577 // PLOTHITS - plot hits
578 // PLOTTRACKLETS - plot tracklets
579 if (!checkInitialized()) {
580 return;
581 }
582 TFile* rootfile = new TFile("trdtrackletplots.root", "UPDATE");
583 TCanvas* c1 = new TCanvas(Form("canvas_%i_%i:%i:%i_%i", index, mDetector, mRobPos, mMcmPos, (int)mTrackletArray64.size()));
584 TH2F* hist = new TH2F(Form("mcmdata_%i", index),
585 Form("Data of MCM %i on ROB %i in detector %i ", mMcmPos, mRobPos, mDetector),
586 NADCMCM,
587 -0.5,
588 NADCMCM - 0.5,
590 -0.5,
591 getNumberOfTimeBins() - 0.5);
592 hist->GetXaxis()->SetTitle("ADC Channel");
593 hist->GetYaxis()->SetTitle("Timebin");
594 hist->SetStats(false);
595 TH2F* histfiltered = new TH2F(Form("mcmdataf_%i", index),
596 Form("Data of MCM %i on ROB %i in detector %i filtered", mMcmPos, mRobPos, mDetector),
597 NADCMCM,
598 -0.5,
599 NADCMCM - 0.5,
601 -0.5,
602 getNumberOfTimeBins() - 0.5);
603 histfiltered->GetXaxis()->SetTitle("ADC Channel");
604 histfiltered->GetYaxis()->SetTitle("Timebin");
605
606 if ((choice & PLOTRAW) != 0) {
607 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
608 for (int iAdc = 0; iAdc < NADCMCM; iAdc++) {
609 hist->SetBinContent(iAdc + 1, iTimeBin + 1, mADCR[iAdc * mNTimeBin + iTimeBin] >> mgkAddDigits);
610 }
611 }
612 hist->Draw("COLZ");
613 } else {
614 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
615 for (int iAdc = 0; iAdc < NADCMCM; iAdc++) {
616 histfiltered->SetBinContent(iAdc + 1, iTimeBin + 1, mADCF[iAdc * mNTimeBin + iTimeBin] >> mgkAddDigits);
617 }
618 }
619 histfiltered->Draw("COLZ");
620 }
621
622 if ((choice & PLOTTRACKLETS) != 0) {
623 TLine* trklLines = new TLine[4];
624 LOG(debug) << "Tracklet start for index : " << index;
625 if (mTrackletArray64.size() > 0) {
626 LOG(debug) << "Tracklet : for " << mTrackletArray64[0].getDetector() << "::" << mTrackletArray64[0].getROB() << " : " << mTrackletArray64[0].getMCM();
627 } else {
628 LOG(debug) << "Tracklet : for trackletarray size of zero ";
629 }
630 for (int iTrkl = 0; iTrkl < mTrackletArray64.size(); iTrkl++) {
631 Tracklet64 trkl = mTrackletArray64[iTrkl];
632 float position = trkl.getPosition();
633 int ndrift = mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos) >> 5;
634 float slope = trkl.getSlope();
635
636 int t0 = mTrapConfig->getTrapReg(TrapConfig::kTPFS, mDetector, mRobPos, mMcmPos);
637 int t1 = mTrapConfig->getTrapReg(TrapConfig::kTPFE, mDetector, mRobPos, mMcmPos);
638
639 trklLines[iTrkl].SetX1(position - slope * t0);
640 trklLines[iTrkl].SetY1(t0);
641 trklLines[iTrkl].SetX2(position - slope * t1);
642 trklLines[iTrkl].SetY2(t1);
643 trklLines[iTrkl].SetLineColor(2);
644 trklLines[iTrkl].SetLineWidth(2);
645 LOG(debug) << "Tracklet " << iTrkl << ": y = " << trkl.getPosition() << ", slope = " << (float)trkl.getSlope() << "for a det:rob:mcm combo of : " << mDetector << ":" << mRobPos << ":" << mMcmPos;
646 LOG(debug) << "Tracklet " << iTrkl << ": x1,y1,x2,y2 :: " << trklLines[iTrkl].GetX1() << "," << trklLines[iTrkl].GetY1() << "," << trklLines[iTrkl].GetX2() << "," << trklLines[iTrkl].GetY2();
647 LOG(debug) << "Tracklet " << iTrkl << ": t0 : " << t0 << ", t1 " << t1 << ", slope:" << slope << ", which comes from : " << mTrapConfig->getDmemUnsigned(mgkDmemAddrNdrift, mDetector, mRobPos, mMcmPos) << " shifted 5 to the right ";
648 trklLines[iTrkl].Draw();
649 }
650 LOG(debug) << "Tracklet end ...";
651 }
652 c1->Write();
653 rootfile->Close();
654}
655
656void TrapSimulator::setData(int adc, const ArrayADC& data, unsigned int digitIdx)
657{
658 //
659 // Store ADC data into array of raw data
660 //
661
662 if (!checkInitialized()) {
663 LOG(error) << "TRAP is not initialized, cannot call setData()";
664 return;
665 }
666
667 if (adc < 0 || adc >= NADCMCM) {
668 LOG(error) << "Error: ADC " << adc << " is out of range (0 .. " << NADCMCM - 1 << ")";
669 return;
670 }
671
672 for (int it = 0; it < mNTimeBin; it++) {
673 mADCR[adc * mNTimeBin + it] = (data[it] << mgkAddDigits) + (mAdditionalBaseline << mgkAddDigits);
674 mADCF[adc * mNTimeBin + it] = (data[it] << mgkAddDigits) + (mAdditionalBaseline << mgkAddDigits);
675 }
676 mDataIsSet = true;
677 mADCFilled |= (1 << adc);
678
679 mADCDigitIndices[adc] = digitIdx;
680}
681
683{
684 //This function exists as in the old simulator, when data was fed into the trapsim, it was done via the whole adc block for the mcm.
685 //if the data was zero or out of spec, the baselines were added
686 //we now add it by singular ADC, so there are adc channels that never get touched.
687 //this fixes that.
688
689 if (!checkInitialized()) {
690 LOG(error) << "TRAP is not initialized, cannot call setBaselines()";
691 return;
692 }
693
694 //loop over all adcs.
695 for (int adc = 0; adc < NADCMCM; adc++) {
696 if ((mADCFilled & (1 << adc)) == 0) { // adc is empty by construction of mADCFilled.
697 for (int timebin = 0; timebin < mNTimeBin; timebin++) {
698 // kFPNP = 32 = 8 << 2 (pedestal correction additive) and kTPFP = 40 = 10 << 2 (filtered pedestal)
699 mADCR[adc * mNTimeBin + timebin] = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos); // OS: not using FPNP here, since in filter() the ADC values from the 'raw' array will be copied into the filtered array
700 mADCF[adc * mNTimeBin + timebin] = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos);
701 }
702 }
703 }
704}
705
707{
708 //
709 // Store ADC data into array of raw data
710 //
711
712 if (!checkInitialized()) {
713 return;
714 }
715
716 if (adc < 0 || adc >= NADCMCM) {
717 return;
718 }
719
720 for (int it = 0; it < mNTimeBin; it++) {
721 mADCR[adc * mNTimeBin + it] = mTrapConfig->getTrapReg(TrapConfig::kFPNP, mDetector, mRobPos, mMcmPos);
722 mADCF[adc * mNTimeBin + it] = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos);
723 }
724}
725
726//TODO figure why I could not get span to work here
727int TrapSimulator::packData(std::vector<uint32_t>& rawdata, uint32_t offset) const
728{
729 // return # of 32 bit words.
730 //
731 //given the, up to 3 tracklets, pack them according to the define data format.
732 //
733 // std::cout << "span size in packData is : " << rawdata.size() << std::endl;
734 //TODO this is left blank so that the dataformats etc. can come in a seperate PR
735 //to keep different work seperate.
736 uint32_t wordswritten = 0; // count the 32 bit words written;
737 // std::cout << &raw[offset] << std::endl;
738 // std::cout << raw.data() << std::endl;;
739 // //TODO query? the mCPU have the packed data, rather use them?
740 TrackletMCMHeader mcmhead;
741 int trackletcount = 0;
742 // TrackletMCMHeader mcmhead;
743 offset++;
744 std::array<TrackletMCMData, 3> tracklets{};
745 mcmhead.oneb = 1;
746 mcmhead.onea = 1;
747 mcmhead.padrow = ((mRobPos >> 1) << 2) | (mMcmPos >> 2);
748 int mcmcol = mMcmPos % NMCMROBINCOL + (mRobPos % 2) * NMCMROBINCOL;
749 int padcol = mcmcol * NCOLMCM + NCOLMCM + 1;
750 mcmhead.col = 1; //TODO check this, cant call FeeParam due to virtual function
751 LOG(debug) << "packing data with trackletarry64 size of : " << mTrackletArray64.size();
752 for (int i = 0; i < 3; i++) {
753 if (i < mTrackletArray64.size()) { // we have a tracklet
754 LOG(debug) << "we have a tracklet at i=" << i << " with trackletword 0x" << mTrackletArray64[i].getTrackletWord();
755 switch (i) {
756 case 0:
757 mcmhead.pid0 = ((mTrackletArray64[0].getQ2()) << 2) + ((mTrackletArray64[0].getQ1()) >> 5);
758 break; // all of Q2 and upper 2 bits of Q1.
759 case 1:
760 mcmhead.pid1 = ((mTrackletArray64[1].getQ2()) << 2) + ((mTrackletArray64[1].getQ1()) >> 5);
761 break; // all of Q2 and upper 2 bits of Q1.
762 case 2:
763 mcmhead.pid2 = ((mTrackletArray64[2].getQ2()) << 2) + ((mTrackletArray64[2].getQ1()) >> 5);
764 break; // all of Q2 and upper 2 bits of Q1.
765 }
766 tracklets[i].checkbit = 1;
767 LOG(debug) << mTrackletArray64[i];
768 tracklets[i].pid = mTrackletArray64[i].getQ0() & (mTrackletArray64[i].getQ1() << 8);
769 tracklets[i].slope = mTrackletArray64[i].getSlope();
770 tracklets[i].pos = mTrackletArray64[i].getPosition();
771 tracklets[i].checkbit = 0;
772 trackletcount++;
773 } else { // else we dont have a tracklet so mark it off in the header.
774 switch (i) {
775 case 1:
776 mcmhead.pid1 = 0xff;
777 LOG(debug) << "setting mcmhead pid1 to 0xff with tracklet array size of " << mTrackletArray64[i];
778 break; // set the pid to ff to signify not there
779 case 2:
780 mcmhead.pid2 = 0xff;
781 break; // set the pid to maximal to signify not there (6bits).
782 }
783 }
784 }
785 // raw.push_back((uint32_t)mcmhead)
786 LOG(debug) << "pushing back mcm head of 0x" << std::hex << mcmhead.word << " with trackletcount of : " << std::dec << trackletcount << ":-:" << wordswritten;
787 rawdata.push_back(mcmhead.word); //memcpy(&rawdata[wordswritten++], &mcmhead, sizeof(mcmhead));
788 wordswritten++;
789 for (int i = 0; i < trackletcount; i++) {
790 LOG(debug) << "pushing back mcmtrackletword of 0x" << std::hex << tracklets[i].word;
791 rawdata.push_back(tracklets[i].word); //memcpy(&rawdata[wordswritten++], &tracklets[i], sizeof(TrackletMCMData));
792 wordswritten++;
793 }
794
795 //display the headers written
796 LOG(debug) << ">>>>> START info OUTPUT OF packData trackletcount:-:wordcount" << trackletcount << ":-:" << wordswritten;
799 if (trackletcount > 1) {
801 }
802 if (trackletcount > 2) {
804 }
805 LOG(debug) << "<<<<< END info OUTPUT OF packData";
806 //must produce between 2 and 4 words ... 1 and 3 tracklets.
807 // assert(wordswritten<5);
808 // assert(wordswritten>1);
809 LOG(debug) << "now to leave pack data after passing asserts with wordswritten = " << wordswritten;
810 return wordswritten; // in units of 32 bits.
811}
812
814{
815 //
816 // Filter the raw ADC values. The active filter stages and their
817 // parameters are taken from TrapConfig.
818 // The raw data is stored separate from the filtered data. Thus,
819 // it is possible to run the filters on a set of raw values
820 // sequentially for parameter tuning.
821 //
822
823 // OS: with the current TRAP config and settings both pedestal and tail filter are bypassed
824
825 if (!checkInitialized()) {
826 return;
827 }
828
829 // Apply filters sequentially. Bypass is handled by filters
830 // since counters and internal registers may be updated even
831 // if the filter is bypassed.
832 // The first filter takes the data from mADCR and
833 // outputs to mADCF.
834
835 // Non-linearity filter not implemented.
837 //filterGain(); // we do not use the gain filter anyway, so disable it completely
838 filterTail();
839 // Crosstalk filter not implemented.
840}
841
843{
844 // Initializes the pedestal filter assuming that the input has
845 // been constant for a long time (compared to the time constant).
846 // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ;
847
848 unsigned short fptc = mTrapConfig->getTrapReg(TrapConfig::kFPTC, mDetector, mRobPos, mMcmPos); // 0..3, 0 - fastest, 3 - slowest
849
850 for (int adc = 0; adc < NADCMCM; adc++) {
851 mInternalFilterRegisters[adc].mPedAcc = (baseline << 2) * (1 << mgkFPshifts[fptc]);
852 }
853 // LOG(debug) << "LEAVE: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ;
854}
855
856unsigned short TrapSimulator::filterPedestalNextSample(int adc, int timebin, unsigned short value)
857{
858 // Returns the output of the pedestal filter given the input value.
859 // The output depends on the internal registers and, thus, the
860 // history of the filter.
861 LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__;
862
863 unsigned short fpnp = mTrapConfig->getTrapReg(TrapConfig::kFPNP, mDetector, mRobPos, mMcmPos); // 0..511 -> 0..127.75, pedestal at the output
864 unsigned short fptc = mTrapConfig->getTrapReg(TrapConfig::kFPTC, mDetector, mRobPos, mMcmPos); // 0..3, 0 - fastest, 3 - slowest
865 unsigned short fpby = mTrapConfig->getTrapReg(TrapConfig::kFPBY, mDetector, mRobPos, mMcmPos); // 0..1 bypass, active low
866
867 unsigned short accumulatorShifted;
868 unsigned short inpAdd;
869
870 inpAdd = value + fpnp;
871
872 accumulatorShifted = (mInternalFilterRegisters[adc].mPedAcc >> mgkFPshifts[fptc]) & 0x3FF; // 10 bits
873 if (timebin == 0) // the accumulator is disabled in the drift time
874 {
875 int correction = (value & 0x3FF) - accumulatorShifted;
876 mInternalFilterRegisters[adc].mPedAcc = (mInternalFilterRegisters[adc].mPedAcc + correction) & 0x7FFFFFFF; // 31 bits
877 }
878
879 if (fpby == 0) {
880 // LOG(info) << "Pedestal filter bypassed";
881 return value;
882 }
883 // LOGF(info, "fpnp(%u), fptc(%u), fpby(%u), inpAdd(%u), accumulatorShifted(%u)", fpnp, fptc, fpby, inpAdd, accumulatorShifted);
884 return value; // FIXME bypass hard-coded for now
885
886 if (inpAdd <= accumulatorShifted) {
887 return 0;
888 } else {
889 inpAdd = inpAdd - accumulatorShifted;
890 if (inpAdd > 0xFFF) {
891 return 0xFFF;
892 } else {
893 return inpAdd;
894 }
895 }
896}
897
899{
900 //
901 // Apply pedestal filter
902 //
903 // As the first filter in the chain it reads data from mADCR
904 // and outputs to mADCF.
905 // It has only an effect if previous samples have been fed to
906 // find the pedestal. Currently, the simulation assumes that
907 // the input has been stable for a sufficiently long time.
908 // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ;
909
910 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
911 for (int iAdc = 0; iAdc < NADCMCM; iAdc++) {
912 int oldadc = mADCF[iAdc * mNTimeBin + iTimeBin];
913 mADCF[iAdc * mNTimeBin + iTimeBin] = filterPedestalNextSample(iAdc, iTimeBin, mADCR[iAdc * mNTimeBin + iTimeBin]);
914 // LOG(debug) << "mADCF : time : " << iTimeBin << " adc : " << iAdc << " change : " << oldadc << " -> " << mADCF[iAdc * mNTimeBin + iTimeBin];
915 }
916 }
917 // LOG(debug) << "BEGIN: " << __FILE__ << ":" << __func__ << ":" << __LINE__ ;
918}
919
921{
922 // Initializes the gain filter. In this case, only threshold
923 // counters are reset.
924
925 for (int adc = 0; adc < NADCMCM; adc++) {
926 // these are counters which in hardware continue
927 // until maximum or reset
928 mInternalFilterRegisters[adc].mGainCounterA = 0;
929 mInternalFilterRegisters[adc].mGainCounterB = 0;
930 }
931}
932
933unsigned short TrapSimulator::filterGainNextSample(int adc, unsigned short value)
934{
935 // Apply the gain filter to the given value.
936 // BEGIN_LATEX O_{i}(t) = #gamma_{i} * I_{i}(t) + a_{i} END_LATEX
937 // The output depends on the internal registers and, thus, the
938 // history of the filter.
939 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value;
940
941 unsigned short mgby = mTrapConfig->getTrapReg(TrapConfig::kFGBY, mDetector, mRobPos, mMcmPos); // bypass, active low
942 unsigned short mgf = mTrapConfig->getTrapReg(TrapConfig::TrapReg_t(TrapConfig::kFGF0 + adc), mDetector, mRobPos, mMcmPos); // 0x700 + (0 & 0x1ff);
943 unsigned short mga = mTrapConfig->getTrapReg(TrapConfig::TrapReg_t(TrapConfig::kFGA0 + adc), mDetector, mRobPos, mMcmPos); // 40;
944 unsigned short mgta = mTrapConfig->getTrapReg(TrapConfig::kFGTA, mDetector, mRobPos, mMcmPos); // 20;
945 unsigned short mgtb = mTrapConfig->getTrapReg(TrapConfig::kFGTB, mDetector, mRobPos, mMcmPos); // 2060;
946 // mgf=256;
947 // mga=8;
948 // mgta=20;
949 // mgtb=2060;
950
951 unsigned int mgfExtended = 0x700 + mgf; // The corr factor which is finally applied has to be extended by 0x700 (hex) or 0.875 (dec)
952 // because fgf=0 correspons to 0.875 and fgf=511 correspons to 1.125 - 2^(-11)
953 // (see TRAP User Manual for details)
954 //if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "ENTER: " << __FILE__ << ":" << __func__ << ":" << __LINE__ << " with adc = " << adc << " value = " << value << " Trapconfig values :" << mgby <<":"<<mgf<<":"<<mga<<":"<<mgta<<":"<<mgtb << ":"<< mgfExtended;
955 unsigned int corr; // corrected value
956
957 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) << "after declaring corr adc = " << adc << " value = " << value;
958 value &= 0xFFF;
959 corr = (value * mgfExtended) >> 11;
960 corr = corr > 0xfff ? 0xfff : corr;
961 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr;
962 corr = addUintClipping(corr, mga, 12);
963 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr;
964
965 // Update threshold counters
966 // not really useful as they are cleared with every new event
967 if (!((mInternalFilterRegisters[adc].mGainCounterA == 0x3FFFFFF) || (mInternalFilterRegisters[adc].mGainCounterB == 0x3FFFFFF)))
968 // stop when full
969 {
970 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgtb : " << mgtb;
971 if (corr >= mgtb) {
972 mInternalFilterRegisters[adc].mGainCounterB++;
973 } else if (corr >= mgta) {
974 mInternalFilterRegisters[adc].mGainCounterA++;
975 }
976 }
977
978 // if(mDetector==75&& mRobPos==5 && mMcmPos==15) LOG(debug) <<__LINE__ << " adc = " << adc << " value = " << value << " corr : " << corr << " mgby : " << mgby;
979 // if (mgby == 1)
980 // return corr;
981 // else
982 return value;
983}
984
986{
987 // Read data from mADCF and apply gain filter.
988
989 for (int adc = 0; adc < NADCMCM; adc++) {
990 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
991 mADCF[adc * mNTimeBin + iTimeBin] = filterGainNextSample(adc, mADCF[adc * mNTimeBin + iTimeBin]);
992 }
993 }
994}
995
997{
998 // Initializes the tail filter assuming that the input has
999 // been at the baseline value (configured by FTFP) for a
1000 // sufficiently long time.
1001
1002 // exponents and weight calculated from configuration
1003 unsigned short alphaLong = 0x3ff & mTrapConfig->getTrapReg(TrapConfig::kFTAL, mDetector, mRobPos, mMcmPos); // the weight of the long component
1004 unsigned short lambdaLong = (1 << 10) | (1 << 9) | (mTrapConfig->getTrapReg(TrapConfig::kFTLL, mDetector, mRobPos, mMcmPos) & 0x1FF); // the multiplier
1005 unsigned short lambdaShort = (0 << 10) | (1 << 9) | (mTrapConfig->getTrapReg(TrapConfig::kFTLS, mDetector, mRobPos, mMcmPos) & 0x1FF); // the multiplier
1006
1007 float lambdaL = lambdaLong * 1.0 / (1 << 11);
1008 float lambdaS = lambdaShort * 1.0 / (1 << 11);
1009 float alphaL = alphaLong * 1.0 / (1 << 11);
1010 float qup, qdn;
1011 qup = (1 - lambdaL) * (1 - lambdaS);
1012 qdn = 1 - lambdaS * alphaL - lambdaL * (1 - alphaL);
1013 float kdc = qup / qdn;
1014
1015 float ql, qs;
1016
1017 if (baseline < 0) {
1018 baseline = mTrapConfig->getTrapReg(TrapConfig::kFPNP, mDetector, mRobPos, mMcmPos);
1019 }
1020
1021 ql = lambdaL * (1 - lambdaS) * alphaL;
1022 qs = lambdaS * (1 - lambdaL) * (1 - alphaL);
1023
1024 for (int adc = 0; adc < NADCMCM; adc++) {
1025 int value = baseline & 0xFFF;
1026 int corr = (value * mTrapConfig->getTrapReg(TrapConfig::TrapReg_t(TrapConfig::kFGF0 + adc), mDetector, mRobPos, mMcmPos)) >> 11;
1027 corr = corr > 0xfff ? 0xfff : corr;
1028 corr = addUintClipping(corr, mTrapConfig->getTrapReg(TrapConfig::TrapReg_t(TrapConfig::kFGA0 + adc), mDetector, mRobPos, mMcmPos), 12);
1029
1030 float kt = kdc * baseline;
1031 unsigned short aout = baseline - (unsigned short)kt;
1032
1033 mInternalFilterRegisters[adc].mTailAmplLong = (unsigned short)(aout * ql / (ql + qs));
1034 mInternalFilterRegisters[adc].mTailAmplShort = (unsigned short)(aout * qs / (ql + qs));
1035 }
1036}
1037
1038unsigned short TrapSimulator::filterTailNextSample(int adc, unsigned short value)
1039{
1040 // Returns the output of the tail filter for the given input value.
1041 // The output depends on the internal registers and, thus, the
1042 // history of the filter.
1043
1044 // exponents and weight calculated from configuration
1045 unsigned short alphaLong = 0x3ff & mTrapConfig->getTrapReg(TrapConfig::kFTAL, mDetector, mRobPos, mMcmPos); // the weight of the long component
1046 unsigned short lambdaLong = (1 << 10) | (1 << 9) | (mTrapConfig->getTrapReg(TrapConfig::kFTLL, mDetector, mRobPos, mMcmPos) & 0x1FF); // the multiplier of the long component
1047 unsigned short lambdaShort = (0 << 10) | (1 << 9) | (mTrapConfig->getTrapReg(TrapConfig::kFTLS, mDetector, mRobPos, mMcmPos) & 0x1FF); // the multiplier of the short component
1048
1049 // intermediate signals
1050 unsigned int aDiff;
1051 unsigned int alInpv;
1052 unsigned short aQ;
1053 unsigned int tmp;
1054
1055 unsigned short inpVolt = value & 0xFFF; // 12 bits
1056
1057 // add the present generator outputs
1058 aQ = addUintClipping(mInternalFilterRegisters[adc].mTailAmplLong, mInternalFilterRegisters[adc].mTailAmplShort, 12);
1059
1060 // calculate the difference between the input and the generated signal
1061 if (inpVolt > aQ) {
1062 aDiff = inpVolt - aQ;
1063 } else {
1064 aDiff = 0;
1065 }
1066
1067 // the inputs to the two generators, weighted
1068 alInpv = (aDiff * alphaLong) >> 11;
1069
1070 // the new values of the registers, used next time
1071 // long component
1072 tmp = addUintClipping(mInternalFilterRegisters[adc].mTailAmplLong, alInpv, 12);
1073 tmp = (tmp * lambdaLong) >> 11;
1074 mInternalFilterRegisters[adc].mTailAmplLong = tmp & 0xFFF;
1075 // short component
1076 tmp = addUintClipping(mInternalFilterRegisters[adc].mTailAmplShort, aDiff - alInpv, 12);
1077 tmp = (tmp * lambdaShort) >> 11;
1078 mInternalFilterRegisters[adc].mTailAmplShort = tmp & 0xFFF;
1079
1080 // the output of the filter
1081 if (mTrapConfig->getTrapReg(TrapConfig::kFTBY, mDetector, mRobPos, mMcmPos) == 0) { // bypass mode, active low
1082 return value;
1083 } else {
1084 return aDiff;
1085 }
1086}
1087
1089{
1090 // Apply tail cancellation filter to all data.
1091
1092 for (int iTimeBin = 0; iTimeBin < mNTimeBin; iTimeBin++) {
1093 for (int iAdc = 0; iAdc < NADCMCM; iAdc++) {
1094 mADCF[iAdc * mNTimeBin + iTimeBin] = filterTailNextSample(iAdc, mADCF[iAdc * mNTimeBin + iTimeBin]);
1095 }
1096 }
1097}
1098
1100{
1101 //
1102 // Zero Suppression Mapping implemented in TRAP chip
1103 // only implemented for up to 30 timebins
1104 //
1105 // See detail TRAP manual "Data Indication" section:
1106 // http://www.kip.uni-heidelberg.de/ti/TRD/doc/trap/TRAP-UserManual.pdf
1107 //
1108
1109 if (!checkInitialized()) {
1110 return;
1111 }
1112
1113 int eBIS = mTrapConfig->getTrapReg(TrapConfig::kEBIS, mDetector, mRobPos, mMcmPos);
1114 int eBIT = mTrapConfig->getTrapReg(TrapConfig::kEBIT, mDetector, mRobPos, mMcmPos);
1115 int eBIL = mTrapConfig->getTrapReg(TrapConfig::kEBIL, mDetector, mRobPos, mMcmPos);
1116 int eBIN = mTrapConfig->getTrapReg(TrapConfig::kEBIN, mDetector, mRobPos, mMcmPos);
1117
1118 for (int iAdc = 0; iAdc < NADCMCM; iAdc++) {
1119 mZSMap[iAdc] = -1;
1120 }
1121
1122 for (int it = 0; it < mNTimeBin; it++) {
1123 int iAdc; // current ADC channel
1124 int ap;
1125 int ac;
1126 int an;
1127 int mask;
1128 int supp; // suppression of the current channel (low active)
1129
1130 // ----- first channel -----
1131 iAdc = 0;
1132
1133 ap = 0 >> mgkAddDigits; // previous
1134 ac = mADCF[iAdc * mNTimeBin + it] >> mgkAddDigits; // current
1135 an = mADCF[(iAdc + 1) * mNTimeBin + it] >> mgkAddDigits; // next
1136
1137 mask = (ac >= ap && ac >= an) ? 0 : 0x1; // peak center detection
1138 mask += (ap + ac + an > eBIT) ? 0 : 0x2; // cluster
1139 mask += (ac > eBIS) ? 0 : 0x4; // absolute large peak
1140
1141 supp = (eBIL >> mask) & 1;
1142
1143 mZSMap[iAdc] &= ~((1 - supp) << it);
1144 if (eBIN == 0) { // neighbour sensitivity
1145 mZSMap[iAdc + 1] &= ~((1 - supp) << it);
1146 }
1147
1148 // ----- last channel -----
1149 iAdc = NADCMCM - 1;
1150
1151 ap = mADCF[(iAdc - 1) * mNTimeBin + it] >> mgkAddDigits; // previous
1152 ac = mADCF[iAdc * mNTimeBin + it] >> mgkAddDigits; // current
1153 an = 0 >> mgkAddDigits; // next
1154
1155 mask = (ac >= ap && ac >= an) ? 0 : 0x1; // peak center detection
1156 mask += (ap + ac + an > eBIT) ? 0 : 0x2; // cluster
1157 mask += (ac > eBIS) ? 0 : 0x4; // absolute large peak
1158
1159 supp = (eBIL >> mask) & 1;
1160
1161 mZSMap[iAdc] &= ~((1 - supp) << it);
1162 if (eBIN == 0) { // neighbour sensitivity
1163 mZSMap[iAdc - 1] &= ~((1 - supp) << it);
1164 }
1165
1166 // ----- middle channels -----
1167 for (iAdc = 1; iAdc < NADCMCM - 1; iAdc++) {
1168 ap = mADCF[(iAdc - 1) * mNTimeBin + it] >> mgkAddDigits; // previous
1169 ac = mADCF[iAdc * mNTimeBin + it] >> mgkAddDigits; // current
1170 an = mADCF[(iAdc + 1) * mNTimeBin + it] >> mgkAddDigits; // next
1171
1172 mask = (ac >= ap && ac >= an) ? 0 : 0x1; // peak center detection
1173 mask += (ap + ac + an > eBIT) ? 0 : 0x2; // cluster
1174 mask += (ac > eBIS) ? 0 : 0x4; // absolute large peak
1175
1176 supp = (eBIL >> mask) & 1;
1177
1178 mZSMap[iAdc] &= ~((1 - supp) << it);
1179 if (eBIN == 0) { // neighbour sensitivity
1180 mZSMap[iAdc - 1] &= ~((1 - supp) << it);
1181 mZSMap[iAdc + 1] &= ~((1 - supp) << it);
1182 }
1183 }
1184 }
1185}
1186
1187void TrapSimulator::addHitToFitreg(int adc, unsigned short timebin, unsigned short qtot, short ypos)
1188{
1189 // Add the given hit to the fit register which will be used for
1190 // the tracklet calculation.
1191 // In addition to the fit sums in the fit register
1192 //
1193 /*
1194 if ((timebin >= mTrapConfig->getTrapReg(TrapConfig::kTPQS0, mDetector, mRobPos, mMcmPos)) &&
1195 (timebin < mTrapConfig->getTrapReg(TrapConfig::kTPQE0, mDetector, mRobPos, mMcmPos))) {
1196 mFitReg[adc].q0 += qtot;
1197 }
1198
1199 if ((timebin >= mTrapConfig->getTrapReg(TrapConfig::kTPQS1, mDetector, mRobPos, mMcmPos)) &&
1200 (timebin < mTrapConfig->getTrapReg(TrapConfig::kTPQE1, mDetector, mRobPos, mMcmPos))) {
1201 mFitReg[adc].q1 += qtot;
1202 }
1203 */
1204 if (timebin >= 1 && timebin < 6) {
1205 mFitReg[adc].q0 += qtot;
1206 }
1207
1208 if (timebin >= 14 && timebin < 20) {
1209 mFitReg[adc].q1 += qtot;
1210 }
1211
1212 if ((timebin >= 1) &&
1213 (timebin < 24)) {
1214 mFitReg[adc].sumX += timebin;
1215 mFitReg[adc].sumX2 += timebin * timebin;
1216 mFitReg[adc].nHits++;
1217 mFitReg[adc].sumY += ypos;
1218 mFitReg[adc].sumY2 += ypos * ypos;
1219 mFitReg[adc].sumXY += timebin * ypos;
1220 LOGF(debug, "FitReg for channel %i and timebin %u: ypos(%i), qtot(%i)", adc, timebin, ypos, qtot);
1221 // mFitReg.Print();
1222 }
1223}
1224
1226{
1227 // Preprocessing.
1228 // Detect the hits and fill the fit registers.
1229 // Requires 12-bit data from mADCF which means Filter()
1230 // has to be called before even if all filters are bypassed.
1231 //??? to be clarified:
1232
1233 // find first timebin to be looked at
1234 unsigned short timebin1 = mTrapConfig->getTrapReg(TrapConfig::kTPFS, mDetector, mRobPos, mMcmPos);
1235 if (mTrapConfig->getTrapReg(TrapConfig::kTPQS0, mDetector, mRobPos, mMcmPos) < timebin1) {
1236 timebin1 = mTrapConfig->getTrapReg(TrapConfig::kTPQS0, mDetector, mRobPos, mMcmPos);
1237 }
1238 if (mTrapConfig->getTrapReg(TrapConfig::kTPQS1, mDetector, mRobPos, mMcmPos) < timebin1) {
1239 timebin1 = mTrapConfig->getTrapReg(TrapConfig::kTPQS1, mDetector, mRobPos, mMcmPos);
1240 }
1241
1242 // find last timebin to be looked at
1243 unsigned short timebin2 = mTrapConfig->getTrapReg(TrapConfig::kTPFE, mDetector, mRobPos, mMcmPos);
1244 if (mTrapConfig->getTrapReg(TrapConfig::kTPQE0, mDetector, mRobPos, mMcmPos) > timebin2) {
1245 timebin2 = mTrapConfig->getTrapReg(TrapConfig::kTPQE0, mDetector, mRobPos, mMcmPos);
1246 }
1247 if (mTrapConfig->getTrapReg(TrapConfig::kTPQE1, mDetector, mRobPos, mMcmPos) > timebin2) {
1248 timebin2 = mTrapConfig->getTrapReg(TrapConfig::kTPQE1, mDetector, mRobPos, mMcmPos);
1249 }
1250
1251 // FIXME: overwrite fit start with values as in Venelin's simulation:
1252 timebin1 = 1;
1253 timebin2 = 24;
1254
1255 // reset the fit registers
1256 for (auto& fitreg : mFitReg) {
1257 fitreg.ClearReg();
1258 }
1259
1260 for (unsigned int timebin = timebin1; timebin < timebin2; timebin++) {
1261 // first find the hit candidates and store the total cluster charge in qTotal array
1262 // in case of not hit store 0 there.
1263 std::array<unsigned short, 20> qTotal{}; //[19 + 1]; // the last is dummy
1264 int adcLeft, adcCentral, adcRight;
1265 for (int adcch = 0; adcch < NADCMCM - 2; adcch++) {
1266 adcLeft = mADCF[adcch * mNTimeBin + timebin];
1267 adcCentral = mADCF[(adcch + 1) * mNTimeBin + timebin];
1268 adcRight = mADCF[(adcch + 2) * mNTimeBin + timebin];
1269 bool hitQual = false;
1270 if (mTrapConfig->getTrapReg(TrapConfig::kTPVBY, mDetector, mRobPos, mMcmPos) == 0) {
1271 // bypass the cluster verification
1272 hitQual = true;
1273 } else {
1274 hitQual = ((adcLeft * adcRight) <
1275 ((mTrapConfig->getTrapReg(TrapConfig::kTPVT, mDetector, mRobPos, mMcmPos) * adcCentral * adcCentral) >> 10));
1276 if (hitQual) {
1277 LOG(debug) << "cluster quality cut passed with " << adcLeft << ", " << adcCentral << ", "
1278 << adcRight << " - threshold " << mTrapConfig->getTrapReg(TrapConfig::kTPVT, mDetector, mRobPos, mMcmPos)
1279 << " -> " << mTrapConfig->getTrapReg(TrapConfig::kTPVT, mDetector, mRobPos, mMcmPos) * adcCentral * adcCentral;
1280 }
1281 }
1282
1283 // The accumulated charge is with the pedestal!!!
1284 int qtotTemp = adcLeft + adcCentral + adcRight;
1285
1286 if ((hitQual) &&
1287 (qtotTemp >= mTrapConfig->getTrapReg(TrapConfig::kTPHT, mDetector, mRobPos, mMcmPos)) &&
1288 (adcLeft <= adcCentral) &&
1289 (adcCentral > adcRight)) {
1290 qTotal[adcch] = qtotTemp;
1291 } else {
1292 qTotal[adcch] = 0;
1293 }
1294 }
1295
1296 short fromLeft = -1;
1297 short adcch = 0;
1298 short found = 0;
1299 std::array<unsigned short, 6> marked{};
1300 marked[4] = 19; // invalid channel
1301 marked[5] = 19; // invalid channel
1302 qTotal[19] = 0;
1303 while ((adcch < 16) && (found < 3)) {
1304 if (qTotal[adcch] > 0) {
1305 fromLeft = adcch;
1306 marked[2 * found + 1] = adcch;
1307 found++;
1308 }
1309 adcch++;
1310 }
1311
1312 short fromRight = -1;
1313 adcch = 18;
1314 found = 0;
1315 while ((adcch > 2) && (found < 3)) {
1316 if (qTotal[adcch] > 0) {
1317 marked[2 * found] = adcch;
1318 found++;
1319 fromRight = adcch;
1320 }
1321 adcch--;
1322 }
1323
1324 // here mask the hit candidates in the middle, if any
1325 if ((fromLeft >= 0) && (fromRight >= 0) && (fromLeft < fromRight)) {
1326 for (adcch = fromLeft + 1; adcch < fromRight; adcch++) {
1327 qTotal[adcch] = 0;
1328 }
1329 }
1330
1331 found = 0;
1332 for (adcch = 0; adcch < 19; adcch++) {
1333 if (qTotal[adcch] > 0) {
1334 found++;
1335 // NOT READY
1336 }
1337 }
1338 if (found > 4) // sorting like in the TRAP in case of 5 or 6 candidates!
1339 {
1340 if (marked[4] == marked[5]) {
1341 marked[5] = 19;
1342 }
1343 std::array<unsigned short, 6> qMarked;
1344 for (found = 0; found < 6; found++) {
1345 qMarked[found] = qTotal[marked[found]] >> 4;
1346 }
1347
1348 unsigned short worse1, worse2;
1349 sort6To2Worst(marked[0], marked[3], marked[4], marked[1], marked[2], marked[5],
1350 qMarked[0],
1351 qMarked[3],
1352 qMarked[4],
1353 qMarked[1],
1354 qMarked[2],
1355 qMarked[5],
1356 &worse1, &worse2);
1357 // Now mask the two channels with the smallest charge
1358 if (worse1 < 19) {
1359 qTotal[worse1] = 0;
1360 }
1361 if (worse2 < 19) {
1362 qTotal[worse2] = 0;
1363 }
1364 }
1365
1366 for (adcch = 0; adcch < 19; adcch++) {
1367 if (qTotal[adcch] > 0) // the channel is marked for processing
1368 {
1369 adcLeft = mADCF[adcch * mNTimeBin + timebin];
1370 adcCentral = mADCF[(adcch + 1) * mNTimeBin + timebin];
1371 adcRight = mADCF[(adcch + 2) * mNTimeBin + timebin];
1372 LOGF(debug, "ch(%i): left(%i), central(%i), right(%i)", adcch, adcLeft, adcCentral, adcRight);
1373 // hit detected, in TRAP we have 4 units and a hit-selection, here we proceed all channels!
1374 // subtract the pedestal TPFP, clipping instead of wrapping
1375
1376 int regTPFP = mTrapConfig->getTrapReg(TrapConfig::kTPFP, mDetector, mRobPos, mMcmPos); //TODO put this together with the others as members of trapsim, which is initiliased by det,rob,mcm.
1377 LOG(debug) << "Hit found, time=" << timebin << ", adcch=" << adcch << "/" << adcch + 1 << "/"
1378 << adcch + 2 << ", adc values=" << adcLeft << "/" << adcCentral << "/"
1379 << adcRight << ", regTPFP=" << regTPFP << ", TPHT=" << mTrapConfig->getTrapReg(TrapConfig::kTPHT, mDetector, mRobPos, mMcmPos);
1380 // regTPFP >>= 2; // OS: this line should be commented out when checking real data. It's only needed for comparison with Venelin's simulation if in addition mgkAddDigits == 0
1381 if (adcLeft < regTPFP) {
1382 adcLeft = 0;
1383 } else {
1384 adcLeft -= regTPFP;
1385 }
1386 if (adcCentral < regTPFP) {
1387 adcCentral = 0;
1388 } else {
1389 adcCentral -= regTPFP;
1390 }
1391 if (adcRight < regTPFP) {
1392 adcRight = 0;
1393 } else {
1394 adcRight -= regTPFP;
1395 }
1396
1397 // Calculate the center of gravity
1398 // checking for adcCentral != 0 (in case of "bad" configuration)
1399 if (adcCentral == 0) {
1400 LOG(error) << "bad configuration detected";
1401 continue;
1402 }
1403 short ypos = 128 * (adcRight - adcLeft) / adcCentral;
1404 if (ypos < 0) {
1405 ypos = -ypos;
1406 }
1407 // ypos element of [0:128]
1408 // make the correction using the position LUT
1409 // LOG(info) << "ypos raw is " << ypos << " adcrigh-adcleft/adccentral " << adcRight << "-" << adcLeft << "/" << adcCentral << "==" << (adcRight - adcLeft) / adcCentral << " 128 * numerator : " << 128 * (adcRight - adcLeft) / adcCentral;
1410 // LOG(info) << "ypos before lut correction : " << ypos;
1411 ypos = ypos + mTrapConfig->getTrapReg((TrapConfig::TrapReg_t)(TrapConfig::kTPL00 + (ypos & 0x7F)),
1412 mDetector, mRobPos, mMcmPos);
1413 // ypos += LUT_POS[ypos & 0x7f]; // FIXME use this LUT to obtain the same results as Venelin
1414 // LOG(info) << "ypos after lut correction : " << ypos;
1415 if (adcLeft > adcRight) {
1416 ypos = -ypos;
1417 }
1418 LOGF(debug, "ch(%i): left(%i), central(%i), right(%i), ypos(%i)", adcch, adcLeft, adcCentral, adcRight, ypos);
1419 addHitToFitreg(adcch, timebin, qTotal[adcch] >> mgkAddDigits, ypos);
1420 }
1421 }
1422 }
1423}
1424
1426{
1427 // Select up to 3 tracklet candidates from the fit registers
1428 // and assign them to the CPUs.
1429 unsigned short adcIdx, i, j, ntracks, tmp;
1430 std::array<unsigned short, 18> trackletCandch{}; // store the adcch for all tracklet candidates
1431 std::array<unsigned short, 18> trackletCandhits{}; // store the number of hits for all tracklet candidates
1432
1433 ntracks = 0;
1434 // LOG(info) << "kTPCL: " << mTrapConfig->getTrapReg(TrapConfig::kTPCL, mDetector, mRobPos, mMcmPos);
1435 // LOG(info) << "kTPCT: " << mTrapConfig->getTrapReg(TrapConfig::kTPCT, mDetector, mRobPos, mMcmPos);
1436 for (adcIdx = 0; adcIdx < 18; adcIdx++) { // ADCs
1437 if ((mFitReg[adcIdx].nHits >= mTrapConfig->getTrapReg(TrapConfig::kTPCL, mDetector, mRobPos, mMcmPos)) &&
1438 (mFitReg[adcIdx].nHits + mFitReg[adcIdx + 1].nHits >= 8)) { // FIXME was 10 otherwise
1439 trackletCandch[ntracks] = adcIdx;
1440 trackletCandhits[ntracks] = mFitReg[adcIdx].nHits + mFitReg[adcIdx + 1].nHits;
1441 // LOG(debug) << ntracks << " " << trackletCandch[ntracks] << " " << trackletCandhits[ntracks];
1442 ntracks++;
1443 };
1444 }
1445 LOG(debug) << "Number of track candidates:" << ntracks;
1446 for (i = 0; i < ntracks; i++) {
1447 LOG(debug) << "TRACKS: " << i << " " << trackletCandch[i] << " " << trackletCandhits[i];
1448 }
1449 if (ntracks > 4) {
1450 // primitive sorting according to the number of hits
1451 for (j = 0; j < (ntracks - 1); j++) {
1452 for (i = j + 1; i < ntracks; i++) {
1453 if ((trackletCandhits[j] < trackletCandhits[i]) ||
1454 ((trackletCandhits[j] == trackletCandhits[i]) && (trackletCandch[j] < trackletCandch[i]))) {
1455 // swap j & i
1456 tmp = trackletCandhits[j];
1457 trackletCandhits[j] = trackletCandhits[i];
1458 trackletCandhits[i] = tmp;
1459 tmp = trackletCandch[j];
1460 trackletCandch[j] = trackletCandch[i];
1461 trackletCandch[i] = tmp;
1462 }
1463 }
1464 }
1465 ntracks = 4; // cut the rest, 4 is the max
1466 }
1467 // else is not necessary to sort
1468
1469 // now sort, so that the first tracklet going to CPU0 corresponds to the highest adc channel - as in the TRAP
1470 for (j = 0; j < (ntracks - 1); j++) {
1471 for (i = j + 1; i < ntracks; i++) {
1472 if (trackletCandch[j] < trackletCandch[i]) {
1473 // swap j & i
1474 tmp = trackletCandhits[j];
1475 trackletCandhits[j] = trackletCandhits[i];
1476 trackletCandhits[i] = tmp;
1477 tmp = trackletCandch[j];
1478 trackletCandch[j] = trackletCandch[i];
1479 trackletCandch[i] = tmp;
1480 }
1481 }
1482 }
1483 for (i = 0; i < ntracks; i++) { // CPUs with tracklets.
1484 mFitPtr[i] = trackletCandch[i]; // pointer to the left channel with tracklet for CPU[i]
1485 }
1486 for (i = ntracks; i < 4; i++) { // CPUs without tracklets
1487 mFitPtr[i] = NOTRACKLETFIT; // pointer to the left channel with tracklet for CPU[i] = NOTRACKLETFIT (invalid)
1488 }
1489
1490 // reject multiple tracklets
1491 // FIXME is now done in fitTracklet() - is this actually optional or always done anyways?
1492 /*
1493 if (FeeParam::instance()->getRejectMultipleTracklets()) {
1494 unsigned short counts = 0;
1495 for (j = 0; j < (ntracks - 1); j++) {
1496 if (mFitPtr[j] == NOTRACKLETFIT) {
1497 continue;
1498 }
1499
1500 for (i = j + 1; i < ntracks; i++) {
1501 // check if tracklets are from neighbouring ADC channels
1502 if (TMath::Abs(mFitPtr[j] - mFitPtr[i]) > 1.) {
1503 continue;
1504 }
1505
1506 // check which tracklet candidate has higher amount of hits
1507 if ((mFitReg[mFitPtr[j]].nHits + mFitReg[mFitPtr[j] + 1].nHits) >=
1508 (mFitReg[mFitPtr[i]].nHits + mFitReg[mFitPtr[i] + 1].nHits)) {
1509 mFitPtr[i] = NOTRACKLETFIT;
1510 counts++;
1511 } else {
1512 mFitPtr[j] = NOTRACKLETFIT;
1513 counts++;
1514 break;
1515 }
1516 }
1517 }
1518
1519 ntracks = ntracks - counts;
1520 }
1521 */
1522}
1523
1525{
1526 // Perform the actual tracklet fit based on the fit sums
1527 // which have been filled in the fit registers.
1528
1529 std::array<uint32_t, NCPU> adcChannelMask = {0}; // marks the channels which contribute to a tracklet
1530 std::array<uint32_t, NCPU> charges = {0}; // the charges calculated by each CPU
1531 std::array<uint16_t, NADCMCM> trap_adc_q2_sum = {0}; // integrated charges in the third window
1532 int32_t wrks; // signed integer as temporary variable
1533 uint32_t wrku; // unsigned integer as temporary variable
1534 for (int cpu = 0; cpu < NCPU - 1; ++cpu) {
1535 // only cpu0..2 search for tracklets
1536 if (mFitPtr[cpu] == NOTRACKLETFIT) {
1537 // 0xFF as 8-bit charge from each CPU in the MCM header is an indicator for missing tracklet
1538 charges[cpu] = 0xff << (8 * cpu);
1539 adcChannelMask[cpu] = CHANNELNRNOTRKLT;
1540 } else {
1541 adcChannelMask[cpu] = mFitPtr[cpu];
1542 }
1543 }
1544 // eliminate double tracklets
1545 for (int cpu = 1; cpu < NCPU - 1; ++cpu) {
1546 // only cpu1..2 search for double tracklets
1547 if ((mFitPtr[cpu] == mFitPtr[cpu - 1] + 1) || (mFitPtr[cpu] + 1 == mFitPtr[cpu - 1])) {
1548 // tracklet positions are apart by +1 or -1
1549 adcChannelMask[cpu] = CHANNELNRNOTRKLT;
1550 // 0xFF as 8-bit charge from each CPU in the MCM header is an indicator for missing tracklet
1551 charges[cpu] = 0xff << (8 * cpu);
1552 }
1553 }
1554 for (int cpu = 0; cpu < NCPU; ++cpu) {
1555 mMCMT[cpu] = TRACKLETENDMARKER;
1556 }
1557 // cpu3 prepares the complete ADC channels mask
1558 // OS: now we mask the left channel which contributes to a tracklet + 3 channels to the right. Should we not take the two neighbouring channels of the tracklet fit?
1559 wrku = 0xf0; // for one tracklet we mask up to 4 ADC channels
1560 for (int cpu = 0; cpu < NCPU - 1; ++cpu) {
1561 wrks = adcChannelMask[cpu];
1562 wrks -= 4;
1563 if (wrks > 15) {
1564 // this indicates that no tracklet is assigned (adcChannelMask[cpu] == CHANNELNRNOTRKLT)
1565 wrks -= 32; // the shift in TRAP has as argument a 5 bit signed integer!
1566 }
1567 if (wrks > 0) {
1568 adcChannelMask[3] |= wrku << wrks;
1569 } else {
1570 adcChannelMask[3] |= wrku >> (-wrks); // has no effect in case tracklet was missing, since wrks = -13 in that case and wrku >> 13 == 0
1571 }
1572 }
1573 // adcChannelMask &= ADC_CHANNEL_MASK_MCM; // FIXME: add internal channel mask for each MCM
1574 if (adcChannelMask[3] > 0) {
1575 // there are tracklets, as there are marked ADC channels
1576 // charge integration in the third window, defined by Q2_LEFT_MRG_VAL, Q2_WIN_WIDTH_VAL
1577 // each CPU (0..3) has access to a part of the event buffers (0..4, 5..9, 10..14, 15..20 channels)
1578 for (int ch = 0; ch < NADCMCM; ch++) {
1579 if ((adcChannelMask[3] >> ch) & 1) {
1580 // the channel is masked as contributing to a tracklet
1581 for (int timebin = mQ2LeftMargin; timebin < (mQ2LeftMargin + mQ2WindowWidth); timebin++) {
1582 trap_adc_q2_sum[ch] += (getDataFiltered(ch, timebin));
1583 LOGF(debug, "Adding in ch(%i), tb(%i): %i\n", ch, timebin, getDataFiltered(ch, timebin));
1584 }
1585 }
1586 LOGF(debug, "trap_adc_q2_sum[%i]=%i", ch, trap_adc_q2_sum[ch]);
1587 }
1588
1589 // begin actual tracklet fit
1590 int decPlaces = 5;
1591 int decPlacesSlope = 2;
1592 int rndAdd = 1 << (decPlaces - 1);
1593
1594 int yoffs = (21 << (8 + decPlaces)) / 2; // we need to shift to the MCM center
1595
1596 // add corrections for mis-alignment
1598 LOG(debug) << "using mis-alignment correction";
1599 yoffs += (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrYcorr, mDetector, mRobPos, mMcmPos);
1600 }
1601
1602 uint64_t shift = 1UL << 32;
1603 uint64_t scaleY = (shift >> 8) * PADGRANULARITYTRKLPOS;
1604 uint64_t scaleD = (shift >> 8) * PADGRANULARITYTRKLSLOPE;
1605
1606 for (int cpu = 0; cpu < 3; cpu++) {
1607 if (adcChannelMask[cpu] != CHANNELNRNOTRKLT) {
1608 FitReg* fit0 = &mFitReg[mFitPtr[cpu]];
1609 FitReg* fit1 = &mFitReg[mFitPtr[cpu] + 1]; // next channel
1610 // fit0->dumpHex(mFitPtr[cpu]);
1611 // fit1->dumpHex(mFitPtr[cpu] + 1);
1612
1613 int64_t mult64 = 1L << (32 + decPlaces);
1614
1615 // time offset for fit sums
1616 const int t0 = FeeParam::instance()->getUseTimeOffset() ? (int)mTrapConfig->getDmemUnsigned(mgkDmemAddrTimeOffset, mDetector, mRobPos, mMcmPos) : 0;
1617
1618 LOG(debug) << "using time offset of t0 = " << t0;
1619
1620 // Merging
1621 uint16_t nHits = fit0->nHits + fit1->nHits; // number of hits
1622 int32_t sumX = fit0->sumX + fit1->sumX;
1623 int32_t sumX2 = fit0->sumX2 + fit1->sumX2;
1624 uint32_t q0 = fit0->q0 + fit1->q0;
1625 uint32_t q1 = fit0->q1 + fit1->q1;
1626 int32_t sumY = fit0->sumY + fit1->sumY + 256 * fit1->nHits;
1627 int32_t sumXY = fit0->sumXY + fit1->sumXY + 256 * fit1->sumX;
1628 int32_t sumY2 = fit0->sumY2 + fit1->sumY2 + 512 * fit1->sumY + 256 * 256 * fit1->nHits; // not used in the current TRAP program, used for error calculation (simulation only)
1629 LOGF(debug, "Q0(%i), Q1(%i)", q0, q1);
1630
1631 int32_t denom = nHits * sumX2 - sumX * sumX;
1632 int32_t mult32 = mult64 / denom; // exactly like in the TRAP program, divide 64 bit to 32 bit and get 32 bit result
1633
1634 // still without divider here
1635 int32_t slope = nHits * sumXY - sumX * sumY;
1636 int32_t position = sumX2 * sumY - sumX * sumXY;
1637
1638 // first take care of slope
1639 int64_t temp = slope;
1640 temp *= mult32;
1641 slope = temp >> 32;
1642 // same for offset
1643 temp = position;
1644 temp *= mult32;
1645 position = temp >> 32;
1646 LOGF(debug, "2 slope=%i, position=%i", slope, position);
1647
1648 position = position << decPlaces;
1649 position += t0 * nHits * sumXY - t0 * sumX * sumY;
1650 position = position >> decPlaces;
1651
1652 wrks = (mFitPtr[cpu] << (8 + decPlaces)) - yoffs;
1653 LOGF(debug, "yoffs=%i, wrks=%i", yoffs, wrks);
1654 position += wrks;
1655
1656 mult64 = scaleD;
1657 mult64 *= slope;
1658 slope = mult64 >> 32; // take the upper 32 bit
1659
1660 position = -position; // do the inversion as in the TRAP
1661
1662 mult64 = scaleY;
1663 mult64 *= position;
1664 position = mult64 >> 32; // take the upper 32 bit
1665 LOGF(debug, "3 slope=%i, position=%i", slope, position);
1666 // rounding, as in the TRAP
1667 slope = (slope + rndAdd) >> decPlacesSlope;
1668 position = (position + rndAdd) >> decPlaces;
1669
1670 slope = -slope; // inversion as for position FIXME: when changed in the actual trap this line can be removed
1671
1672 LOGF(debug, " pos =%5d, slope =%5d\n", position, slope);
1673
1674 // ============> calculation with floating point arithmetic not done in the actual TRAP
1675 float fitSlope = (float)(nHits * sumXY - sumX * sumY) / (nHits * sumX2 - sumX * sumX);
1676 float fitOffset = (float)(sumX2 * sumY - sumX * sumXY) / (nHits * sumX2 - sumX * sumX);
1677 LOGF(debug, "Fit results as float: offset(%f), slope(%f)", fitOffset, fitSlope);
1678 float sx = (float)sumX;
1679 float sx2 = (float)sumX2;
1680 float sy = (float)sumY;
1681 float sy2 = (float)sumY2;
1682 float sxy = (float)sumXY;
1683 float fitError = sy2 - (sx2 * sy * sy - 2 * sx * sxy * sy + nHits * sxy * sxy) / (nHits * sx2 - sx * sx);
1684 // <========== end calculation with floating point arithmetic
1685
1686 // lets check boundaries
1687 if (slope < -128 || slope > 127) {
1688 LOGF(debug, "Slope is outside of allowed range: %i", slope);
1689 }
1690 if (position < -1023) {
1691 LOGF(warning, "Position is smaller than allowed range (%i), clipping it", position);
1692 position = -1023;
1693 }
1694 if (position > 1023) {
1695 LOGF(warning, "Position is larger than allowed range (%i), clipping it", position);
1696 position = 1023;
1697 }
1698 // printf("pos=%i, slope=%i\n", position, slope);
1699 if (slope < -127 || slope > 127) {
1700 // FIXME put correct boundaries for slope and position in TRAP config?
1701 LOGF(debug, "Dropping tracklet of CPU %i with slope %i which is out of range", cpu, slope);
1702 charges[cpu] = 0xff << (8 * cpu);
1703 mMCMT[cpu] = TRACKLETENDMARKER;
1704 } else {
1705 slope = slope & 0xff;
1706 position = position & 0x7ff;
1707
1708 // now comes the charge calculation...
1709 uint32_t q2 = trap_adc_q2_sum[mFitPtr[cpu]] + trap_adc_q2_sum[mFitPtr[cpu] + 1] + trap_adc_q2_sum[mFitPtr[cpu] + 2] + trap_adc_q2_sum[mFitPtr[cpu] + 3]; // from -1 to +2 or from 0 to +3?
1710 LOGF(debug, "IntCharge of %d ... %d : 0x%04x, 0x%04x 0x%04x, 0x%04x", mFitPtr[cpu], mFitPtr[cpu] + 3, trap_adc_q2_sum[mFitPtr[cpu]], trap_adc_q2_sum[mFitPtr[cpu] + 1], trap_adc_q2_sum[mFitPtr[cpu] + 2], trap_adc_q2_sum[mFitPtr[cpu] + 3]);
1711 LOGF(debug, "q2 = %i", q2);
1712 q2 >>= 4; // OS: FIXME understand this factor! If not applied, q2 is usually out of range (> 62)
1713
1714 if (mUseFloatingPointForQ) {
1715 // floating point, with 6 bit mantissa and 2 bits for exp
1716 int shft, shcd;
1717 wrku = q0 | q1 | q2;
1718 wrku >>= mDynSize;
1719 if ((wrku >> mDynShift0) == 0) {
1720 shft = mDynShift0;
1721 shcd = 0;
1722 } else if ((wrku >> mDynShift1) == 0) {
1723 shft = mDynShift1;
1724 shcd = 1;
1725 } else if ((wrku >> mDynShift2) == 0) {
1726 shft = mDynShift2;
1727 shcd = 2;
1728 } else {
1729 shft = mDynShift3;
1730 shcd = 3;
1731 }
1732 q0 >>= shft;
1733 q0 &= mDynMask;
1734 q1 >>= shft;
1735 q1 &= mDynMask;
1736 q2 >>= shft;
1737 q2 &= mDynMask;
1738 LOGF(debug, "Compressed Q0 %4d, Q1 %4d, Q2 %4d", q0 << shft, q1 << shft, q2 << shft);
1739 q2 |= shcd << mDynSize;
1740 if (q2 == mEmptyHPID8) {
1741 // prevent sending the HPID code for no tracklet
1742 --q2;
1743 }
1744 charges[cpu] = q2;
1745 charges[cpu] <<= mDynSize;
1746 charges[cpu] |= q1;
1747 charges[cpu] <<= mDynSize;
1748 charges[cpu] |= q0;
1749 } else {
1750 // fixed multiplier
1751 temp = q0; // temporarily move to 64bit variable
1752 temp *= mScaleQ;
1753 q0 = temp >> 32;
1754
1755 temp = q1; // temporarily move to 64bit variable
1756 temp *= mScaleQ;
1757 q1 = temp >> 32;
1758
1759 temp = q2; // temporarily move to 64bit variable
1760 temp *= mScaleQ;
1761 q2 = temp >> 32;
1762 q2 >>= 1; // q2 needs additional shift, since we want the same range as q0 and q1 and q2 is only 6 bit wide
1763
1764 // clip the charges
1765 if (q0 > mMaskQ0Q1) {
1766 q0 = mMaskQ0Q1;
1767 }
1768 if (q1 > mMaskQ0Q1) {
1769 q1 = mMaskQ0Q1;
1770 }
1771 if (q2 > mMaxQ2) {
1772 q2 = mMaxQ2;
1773 }
1774
1775 charges[cpu] = q2;
1776 charges[cpu] <<= mSizeQ0Q1;
1777 charges[cpu] |= q1;
1778 charges[cpu] <<= mSizeQ0Q1;
1779 charges[cpu] |= q0;
1780 }
1781
1782 // < pad_position within the MCM (11 bit) | LPID (12 bit) | slope (8 bit) | 0 >
1783 // the index here is +1, as CPU0 sends the header, CPU1..3 send the tracklets of
1784 // CPU0..2.
1785 // the tracklets output is here what exactly sends CPUx
1786 LOGF(debug, "We have a tracklet! Position(%i), Slope(%i), q0(%i), q1(%i), q2(%i)", position ^ 0x80, slope ^ 0x80, q0, q1, q2);
1787 // two bits are inverted in order to avoid misinterpretation of tracklet word as end marker
1788 mMCMT[cpu + 1] = position ^ 0x80;
1789 mMCMT[cpu + 1] <<= mSizeLPID;
1790 mMCMT[cpu + 1] |= charges[cpu] & mMaskLPID;
1791 mMCMT[cpu + 1] <<= 8;
1792 mMCMT[cpu + 1] |= slope ^ 0x80;
1793 mMCMT[cpu + 1] <<= 1;
1794 // here charges is the HPIDx shifted to the proper position (16 for CPU2, 8 for CPU1)
1795 charges[cpu] >>= 12;
1796 charges[cpu] <<= 8 * cpu;
1797
1798 // prepare 64 bit tracklet word directly
1799 uint64_t trkltWord64 = mTrkltWordEmpty;
1800 trkltWord64 |= (static_cast<uint64_t>(position & 0x7ff) << Tracklet64::posbs) | (static_cast<uint64_t>(slope & 0xff) << Tracklet64::slopebs) | (q2 << Tracklet64::Q2bs) | (q1 << Tracklet64::Q1bs) | q0;
1801 mTrackletArray64.emplace_back(trkltWord64);
1802
1803 // calculate number of hits and MC label
1804 mTrackletDigitCount.push_back(0);
1805 for (int ch = 0; ch < NCOLMCM; ch++) { // TODO: check if one should not check each channel instead of each pad?
1806 if (mADCDigitIndices[ch] >= 0 && ((ch == mFitPtr[cpu]) || (ch == mFitPtr[cpu] + 1))) {
1807 // we have a digit in one of the two channels which were used to fit the tracklet
1808 mTrackletDigitCount.back() += 1;
1809 mTrackletDigitIndices.push_back(mADCDigitIndices[ch]);
1810 }
1811 }
1812 } // tracklet did pass slope selection
1813 } // there is a tracklet available for this CPU
1814 } // loop over CPUs for tracklet calculation
1815 } // tracklet are available for at least one CPU for this MCM
1816
1817 // mMCMT[0] stores the MCM tracklet header, the part without HPIDs (mMcmHeaderEmpty) prepared already
1818 // < 1 | padrow (4 bits) | column (2 bits) | HPID2 (8 bit) | HPID1 (8 bit) | HPID0 (8 bit) | 1 >
1819 wrku = charges[0] | charges[1] | charges[2];
1820 // send only if at least one of the HPIDs different from the empty one OR
1821 // the sending of header without tracklets is not disabled
1822 if ((wrku != mEmptyHPID24) || !mDontSendEmptyHeaderTrklt) // send MCM header
1823 {
1824 mMCMT[0] = mMcmHeaderEmpty | (wrku << 1);
1825 }
1826
1827 LOG(debug) << "4x32 bit tracklet data:";
1828 for (int i = 0; i < 4; ++i) {
1829 LOGF(debug, "0x%08x", mMCMT[i]);
1830 }
1831}
1832
1834{
1835 // Run the tracklet calculation by calling sequentially:
1836 // calcFitreg(); trackletSelection(); fitTracklet()
1837 // and store the tracklets
1838
1839 if (!mInitialized) {
1840 return;
1841 }
1842
1843 calcFitreg();
1845 fitTracklet();
1846}
1847
1848// help functions, to be cleaned up
1849
1850unsigned int TrapSimulator::addUintClipping(unsigned int a, unsigned int b, unsigned int nbits) const
1851{
1852 //
1853 // This function adds a and b (unsigned) and clips to
1854 // the specified number of bits.
1855 //
1856
1857 unsigned int sum = a + b;
1858 if (nbits < 32) {
1859 unsigned int maxv = (1 << nbits) - 1;
1860 if (sum > maxv) {
1861 sum = maxv;
1862 }
1863 } else {
1864 if ((sum < a) || (sum < b)) {
1865 sum = 0xFFFFFFFF;
1866 }
1867 }
1868 return sum;
1869}
1870
1871void TrapSimulator::sort2(uint16_t idx1i, uint16_t idx2i,
1872 uint16_t val1i, uint16_t val2i,
1873 uint16_t* idx1o, uint16_t* idx2o,
1874 uint16_t* val1o, uint16_t* val2o) const
1875{
1876 // sorting for tracklet selection
1877
1878 if (val1i > val2i) {
1879 *idx1o = idx1i;
1880 *idx2o = idx2i;
1881 *val1o = val1i;
1882 *val2o = val2i;
1883 } else {
1884 *idx1o = idx2i;
1885 *idx2o = idx1i;
1886 *val1o = val2i;
1887 *val2o = val1i;
1888 }
1889}
1890
1891void TrapSimulator::sort3(uint16_t idx1i, uint16_t idx2i, uint16_t idx3i,
1892 uint16_t val1i, uint16_t val2i, uint16_t val3i,
1893 uint16_t* idx1o, uint16_t* idx2o, uint16_t* idx3o,
1894 uint16_t* val1o, uint16_t* val2o, uint16_t* val3o) const
1895{
1896 // sorting for tracklet selection
1897
1898 int sel;
1899
1900 if (val1i > val2i) {
1901 sel = 4;
1902 } else {
1903 sel = 0;
1904 }
1905 if (val2i > val3i) {
1906 sel = sel + 2;
1907 }
1908 if (val3i > val1i) {
1909 sel = sel + 1;
1910 }
1911 switch (sel) {
1912 case 6: // 1 > 2 > 3 => 1 2 3
1913 case 0: // 1 = 2 = 3 => 1 2 3 : in this case doesn't matter, but so is in hardware!
1914 *idx1o = idx1i;
1915 *idx2o = idx2i;
1916 *idx3o = idx3i;
1917 *val1o = val1i;
1918 *val2o = val2i;
1919 *val3o = val3i;
1920 break;
1921
1922 case 4: // 1 > 2, 2 <= 3, 3 <= 1 => 1 3 2
1923 *idx1o = idx1i;
1924 *idx2o = idx3i;
1925 *idx3o = idx2i;
1926 *val1o = val1i;
1927 *val2o = val3i;
1928 *val3o = val2i;
1929 break;
1930
1931 case 2: // 1 <= 2, 2 > 3, 3 <= 1 => 2 1 3
1932 *idx1o = idx2i;
1933 *idx2o = idx1i;
1934 *idx3o = idx3i;
1935 *val1o = val2i;
1936 *val2o = val1i;
1937 *val3o = val3i;
1938 break;
1939
1940 case 3: // 1 <= 2, 2 > 3, 3 > 1 => 2 3 1
1941 *idx1o = idx2i;
1942 *idx2o = idx3i;
1943 *idx3o = idx1i;
1944 *val1o = val2i;
1945 *val2o = val3i;
1946 *val3o = val1i;
1947 break;
1948
1949 case 1: // 1 <= 2, 2 <= 3, 3 > 1 => 3 2 1
1950 *idx1o = idx3i;
1951 *idx2o = idx2i;
1952 *idx3o = idx1i;
1953 *val1o = val3i;
1954 *val2o = val2i;
1955 *val3o = val1i;
1956 break;
1957
1958 case 5: // 1 > 2, 2 <= 3, 3 > 1 => 3 1 2
1959 *idx1o = idx3i;
1960 *idx2o = idx1i;
1961 *idx3o = idx2i;
1962 *val1o = val3i;
1963 *val2o = val1i;
1964 *val3o = val2i;
1965 break;
1966
1967 default: // the rest should NEVER happen!
1968 LOG(error) << "ERROR in Sort3!!!";
1969 break;
1970 }
1971}
1972
1973void TrapSimulator::sort6To4(uint16_t idx1i, uint16_t idx2i, uint16_t idx3i, uint16_t idx4i, uint16_t idx5i, uint16_t idx6i,
1974 uint16_t val1i, uint16_t val2i, uint16_t val3i, uint16_t val4i, uint16_t val5i, uint16_t val6i,
1975 uint16_t* idx1o, uint16_t* idx2o, uint16_t* idx3o, uint16_t* idx4o,
1976 uint16_t* val1o, uint16_t* val2o, uint16_t* val3o, uint16_t* val4o) const
1977{
1978 // sorting for tracklet selection
1979
1980 uint16_t idx21s, idx22s, idx23s, dummy;
1981 uint16_t val21s, val22s, val23s;
1982 uint16_t idx23as, idx23bs;
1983 uint16_t val23as, val23bs;
1984
1985 sort3(idx1i, idx2i, idx3i, val1i, val2i, val3i,
1986 idx1o, &idx21s, &idx23as,
1987 val1o, &val21s, &val23as);
1988
1989 sort3(idx4i, idx5i, idx6i, val4i, val5i, val6i,
1990 idx2o, &idx22s, &idx23bs,
1991 val2o, &val22s, &val23bs);
1992
1993 sort2(idx23as, idx23bs, val23as, val23bs, &idx23s, &dummy, &val23s, &dummy);
1994
1995 sort3(idx21s, idx22s, idx23s, val21s, val22s, val23s,
1996 idx3o, idx4o, &dummy,
1997 val3o, val4o, &dummy);
1998}
1999
2000void TrapSimulator::sort6To2Worst(uint16_t idx1i, uint16_t idx2i, uint16_t idx3i, uint16_t idx4i, uint16_t idx5i, uint16_t idx6i,
2001 uint16_t val1i, uint16_t val2i, uint16_t val3i, uint16_t val4i, uint16_t val5i, uint16_t val6i,
2002 uint16_t* idx5o, uint16_t* idx6o) const
2003{
2004 // sorting for tracklet selection
2005
2006 uint16_t idx21s, idx22s, idx23s, dummy1, dummy2, dummy3, dummy4, dummy5;
2007 uint16_t val21s, val22s, val23s;
2008 uint16_t idx23as, idx23bs;
2009 uint16_t val23as, val23bs;
2010
2011 sort3(idx1i, idx2i, idx3i, val1i, val2i, val3i,
2012 &dummy1, &idx21s, &idx23as,
2013 &dummy2, &val21s, &val23as);
2014
2015 sort3(idx4i, idx5i, idx6i, val4i, val5i, val6i,
2016 &dummy1, &idx22s, &idx23bs,
2017 &dummy2, &val22s, &val23bs);
2018
2019 sort2(idx23as, idx23bs, val23as, val23bs, &idx23s, idx5o, &val23s, &dummy1);
2020
2021 sort3(idx21s, idx22s, idx23s, val21s, val22s, val23s,
2022 &dummy1, &dummy2, idx6o,
2023 &dummy3, &dummy4, &dummy5);
2024}
2025
2026bool TrapSimulator::readPackedConfig(TrapConfig* cfg, int hc, unsigned int* data, int size)
2027{
2028 // Read the packed configuration from the passed memory block
2029 //
2030 // To be used to retrieve the TRAP configuration from the
2031 // configuration as sent in the raw data.
2032
2033 LOG(debug) << "Reading packed configuration";
2034
2035 int det = hc / 2;
2036
2037 int idx = 0;
2038 int err = 0;
2039 int step, bwidth, nwords, exitFlag, bitcnt;
2040
2041 unsigned short caddr;
2042 unsigned int dat, msk, header, dataHi;
2043
2044 while (idx < size && *data != 0x00000000) {
2045
2046 int rob = (*data >> 28) & 0x7;
2047 int mcm = (*data >> 24) & 0xf;
2048
2049 LOG(debug) << "Config of det. " << det << " MCM " << rob << ":" << mcm << " (0x" << std::hex << *data << ")";
2050 data++;
2051
2052 while (idx < size && *data != 0x00000000) {
2053
2054 header = *data;
2055 data++;
2056 idx++;
2057
2058 LOG(debug) << "read: 0x" << hex << header;
2059
2060 if (header & 0x01) // single data
2061 {
2062 dat = (header >> 2) & 0xFFFF; // 16 bit data
2063 caddr = (header >> 18) & 0x3FFF; // 14 bit address
2064
2065 if (caddr != 0x1FFF) // temp!!! because the end marker was wrong
2066 {
2067 if (header & 0x02) // check if > 16 bits
2068 {
2069 dataHi = *data;
2070 LOG(debug) << "read: 0x" << hex << dataHi;
2071 data++;
2072 idx++;
2073 err += ((dataHi ^ (dat | 1)) & 0xFFFF) != 0;
2074 dat = (dataHi & 0xFFFF0000) | dat;
2075 }
2076 LOG(debug) << "addr=0x" << hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << dat;
2077 if (!cfg->poke(caddr, dat, det, rob, mcm)) {
2078 LOG(debug) << "(single-write): non-existing address 0x" << std::hex << caddr << " containing 0x" << std::hex << header;
2079 }
2080 if (idx > size) {
2081 LOG(debug) << "(single-write): no more data, missing end marker";
2082 return -err;
2083 }
2084 } else {
2085 LOG(debug) << "(single-write): address 0x" << setw(4) << std::hex << caddr << " => old endmarker?" << std::dec;
2086 return err;
2087 }
2088 }
2089
2090 else // block of data
2091 {
2092 step = (header >> 1) & 0x0003;
2093 bwidth = ((header >> 3) & 0x001F) + 1;
2094 nwords = (header >> 8) & 0x00FF;
2095 caddr = (header >> 16) & 0xFFFF;
2096 exitFlag = (step == 0) || (step == 3) || (nwords == 0);
2097
2098 if (exitFlag) {
2099 break;
2100 }
2101
2102 switch (bwidth) {
2103 case 15:
2104 case 10:
2105 case 7:
2106 case 6:
2107 case 5: {
2108 msk = (1 << bwidth) - 1;
2109 bitcnt = 0;
2110 while (nwords > 0) {
2111 nwords--;
2112 bitcnt -= bwidth;
2113 if (bitcnt < 0) {
2114 header = *data;
2115 LOG(debug) << "read 0x" << setw(8) << std::hex << header << std::dec;
2116 data++;
2117 idx++;
2118 err += (header & 1);
2119 header = header >> 1;
2120 bitcnt = 31 - bwidth;
2121 }
2122 LOG(debug) << "addr=0x" << setw(4) << std::hex << caddr << "(" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << setw(8) << std::hex << (header & msk);
2123 if (!cfg->poke(caddr, header & msk, det, rob, mcm)) {
2124 LOG(debug) << "(single-write): non-existing address 0x" << setw(4) << std::hex << caddr << " containing 0x" << setw(8) << std::hex << header << std::dec;
2125 }
2126
2127 caddr += step;
2128 header = header >> bwidth;
2129 if (idx >= size) {
2130 LOG(debug) << "(block-write): no end marker! " << idx << " words read";
2131 return -err;
2132 }
2133 }
2134 break;
2135 } // end case 5-15
2136 case 31: {
2137 while (nwords > 0) {
2138 header = *data;
2139 LOG(debug) << "read 0x" << setw(8) << std::hex << header;
2140 data++;
2141 idx++;
2142 nwords--;
2143 err += (header & 1);
2144
2145 LOG(debug) << "addr=0x" << hex << setw(4) << caddr << " (" << cfg->getRegName(cfg->getRegByAddress(caddr)) << ") data=0x" << hex << setw(8) << (header >> 1);
2146 if (!cfg->poke(caddr, header >> 1, det, rob, mcm)) {
2147 LOG(debug) << "(single-write): non-existing address 0x" << setw(4) << std::hex << " containing 0x" << setw(8) << std::hex << header << std::dec;
2148 }
2149
2150 caddr += step;
2151 if (idx >= size) {
2152 LOG(debug) << "no end marker! " << idx << " words read";
2153 return -err;
2154 }
2155 }
2156 break;
2157 }
2158 default:
2159 return err;
2160 } // end switch
2161 } // end block case
2162 }
2163 } // end while
2164 LOG(debug) << "no end marker! " << idx << " words read";
2165 return -err; // only if the max length of the block reached!
2166}
uint16_t mcm
uint16_t rob
int32_t i
bool const GPUTPCGMMerger::trackCluster * c1
std::vector< uint16_t > nsamples
Definition testDigit.cxx:38
uint32_t cpu
Definition RawData.h:6
uint32_t j
Definition RawData.h:0
uint16_t slope
Definition RawData.h:1
uint16_t pid
Definition RawData.h:2
uint32_t c
Definition RawData.h:2
uint32_t padrow
Definition RawData.h:5
std::ostringstream debug
Class for time synchronization of RawReader instances.
bool getUseTimeOffset() const
Definition FeeParam.h:80
static int getPadRowFromMCM(int irob, int imcm)
Definition FeeParam.cxx:95
static FeeParam * instance()
Definition FeeParam.cxx:58
bool getUseMisalignCorr() const
Definition FeeParam.h:78
static constexpr uint64_t posbs
Definition Tracklet64.h:224
static constexpr uint64_t Q1bs
Definition Tracklet64.h:228
static constexpr uint64_t colbs
Definition Tracklet64.h:223
static constexpr uint64_t slopebs
Definition Tracklet64.h:225
static constexpr uint64_t Q2bs
Definition Tracklet64.h:227
static constexpr uint64_t padrowbs
Definition Tracklet64.h:222
static constexpr uint64_t hcidbs
Definition Tracklet64.h:221
static constexpr uint64_t formatbs
Definition Tracklet64.h:220
void printDatx(std::ostream &os, unsigned int addr, unsigned int data, int rob, int mcm)
bool poke(int addr, unsigned int value, int det, int rob, int mcm)
unsigned int getDmemUnsigned(int addr, int det, int rob, int mcm)
std::string getRegName(TrapReg_t reg)
Definition TrapConfig.h:526
int getTrapReg(TrapReg_t reg, int det=-1, int rob=-1, int mcm=-1)
TrapReg_t getRegByAddress(int address)
void filterPedestalInit(int baseline=10)
static const int mgkFormatIndex
unsigned short filterTailNextSample(int adc, unsigned short value)
static std::ostream & raw(std::ostream &os)
void printFitRegXml(std::ostream &os) const
static constexpr int mgkDmemAddrTimeOffset
static bool readPackedConfig(TrapConfig *cfg, int hc, unsigned int *data, int size)
void printAdcDatDatx(std::ostream &os, bool broadcast=kFALSE, int timeBinOffset=-1) const
static std::ostream & cfdat(std::ostream &os)
void noiseTest(int nsamples, int mean, int sigma, int inputGain=1, int inputTail=2)
int getDataFiltered(int iadc, int timebin) const
int getNumberOfTimeBins() const
void printAdcDatTxt(std::ostream &os) const
void printAdcDatXml(std::ostream &os) const
bool checkInitialized() const
static std::ostream & text(std::ostream &os)
static constexpr int mgkDmemAddrNdrift
int getDataRaw(int iadc, int timebin) const
static const std::array< unsigned short, 4 > mgkFPshifts
static const int mgkAddDigits
void setData(int iadc, const ArrayADC &adc, unsigned int digitIdx)
unsigned short filterGainNextSample(int adc, unsigned short value)
unsigned short filterPedestalNextSample(int adc, int timebin, unsigned short value)
void printTrackletsXml(std::ostream &os) const
void print(int choice) const
void draw(int choice, int index)
static constexpr int mgkDmemAddrYcorr
void filterTailInit(int baseline=-1)
void init(TrapConfig *trapconfig, int det, int rob, int mcm)
void printAdcDatHuman(std::ostream &os) const
void addHitToFitreg(int adc, unsigned short timebin, unsigned short qtot, short ypos)
int packData(std::vector< uint32_t > &rawdata, uint32_t offset) const
void setDataPedestal(int iadc)
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLsizei bufSize
Definition glcorearb.h:790
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition glcorearb.h:5034
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
GLint GLuint mask
Definition glcorearb.h:291
GLint GLint GLsizei GLint GLenum format
Definition glcorearb.h:275
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition glcorearb.h:5034
constexpr int NMCMROBINCOL
the number of MCMs per ROB in column direction
Definition Constants.h:49
constexpr int TRACKLETENDMARKER
marker for the end of tracklets in raw data, 2 of these.
Definition Constants.h:88
constexpr int NCPU
the number of CPUs inside the TRAP chip
Definition Constants.h:60
constexpr int NOTRACKLETFIT
this value is assigned to the fit pointer in case no tracklet is available
Definition Constants.h:87
constexpr int PADGRANULARITYTRKLSLOPE
tracklet deflection is stored in units of 1/128 pad per time bin
Definition Constants.h:68
constexpr int PADGRANULARITYTRKLPOS
tracklet position is stored in units of 1/40 pad
Definition Constants.h:67
constexpr int NADCMCM
the number of ADC channels per MCM
Definition Constants.h:52
constexpr int NCOLMCM
the number of pads per MCM
Definition Constants.h:53
constexpr int CHANNELNRNOTRKLT
this marks channels in the ADC mask which don't contribute to a tracklet
Definition Constants.h:86
void printTrackletMCMHeader(const o2::trd::TrackletMCMHeader &mcmhead)
Definition RawData.cxx:223
std::array< ADC_t, constants::TIMEBINS > ArrayADC
Definition Digit.h:32
void printTrackletMCMData(const o2::trd::TrackletMCMData &tracklet)
Definition RawData.cxx:218
std::ostream & operator<<(std::ostream &stream, const Digit &d)
Definition Digit.cxx:78
Defining DataPointCompositeObject explicitly as copiable.
Header for MCM tracklet data outuput.
Definition RawData.h:162
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row
std::vector< Tracklet64 > tracklets
ArrayADC adc