source: trunk/Mars/msimcamera/MSimReadout.cc@ 19666

Last change on this file since 19666 was 19666, checked in by tbretz, 5 years ago
Adapted unit conversion to intended trigger position in nanoseconds, and trigge rposition in nanoseconds.
File size: 11.7 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// MSimReadout
28//
29// Task to convert the analog channels into a digital signal. This should
30// simulate the conversion and saturation bahaviour of the FADC/readout
31// system.
32//
33// You can give a conversion factor from the unitx of your analog signal
34// to the units of your adc. This is a fixed factor because it is just
35// a matter of what the meaning of an adc count is, nothing which could
36// jitter or is a real part of the electronics. Such effects should
37// be simulated somewhere else.
38//
39//
40// Input Containers:
41// MGeomCam
42// MAnalogChannels
43// TriggerPos [MParameterD]
44// IntendedPulsePos [MParameterD]
45// MRawRunHeader
46//
47// Output Containers:
48// MRawEvtData
49// MRawEvtHeader
50//
51//////////////////////////////////////////////////////////////////////////////
52#include "MSimReadout.h"
53
54#include "MLog.h"
55#include "MLogManip.h"
56
57#include "MArrayI.h"
58
59#include "MParList.h"
60#include "MParameters.h"
61
62#include "MGeomCam.h"
63
64#include "MRawRunHeader.h"
65#include "MRawEvtHeader.h"
66#include "MRawEvtData.h"
67
68#include "MAnalogSignal.h"
69#include "MAnalogChannels.h"
70
71ClassImp(MSimReadout);
72
73using namespace std;
74
75
76// ------------------------------------------------------------------------
77//
78// Default constructor
79//
80MSimReadout::MSimReadout(const char* name, const char *title)
81 : fRunHeader(0), fEvtHeader(0), fCamera(0), fPulsePos(0), fTrigger(0), fData(0),
82 fConversionFactor(1)
83{
84 fName = name ? name : "MSimReadout";
85 fTitle = title ? title : "Task to simulate the analog readout (FADCs)";
86}
87
88// ------------------------------------------------------------------------
89//
90// Look for the needed parameter containers.
91// Initialize MRawEvtData from MRawEvtRunHeader.
92//
93Int_t MSimReadout::PreProcess(MParList *pList)
94{
95 fCamera = (MAnalogChannels*)pList->FindObject("MAnalogChannels");
96 if (!fCamera)
97 {
98 *fLog << err << "MAnalogChannels not found... aborting." << endl;
99 return kFALSE;
100 }
101
102 fTrigger = (MParameterD*)pList->FindObject("TriggerPos", "MParameterD");
103 if (!fTrigger)
104 {
105 *fLog << err << "TriggerPos [MParameterD] not found... aborting." << endl;
106 return kFALSE;
107 }
108
109 fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
110 if (!fPulsePos)
111 {
112 *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
113 return kFALSE;
114 }
115
116 fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
117 if (!fRunHeader)
118 {
119 *fLog << err << "MRawRunHeader not found... aborting." << endl;
120 return kFALSE;
121 }
122
123 fEvtHeader = (MRawEvtHeader*)pList->FindCreateObj("MRawEvtHeader");
124 if (!fEvtHeader)
125 return kFALSE;
126
127 fData = (MRawEvtData*)pList->FindCreateObj("MRawEvtData");
128 if (!fData)
129 return kFALSE;
130
131 return kTRUE;
132}
133
134Bool_t MSimReadout::ReInit(MParList *plist)
135{
136 MGeomCam *cam = (MGeomCam*)plist->FindObject("MGeomCam");
137 if (!cam)
138 {
139 *fLog << err << "MGeomCam not found... aborting." << endl;
140 return kFALSE;
141 }
142
143 fRunHeader->InitPixels(cam->GetNumPixels());
144
145 fData->InitRead(fRunHeader);
146 fData->ResetPixels();
147 fData->InitStartCells();
148 fData->SetIndices();
149
150 return kTRUE;
151}
152
153// ------------------------------------------------------------------------
154//
155// Convert (digitize) the analog channels into digital (FADC) data.
156//
157Int_t MSimReadout::Process()
158{
159 // Sanity checks
160 if (fData->GetNumLoGainSamples()>0)
161 {
162 *fLog << err << "ERROR - MSimReadout: Lo-gains not implemented yet." << endl;
163 return kERROR;
164 }
165
166 // Make sure that we have not more analog channels than pixels
167 // FIXME: Is this really necessary?
168 if (fCamera->GetNumChannels()>fData->GetNumPixels())
169 {
170 *fLog << err;
171 *fLog << "ERROR - Number of analog channels " << fCamera->GetNumChannels();
172 *fLog << " exceeds number of pixels " << fData->GetNumPixels() << endl;
173 return kERROR;
174 }
175
176 if (fTrigger->GetVal()<0)
177 {
178 *fLog << err << "ERROR - MSimReadout: MSimReadout executed for an event which has no trigger." << endl;
179 return kERROR;
180 }
181
182 // Get the intended pulse position and convert it to slices
183 const Float_t pulpos = fPulsePos->GetVal();
184
185 // Get trigger position and correct for intended pulse position (convert from ns to samples)
186 const Int_t trig = TMath::CeilNint((fTrigger->GetVal()-pulpos)*fRunHeader->GetFreqSampling()/1000.);
187
188 // Check if the position is valid
189 if (trig<0)
190 {
191 *fLog << err;
192 *fLog << "ERROR - Trigger position before analog signal." << endl;
193 *fLog << " Trigger: " << fTrigger->GetVal() << endl;
194 *fLog << " PulsePos: " << pulpos << endl;
195 return kERROR;
196 }
197
198 // Get Number of samples in analog channels
199 const Int_t nsamp = fCamera->GetNumSamples();
200
201 // Get number of samples to be digitized
202 const Int_t nslices = fData->GetNumSamples();
203
204 // Check if the whole requested signal can be digitized
205 if (trig+nslices>nsamp)
206 {
207 *fLog << err << "ERROR - Trigger position beyond valid analog signal range." << endl;
208 *fLog << " Trigger: " << fTrigger->GetVal() << endl;
209 *fLog << " PulsePos: " << pulpos << endl;
210 *fLog << " SamplesIn: " << nsamp << endl;
211 *fLog << " SamplesOut: " << nslices << endl;
212 return kERROR;
213 }
214
215 const Float_t offset = 0;//128;
216 // FTemme: Don't need this anymore:
217// const UInt_t max = fData->GetMax();
218// const UInt_t min = fData->GetMin();
219
220
221 // FIXME: Take this into account
222// const UInt_t scale = 16;
223// const UInt_t resolution = 12;
224
225 // Digitize into a buffer
226 MArrayI buffer(nslices*fData->GetNumPixels());
227
228 // Loop over all channels/pixels
229 for (UInt_t i=0; i<fCamera->GetNumChannels(); i++)
230 {
231 // Get i-th canalog hannel
232 const MAnalogSignal &sig = (*fCamera)[i];
233
234 // Digitize all slices
235 for (Int_t j=0; j<nslices; j++)
236 {
237
238 Float_t slice = 0;
239 if (j+trig >= (Int_t)sig.GetSize())
240 {
241 // DN: This, IMHO can never happen, since the check in line 205
242 // already took care for this.
243 // DN: But I don't understand why Thomas did this?
244 // We need to add noise at least ?!
245 slice = offset;
246 }
247 else
248 {
249 // normal case
250
251 // Why do we add 'offset' when it is a hardcoded zero?
252 // And why do we multiply, while this value *may* be changed
253 // by a user, but it should not? Why do we care?
254 // Because we can?
255 slice = sig[j+trig] * fConversionFactor + offset;
256 }
257
258
259 // Saturation in FACT is done as follows:
260 // If the digitized signal is larger than an upper limit 'max'
261 // the ADC does set a special bit! The overflow bit ...
262 // So while we say we have a 12bit ADC ... in fact we sometimes
263 // also use a 13th bit ...
264 // but this does not increase our resolution by a factor of 2!
265
266 // There are different binary formats for signed integers,
267 // however the 'Two's complement' format
268 // http://en.wikipedia.org/wiki/Two%27s_complement
269 // is increadibly common, and this is also what is used by FACTs ADCs.
270
271 // A normal 12bit (two's complement formatted) signed integer
272 // goes from -2048 to +2047 and is coded like this:
273 // from -2048 = 0x800 = 1000.0000.0000
274 // to +2047 = 0x7FF = 0111.1111.1111
275 //
276 // But on a normal PC we store these 12 bit numbers in a space, that
277 // was designed for 16bit numbers. This is no problem for the positive numbers
278 // 12bit: 0x7FF = 0111.1111.1111 --> 16bit: 0x07FF = 0000.0111.1111.1111
279 // This bit combination is always understood as +2047 .. no problem!
280 // But the negative numbers:
281 // 12bit: 0x800 = 1000.0000.0000 --> 16bit: 0x0800 = 0000.1000.0000.0000
282 // This *would* normally be understood as +2048, because we need to
283 // 'enlarge' the 'sign bit'
284 // so our largest negative number written into a 16bit storage space
285 // should look like this:
286 // 0xF800 = 1111.1000.0000.0000 --> -2048
287
288 // The enlargement of the sign bit is autotically done on the FACT FAD
289 // board already before the data is send to any PC, because we can do it
290 // damn fast on that board, and a PC would need to touch every incoming
291 // data word again....
292 // But now since we have enlarged the 12th bit ... the sign bit into
293 // the space of bits 13,14,15 and 16 ... where did the overflow-bit go?
294 //
295 // Well .. we still have plenty of bit-combinations, which are normally
296 // forbidden for a 12bit ADC, and these we can use to encode both,
297 // the positive and negative overflow.
298 // we decided to do this:
299 // positive overflow
300 // 0000.1000.0000.0000 --> interpreted by a PC as +2048 and thus out of 12 bit range!
301 // negative underflow
302 // 1111.0111.1111.1111 --> interpreted by a PC as -2049 and thus out of 12 bit range!
303
304 // we will simulate exactly the same behaviour here!
305
306 // max and min can be set, by the user currently ..
307 // but I don't see why this should be possible.
308 Int_t digitized_value = TMath::Nint(slice);
309 if (digitized_value > 2047) // positive overflow
310 buffer[nslices*i + j] = 0x0800; // <-- +2048
311 else if (digitized_value < -2048)
312 buffer[nslices*i + j] = 0xF7FF; // <-- -2049
313 else
314 buffer[nslices*i + j] = digitized_value;
315 }
316 }
317
318 // Set samples as raw-data
319 fData->Set(buffer);
320 fData->SetReadyToSave();
321
322 // Set the trigger/daq event number
323 fEvtHeader->SetDAQEvtNumber(GetNumExecutions());
324 fEvtHeader->SetReadyToSave();
325
326 // FIMXE: This will never be stored correctly :(
327 fRunHeader->SetNumEvents(fRunHeader->GetNumEvents()+1);
328
329 return kTRUE;
330}
331
332// --------------------------------------------------------------------------
333//
334// Read the parameters from the resource file.
335//
336// ConversionFactor: 1
337//
338Int_t MSimReadout::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
339{
340 Bool_t rc = kFALSE;
341 if (IsEnvDefined(env, prefix, "ConversionFactor", print))
342 {
343 rc = kTRUE;
344 fConversionFactor = GetEnvValue(env, prefix, "ConversionFactor", fConversionFactor);
345 }
346
347 return rc;
348}
Note: See TracBrowser for help on using the repository browser.