source: trunk/Mars/msimcamera/MSimTrigger.cc@ 19843

Last change on this file since 19843 was 19698, checked in by tbretz, 5 years ago
Changed the default of BaselineShift to false. This is what we use in all our simulations so far. Instead, it can now be manually enabled as a none baseline shft introduces strange values (which depend on the number of connected pixels) due to the clipping.
File size: 29.5 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of CheObs, the Modular Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appears in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 1/2009 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: CheObs Software Development, 2000-2009
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MSimTrigger
28//
29// This task takes the pure analog channels and simulates a trigger
30// electronics.
31//
32// In a first step several channels can be summed together by a look-up table
33// fRouteAC.
34//
35// In a second step from these analog channels the output of a discriminator
36// is calculated using a threshold and optional a fixed digital signal length.
37//
38// The signal length of the digital signal emitted by the discriminator
39// can either be bound to the time the signal is above the threshold
40// defined by fDiscriminatorThreshold if fDigitalSignalLength<0 or set to a
41// fixed length (fDigitalSignalLength>0).
42//
43// With a second look-up table fCoincidenceMap the analog channels are
44// checked for coincidences. The coincidence must at least be of the length
45// defined by fCoincidenceTime. The earliest coincide is then stored as
46// trigger position.
47//
48// If a minimum multiplicity m is given, m signals above threshold
49// in the coincidence patterns are enough to emit a trigger signal.
50//
51//
52// For MAGIC1:
53// - fDigitalSignalLength between 6ns and 12ns
54// - fCoincidenceTime between 0.25ns to 1ns
55//
56//
57// Input Containers:
58// IntendedPulsePos [MParameterD]
59// MAnalogChannels
60// MRawRunHeader
61//
62// Output Containers:
63// TriggerPos [MParameterD]
64// MRawEvtHeader
65//
66//////////////////////////////////////////////////////////////////////////////
67#include "MSimTrigger.h"
68
69#include "MLog.h"
70#include "MLogManip.h"
71
72#include "MParList.h"
73#include "MParameters.h"
74
75#include "MLut.h"
76#include "MArrayI.h"
77
78#include "MRawEvtHeader.h"
79#include "MRawRunHeader.h"
80
81#include "MAnalogSignal.h"
82#include "MAnalogChannels.h"
83#include "MDigitalSignal.h"
84
85#include "MTriggerPattern.h"
86
87#include "MPedestalCam.h"
88#include "MPedestalPix.h"
89
90ClassImp(MSimTrigger);
91
92using namespace std;
93
94// --------------------------------------------------------------------------
95//
96// Default Constructor.
97//
98MSimTrigger::MSimTrigger(const char *name, const char *title)
99 : fCamera(0),
100 fPulsePos(0),
101 fTrigger(0),
102 fRunHeader(0),
103 fEvtHeader(0),
104 fElectronicNoise(0),
105 fGain(0),
106 fDiscriminatorThreshold(-1),
107 fDigitalSignalLength(8),
108 fCoincidenceTime(0.5),
109 fShiftBaseline(kFALSE),
110 fUngainSignal(kTRUE),
111 fSimulateElectronics(kTRUE),
112 fMinMultiplicity(-1),
113 fCableDelay(21),
114 fCableDamping(0.), // default Damping Set to zero, so users, who do not set
115 fDebugTrigger(kFALSE) // the CableDamoing in the ceres.rc do not see a difference.
116
117{
118 fName = name ? name : "MSimTrigger";
119 fTitle = title ? title : "Task to simulate trigger electronics";
120}
121
122// --------------------------------------------------------------------------
123//
124// Take two TObjArrays with a collection of digital signals.
125// Every signal from one array is compared with any from the other array.
126// For all signals which overlap and which have an overlap time >gate
127// a new digital signal is created storing start time and length of overlap.
128// They are collected in a newly allocated TObjArray. A pointer to this array
129// is returned.
130//
131// The user gains owenership of the object, i.e., the user is responsible of
132// deleting the memory.
133//
134TObjArray *MSimTrigger::CalcCoincidence(const TObjArray &arr1, const TObjArray &arr2/*, Float_t gate*/) const
135{
136 TObjArray *res = new TObjArray;
137
138 if (arr1.GetEntriesFast()==0 || arr2.GetEntriesFast()==0)
139 return res;
140
141 TIter Next1(&arr1);
142 MDigitalSignal *ttl1 = 0;
143 while ((ttl1=static_cast<MDigitalSignal*>(Next1())))
144 {
145 TIter Next2(&arr2);
146 MDigitalSignal *ttl2 = 0;
147 while ((ttl2=static_cast<MDigitalSignal*>(Next2())))
148 {
149 MDigitalSignal *ttl = new MDigitalSignal(*ttl1, *ttl2);
150 /*
151 if (ttl->GetLength()<=gate)
152 {
153 delete ttl;
154 continue;
155 }
156 */
157 res->Add(ttl);
158 }
159 }
160
161 res->SetOwner();
162
163 return res;
164}
165
166class Edge : public TObject
167{
168private:
169 Double_t fEdge;
170 Int_t fRising;
171
172public:
173 Edge(Double_t t, Int_t rising) : fEdge(t), fRising(rising) { }
174 Bool_t IsSortable() const { return kTRUE; }
175 Int_t Compare(const TObject *o) const { const Edge *e = static_cast<const Edge*>(o); if (e->fEdge<fEdge) return 1; if (e->fEdge>fEdge) return -1; return 0; }
176
177 Int_t IsRising() const { return fRising; }
178 Double_t GetEdge() const { return fEdge; }
179};
180
181// --------------------------------------------------------------------------
182//
183// Calculate a multiplicity trigger on the given array(s). The idx-array
184// conatins all channels which should be checked for coincidences
185// and the ttls array conatins the arrays with the digital signals.
186//
187// For the windows in which more or euqal than threshold channels have
188// a high signal a new MDigitalSignal is created. newly allocated
189// array with a collection of these trigger signals is returned.
190//
191TObjArray *MSimTrigger::CalcMinMultiplicity(const MArrayI &idx, const TObjArray &ttls, Int_t threshold) const
192{
193 // Create a new array for the rising and falling edges of the signals
194 TObjArray times;
195 times.SetOwner();
196
197 // Fill the array with edges from all digital signals of all our channels
198 for (UInt_t k=0; k<idx.GetSize(); k++)
199 {
200 TObjArray *arr = static_cast<TObjArray*>(ttls[idx[k]]);
201
202 TIter Next(arr);
203 MDigitalSignal *ttl = 0;
204 while ((ttl=static_cast<MDigitalSignal*>(Next())))
205 {
206 times.Add(new Edge(ttl->GetStart(), 1));
207 times.Add(new Edge(ttl->GetEnd(), -1));
208 }
209 }
210
211 // Sort them in time
212 times.Sort();
213
214 // Start with no channel active
215 Int_t lvl = 0;
216
217 TObjArray *res = new TObjArray;
218 res->SetOwner();
219
220 // First remove all edges which do not change the status
221 // "below threshold" or "above threshold"
222 for (int i=0; i<times.GetEntriesFast(); i++)
223 {
224 // Get i-th edge
225 const Edge &e = *static_cast<Edge*>(times.UncheckedAt(i));
226
227 // Claculate what the number of active channels after the edge is
228 const Int_t lvl1 = lvl + e.IsRising();
229
230 // Remove edge if number of active channels before and after the
231 // edge lower is lower than the threshold or higher than
232 // the threshold
233 if (lvl+1<threshold || lvl-1>=threshold)
234 delete times.RemoveAt(i);
235
236 // keep the (now) "previous" level
237 lvl = lvl1<0 ? 0 : lvl1;
238 }
239
240 // Remove the empty slots from the array
241 times.Compress();
242
243 //
244 for (int i=0; i<times.GetEntriesFast()-1; i++)
245 {
246 // get the current edge
247 const Edge &e0 = *static_cast<Edge*>(times.UncheckedAt(i));
248
249 // go ahead if this is a falling edge
250 if (e0.IsRising()!=1)
251 continue;
252
253 // get the following edge (must be a falling edge now)
254 const Edge &e1 = *static_cast<Edge*>(times.UncheckedAt(i+1));
255
256 // calculate the length of the digital signal
257 const Double_t len = e1.GetEdge()-e0.GetEdge();
258
259 // Create a digital trigger signal
260 MDigitalSignal *ds = new MDigitalSignal(e0.GetEdge(), len);
261 //ds->SetIndex(lvl);
262 res->Add(ds);
263 }
264
265 return res;
266}
267
268// --------------------------------------------------------------------------
269//
270// Check for the necessary parameter containers. Read the luts.
271//
272Int_t MSimTrigger::PreProcess(MParList *pList)
273{
274 fTrigger = (MParameterD*)pList->FindCreateObj("MParameterD", "TriggerPos");
275 if (!fTrigger)
276 return kFALSE;
277
278 fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
279 if (!fPulsePos)
280 {
281 *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
282 return kFALSE;
283 }
284
285 fCamera = (MAnalogChannels*)pList->FindObject("MAnalogChannels");
286 if (!fCamera)
287 {
288 *fLog << err << "MAnalogChannels not found... aborting." << endl;
289 return kFALSE;
290 }
291
292 fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
293 if (!fRunHeader)
294 {
295 *fLog << err << "MRawRunHeader not found... aborting." << endl;
296 return kFALSE;
297 }
298
299 fEvtHeader = (MRawEvtHeader*)pList->FindCreateObj("MRawEvtHeader");
300 if (!fEvtHeader)
301 return kFALSE;
302
303 if (!fSimulateElectronics && !fDebugTrigger)
304 {
305 *fLog << inf << "Simulation of electronics switched off... first photon will trigger." << endl;
306 return kTRUE;
307 }
308
309 fElectronicNoise = 0;
310 if (fShiftBaseline)
311 {
312 fElectronicNoise = (MPedestalCam*)pList->FindObject("ElectronicNoise", "MPedestalCam");
313 if (!fElectronicNoise)
314 {
315 *fLog << err << "ElectronicNoise [MPedestalCam] not found... aborting." << endl;
316 return kFALSE;
317 }
318 *fLog << inf << "Baseline will be shifted back to 0 for discriminator." << endl;
319 }
320
321 fGain = 0;
322 if (fUngainSignal)
323 {
324 fGain = (MPedestalCam*)pList->FindObject("Gain", "MPedestalCam");
325 if (!fGain)
326 {
327 *fLog << err << "Gain [MPedestalCam] not found... aborting." << endl;
328 return kFALSE;
329 }
330 *fLog << inf << "Discriminator will be multiplied by applied gain." << endl;
331 }
332
333 fRouteAC.Delete();
334 if (!fNameRouteAC.IsNull() && fRouteAC.ReadFile(fNameRouteAC)<0)
335 return kFALSE;
336
337 fCoincidenceMap.Delete();
338 if (!fNameCoincidenceMap.IsNull() && fCoincidenceMap.ReadFile(fNameCoincidenceMap)<0)
339 return kFALSE;
340
341 // ---------------- Consistency checks ----------------------
342
343 if (!fRouteAC.IsEmpty() && !fCoincidenceMap.IsEmpty() &&
344 fCoincidenceMap.GetMaxIndex()>fRouteAC.GetNumRows()-1)
345 {
346 *fLog << err;
347 *fLog << "ERROR - AC routing produces " << fRouteAC.GetNumRows() << " analog channels," << endl;
348 *fLog << " but the coincidence map expects at least " << fCoincidenceMap.GetMaxIndex()+1 << " channels." << endl;
349 return kERROR;
350 }
351
352// if (fDiscriminatorThreshold<=0)
353// {
354// *fLog << err << "ERROR - Discriminator threshold " << fDiscriminatorThreshold << " invalid." << endl;
355// return kFALSE;
356// }
357/*
358 if (fElectronicNoise && !fRouteAC.IsEmpty() && !fRouteAC.IsDefaultCol())
359 {
360 // FIXME: Apply to analog channels when summing
361 *fLog << warn << "WARNING - A baseline shift doesn't make sense for sum-channels... reset." << endl;
362 fElectronicNoise = 0;
363 }
364*/
365 if (fGain && !fRouteAC.IsEmpty() && !fRouteAC.IsDefaultCol())
366 {
367 // FIXME: Apply to analog channels when summing
368 *fLog << warn << "WARNING - Ungain doesn't make sense for sum-channels... reset." << endl;
369 fGain = 0;
370 }
371
372
373 // ---------------- Information output ----------------------
374
375 *fLog << inf;
376
377 if (fRouteAC.IsEmpty())
378 *fLog << "Re-routing/summing of analog channels before discriminator switched off." << endl;
379 else
380 *fLog << "Using " << fNameRouteAC << " for re-routing/summing of analog channels before discriminator." << endl;
381
382 if (fCoincidenceMap.IsEmpty() && fMinMultiplicity<=0)
383 *fLog << "No coincidences of digital channels will be checked. Signal-above-threshold trigger applied." << endl;
384 else
385 {
386 *fLog << "Using ";
387 if (fCoincidenceMap.IsEmpty())
388 *fLog << "the whole camera";
389 else
390 *fLog << "patterns from " << fNameCoincidenceMap;
391 *fLog << " to check for ";
392 if (fMinMultiplicity>0)
393 *fLog << fMinMultiplicity << " multiplicity." << endl;
394 else
395 *fLog << "coincidences of the digital channels." << endl;
396 }
397
398 *fLog << "Using discriminator threshold of " << fDiscriminatorThreshold << endl;
399
400 *fLog << "Using fCableDelay " << fCableDelay << " samples" << endl;
401 *fLog << "Using fCableDamping " << fCableDamping << endl;
402
403 if (!fSimulateElectronics)
404 *fLog << inf << "Simulation of electronics switched off... first photon will trigger." << endl;
405
406 ////////////////////////////////
407 // open some output files for debugging
408// patch_file.open("/home/fact_opr/patch_file.csv", ios_base::out);
409// clipped_file.open("/home/fact_opr/clipped_file.csv", ios_base::out);
410// digital_file.open("/home/fact_opr/digital_file.csv", ios_base::out);
411// ratescan_file.open("/home/fact_opr/ratescan_file.csv", ios_base::out);
412
413
414
415 return kTRUE;
416}
417
418/*
419class MDigitalChannel : public TObjArray
420{
421private:
422 TObjArray fArray;
423
424public:
425 MDigitalSignal *GetSignal(UInt_t i) { return static_cast<MDigitalSignal*>(fArray[i]); }
426
427};
428*/
429
430#include "MCamEvent.h"
431class MTriggerSignal : public MParContainer, public MCamEvent
432{
433private:
434 TObjArray fSignals;
435
436public:
437 MTriggerSignal() { fSignals.SetOwner(); }
438
439 void Add(MDigitalSignal *signal) { fSignals.Add(signal); }
440
441 MDigitalSignal *GetSignal(UInt_t i) { return static_cast<MDigitalSignal*>(fSignals[i]); }
442
443 void Sort() { fSignals.Sort(); }
444
445 Int_t GetNumSignals() const { return fSignals.GetEntriesFast(); }
446
447 Float_t GetFirstTrigger() const
448 {
449 MDigitalSignal *sig = static_cast<MDigitalSignal*>(fSignals[0]);
450 return sig ? sig->GetStart() : -1;
451 }
452 Int_t GetFirstIndex() const
453 {
454 MDigitalSignal *sig = static_cast<MDigitalSignal*>(fSignals[0]);
455 return sig ? sig->GetIndex() : -1;
456 }
457 Bool_t GetPixelContent(Double_t&, Int_t, const MGeomCam&, Int_t) const
458 {
459 switch (1)
460 {
461 case 1: // yes/no
462 case 2: // first time
463 case 3: // length
464 case 4: // n
465 break;
466 }
467
468 return kTRUE;
469 }
470 void DrawPixelContent(Int_t) const
471 {
472 }
473};
474
475
476void MSimTrigger::SetTrigger(Double_t pos, Int_t idx)
477{
478 // FIXME: Jitter! (Own class?)
479 fTrigger->SetVal(pos);
480 fTrigger->SetReadyToSave();
481
482 // Flag this event as triggered by the lvl1 trigger (FIXME?)
483 fEvtHeader->SetTriggerPattern(pos<0 ? 0 : 4);
484 fEvtHeader->SetNumTrigLvl1((UInt_t)idx);
485 fEvtHeader->SetReadyToSave();
486}
487
488// --------------------------------------------------------------------------
489//
490Int_t MSimTrigger::Process()
491{
492 // Invalidate trigger
493 //fTrigger->SetVal(-1);
494 // Calculate the minimum and maximum time for a valid trigger
495 const Double_t freq = fRunHeader->GetFreqSampling()/1000.;
496 const Float_t nsamp = fRunHeader->GetNumSamplesHiGain();
497
498 // The trigger position in the readout window
499 // FIXME: This currently corresponds to the start of the spline!
500 const Float_t pulspos = fPulsePos->GetVal()*freq;
501
502 // Valid range in units of bins for the trigger
503 //
504 // GetValidRangeMin/Max contains the earliest and latest
505 // reasonable sample. The earliest is determined by the
506 // the fact that at least a full pulse must fit in front.
507 // The latest ends with the full sampling range.
508 //
509 // As the first trigger can only be initiated by the first
510 // photon from the shower, the valid range for triggers
511 // starts the pulsewidth before the trigger position,
512 // i.e. ValidRangeMin+triggerposition
513 //
514 // If the last photon triggers, then there must at least
515 // be sampling window minus trigger position samples left.
516 // Therefore, the last trigger must be at
517 // ValidRangeMax-(window-triggerpositon)
518 const Float_t min = fCamera->GetValidRangeMin()+pulspos;
519 const Float_t max = fCamera->GetValidRangeMax()-(nsamp-pulspos);
520
521 // Check if routing should be done
522 const Bool_t empty = fRouteAC.IsEmpty();
523
524 if (!fSimulateElectronics && (empty || (!empty && !fDebugTrigger)))
525 {
526 SetTrigger(min, -1);
527 return kTRUE;
528 }
529
530 // ================== Simulate channel bundling ====================
531
532 // FIXME: Before we can bundle the channels we have to make a copy
533 // and simulate clipping
534
535 // If no channels are summed the number of patches stays the same
536 const UInt_t npatch = empty ? fCamera->GetNumChannels() : fRouteAC.GetEntriesFast();
537
538 // Use the given analog channels as default out. If channels are
539 // summed overwrite with a newly allocated set of analog channels
540 MAnalogChannels *patches = fCamera;
541 //MAnalogChannels *raw_patches = fCamera;
542 if (!empty)
543 {
544 // FIXME: Can we add gain and offset here into a new container?
545
546 patches = new MAnalogChannels(npatch, fCamera->GetNumSamples());
547 //raw_patches = new MAnalogChannels(npatch, fCamera->GetNumSamples());
548 for (UInt_t patch_id=0; patch_id<npatch; patch_id++)
549 {
550 const MArrayI &row = fRouteAC.GetRow(patch_id);
551 for (UInt_t pxl_in_patch=0; pxl_in_patch<row.GetSize(); pxl_in_patch++)
552 {
553 const UInt_t pixel_id = row[pxl_in_patch];
554
555 // FIXME: Shrinking the mapping table earlier (e.g.
556 // ReInit) would avoid a lot of if's
557 if (pixel_id<fCamera->GetNumChannels())
558 {
559 // FIXME: There must also be a correction for the AC-coupling. Fortunately it is tiny
560 // and for one channel in the order of a few ADC counts
561 if (fShiftBaseline && fElectronicNoise)
562 (*patches)[patch_id].ShiftSignal(-(1+fCableDamping)*(*fElectronicNoise)[pixel_id].GetPedestal());
563
564 (*patches)[patch_id].AddSignal((*fCamera)[pixel_id]);
565 (*patches)[patch_id].AddSignal((*fCamera)[pixel_id], fCableDelay, fCableDamping);
566 }
567 }
568 }
569
570 if (fDebugTrigger)
571 {
572 for (UInt_t patch_id=0; patch_id<npatch; patch_id++)
573 {
574 const MArrayI &row = fRouteAC.GetRow(patch_id);
575 for (UInt_t pxl_in_patch=0; pxl_in_patch<row.GetSize(); pxl_in_patch++)
576 {
577 const UInt_t pixel_id = row[pxl_in_patch];
578 if (pixel_id<fCamera->GetNumChannels())
579 (*fCamera)[pixel_id].CopySignal((*patches)[patch_id]);
580 }
581 }
582 }
583 }
584
585 if (!fSimulateElectronics)
586 {
587 SetTrigger(min, -1);
588 return kTRUE;
589 }
590
591 // DN: 20140219 Ratescan:
592 //
593 //
594// for (UInt_t patch_id=0; patch_id<npatch; patch_id++)
595// {
596// MAnalogSignal current_patch = (*raw_patches)[patch_id];
597// float max = current_patch[0];
598// for (UInt_t i=1; i<current_patch.GetSize(); i++)
599// {
600// if (current_patch[i] > max)
601// {
602// max = current_patch[i];
603// }
604// }
605// ratescan_file << max << " ";
606// }
607// ratescan_file << endl;
608
609// // DN 20131108: DEBUGGING:
610// for (UInt_t patch_id=0; patch_id<npatch; patch_id++)
611// {
612// for (UInt_t slice=0; slice<fCamera->GetNumSamples(); slice++)
613// {
614// patch_file << (*raw_patches)[patch_id][slice] << "\t";
615// clipped_file << (*patches)[patch_id][slice] << "\t";
616// }
617// patch_file << endl;
618// clipped_file << endl;
619// }
620
621
622
623 // FIXME: Write patches
624
625 // ================== Simulate discriminators ====================
626
627 TObjArray ttls(npatch);
628 ttls.SetOwner();
629
630 for (UInt_t i=0; i<npatch; i++)
631 {
632 // FIXME: What if the gain was also allpied to the baseline?
633 const Double_t offset = fElectronicNoise && empty ? (*fElectronicNoise)[i].GetPedestal() : 0;
634 const Double_t gain = fGain ? (*fGain)[i].GetPedestal() : 1;
635 // FIXME: fCableDelay not taken into account when calculating the
636 // valid range, therefore, fCableDelay must be smaller than the pulse width
637 // FIXME: Start seraching at pulsepos is faster, but breaks things like
638 // ratescans triggering on noise events
639 // We start one sample after cable delay as the spline knots up to cable delay
640 // are still affected by the none simulation of the cable delay
641 ttls.AddAt(
642 (*patches)[i].Discriminate(
643 fDiscriminatorThreshold*gain+offset, // treshold
644 Double_t(fCableDelay)+1, // start
645 Double_t(fCamera->GetNumSamples() - fCableDelay), // end
646 //fDigitalSignalLength // time-over-threshold, or fixed-length?
647 -1 // -1 = time-over-threshold
648 ),
649 i
650 );
651 }
652
653 // FIXME: Write TTLs!
654
655 // If analog channels had been newly allocated free memmory
656 if (patches!=fCamera)
657 delete patches;
658 //if (raw_patches!=fCamera)
659 // delete raw_patches;
660
661 // =================== Simulate coincidences ======================
662
663 // If the map is empty we create a one-pixel-coincidence map
664 // FIMXE: This could maybe be accelerated if the Clone can be
665 // omitted in the loop
666 if (fCoincidenceMap.IsEmpty())
667 {
668 if (fMinMultiplicity>0)
669 fCoincidenceMap.SetDefaultRow(npatch);
670 else
671 fCoincidenceMap.SetDefaultCol(npatch);
672 }
673
674 // Create an array for the individual triggers
675 MTriggerSignal triggers;
676
677 Int_t cnt = 0;
678 Int_t rmlo = 0;
679 Int_t rmhi = 0;
680
681// cout << "MSimTrigger::fMinMultiplicity = " << fMinMultiplicity << endl;
682// cout << "MSimTrigger::fCoincidenceTime = " << fCoincidenceTime << endl;
683// cout << "fCoincidenceMap.GetEntries() = " << fCoincidenceMap.GetEntries() << endl;
684// cout << "MSimTrigger::fCableDelay = " << fCableDelay << endl;
685// cout << "MSimTrigger::fCableDamping = " << fCableDamping << endl;
686// cout << "min:" << min << endl;
687// cout << "max:" << max << endl;
688
689 for (int j=0; j<fCoincidenceMap.GetEntries(); j++)
690 {
691 const MArrayI &idx = fCoincidenceMap.GetRow(j);
692
693 TObjArray *arr = 0;
694
695 if (fMinMultiplicity>0)
696 {
697 arr = CalcMinMultiplicity(idx, ttls, fMinMultiplicity);
698 }
699 else
700 {
701 arr = CalcMinMultiplicity(idx, ttls, idx.GetSize());
702 /*
703 // Start with a copy of the first coincidence channel
704 arr = static_cast<TObjArray*>(ttls[idx[0]]->Clone());
705 arr->SetOwner();
706
707 // compare to all other channels in this coincidence patch, one by one
708 for (UInt_t k=1; k<idx.GetSize() && arr->GetEntriesFast()>0; k++)
709 {
710 TObjArray *res = CalcCoincidence(*arr, *static_cast<TObjArray*>(ttls[idx[k]]));//, fCoincidenceTime);
711
712 // Delete the original array and keep the new one
713 delete arr;
714 arr = res;
715 }*/
716 }
717
718 // Count the number of totally emitted coincidence signals
719 cnt += arr->GetEntriesFast();
720
721 // Remove all signals which are not in the valid digitization range
722 // (This is not the digitization window, but the region in which
723 // the analog channels contain usefull data)
724 // and which are shorter than the defined coincidence gate.
725 TIter Next(arr);
726 MDigitalSignal *ttl = 0;
727 while ((ttl=static_cast<MDigitalSignal*>(Next())))
728 {
729 if (ttl->GetLength()<fCoincidenceTime)
730 {
731 delete arr->Remove(ttl);
732 continue;
733 }
734
735 if (ttl->GetStart()<min)
736 {
737 delete arr->Remove(ttl);
738 rmlo++;
739 continue;
740 }
741 if (ttl->GetStart()>max)
742 {
743 delete arr->Remove(ttl);
744 rmhi++;
745 continue;
746 }
747
748 // Set trigger-channel index to keep this information
749 //ttl->SetIndex(j);
750 }
751
752 // Remove the empty slots
753 arr->Compress();
754
755// cout << "ttls(j=" << j << "):";
756// TObjArray *arr2 = static_cast<TObjArray*>(ttls[j]);
757// TIter Nexty(arr);
758// MDigitalSignal *ttly = 0;
759// while ((ttly=static_cast<MDigitalSignal*>(Nexty())))
760// {
761// cout << "|"<< ttly->GetStart() << ", " << ttly->GetLength();
762// }
763// cout << endl;
764
765
766 // If we have at least one trigger keep the earliest one.
767 // FIXME: The triggers might be ordered in time automatically:
768 // To be checked!
769 // FIXME: Simulate trigger dead-time!
770 if (arr->GetEntriesFast()>0)
771 {
772 ttl = static_cast<MDigitalSignal*>(arr->RemoveAt(0));
773 // Set trigger-channel index to keep this information
774 ttl->SetIndex(j);
775 triggers.Add(ttl);
776 }
777
778 // delete the allocated space
779 delete arr;
780 }
781
782 // There are usually not enough entries that it is worth to search
783 // for the earliest instead of just sorting and taking the first one
784 // FIXME: This could be improved if checking for IsSortable
785 // is omitted
786 triggers.Sort();
787 // FIXME: Store triggers! (+ Reversed pixels?)
788
789 // Shift the trigger such that the pulse position X=0 coincides with the
790 // the trigger position in the readout window
791 SetTrigger(triggers.GetFirstTrigger()/freq, triggers.GetFirstIndex());
792
793 // No trigger issued. Go on.
794 if (triggers.GetNumSignals()==0)
795 {
796 if (rmlo>0 || rmhi>0)
797 *fLog << inf2 << GetNumExecutions() << ": " << rmlo << "/" << rmhi << " trigger out of valid range. No trigger raised." << endl;
798 return kTRUE;
799 }
800
801 // Number of patches which have triggered out of the total number of
802 // Coincidence signals emitted. (If the total number is higher than
803 // the number of triggers either some triggers had to be removed or
804 // a patch has emitted more than one trigger signal)
805 // FIXME: inf2?
806 *fLog << inf << GetNumExecutions() << ": ";
807 *fLog << setw(3) << triggers.GetNumSignals() << " triggers left out of ";
808 *fLog << setw(3) << cnt << " (" << rmlo << "/" << rmhi << " trigger out of valid range), T=" << fTrigger->GetVal()-fCamera->GetValidRangeMin()/freq << "ns";
809 *fLog << endl;
810
811 //# Trigger characteristics: gate length (ns), min. overlapping time (ns),
812 //# amplitude and FWHM of (gaussian) single phe response for trigger:
813 //trigger_prop 3.0 0.25 1.0 2.0
814
815 return kTRUE;
816}
817
818Int_t MSimTrigger::PostProcess()
819{
820// patch_file.close();
821// clipped_file.close();
822// digital_file.close();
823// ratescan_file.close();
824 return kTRUE;
825}
826
827
828// --------------------------------------------------------------------------
829//
830// FileNameRouteac: routeac.txt
831// FileNameCoincidenceMap: coincidence.txt
832// DiscriminatorTheshold: 3.5
833// DigitalSignalLength: 8
834// CoincidenceTime: 0.5
835// SimulateElectronics: Yes
836//
837Int_t MSimTrigger::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
838{
839 Bool_t rc = kFALSE;
840 if (IsEnvDefined(env, prefix, "FileNameRouteAC", print))
841 {
842 rc = kTRUE;
843 fNameRouteAC = GetEnvValue(env, prefix, "FileNameRouteAC", fNameRouteAC);
844 }
845
846 if (IsEnvDefined(env, prefix, "FileNameCoincidenceMap", print))
847 {
848 rc = kTRUE;
849 fNameCoincidenceMap = GetEnvValue(env, prefix, "FileNameCoincidenceMap", fNameCoincidenceMap);
850 }
851
852 if (IsEnvDefined(env, prefix, "DiscriminatorThreshold", print))
853 {
854 rc = kTRUE;
855 fDiscriminatorThreshold = GetEnvValue(env, prefix, "DiscriminatorThreshold", fDiscriminatorThreshold);
856 }
857
858 if (IsEnvDefined(env, prefix, "DigitalSignalLength", print))
859 {
860 rc = kTRUE;
861 fDigitalSignalLength = GetEnvValue(env, prefix, "DigitalSignalLength", fDigitalSignalLength);
862 }
863
864 if (IsEnvDefined(env, prefix, "CoincidenceTime", print))
865 {
866 rc = kTRUE;
867 fCoincidenceTime = GetEnvValue(env, prefix, "CoincidenceTime", fCoincidenceTime);
868 }
869
870 if (IsEnvDefined(env, prefix, "SimulateElectronics", print))
871 {
872 rc = kTRUE;
873 fSimulateElectronics = GetEnvValue(env, prefix, "SimulateElectronics", fSimulateElectronics);
874 }
875
876 if (IsEnvDefined(env, prefix, "MinMultiplicity", print))
877 {
878 rc = kTRUE;
879 fMinMultiplicity = GetEnvValue(env, prefix, "MinMultiplicity", fMinMultiplicity);
880 }
881
882 if (IsEnvDefined(env, prefix, "CableDelay", print))
883 {
884 rc = kTRUE;
885 fCableDelay = GetEnvValue(env, prefix, "CableDelay", fCableDelay);
886 }
887
888 if (IsEnvDefined(env, prefix, "CableDamping", print))
889 {
890 rc = kTRUE;
891 fCableDamping = GetEnvValue(env, prefix, "CableDamping", fCableDamping);
892 }
893
894 if (IsEnvDefined(env, prefix, "DebugTrigger", print))
895 {
896 rc = kTRUE;
897 fDebugTrigger = GetEnvValue(env, prefix, "DebugTrigger", fDebugTrigger);
898 }
899
900 if (IsEnvDefined(env, prefix, "ShiftBaseline", print))
901 {
902 rc = kTRUE;
903 fShiftBaseline = GetEnvValue(env, prefix, "ShiftBaseline", fShiftBaseline);
904 }
905
906 return rc;
907}
Note: See TracBrowser for help on using the repository browser.