source: trunk/MagicSoft/Mars/msimcamera/MSimTrigger.cc@ 9318

Last change on this file since 9318 was 9318, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 15.3 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 coincidense must at least be of the length
45// defined by fCoincidenceTime. The earliest coincide is then stored as
46// trigger position.
47//
48//
49// For MAGIC1:
50// - fDigitalSignalLength between 6ns and 12ns
51// - fCoincidenceTime between 0.25ns to 1ns
52//
53//
54// Input Containers:
55// IntendedPulsePos [MParameterD]
56// MAnalogChannels
57// MRawRunHeader
58//
59// Output Containers:
60// TriggerPos [MParameterD]
61// MRawEvtHeader
62//
63//////////////////////////////////////////////////////////////////////////////
64#include "MSimTrigger.h"
65
66#include "MLog.h"
67#include "MLogManip.h"
68
69#include "MParList.h"
70#include "MParameters.h"
71
72#include "MLut.h"
73#include "MArrayI.h"
74
75#include "MRawEvtHeader.h"
76#include "MRawRunHeader.h"
77
78#include "MAnalogSignal.h"
79#include "MAnalogChannels.h"
80#include "MDigitalSignal.h"
81
82#include "MTriggerPattern.h"
83
84#include "MPedestalCam.h"
85#include "MPedestalPix.h"
86
87ClassImp(MSimTrigger);
88
89using namespace std;
90
91// --------------------------------------------------------------------------
92//
93// Default Constructor.
94//
95MSimTrigger::MSimTrigger(const char *name, const char *title)
96 : fCamera(0), fPulsePos(0), fTrigger(0), fRunHeader(0),
97 fEvtHeader(0), fElectronicNoise(0), fGain(0),
98 fDiscriminatorThreshold(-1), fDigitalSignalLength(8), fCoincidenceTime(0.5),
99 fShiftBaseline(kTRUE), fUngainSignal(kTRUE)
100{
101 fName = name ? name : "MSimTrigger";
102 fTitle = title ? title : "Task to simulate trigger electronics";
103}
104
105// --------------------------------------------------------------------------
106//
107// Take two TObjArrays with a collection of digital signals.
108// Every signal from one array is compared with any from the other array.
109// For all signals whihc overlaps and which have an overlap time >gate
110// a new digital signal is created storing start time and length of overlap.
111// They are collected in a newly allocated TObjArray. A pointer to this array
112// is returned.
113//
114// Th euser gains owenership of the object, ie.e., the user is responsible of
115// deleting the memory.
116//
117TObjArray *MSimTrigger::CalcCoincidence(const TObjArray &arr1, const TObjArray &arr2, Float_t gate) const
118{
119 TObjArray *res = new TObjArray;
120
121 if (arr1.GetEntriesFast()==0 || arr2.GetEntriesFast()==0)
122 return res;
123
124 TIter Next1(&arr1);
125 MDigitalSignal *ttl1 = 0;
126 while ((ttl1=static_cast<MDigitalSignal*>(Next1())))
127 {
128 TIter Next2(&arr2);
129 MDigitalSignal *ttl2 = 0;
130 while ((ttl2=static_cast<MDigitalSignal*>(Next2())))
131 {
132 MDigitalSignal *ttl = new MDigitalSignal(*ttl1, *ttl2);
133
134 if (ttl->GetLength()<=gate)
135 {
136 delete ttl;
137 continue;
138 }
139
140 res->Add(ttl);
141 }
142 }
143
144 res->SetOwner();
145
146 return res;
147}
148
149// --------------------------------------------------------------------------
150//
151// Check for the necessary parameter containers. Read the luts.
152//
153Int_t MSimTrigger::PreProcess(MParList *pList)
154{
155 fTrigger = (MParameterD*)pList->FindCreateObj("MParameterD", "TriggerPos");
156 if (!fTrigger)
157 return kFALSE;
158
159 fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
160 if (!fPulsePos)
161 {
162 *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
163 return kFALSE;
164 }
165
166 fCamera = (MAnalogChannels*)pList->FindObject("MAnalogChannels");
167 if (!fCamera)
168 {
169 *fLog << err << "MAnalogChannels not found... aborting." << endl;
170 return kFALSE;
171 }
172
173 fElectronicNoise = 0;
174 if (fShiftBaseline)
175 {
176 fElectronicNoise = (MPedestalCam*)pList->FindObject("ElectronicNoise", "MPedestalCam");
177 if (!fElectronicNoise)
178 {
179 *fLog << err << "ElectronicNoise [MPedestalCam] not found... aborting." << endl;
180 return kFALSE;
181 }
182 *fLog << inf << "Baseline will be shifted back to 0 for discriminator." << endl;
183 }
184
185 fGain = 0;
186 if (fUngainSignal)
187 {
188 fGain = (MPedestalCam*)pList->FindObject("Gain", "MPedestalCam");
189 if (!fGain)
190 {
191 *fLog << err << "Gain [MPedestalCam] not found... aborting." << endl;
192 return kFALSE;
193 }
194 *fLog << inf << "Discriminator will be multiplied by applied gain." << endl;
195 }
196
197 fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
198 if (!fRunHeader)
199 {
200 *fLog << err << "MRawRunHeader not found... aborting." << endl;
201 return kFALSE;
202 }
203
204 fEvtHeader = (MRawEvtHeader*)pList->FindCreateObj("MRawEvtHeader");
205 if (!fEvtHeader)
206 return kFALSE;
207
208 fRouteAC.Delete();
209 if (!fNameRouteAC.IsNull() && fRouteAC.ReadFile(fNameRouteAC)<0)
210 return kFALSE;
211
212 fCoincidenceMap.Delete();
213 if (!fNameCoincidenceMap.IsNull() && fCoincidenceMap.ReadFile(fNameCoincidenceMap)<0)
214 return kFALSE;
215
216 // ---------------- Consistency checks ----------------------
217
218 if (!fRouteAC.IsEmpty() && !fCoincidenceMap.IsEmpty() &&
219 fCoincidenceMap.GetMaxIndex()>fRouteAC.GetNumRows()-1)
220 {
221 *fLog << err;
222 *fLog << "ERROR - AC routing produces " << fRouteAC.GetNumRows() << " analog channels," << endl;
223 *fLog << " but the coincidence map expects at least " << fCoincidenceMap.GetMaxIndex()+1 << " channels." << endl;
224 return kERROR;
225 }
226
227 if (fDiscriminatorThreshold<=0)
228 {
229 *fLog << err << "ERROR - Discriminator threshold " << fDiscriminatorThreshold << " invalid." << endl;
230 return kFALSE;
231 }
232
233 if (fElectronicNoise && !fRouteAC.IsEmpty() && !fRouteAC.IsDefault())
234 {
235 // FIXME: Apply to analog channels when summing
236 *fLog << warn << "WARNING - A baseline shift doesn't make sense for sum-channels... reset." << endl;
237 fElectronicNoise = 0;
238 }
239
240 if (fGain && !fRouteAC.IsEmpty() && !fRouteAC.IsDefault())
241 {
242 // FIXME: Apply to analog channels when summing
243 *fLog << warn << "WARNING - Ungain doesn't make sense for sum-channels... reset." << endl;
244 fGain = 0;
245 }
246
247
248 // ---------------- Information output ----------------------
249
250 *fLog << inf;
251
252 if (fRouteAC.IsEmpty())
253 *fLog << "Re-routing/summing of analog channels before discriminator switched off." << endl;
254 else
255 *fLog << "Using " << fNameRouteAC << " for re-routing/summing of analog channels before discriminator." << endl;
256
257 if (fCoincidenceMap.IsEmpty())
258 *fLog << "No coincidences of digital channels will be checked. Signal-above-threshold trigger applied." << endl;
259 else
260 *fLog << "Using " << fNameCoincidenceMap << " to check for coincidences of the digital channels." << endl;
261
262 *fLog << "Using discriminator threshold of " << fDiscriminatorThreshold << endl;
263
264 return kTRUE;
265}
266
267// --------------------------------------------------------------------------
268//
269Int_t MSimTrigger::Process()
270{
271 // Invalidate trigger
272 fTrigger->SetVal(-1);
273
274 // ================== Simulate channel bundling ====================
275
276 // FIXME: Before we can bundle the channels we have to make a copy
277 // and simulate clipping
278
279 // Check if routing should be done
280 const Bool_t empty = fRouteAC.IsEmpty();
281
282 // If no channels are summed the number of patches stays the same
283 const UInt_t npatch = empty ? fCamera->GetNumChannels() : fRouteAC.GetEntriesFast();
284
285 // Use the given analog channels as default out. If channels are
286 // summed overwrite with a newly allocated set of analog channels
287 MAnalogChannels *patches = fCamera;
288 if (!empty)
289 {
290 // FIXME: Can we add gain and offset here into a new container?
291
292 patches = new MAnalogChannels(npatch, fCamera->GetNumSamples());
293 for (UInt_t i=0; i<npatch; i++)
294 {
295 const MArrayI &row = fRouteAC.GetRow(i);
296 for (UInt_t j=0; j<row.GetSize(); j++)
297 {
298 const UInt_t idx = row[j];
299 (*patches)[i].AddSignal((*fCamera)[idx]);
300 }
301 }
302 }
303
304 // FIXME: Write patches
305
306 // ================== Simulate discriminators ====================
307
308 TObjArray ttls(npatch);
309 ttls.SetOwner();
310
311 for (UInt_t i=0; i<npatch; i++)
312 {
313 // FIXME: What if the gain was also allpied to the baseline?
314 const Double_t offset = fElectronicNoise ? (*fElectronicNoise)[i].GetPedestal() : 0;
315 const Double_t gain = fGain ? (*fGain)[i].GetPedestal() : 1;
316 ttls.AddAt((*patches)[i].Discriminate(fDiscriminatorThreshold*gain+offset, fDigitalSignalLength), i);
317 }
318
319 // FIXME: Write TTLs!
320
321 // If analog channels had been newly allocated free memmory
322 if (patches!=fCamera)
323 delete patches;
324
325 // =================== Simulate coincidences ======================
326
327 // If the map is empty we create a one-pixel-coincidence map
328 // FIMXE: This could maybe be accelerated if the Clone can be
329 // omitted in the loop
330 if (fCoincidenceMap.IsEmpty())
331 fCoincidenceMap.SetDefault(npatch);
332
333 // Calculate the minimum and maximum time for a valid trigger
334 const Double_t freq = fRunHeader->GetFreqSampling()/1000.;
335 const Float_t nsamp = fRunHeader->GetNumSamplesHiGain();
336 const Float_t pulspos = fPulsePos->GetVal()/freq;
337
338 // Valid range in units of bins
339 const Float_t min = fCamera->GetValidRangeMin()+pulspos;
340 const Float_t max = fCamera->GetValidRangeMax()-(nsamp-pulspos);
341
342 // Create an array for the individual triggers
343 TObjArray triggers;
344 triggers.SetOwner();
345
346 Int_t cnt = 0;
347 Int_t rmlo = 0;
348 Int_t rmhi = 0;
349
350 for (int j=0; j<fCoincidenceMap.GetEntries(); j++)
351 {
352 const MArrayI &idx = fCoincidenceMap.GetRow(j);
353
354 // Start with a copy of the first coincidence channel
355 TObjArray *arr = static_cast<TObjArray*>(ttls[idx[0]]->Clone());
356 arr->SetOwner();
357
358 // compare to all other channels in this coincidence patch, one by one
359 for (UInt_t k=1; k<idx.GetSize() && arr->GetEntriesFast()>0; k++)
360 {
361 TObjArray *res = CalcCoincidence(*arr, *static_cast<TObjArray*>(ttls[idx[k]]),
362 fCoincidenceTime);
363
364 // Delete the original array and keep the new one
365 delete arr;
366 arr = res;
367 }
368
369 // Remove all signals which are not in the valid digitization range
370 // (This is not the digitization window, but the region in which
371 // the analog channels contain usefull data)
372 TIter Next(arr);
373 MDigitalSignal *ttl = 0;
374 while ((ttl=static_cast<MDigitalSignal*>(Next())))
375 {
376 if (ttl->GetStart()<min)
377 {
378 delete arr->Remove(ttl);
379 rmlo++;
380 }
381 if (ttl->GetStart()>max)
382 {
383 delete arr->Remove(ttl);
384 rmhi++;
385 }
386 }
387
388 // Remove the empty slots
389 arr->Compress();
390
391 cnt += arr->GetEntriesFast();
392
393 // If we have at least one trigger keep the earliest one.
394 // FIXME: The triggers should be ordered in time automatically: To be checked!
395 // FIXME: Simulate trigger dead-time!
396 if (arr->GetEntriesFast()>0)
397 triggers.Add(arr->RemoveAt(0));
398
399 // delete the allocated space
400 delete arr;
401 }
402
403 // No trigger issued. Go on.
404 if (triggers.GetEntriesFast()==0)
405 {
406 if (rmlo>0 || rmhi>0)
407 *fLog << inf2 << rmlo << "/" << rmhi << " trigger out of valid range. No trigger raised." << endl;
408 return kTRUE;
409 }
410
411 // There are usually not enough entries that it is worth to search
412 // for the earliest instead of just sorting and taking the first one
413 // FIXME: This could be improved if checking for IsSortable
414 // is omitted
415 triggers.Sort();
416
417 // FIXME: Jitter! (Own class?)
418 fTrigger->SetVal(static_cast<MDigitalSignal*>(triggers[0])->GetStart());
419 fTrigger->SetReadyToSave();
420
421 // Flag this event as triggered by the lvl1 trigger (FIXME?)
422 fEvtHeader->SetTriggerPattern((UInt_t)~(MTriggerPattern::kTriggerLvl1 | (MTriggerPattern::kTriggerLvl1<<8)));
423 fEvtHeader->SetReadyToSave();
424
425 // inf2?
426 *fLog << inf;
427 *fLog << cnt << " triggers left in " << triggers.GetEntriesFast() << " patches (" << rmlo << "/" << rmhi << " trigger out of valid range), T=" << fTrigger->GetVal();
428 *fLog << endl;
429
430 return kTRUE;
431}
432
433// --------------------------------------------------------------------------
434//
435// FileNameRouteac: routeac.txt
436// FileNameCoincidenceMap: coincidence.txt
437// DiscriminatorTheshold: 3.5
438// DigitalSignalLength: 8
439// CoincidenceTime: 0.5
440//
441Int_t MSimTrigger::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
442{
443 Bool_t rc = kFALSE;
444 if (IsEnvDefined(env, prefix, "FileNameRouteAC", print))
445 {
446 rc = kTRUE;
447 fNameRouteAC = GetEnvValue(env, prefix, "FileNameRouteAC", fNameRouteAC);
448 }
449
450 if (IsEnvDefined(env, prefix, "FileNameCoincidenceMap", print))
451 {
452 rc = kTRUE;
453 fNameCoincidenceMap = GetEnvValue(env, prefix, "FileNameCoincidenceMap", fNameCoincidenceMap);
454 }
455
456 if (IsEnvDefined(env, prefix, "DiscriminatorThreshold", print))
457 {
458 rc = kTRUE;
459 fDiscriminatorThreshold = GetEnvValue(env, prefix, "DiscriminatorThreshold", fDiscriminatorThreshold);
460 }
461
462 if (IsEnvDefined(env, prefix, "DigitalSignalLength", print))
463 {
464 rc = kTRUE;
465 fDigitalSignalLength = GetEnvValue(env, prefix, "DigitalSignalLength", fDigitalSignalLength);
466 }
467
468 if (IsEnvDefined(env, prefix, "CoincidenceTime", print))
469 {
470 rc = kTRUE;
471 fCoincidenceTime = GetEnvValue(env, prefix, "CoincidenceTime", fCoincidenceTime);
472 }
473
474 return rc;
475}
Note: See TracBrowser for help on using the repository browser.