source: branches/Mars_use_drstimefiles/mcore/DrsCalib.h@ 19993

Last change on this file since 19993 was 17995, checked in by dneise, 10 years ago
new method DrsCalibrateTime::WriteToFits(char*) --> writes the calibration constants into a fits file new constructor DrsCalibrateTime::DrsCalibrateTime(char) --> read the constants from the fits file back into the class.
File size: 50.7 KB
Line 
1#ifndef MARS_DrsCalib
2#define MARS_DrsCalib
3
4#include <math.h> // fabs
5#include <errno.h> // errno
6
7#ifndef MARS_fits
8#include "fits.h"
9#endif
10
11#ifndef MARS_ofits
12#include "ofits.h"
13#endif
14
15class DrsCalibrate
16{
17protected:
18 int64_t fNumEntries;
19
20 size_t fNumSamples;
21 size_t fNumChannels;
22
23 std::vector<int64_t> fSum;
24 std::vector<int64_t> fSum2;
25
26public:
27 DrsCalibrate() : fNumEntries(0), fNumSamples(0), fNumChannels(0)
28 {
29 fSum.reserve(1024*1440);
30 fSum2.reserve(1024*1440);
31 }
32
33 void Reset()
34 {
35 fNumEntries = 0;
36 fNumSamples = 0;
37 fNumChannels = 0;
38
39 fSum.clear();
40 fSum2.clear();
41 }
42
43 void InitSize(uint16_t channels, uint16_t samples)
44 {
45 fNumChannels = channels;
46 fNumSamples = samples;
47
48 fSum.assign(samples*channels, 0);
49 fSum2.assign(samples*channels, 0);
50 }
51
52 void AddRel(const int16_t *val, const int16_t *start)
53 {
54 /*
55 for (size_t ch=0; ch<fNumChannels; ch++)
56 {
57 const int16_t &spos = start[ch];
58 if (spos<0)
59 continue;
60
61 const size_t pos = ch*1024;
62 for (size_t i=0; i<1024; i++)
63 {
64 // Value is relative to trigger
65 // Abs is corresponding index relative to DRS pipeline
66 const size_t rel = pos + i;
67 const size_t abs = pos + (spos+i)%1024;
68
69 const int64_t v = val[rel];
70
71 fSum[abs] += v;
72 fSum2[abs] += v*v;
73 }
74 }*/
75
76 // This version is 2.5 times faster because the compilers optimization
77 // is not biased by the evaluation of %1024
78 for (size_t ch=0; ch<fNumChannels; ch++)
79 {
80 const int16_t &spos = start[ch];
81 if (spos<0)
82 continue;
83
84 const size_t pos = ch*1024;
85
86 const int16_t *beg_val = val + pos;
87 int64_t *beg_sum = fSum.data() + pos;
88 int64_t *beg_sum2 = fSum2.data() + pos;
89
90 const int16_t *pval = beg_val; // val[rel]
91 int64_t *psum = beg_sum + spos; // fSum[abs]
92 int64_t *psum2 = beg_sum2 + spos; // fSum2[abs]
93
94 while (psum<beg_sum+1024)
95 {
96 const int64_t v = *pval++;
97
98 *psum++ += v;
99 *psum2++ += v*v;
100 }
101
102 psum = beg_sum;
103 psum2 = beg_sum2;
104
105 while (pval<beg_val+1024)
106 {
107 const int64_t v = *pval++;
108
109 *psum++ += v;
110 *psum2++ += v*v;
111 }
112 }
113
114 fNumEntries++;
115 }
116
117 void AddRel(const int16_t *val, const int16_t *start,
118 const int32_t *offset, const int64_t scale)
119 {
120 /*
121 for (size_t ch=0; ch<fNumChannels; ch++)
122 {
123 const int16_t spos = start[ch];
124 if (spos<0)
125 continue;
126
127 const size_t pos = ch*1024;
128
129 for (size_t i=0; i<fNumSamples; i++)
130 {
131 // Value is relative to trigger
132 // Offset is relative to DRS pipeline
133 // Abs is corresponding index relative to DRS pipeline
134 const size_t rel = pos + i;
135 const size_t abs = pos + (spos+i)%1024;
136
137 const int64_t v = int64_t(val[rel])*scale-offset[abs];
138
139 fSum[abs] += v;
140 fSum2[abs] += v*v;
141 }
142 }*/
143
144 // This version is 2.5 times faster because the compilers optimization
145 // is not biased by the evaluation of %1024
146 for (size_t ch=0; ch<fNumChannels; ch++)
147 {
148 const int16_t &spos = start[ch];
149 if (spos<0)
150 continue;
151
152 const size_t pos = ch*1024;
153
154 const int16_t *beg_val = val + pos;
155 const int32_t *beg_offset = offset + pos;
156 int64_t *beg_sum = fSum.data() + pos;
157 int64_t *beg_sum2 = fSum2.data() + pos;
158
159
160 const int16_t *pval = beg_val; // val[rel]
161 const int32_t *poffset = beg_offset + spos; // offset[abs]
162 int64_t *psum = beg_sum + spos; // fSum[abs]
163 int64_t *psum2 = beg_sum2 + spos; // fSum2[abs]
164
165 while (psum<beg_sum+1024)
166 {
167 const int64_t v = int64_t(*pval++)*scale - *poffset++;
168
169 *psum++ += v;
170 *psum2++ += v*v;
171 }
172
173 psum = beg_sum;
174 psum2 = beg_sum2;
175 poffset = beg_offset;
176
177 while (pval<beg_val+1024)
178 {
179 const int64_t v = int64_t(*pval++)*scale - *poffset++;
180
181 *psum++ += v;
182 *psum2++ += v*v;
183 }
184 }
185
186 fNumEntries++;
187 }
188 /*
189 void AddAbs(const int16_t *val, const int16_t *start,
190 const int32_t *offset, const uint32_t scale)
191 {
192 for (size_t ch=0; ch<fNumChannels; ch++)
193 {
194 const int16_t spos = start[ch];
195 if (spos<0)
196 continue;
197
198 const size_t pos = ch*fNumSamples;
199
200 for (size_t i=0; i<fNumSamples; i++)
201 {
202 // Value is relative to trigger
203 // Offset is relative to DRS pipeline
204 // Abs is corresponding index relative to DRS pipeline
205 const size_t rel = pos + i;
206 const size_t abs = pos + (spos+i)%1024;
207
208 const int64_t v = int64_t(val[rel])*scale-offset[abs];
209
210 fSum[rel] += v;
211 fSum2[rel] += v*v;
212 }
213 }
214
215 fNumEntries++;
216 }*/
217
218 void AddAbs(const int16_t *val, const int16_t *start,
219 const int32_t *offset, const int64_t scale)
220 {
221 /*
222 // 1440 without tm, 1600 with tm
223 for (size_t ch=0; ch<fNumChannels; ch++)
224 {
225 const int16_t spos = start[ch];
226 if (spos<0)
227 continue;
228
229 const size_t pos = ch*fNumSamples;
230 const size_t drs = ch>1439 ? ((ch-1440)*9+8)*1024 : ch*1024;
231
232 for (size_t i=0; i<fNumSamples; i++)
233 {
234 // Value is relative to trigger
235 // Offset is relative to DRS pipeline
236 // Abs is corresponding index relative to DRS pipeline
237 const size_t rel = pos + i;
238 const size_t abs = drs + (spos+i)%1024;
239
240 const int64_t v = int64_t(val[rel])*scale-offset[abs];
241
242 fSum[rel] += v;
243 fSum2[rel] += v*v;
244 }
245 }*/
246
247 // This version is 1.5 times faster because the compilers optimization
248 // is not biased by the evaluation of %1024
249 for (size_t ch=0; ch<fNumChannels; ch++)
250 {
251 const int16_t &spos = start[ch];
252 if (spos<0)
253 continue;
254
255 const size_t pos = ch*fNumSamples;
256
257 const int32_t *beg_offset = offset + ch*1024;
258 const int16_t *beg_val = val + pos;
259 int64_t *beg_sum = fSum.data() + pos;
260 int64_t *beg_sum2 = fSum2.data() + pos;
261
262
263 const int16_t *pval = beg_val; // val[rel]
264 const int32_t *poffset = beg_offset + spos; // offset[abs]
265 int64_t *psum = beg_sum; // fSum[rel]
266 int64_t *psum2 = beg_sum2; // fSum2[rel]
267
268 if (spos+fNumSamples>1024)
269 {
270 while (poffset<beg_offset+1024)
271 {
272 const int64_t v = int64_t(*pval++)*scale - *poffset++;
273
274 *psum++ += v;
275 *psum2++ += v*v;
276 }
277
278 poffset = beg_offset;
279 }
280
281 while (psum<beg_sum+fNumSamples)
282 {
283 const int64_t v = int64_t(*pval++)*scale - *poffset++;
284
285 *psum++ += v;
286 *psum2++ += v*v;
287 }
288 }
289
290 fNumEntries++;
291 }
292
293
294 static void ApplyCh(float *vec, const int16_t *val, int16_t start, uint32_t roi,
295 const int32_t *offset, const int64_t scaleabs,
296 const int64_t *gain, const int64_t scalegain)
297 {
298 if (start<0)
299 {
300 memset(vec, 0, roi);
301 return;
302 }
303 /*
304 for (size_t i=0; i<roi; i++)
305 {
306 // Value is relative to trigger
307 // Offset is relative to DRS pipeline
308 // Abs is corresponding index relative to DRS pipeline
309 const size_t abs = (start+i)%1024;
310
311 const int64_t v =
312 + int64_t(val[i])*scaleabs-offset[abs]
313 ;
314
315 const int64_t div = gain[abs];
316 vec[i] = div==0 ? 0 : double(v)*scalegain/div;
317 }
318 */
319
320 // This version is faster because the compilers optimization
321 // is not biased by the evaluation of %1024
322 // (Here we are dominated by numerics... improvement ~10%)
323 const int32_t *poffset = offset + start; // offset[abs]
324 const int64_t *pgain = gain + start; // gain[abs]
325 const int16_t *pval = val; // val[rel]
326 float *pvec = vec; // vec[rel]
327
328 if (start+roi>1024)
329 {
330 while (poffset<offset+1024)
331 {
332 const int64_t v =
333 + int64_t(*pval++)*scaleabs - *poffset++
334 ;
335
336 *pvec++ = *pgain==0 ? 0 : double(v)*scalegain / *pgain;
337
338 pgain++;
339 }
340
341 poffset = offset;
342 pgain = gain;
343 }
344
345 while (pvec<vec+roi)
346 {
347 const int64_t v =
348 + int64_t(*pval++)*scaleabs - *poffset++
349 ;
350
351 *pvec++ = *pgain==0 ? 0 : double(v)*scalegain / *pgain;
352
353 pgain++;
354 }
355 }
356
357 static void ApplyCh(float *vec, const int16_t *val, int16_t start, uint32_t roi,
358 const int32_t *offset, const int64_t scaleabs,
359 const int64_t *gain, const int64_t scalegain,
360 const int64_t *trgoff, const int64_t scalerel)
361 {
362 if (start<0)
363 {
364 memset(vec, 0, roi);
365 return;
366 }
367 /*
368 for (size_t i=0; i<roi; i++)
369 {
370 // Value is relative to trigger
371 // Offset is relative to DRS pipeline
372 // Abs is corresponding index relative to DRS pipeline
373 const size_t abs = (start+i)%1024;
374
375 const int64_t v =
376 + (int64_t(val[i])*scaleabs-offset[abs])*scalerel
377 - trgoff[i]
378 ;
379
380 const int64_t div = gain[abs]*scalerel;
381 vec[i] = div==0 ? 0 : double(v)*scalegain/div;
382 }
383 */
384 // (Here we are dominated by numerics... improvement ~10%)
385 const int32_t *poffset = offset + start; // offset[abs]
386 const int64_t *pgain = gain + start; // gain[abs]
387 const int16_t *pval = val; // val[rel]
388 const int64_t *ptrgoff = trgoff; // trgoff[rel]
389 float *pvec = vec; // vec[rel]
390
391 if (start+roi>1024)
392 {
393 while (poffset<offset+1024)
394 {
395 const int64_t v =
396 + (int64_t(*pval++)*scaleabs - *poffset++)*scalerel
397 - *ptrgoff++;
398 ;
399
400 const int64_t div = *pgain * scalerel;
401 *pvec++ = div==0 ? 0 : double(v)*scalegain / div;
402
403 pgain++;
404 }
405
406 poffset = offset;
407 pgain = gain;
408 }
409
410 while (pvec<vec+roi)
411 {
412 const int64_t v =
413 + (int64_t(*pval++)*scaleabs - *poffset++)*scalerel
414 - *ptrgoff++;
415 ;
416
417 const int64_t div = *pgain * scalerel;
418 *pvec++ = div==0 ? 0 : double(v)*scalegain / div;
419
420 pgain++;
421 }
422 }
423
424 static double FindStep(const size_t ch0, const float *vec, int16_t roi, const int16_t pos, const uint16_t *map=NULL)
425 {
426 // We have about 1% of all cases which are not ahndled here,
427 // because the baseline jumps up just before the readout window
428 // and down just after it. In this cases we could determine the jump
429 // from the board time difference or throw the event away.
430 if (pos==0 || pos>=roi)
431 return 0;
432
433 double step = 0; // before
434 double rms = 0; // before
435 int cnt = 0;
436
437 // Exclude TM channel
438 for (int p=0; p<8; p++)
439 {
440 const size_t hw = ch0+p;
441 const size_t sw = (map?map[hw]:hw)*roi + pos;
442
443 const double diff = vec[sw]-vec[sw-1];
444
445 step += diff;
446 rms += (vec[sw]-vec[sw-1])*(vec[sw]-vec[sw-1]);
447
448 cnt++;
449 }
450
451 return cnt==0 ? 0 : step/cnt;
452 }
453
454 static void SubtractStep(const size_t ch0, const double avg, float *vec, int16_t roi, int32_t pos, const uint16_t *map=NULL)
455 {
456 if (pos==0 || pos>=roi)
457 return;
458
459 const int begin = avg>0 ? pos : 0;
460 const int end = avg>0 ? roi : pos;
461
462 const double sub = fabs(avg);
463
464 for (int p=0; p<9; p++)
465 {
466 for (int j=begin; j<end; j++)
467 {
468 const size_t hw = ch0+p;
469 const size_t sw = (map?map[hw]:hw)*roi + j;
470
471 vec[sw] -= sub;
472 }
473 }
474 }
475
476 struct Step
477 {
478 Step() : avg(0), rms(0), pos(0), cnt(0) { }
479 double avg;
480 double rms;
481 double pos;
482 uint16_t cnt;
483
484 static bool sort(const Step &s, const Step &r) { return s.avg<r.avg; }
485 };
486
487 static Step AverageSteps(const std::vector<Step>::iterator beg, const std::vector<Step>::iterator end)
488 {
489 Step rc;
490 for (auto it=beg; it!=end; it++)
491 {
492 rc.pos += it->pos;
493 rc.avg += it->avg;
494 rc.rms += it->avg*it->avg;
495 }
496
497 rc.cnt = end-beg;
498
499 rc.pos /= rc.cnt;
500 rc.avg /= rc.cnt;
501 rc.rms /= rc.cnt;
502 rc.rms -= rc.avg*rc.avg;
503 rc.rms = rc.rms<0 ? 0 : sqrt(rc.rms);
504
505 return rc;
506 }
507
508
509 static Step CorrectStep(float *vec, uint16_t nch, uint16_t roi,
510 const int16_t *prev, const int16_t *start,
511 const int16_t offset, const uint16_t *map=NULL)
512 {
513
514 std::vector<Step> list;
515 list.reserve(nch);
516
517 // Fill steps into array
518 // Exclude broken pixels?
519 // Remove maximum and minimum patches (4max and 4min)?
520 for (size_t ch=0; ch<nch; ch += 9)
521 {
522 if (prev[ch]<0 || start[ch]<0)
523 continue;
524
525 const int16_t dist = (prev[ch]-start[ch]+1024+offset)%1024;
526 const double step = FindStep(ch, vec, roi, dist, map);
527 if (step==0)
528 continue;
529
530 Step rc;
531 rc.pos = dist;
532 rc.avg = step;
533 list.push_back(rc);
534 }
535
536 if (list.empty())
537 return Step();
538
539 Step rc = AverageSteps(list.begin(), list.begin()+list.size());;
540
541 if (rc.avg==0)
542 return Step();
543
544 // std::cout << " A0=" << rc.avg << " rms=" << rc.rms << std::endl;
545 if (rc.rms>5)
546 {
547 sort(list.begin(), list.end(), Step::sort);
548
549 //for (auto it=list.begin(); it!=list.end(); it++)
550 // std::cout << " " << it->avg << std::endl;
551
552 const size_t skip = list.size()/10;
553 rc = AverageSteps(list.begin()+skip, list.begin()+list.size()-skip);
554
555 // std::cout << " A1=" << rc.avg << " rms=" << rc.rms << std::endl;
556 }
557
558 for (size_t ch=0; ch<nch; ch += 9)
559 {
560 const int16_t dist = (prev[ch]-start[ch]+1024+offset)%1024;
561 SubtractStep(ch, rc.avg, vec, roi, dist, map);
562 }
563
564 return rc;
565 }
566
567 static void RemoveSpikes(float *p, uint32_t roi)
568 {
569 if (roi<4)
570 return;
571
572 for (size_t i=1; i<roi-2; i++)
573 {
574 if (p[i]-p[i-1]>25 && p[i]-p[i+1]>25)
575 {
576 p[i] = (p[i-1]+p[i+1])/2;
577 }
578
579 if (p[i]-p[i-1]>22 && fabs(p[i]-p[i+1])<4 && p[i+1]-p[i+2]>22)
580 {
581 p[i] = (p[i-1]+p[i+2])/2;
582 p[i+1] = p[i];
583 }
584 }
585 }
586
587 static void RemoveSpikes2(float *p, uint32_t roi)//from Werner
588 {
589 if (roi<4)
590 return;
591
592 std::vector<float> Ameas(p, p+roi);
593
594 std::vector<float> diff(roi);
595 for (size_t i=1; i<roi-1; i++)
596 diff[i] = (p[i-1] + p[i+1])/2 - p[i];
597
598 //std::vector<float> N1mean(roi);
599 //for (size_t i=1; i<roi-1; i++)
600 // N1mean[i] = (p[i-1] + p[i+1])/2;
601
602 const float fract = 0.8;
603
604 for (size_t i=0; i<roi-3; i++)
605 {
606 if (diff[i]<5)
607 continue;
608
609 if (Ameas[i+2] - (Ameas[i] + Ameas[i+3])/2 > 10)
610 {
611 p[i+1]= (Ameas[i+3] - Ameas[i])/3 + Ameas[i];
612 p[i+2]= 2*(Ameas[i+3] - Ameas[i])/3 + Ameas[i];
613
614 i += 3;
615
616 continue;
617 }
618
619 if ( (diff[i+1]<-diff[i]*fract*2) && (diff[i+2]>10) )
620 {
621 p[i+1] = (Ameas[i]+Ameas[i+2])/2;
622 diff[i+2] = (p[i+1] + Ameas[i+3])/2 - Ameas[i+2];
623
624 i += 2;
625 }
626
627 // const float x = Ameas[i] - N1mean[i];
628 // if (x > -5.)
629 // continue;
630
631 // if (Ameas[i+2] - (Ameas[i] + Ameas[i+3])/2. > 10.)
632 // {
633 // p[i+1]= (Ameas[i+3] - Ameas[i])/3 + Ameas[i];
634 // p[i+2]= 2*(Ameas[i+3] - Ameas[i])/3 + Ameas[i];
635 // i += 3;
636 // continue;
637 // }
638
639 // const float xp = Ameas[i+1] - N1mean[i+1];
640 // const float xpp = Ameas[i+2] - N1mean[i+2];
641
642 // if ( (xp > -2.*x*fract) && (xpp < -10.) )
643 // {
644 // p[i+1] = N1mean[i+1];
645 // N1mean[i+2] = Ameas[i+1] - Ameas[i+3]/2;
646 //
647 // i += 2;
648 // }
649 }
650 }
651
652 static void RemoveSpikes3(float *vec, uint32_t roi)//from Werner
653 {
654 if (roi<4)
655 return;
656
657 const float SingleCandidateTHR = -10.;
658 const float DoubleCandidateTHR = -5.;
659
660 const std::vector<float> src(vec, vec+roi);
661
662 std::vector<float> diff(roi);
663 for (size_t i=1; i<roi-1; i++)
664 diff[i] = src[i] - (src[i-1] + src[i+1])/2;
665
666 // find the spike and replace it by mean value of neighbors
667 for (unsigned int i=1; i<roi-3; i++)
668 {
669 // Speed up (no leading edge)
670 if (diff[i]>=DoubleCandidateTHR)
671 continue;
672
673 //bool checkDouble = false;
674
675 // a single spike candidate
676 if (diff[i]<SingleCandidateTHR)
677 {
678 // check consistency with a single channel spike
679 if (diff[i+1] > -1.6*diff[i])
680 {
681 vec[i+1] = (src[i] + src[i+2]) / 2;
682
683 i += 2;
684
685 /*** NEW ***/
686 continue;
687 /*** NEW ***/
688 }
689 /*
690 else
691 {
692 // do nothing - not really a single spike,
693 // but check if it is a double
694 checkDouble = true;
695 }*/
696 }
697
698 // a double spike candidate
699 //if (diff[i]>DoubleCandidateTHR || checkDouble == 1)
700 {
701 // check the consistency with a double spike
702 if ((diff[i+1] > -DoubleCandidateTHR) &&
703 (diff[i+2] > -DoubleCandidateTHR))
704 {
705 vec[i+1] = (src[i+3] - src[i])/3 + src[i];
706 vec[i+2] = 2*(src[i+3] - src[i])/3 + src[i];
707
708 //vec[i] = (src[i-1] + src[i+2]) / 2.;
709 //vec[i+1] = (src[i-1] + src[i+2]) / 2.;
710
711 //do not care about the next sample it was the spike
712 i += 3;
713 }
714 }
715 }
716 }
717
718 static void RemoveSpikes4(float *ptr, uint32_t roi)
719 {
720 if (roi<7)
721 return;
722
723 for (uint32_t i=0; i<roi-6; i++)
724 {
725 double d10, d21, d32, d43, d54;
726
727 // ============================================
728 d43 = ptr[i+4]-ptr[i+3];
729 d54 = ptr[i+5]-ptr[i+4];
730
731 if ((d43>35 && -d54>35) || (d43<-35 && -d54<-35))
732 {
733 ptr[i+4] = (ptr[i+3]+ptr[i+5])/2;
734 }
735
736 // ============================================
737 d32 = ptr[i+3]-ptr[i+2];
738 d54 = ptr[i+5]-ptr[i+4];
739
740 if ((d32>9 && -d54>13 && d32-d54>31)/* || (d32<-13 && -d54<-13 && d32+d54<-63)*/)
741 {
742 double avg0 = (ptr[i+2]+ptr[i+5])/2;
743 double avg1 = (ptr[i+3]+ptr[i+4])/2;
744
745 ptr[i+3] = ptr[i+3] - avg1+avg0;
746 ptr[i+4] = ptr[i+4] - avg1+avg0;
747 }
748
749 // ============================================
750 d21 = ptr[i+2]-ptr[i+1];
751 d54 = ptr[i+5]-ptr[i+4];
752
753 if (d21>15 && -d54>17)
754 {
755 double avg0 = (ptr[i+1]+ptr[i+5])/2;
756 double avg1 = (ptr[i+2]+ptr[i+3]+ptr[i+4])/3;
757
758 ptr[i+2] = ptr[i+2] - avg1+avg0;
759 ptr[i+3] = ptr[i+3] - avg1+avg0;
760 ptr[i+4] = ptr[i+4] - avg1+avg0;
761 }
762
763 // ============================================
764 d10 = ptr[i+1]-ptr[i];
765 d54 = ptr[i+5]-ptr[i+4];
766
767 if (d10>18 && -d54>20)
768 {
769 double avg0 = (ptr[i]+ptr[i+5])/2;
770 double avg1 = (ptr[i+1]+ptr[i+2]+ptr[i+3]+ptr[i+4])/4;
771
772 ptr[i+1] = ptr[i+1] - avg1+avg0;
773 ptr[i+2] = ptr[i+2] - avg1+avg0;
774 ptr[i+3] = ptr[i+3] - avg1+avg0;
775 ptr[i+4] = ptr[i+4] - avg1+avg0;
776 }
777 }
778 }
779
780 static void SlidingAverage(float *const vec, const uint32_t roi, const uint16_t w)
781 {
782 if (w==0 || w>roi)
783 return;
784
785 for (float *pix=vec; pix<vec+1440*roi; pix += roi)
786 {
787 for (float *ptr=pix; ptr<pix+roi-w; ptr++)
788 {
789 for (float *p=ptr+1; p<ptr+w; p++)
790 *ptr += *p;
791 *ptr /= w;
792 }
793 }
794 }
795
796 std::pair<std::vector<double>,std::vector<double> > GetSampleStats() const
797 {
798 if (fNumEntries==0)
799 return make_pair(std::vector<double>(),std::vector<double>());
800
801 std::vector<double> mean(fSum.size());
802 std::vector<double> error(fSum.size());
803
804 std::vector<int64_t>::const_iterator it = fSum.begin();
805 std::vector<int64_t>::const_iterator i2 = fSum2.begin();
806 std::vector<double>::iterator im = mean.begin();
807 std::vector<double>::iterator ie = error.begin();
808
809 while (it!=fSum.end())
810 {
811 *im = /*cnt<fResult.size() ? fResult[cnt] :*/ double(*it)/fNumEntries;
812 *ie = sqrt(double(*i2*int64_t(fNumEntries) - *it * *it))/fNumEntries;
813
814 im++;
815 ie++;
816 it++;
817 i2++;
818 }
819
820
821 /*
822 valarray<double> ...
823
824 mean /= fNumEntries;
825 error = sqrt(error/fNumEntries - mean*mean);
826 */
827
828 return make_pair(mean, error);
829 }
830
831 void GetSampleStats(float *ptr, float scale) const
832 {
833 const size_t sz = fNumSamples*fNumChannels;
834
835 if (fNumEntries==0)
836 {
837 memset(ptr, 0, sizeof(float)*sz*2);
838 return;
839 }
840
841 std::vector<int64_t>::const_iterator it = fSum.begin();
842 std::vector<int64_t>::const_iterator i2 = fSum2.begin();
843
844 while (it!=fSum.end())
845 {
846 *ptr = scale*double(*it)/fNumEntries;
847 *(ptr+sz) = scale*sqrt(double(*i2*fNumEntries - *it * *it))/fNumEntries;
848
849 ptr++;
850 it++;
851 i2++;
852 }
853 }
854
855 static double GetPixelStats(float *ptr, const float *data, uint16_t roi, uint16_t begskip=0, uint16_t endskip=0)
856 {
857 if (roi==0)
858 return -1;
859
860 // Skip first 10 samples
861 const uint beg = roi>begskip ? begskip : 0;
862 const uint end = roi-beg>endskip ? roi-endskip : roi;
863 const uint len = end-beg;
864
865 double max = 0;
866 double patch = 0;
867 for (uint i=0; i<1440; i++)
868 {
869 const float *vec = data+i*roi;
870
871 uint pos = beg;
872 double sum = vec[beg];
873 double sum2 = vec[beg]*vec[beg];
874
875 for (uint j=beg+1; j<end; j++)
876 {
877 sum += vec[j];
878 sum2 += vec[j]*vec[j];
879
880 if (vec[j]>vec[pos])
881 pos = j;
882 }
883 sum /= len;
884 sum2 /= len;
885 sum2 -= sum*sum;
886
887 if (i%9!=8)
888 patch += vec[pos];
889 else
890 {
891 if (patch > max)
892 max = patch;
893 patch = 0;
894 }
895
896 *(ptr+0*1440+i) = sum;
897 *(ptr+1*1440+i) = sum2<0 ? 0 : sqrt(sum2);
898 *(ptr+2*1440+i) = vec[pos];
899 *(ptr+3*1440+i) = pos;
900 }
901
902 return max/8;
903 }
904
905 static void GetPixelMax(float *max, const float *data, uint16_t roi, int32_t first, int32_t last)
906 {
907 if (roi==0 || first<0 || last<0 || first>=roi || last>=roi || last<first)
908 return;
909
910 for (int i=0; i<1440; i++)
911 {
912 const float *beg = data+i*roi+first;
913 const float *end = data+i*roi+last;
914
915 const float *pmax = beg;
916
917 for (const float *ptr=beg+1; ptr<=end; ptr++)
918 if (*ptr>*pmax)
919 pmax = ptr;
920
921 max[i] = *pmax;
922 }
923 }
924
925 const std::vector<int64_t> &GetSum() const { return fSum; }
926
927 int64_t GetNumEntries() const { return fNumEntries; }
928};
929
930class DrsCalibrateTime
931{
932public:
933 int64_t fNumEntries;
934
935 size_t fNumSamples;
936 size_t fNumChannels;
937
938 std::vector<std::pair<double, double>> fStat;
939
940public:
941 DrsCalibrateTime() : fNumEntries(0), fNumSamples(0), fNumChannels(0)
942 {
943 InitSize(160, 1024);
944 }
945
946 DrsCalibrateTime(const DrsCalibrateTime &p) : fNumEntries(p.fNumEntries), fNumSamples(p.fNumSamples), fNumChannels(p.fNumChannels), fStat(p.fStat)
947 {
948 }
949
950 // DN: To be done:
951 // include also reading of fStat[i].second into the file
952 // not done, because it's not yet written into the file.
953 DrsCalibrateTime(const char* fits_file_path) : fNumEntries(0), fNumSamples(0), fNumChannels(0)
954 {
955 fits drs_time_file(fits_file_path);
956
957 fNumSamples = drs_time_file.GetInt("NCHIPS");
958 fNumChannels = drs_time_file.GetInt("NCELLS");
959 fNumEntries = drs_time_file.GetInt("NENTRIES"); // the number of events, that were in the original file.
960 InitSize(fNumChannels, fNumSamples);
961
962 double *drs_sampling_time_deviations = new double[fNumChannels * fNumSamples];
963 drs_time_file.SetPtrAddress("SamplingTimeDeviation", drs_sampling_time_deviations);
964 drs_time_file.GetNextRow();
965 for (size_t i=0; i<fNumChannels * fNumSamples; i++){
966 fStat[i].first = drs_sampling_time_deviations[i];
967 }
968 drs_time_file.close();
969 // if deleting drs_sampling_time_deviations, before closing the file,
970 // I get a seg fault. So apparently fits accesses this array not only
971 // in the call to GetNextRow() Why? is that so?
972 delete[] drs_sampling_time_deviations;
973 drs_sampling_time_deviations = NULL;
974 }
975
976 // DN: To be done:
977 // include also writing of fStat[i].second into the file
978 // not done, because I don't know how.
979 void WriteToFits(const char* fits_file_path)
980 {
981 ofits drstimeFile(fits_file_path);
982 drstimeFile.SetDefaultKeys();
983 drstimeFile.AddColumnDouble(
984 fNumChannels*fNumSamples,
985 "SamplingTimeDeviation", "nominal slices",
986 "see following COMMENT."
987 );
988 drstimeFile.SetInt("NCHIPS", fNumChannels, "number of drs chips");
989 drstimeFile.SetInt("NCELLS", fNumSamples, "number of cells of each chip");
990 drstimeFile.SetInt("NENTRIES", fNumEntries, "number of events in raw file");
991
992 drstimeFile.AddComment(
993 "The SamplingTimeDeviation specifies the deviation of the actual ");
994 drstimeFile.AddComment(
995 "sampling time of a certain cell, from its nominal sampling time.");
996 drstimeFile.AddComment(
997 "It is measured in nominal slices.");
998 drstimeFile.AddComment(
999 "In order to convert the sample index into the actual sampling time");
1000 drstimeFile.AddComment(
1001 "just do: ");
1002 drstimeFile.AddComment(
1003 " cell_index + td(cell_index) - td(stop_cell_index)");
1004 drstimeFile.AddComment(
1005 "where td(i) refers to the SamplingTimeDeviation of cell i of the ");
1006 drstimeFile.AddComment(
1007 "current DRS4 chip.");
1008 drstimeFile.AddComment(
1009 "This gives you the actual sampling time of the cell measured in ");
1010 drstimeFile.AddComment(
1011 "nominal slices [nsl] with respect to the stop cells sampling time.");
1012 drstimeFile.AddComment(
1013 "Convert it to ns, simply by multiplication ");
1014 drstimeFile.AddComment(
1015 "with 0.5 ns/nsl.");
1016 drstimeFile.AddComment(
1017 "");
1018
1019 drstimeFile.AddComment(
1020 "In FACT it became common practice to measure un-time-calibrated ");
1021 drstimeFile.AddComment(
1022 " DRS4 data in 'time slices' or simply 'samples', while ");
1023 drstimeFile.AddComment(
1024 " time-calibrated DRS4 data usually measured in ns. Since the method,");
1025 drstimeFile.AddComment(
1026 " that is emplyed to measure the DRS4 time calibration constants has ");
1027 drstimeFile.AddComment(
1028 " no possibility to assert the actual length of a slice is really half");
1029 drstimeFile.AddComment(
1030 " a nanosecond, this practice is not advisable.");
1031 drstimeFile.AddComment(
1032 " I propose instead to call un-time-calibrated data 'samples',");
1033 drstimeFile.AddComment(
1034 " since this is what they are. If one wants to stress the fact,");
1035 drstimeFile.AddComment(
1036 " that no drs time calibration has been applied one should refer to ");
1037 drstimeFile.AddComment(
1038 "'uncalibrated slices'. Since it *should* be common practice to apply");
1039
1040 drstimeFile.AddComment(
1041 " the drs4 time calibration in all cases, I also propose to use the");
1042 drstimeFile.AddComment(
1043 " short term of 'slices' or 'sl'. If one wants to stress, that the");
1044 drstimeFile.AddComment(
1045 " drs4 time calibration has actually been applied to the data,");
1046 drstimeFile.AddComment(
1047 " the term 'calibrated slices' or 'nominal slices' or short 'nsl'.");
1048
1049 drstimeFile.WriteTableHeader("DRS_CELL_TIMES");
1050
1051 double *drs_sampling_time_deviations = new double[fNumChannels * fNumSamples];
1052 for (size_t chip = 0; chip < fNumChannels; chip++){
1053 for (size_t cell = 0; cell < fNumSamples; cell++){
1054 drs_sampling_time_deviations[chip*fNumChannels + cell] =
1055 fStat[chip*fNumChannels + cell].first;
1056 }
1057 }
1058
1059 drstimeFile.WriteRow(drs_sampling_time_deviations, sizeof(double) * fNumChannels * fNumSamples);
1060 drstimeFile.close();
1061
1062 }
1063
1064 virtual ~DrsCalibrateTime()
1065 {
1066 }
1067
1068 double Sum(uint32_t i) const { return fStat[i].first; }
1069 double W(uint32_t i) const { return fStat[i].second; }
1070
1071 virtual void InitSize(uint16_t channels, uint16_t samples)
1072 {
1073 fNumChannels = channels;
1074 fNumSamples = samples;
1075
1076 fNumEntries = 0;
1077
1078 fStat.clear();
1079
1080 fStat.resize(samples*channels);
1081 }
1082
1083 void AddT(const float *val, const int16_t *start, signed char edge=0)
1084 {
1085 if (fNumSamples!=1024 || fNumChannels!=160)
1086 return;
1087
1088 // Rising or falling edge detection has the advantage that
1089 // we are much less sensitive to baseline shifts
1090
1091 for (size_t ch=0; ch<160; ch++)
1092 {
1093 const size_t tm = ch*9+8;
1094
1095 const int16_t spos = start[tm];
1096 if (spos<0)
1097 continue;
1098
1099 const size_t pos = ch*1024;
1100
1101 double p_prev = 0;
1102 int32_t i_prev = -1;
1103
1104 for (size_t i=0; i<1024-1; i++)
1105 {
1106 const size_t rel = tm*1024 + i;
1107
1108 const float &v0 = val[rel]; //-avg;
1109 const float &v1 = val[rel+1];//-avg;
1110
1111 // If edge is positive ignore all falling edges
1112 if (edge>0 && v0>0)
1113 continue;
1114
1115 // If edge is negative ignore all falling edges
1116 if (edge<0 && v0<0)
1117 continue;
1118
1119 // Check if there is a zero crossing
1120 if ((v0<0 && v1<0) || (v0>0 && v1>0))
1121 continue;
1122
1123 // Calculate the position p of the zero-crossing
1124 // within the interval [rel, rel+1] relative to rel
1125 // by linear interpolation.
1126 const double p = v0==v1 ? 0.5 : v0/(v0-v1);
1127
1128 // If this was at least the second zero-crossing detected
1129 if (i_prev>=0)
1130 {
1131 // Calculate the distance l between the
1132 // current and the last zero-crossing
1133 const double l = i+p - (i_prev+p_prev);
1134
1135 // By summation, the average length of each
1136 // cell is calculated. For the first and last
1137 // fraction of a cell, the fraction is applied
1138 // as a weight.
1139 const double w0 = 1-p_prev;
1140 fStat[pos+(spos+i_prev)%1024].first += w0*l;
1141 fStat[pos+(spos+i_prev)%1024].second += w0;
1142
1143 for (size_t k=i_prev+1; k<i; k++)
1144 {
1145 fStat[pos+(spos+k)%1024].first += l;
1146 fStat[pos+(spos+k)%1024].second += 1;
1147 }
1148
1149 const double w1 = p;
1150 fStat[pos+(spos+i)%1024].first += w1*l;
1151 fStat[pos+(spos+i)%1024].second += w1;
1152 }
1153
1154 // Remember this zero-crossing position
1155 p_prev = p;
1156 i_prev = i;
1157 }
1158 }
1159 fNumEntries++;
1160 }
1161
1162 void FillEmptyBins()
1163 {
1164 for (int ch=0; ch<160; ch++)
1165 {
1166 const auto beg = fStat.begin() + ch*1024;
1167 const auto end = beg + 1024;
1168
1169 double avg = 0;
1170 uint32_t num = 0;
1171 for (auto it=beg; it!=end; it++)
1172 {
1173 if (it->second<fNumEntries-0.5)
1174 continue;
1175
1176 avg += it->first / it->second;
1177 num++;
1178 }
1179 avg /= num;
1180
1181 for (auto it=beg; it!=end; it++)
1182 {
1183 if (it->second>=fNumEntries-0.5)
1184 continue;
1185
1186 // {
1187 // result[i+1].first = *is2;
1188 // result[i+1].second = *iw2;
1189 // }
1190 // else
1191 // {
1192 it->first = avg*fNumEntries;
1193 it->second = fNumEntries;
1194 // }
1195 }
1196 }
1197 }
1198
1199 DrsCalibrateTime GetComplete() const
1200 {
1201 DrsCalibrateTime rc(*this);
1202 rc.FillEmptyBins();
1203 return rc;
1204 }
1205
1206 void CalcResult()
1207 {
1208 for (int ch=0; ch<160; ch++)
1209 {
1210 const auto beg = fStat.begin() + ch*1024;
1211 const auto end = beg + 1024;
1212
1213 // First calculate the average length s of a single
1214 // zero-crossing interval in the whole range [0;1023]
1215 // (which is identical to the/ wavelength of the
1216 // calibration signal)
1217 double s = 0;
1218 double w = 0;
1219 for (auto it=beg; it!=end; it++)
1220 {
1221 s += it->first;
1222 w += it->second;
1223 }
1224 s /= w;
1225
1226 // Dividing the average length s of the zero-crossing
1227 // interval in the range [0;1023] by the average length
1228 // in the interval [0;n] yields the relative size of
1229 // the interval in the range [0;n].
1230 //
1231 // Example:
1232 // Average [0;1023]: 10.00 (global interval size in samples)
1233 // Average [0;512]: 8.00 (local interval size in samples)
1234 //
1235 // Globally, on average one interval is sampled by 10 samples.
1236 // In the sub-range [0;512] one interval is sampled on average
1237 // by 8 samples.
1238 // That means that the interval contains 64 periods, while
1239 // in the ideal case (each sample has the same length), it
1240 // should contain 51.2 periods.
1241 // So, the sampling position 512 corresponds to a time 640,
1242 // while in the ideal case with equally spaces samples,
1243 // it would correspond to a time 512.
1244 //
1245 // The offset (defined as 'ideal - real') is then calculated
1246 // as 512*(1-10/8) = -128, so that the time is calculated as
1247 // 'sampling position minus offset'
1248 //
1249 double sumw = 0;
1250 double sumv = 0;
1251 int n = 0;
1252
1253 // Sums about many values are numerically less stable than
1254 // just sums over less. So we do the exercise from both sides.
1255 // First from the left
1256 for (auto it=beg; it!=end-512; it++, n++)
1257 {
1258 const double valv = it->first;
1259 const double valw = it->second;
1260
1261 it->first = sumv>0 ? n*(1-s*sumw/sumv) : 0;
1262
1263 sumv += valv;
1264 sumw += valw;
1265 }
1266
1267 sumw = 0;
1268 sumv = 0;
1269 n = 1;
1270
1271 // Second from the right
1272 for (auto it=end-1; it!=beg-1+512; it--, n++)
1273 {
1274 const double valv = it->first;
1275 const double valw = it->second;
1276
1277 sumv += valv;
1278 sumw += valw;
1279
1280 it->first = sumv>0 ? n*(s*sumw/sumv-1) : 0;
1281 }
1282
1283 // A crosscheck has shown, that the values from the left
1284 // and right perfectly agree over the whole range. This means
1285 // the a calculation from just one side would be enough, but
1286 // doing it from both sides might still make the numerics
1287 // a bit more stable.
1288 }
1289 }
1290
1291 DrsCalibrateTime GetResult() const
1292 {
1293 DrsCalibrateTime rc(*this);
1294 rc.CalcResult();
1295 return rc;
1296 }
1297
1298 double Offset(uint32_t ch, double pos) const
1299 {
1300 const auto p = fStat.begin() + ch*1024;
1301
1302 const uint32_t f = floor(pos);
1303
1304 const double v0 = p[f].first;
1305 const double v1 = p[(f+1)%1024].first;
1306
1307 return v0 + fmod(pos, 1)*(v1-v0);
1308 }
1309
1310 double Calib(uint32_t ch, double pos) const
1311 {
1312 return pos-Offset(ch, pos);
1313 }
1314};
1315
1316struct DrsCalibration
1317{
1318 std::vector<int32_t> fOffset;
1319 std::vector<int64_t> fGain;
1320 std::vector<int64_t> fTrgOff;
1321
1322 int64_t fNumOffset;
1323 int64_t fNumGain;
1324 int64_t fNumTrgOff;
1325
1326 uint32_t fStep;
1327 uint16_t fRoi; // Region of interest for trgoff
1328 uint16_t fNumTm; // Number of time marker channels in trgoff
1329
1330 std::string fDateObs;
1331 std::string fDateRunBeg[3];
1332 std::string fDateRunEnd[3];
1333 std::string fDateEnd;
1334
1335// uint16_t fDAC[8];
1336
1337 DrsCalibration() :
1338 fOffset(1440*1024, 0),
1339 fGain(1440*1024, 4096),
1340 fTrgOff (1600*1024, 0),
1341 fNumOffset(1),
1342 fNumGain(2000),
1343 fNumTrgOff(1),
1344 fStep(0),
1345 fDateObs("1970-01-01T00:00:00"),
1346 fDateEnd("1970-01-01T00:00:00")
1347 {
1348 for (int i=0; i<3; i++)
1349 {
1350 fDateRunBeg[i] = "1970-01-01T00:00:00";
1351 fDateRunEnd[i] = "1970-01-01T00:00:00";
1352 }
1353 }
1354
1355 DrsCalibration(const DrsCalibration &cpy) :
1356 fOffset(cpy.fOffset),
1357 fGain(cpy.fGain),
1358 fTrgOff(cpy.fTrgOff),
1359 fNumOffset(cpy.fNumOffset),
1360 fNumGain(cpy.fNumGain),
1361 fNumTrgOff(cpy.fNumTrgOff),
1362 fStep(cpy.fStep),
1363 fRoi(cpy.fRoi),
1364 fNumTm(cpy.fNumTm),
1365 fDateObs(cpy.fDateObs),
1366 fDateRunBeg(cpy.fDateRunBeg),
1367 fDateRunEnd(cpy.fDateRunEnd),
1368 fDateEnd(cpy.fDateEnd)
1369 {
1370 }
1371
1372 void Clear()
1373 {
1374 // Default gain:
1375 // 0.575*[45590]*2.5V / 2^16 = 0.99999 V
1376 fOffset.assign(1440*1024, 0);
1377 fGain.assign (1440*1024, 4096);
1378 fTrgOff.assign(1600*1024, 0);
1379
1380 fNumOffset = 1;
1381 fNumGain = 2000;
1382 fNumTrgOff = 1;
1383
1384 fStep = 0;
1385
1386 fDateObs = "1970-01-01T00:00:00";
1387 fDateEnd = "1970-01-01T00:00:00";
1388
1389 for (int i=0; i<3; i++)
1390 {
1391 fDateRunBeg[i] = "1970-01-01T00:00:00";
1392 fDateRunEnd[i] = "1970-01-01T00:00:00";
1393 }
1394 }
1395
1396 std::string ReadFitsImp(const std::string &str, std::vector<float> &vec)
1397 {
1398 fits file(str);
1399 if (!file)
1400 {
1401 std::ostringstream msg;
1402 msg << "Could not open file '" << str << "': " << strerror(errno);
1403 return msg.str();
1404 }
1405
1406 if (file.GetStr("TELESCOP")!="FACT")
1407 {
1408 std::ostringstream msg;
1409 msg << "Reading '" << str << "' failed: Not a valid FACT file (TELESCOP not FACT in header)";
1410 return msg.str();
1411 }
1412
1413 if (!file.HasKey("STEP"))
1414 {
1415 std::ostringstream msg;
1416 msg << "Reading '" << str << "' failed: Is not a DRS calib file (STEP not found in header)";
1417 return msg.str();
1418 }
1419
1420 if (file.GetNumRows()!=1)
1421 {
1422 std::ostringstream msg;
1423 msg << "Reading '" << str << "' failed: Number of rows in table is not 1.";
1424 return msg.str();
1425 }
1426
1427 fStep = file.GetUInt("STEP");
1428 fNumOffset = file.GetInt("NBOFFSET");
1429 fNumGain = file.GetInt("NBGAIN");
1430 fNumTrgOff = file.GetInt("NBTRGOFF");
1431 fRoi = file.GetUInt("NROI");
1432 fNumTm = file.HasKey("NTM") ? file.GetUInt("NTM") : 0;
1433
1434 if (file.HasKey("DATE-OBS"))
1435 fDateObs = file.GetStr("DATE-OBS");
1436 if (file.HasKey("DATE-END"))
1437 fDateEnd = file.GetStr("DATE-END");
1438
1439 if (file.HasKey("RUN0-BEG"))
1440 fDateRunBeg[0]= file.GetStr("RUN0-BEG");
1441 if (file.HasKey("RUN1-BEG"))
1442 fDateRunBeg[1]= file.GetStr("RUN1-BEG");
1443 if (file.HasKey("RUN2-BEG"))
1444 fDateRunBeg[2]= file.GetStr("RUN2-BEG");
1445 if (file.HasKey("RUN0-END"))
1446 fDateRunEnd[0]= file.GetStr("RUN0-END");
1447 if (file.HasKey("RUN1-END"))
1448 fDateRunEnd[1]= file.GetStr("RUN1-END");
1449 if (file.HasKey("RUN2-END"))
1450 fDateRunEnd[2]= file.GetStr("RUN2-END");
1451/*
1452 fDAC[0] = file.GetUInt("DAC_A");
1453 fDAC[1] = file.GetUInt("DAC_B");
1454 fDAC[4] = file.GetUInt("DAC_C");
1455*/
1456 vec.resize(1440*1024*4 + (1440+fNumTm)*fRoi*2 + 4);
1457
1458 float *base = vec.data();
1459
1460 reinterpret_cast<uint32_t*>(base)[0] = fRoi;
1461
1462 file.SetPtrAddress("RunNumberBaseline", base+1, 1);
1463 file.SetPtrAddress("RunNumberGain", base+2, 1);
1464 file.SetPtrAddress("RunNumberTriggerOffset", base+3, 1);
1465 file.SetPtrAddress("BaselineMean", base+4+0*1024*1440, 1024*1440);
1466 file.SetPtrAddress("BaselineRms", base+4+1*1024*1440, 1024*1440);
1467 file.SetPtrAddress("GainMean", base+4+2*1024*1440, 1024*1440);
1468 file.SetPtrAddress("GainRms", base+4+3*1024*1440, 1024*1440);
1469 file.SetPtrAddress("TriggerOffsetMean", base+4+4*1024*1440, fRoi*1440);
1470 file.SetPtrAddress("TriggerOffsetRms", base+4+4*1024*1440+fRoi*1440, fRoi*1440);
1471 if (fNumTm>0)
1472 {
1473 file.SetPtrAddress("TriggerOffsetTMMean", base+4+4*1024*1440+ 2*fRoi*1440, fRoi*fNumTm);
1474 file.SetPtrAddress("TriggerOffsetTMRms", base+4+4*1024*1440+ 2*fRoi*1440+ fRoi*fNumTm, fRoi*fNumTm);
1475 }
1476
1477 if (!file.GetNextRow())
1478 {
1479 std::ostringstream msg;
1480 msg << "Reading data from " << str << " failed.";
1481 return msg.str();
1482 }
1483/*
1484 fDAC[2] = fDAC[1];
1485 fDAC[4] = fDAC[1];
1486
1487 fDAC[5] = fDAC[4];
1488 fDAC[6] = fDAC[4];
1489 fDAC[7] = fDAC[4];
1490*/
1491 fOffset.resize(1024*1440);
1492 fGain.resize(1024*1440);
1493
1494 fTrgOff.resize(fRoi*(1440+fNumTm));
1495
1496 // Convert back to ADC counts: 256/125 = 4096/2000
1497 // Convert back to sum (mean * num_entries)
1498 for (int i=0; i<1024*1440; i++)
1499 {
1500 fOffset[i] = fNumOffset *256*base[i+1024*1440*0+4]/125;
1501 fGain[i] = fNumOffset*fNumGain*256*base[i+1024*1440*2+4]/125;
1502 }
1503
1504 for (int i=0; i<fRoi*1440; i++)
1505 fTrgOff[i] = fNumOffset*fNumTrgOff*256*base[i+1024*1440*4+4]/125;
1506
1507 for (int i=0; i<fRoi*fNumTm; i++)
1508 fTrgOff[i+1440*fRoi] = fNumOffset*fNumTrgOff*256*base[i+1024*1440*4+2*fRoi*1440+4]/125;
1509
1510
1511 // DAC: 0..2.5V == 0..65535
1512 // V-mV: 1000
1513 //fNumGain *= 2500*50000;
1514 //for (int i=0; i<1024*1440; i++)
1515 // fGain[i] *= 65536;
1516 if (fStep==0)
1517 {
1518 for (int i=0; i<1024*1440; i++)
1519 fGain[i] = fNumOffset*4096;
1520 }
1521 else
1522 {
1523 fNumGain *= 1953125;
1524 for (int i=0; i<1024*1440; i++)
1525 fGain[i] *= 1024;
1526 }
1527
1528 // Now mark the stored DRS data as "officially valid"
1529 // However, this is not thread safe. It only ensures that
1530 // this data is not used before it is completely and correctly
1531 // read.
1532 fStep++;
1533
1534 return std::string();
1535 }
1536
1537 std::string WriteFitsImp(const std::string &filename, const std::vector<float> &vec, uint32_t night=0) const
1538 {
1539 const size_t n = 1440*1024*4 + 1440*fRoi*2 + fNumTm*fRoi*2 + 3;
1540
1541 ofits file(filename.c_str());
1542 if (!file)
1543 {
1544 std::ostringstream msg;
1545 msg << "Could not open file '" << filename << "': " << strerror(errno);
1546 return msg.str();
1547 }
1548
1549 file.AddColumnInt("RunNumberBaseline");
1550 file.AddColumnInt("RunNumberGain");
1551 file.AddColumnInt("RunNumberTriggerOffset");
1552
1553 file.AddColumnFloat(1024*1440, "BaselineMean", "mV");
1554 file.AddColumnFloat(1024*1440, "BaselineRms", "mV");
1555 file.AddColumnFloat(1024*1440, "GainMean", "mV");
1556 file.AddColumnFloat(1024*1440, "GainRms", "mV");
1557 file.AddColumnFloat(fRoi*1440, "TriggerOffsetMean", "mV");
1558 file.AddColumnFloat(fRoi*1440, "TriggerOffsetRms", "mV");
1559 file.AddColumnFloat(fRoi*fNumTm, "TriggerOffsetTMMean", "mV");
1560 file.AddColumnFloat(fRoi*fNumTm, "TriggerOffsetTMRms", "mV");
1561
1562 file.SetDefaultKeys();
1563 if (night>0)
1564 file.SetInt("NIGHT", night, "Night as int");
1565
1566 file.SetStr("DATE-OBS", fDateObs, "First event of whole DRS calibration");
1567 file.SetStr("DATE-END", fDateEnd, "Last event of whole DRS calibration");
1568 file.SetStr("RUN0-BEG", fDateRunBeg[0], "First event of run 0");
1569 file.SetStr("RUN1-BEG", fDateRunBeg[1], "First event of run 1");
1570 file.SetStr("RUN2-BEG", fDateRunBeg[2], "First event of run 2");
1571 file.SetStr("RUN0-END", fDateRunEnd[0], "Last event of run 0");
1572 file.SetStr("RUN1-END", fDateRunEnd[1], "Last event of run 1");
1573 file.SetStr("RUN2-END", fDateRunEnd[2], "Last event of run 2");
1574
1575 file.SetInt("STEP", fStep, "");
1576
1577 file.SetInt("ADCRANGE", 2000, "Dynamic range of the ADC in mV");
1578 file.SetInt("DACRANGE", 2500, "Dynamic range of the DAC in mV");
1579 file.SetInt("ADC", 12, "Resolution of ADC in bits");
1580 file.SetInt("DAC", 16, "Resolution of DAC in bits");
1581 file.SetInt("NPIX", 1440, "Number of channels in the camera");
1582 file.SetInt("NTM", fNumTm, "Number of time marker channels");
1583 file.SetInt("NROI", fRoi, "Region of interest");
1584
1585 file.SetInt("NBOFFSET", fNumOffset, "Num of entries for offset calibration");
1586 file.SetInt("NBGAIN", fNumGain/1953125, "Num of entries for gain calibration");
1587 file.SetInt("NBTRGOFF", fNumTrgOff, "Num of entries for trigger offset calibration");
1588
1589 // file.WriteKeyNT("DAC_A", fData.fDAC[0], "Level of DAC 0 in DAC counts") ||
1590 // file.WriteKeyNT("DAC_B", fData.fDAC[1], "Leval of DAC 1-3 in DAC counts") ||
1591 // file.WriteKeyNT("DAC_C", fData.fDAC[4], "Leval of DAC 4-7 in DAC counts") ||
1592
1593 file.WriteTableHeader("DrsCalibration");
1594
1595 if (!file.WriteRow(vec.data()+1, n*sizeof(float)))
1596 {
1597 std::ostringstream msg;
1598 msg << "Writing data to " << filename << " failed.";
1599 return msg.str();
1600 }
1601
1602 return std::string();
1603 }
1604
1605
1606 std::string ReadFitsImp(const std::string &str)
1607 {
1608 std::vector<float> vec;
1609 return ReadFitsImp(str, vec);
1610 }
1611
1612 bool IsValid() { return fStep>2; }
1613
1614 bool Apply(float *vec, const int16_t *val, const int16_t *start, uint32_t roi)
1615 {
1616 if (roi!=fRoi)
1617 {
1618 for (size_t ch=0; ch<1440; ch++)
1619 {
1620 const size_t pos = ch*roi;
1621 const size_t drs = ch*1024;
1622
1623 DrsCalibrate::ApplyCh(vec+pos, val+pos, start[ch], roi,
1624 fOffset.data()+drs, fNumOffset,
1625 fGain.data() +drs, fNumGain);
1626 }
1627
1628 return false;
1629 }
1630
1631 for (size_t ch=0; ch<1440; ch++)
1632 {
1633 const size_t pos = ch*fRoi;
1634 const size_t drs = ch*1024;
1635
1636 DrsCalibrate::ApplyCh(vec+pos, val+pos, start[ch], roi,
1637 fOffset.data()+drs, fNumOffset,
1638 fGain.data() +drs, fNumGain,
1639 fTrgOff.data()+pos, fNumTrgOff);
1640 }
1641
1642 for (size_t ch=0; ch<fNumTm; ch++)
1643 {
1644 const size_t pos = (ch+1440)*fRoi;
1645 const size_t drs = (ch*9+8)*1024;
1646
1647 DrsCalibrate::ApplyCh(vec+pos, val+pos, start[ch], roi,
1648 fOffset.data()+drs, fNumOffset,
1649 fGain.data() +drs, fNumGain,
1650 fTrgOff.data()+pos, fNumTrgOff);
1651 }
1652
1653 return true;
1654 }
1655};
1656
1657#endif
Note: See TracBrowser for help on using the repository browser.