pxar
 All Classes Namespaces Functions Variables Typedefs Friends
PixTestSetPh.cc
1 // -- author: Daniel Pitzl
2 // set offset and gain for PH into ADC range
3 
4 #include <stdlib.h> // atof, atoi
5 #include <algorithm> // std::find
6 
7 #include "PixTestSetPh.hh"
8 #include "log.h"
9 #include "constants.h"
10 
11 using namespace std;
12 using namespace pxar;
13 
14 ClassImp(PixTestSetPh)
15 
16 //------------------------------------------------------------------------------
17 PixTestSetPh::PixTestSetPh( PixSetup *a, std::string name )
18 : PixTest(a, name), fParNtrig(-1)
19 {
20  PixTest::init();
21  init();
22 }
23 
24 //------------------------------------------------------------------------------
25 PixTestSetPh::PixTestSetPh() : PixTest()
26 {
27 }
28 
29 //------------------------------------------------------------------------------
30 bool PixTestSetPh::setParameter( string parName, string sval )
31 {
32  bool found(false);
33 
34  for( uint32_t i = 0; i < fParameters.size(); ++i ) {
35 
36  if( fParameters[i].first == parName ) {
37 
38  found = true;
39 
40  if( !parName.compare( "ntrig" ) )
41  fParNtrig = atoi( sval.c_str() );
42 
43  if( !parName.compare( "pix1" ) ) {
44  string::size_type s1 = sval.find( "," );
45  if( string::npos != s1 ) {
46  string str1 = sval.substr(0, s1);
47  uint16_t pixc = atoi( str1.c_str() );
48  string str2 = sval.substr(s1+1);
49  uint16_t pixr = atoi( str2.c_str() );
50  fPIX.push_back( make_pair( pixc, pixr ) );
51  }
52  else {
53  fPIX.push_back( make_pair( -1, -1 ) );
54  }
55  }
56  break;
57  }
58  }
59  return found;
60 }
61 
62 //------------------------------------------------------------------------------
63 void PixTestSetPh::init()
64 {
65  LOG(logINFO) << "PixTestSetPh::init()";
66 
67  fDirectory = gFile->GetDirectory( fName.c_str() );
68  if( !fDirectory )
69  fDirectory = gFile->mkdir( fName.c_str() );
70  fDirectory->cd();
71 }
72 
73 // ----------------------------------------------------------------------
75 {
76  fTestTip = string( "tune PH into ADC range using VOffsetRO and VIref_ADC");
77  fSummaryTip = string("summary plot to be implemented");
78 }
79 
80 //------------------------------------------------------------------------------
81 void PixTestSetPh::bookHist(string name)
82 {
83  LOG(logDEBUG) << "nothing done with " << name;
84 }
85 
86 //------------------------------------------------------------------------------
87 PixTestSetPh::~PixTestSetPh()
88 {
89  LOG(logDEBUG) << "PixTestSetPh dtor";
90  std::list<TH1*>::iterator il;
91  fDirectory->cd();
92  for( il = fHistList.begin(); il != fHistList.end(); ++il ) {
93  LOG(logINFO) << "Write out " << (*il)->GetName();
94  (*il)->SetDirectory(fDirectory);
95  (*il)->Write();
96  }
97 }
98 
99 //------------------------------------------------------------------------------
101 {
102  LOG(logINFO) << "PixTestSetPh::doTest() ntrig = " << fParNtrig;
103 
104  fDirectory->cd();
105  fHistList.clear();
106  PixTest::update();
107 
108  if( fPIX.size() < 1 ) {
109  LOG(logWARNING) << "PixTestSetCalDel: no pixel defined, return";
110  return;
111  }
112 
113  if( fPIX[fPIX.size()-1].first < 0 ) {
114  LOG(logWARNING) << "PixTestSetCalDel: no valid pixel defined, return";
115  return;
116  }
117 
118  uint16_t flags = 0;
119 
120  uint8_t cal = fApi->_dut->getDAC( 0, "Vcal" );
121  uint8_t ctl = fApi->_dut->getDAC( 0, "CtrlReg" );
122 
123  fApi->setDAC( "CtrlReg", 4 ); // all ROCs large Vcal
124  LOG(logINFO) << "CtrlReg 4 (large Vcal)";
125 
126  // Minimize ADC gain for finding the midpoint
127  // This avoids PH clipping
128 
129  fApi->setDAC( "VIref_ADC", 255 ); // 255 = minimal gain
130 
131  const int max_vcal = 255;
132 
133  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
134  // search for min Vcal using one pixel:
135 
136  fApi->_dut->testAllPixels(false);
137 
138  //coordinates of the last pair = presently set pixel
139  int32_t col = fPIX[fPIX.size()-1].first;
140  int32_t row = fPIX[fPIX.size()-1].second;
141 
142  if( col > -1)
143  fApi->_dut->testPixel( col, row, true );
144 
145  size_t nRocs = fPixSetup->getConfigParameters()->getNrocs();
146 
147  int pix_ph[16];
148  int min_vcal[16]; // large Vcal, after trimming
149  bool not_enough = 0;
150  bool too_much = 0;
151 
152  for( size_t i = 0; i < 16; ++i ) {
153  pix_ph[i] = -1;
154  min_vcal[i] = 8;
155  }
156 
157  // measure:
158 
159  do {
160 
161  for( size_t roc = 0; roc < nRocs; ++roc )
162  fApi->setDAC( "Vcal", min_vcal[roc], roc );
163 
164  // measure:
165 
166  std::vector<pixel> vpix =
167  fApi->getPulseheightMap( flags, fParNtrig );
168 
169  LOG(logINFO) << "vpix size " << vpix.size();
170 
171  // unpack:
172 
173  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
174  uint8_t roc = vpix[ipx].roc();
175  if( roc < 16 )
176  pix_ph[roc] = vpix[ipx].value();
177  LOG(logINFO) << "ipx " << setw(2) << ipx
178  << ": ROC " << setw(2) << (int) vpix[ipx].roc()
179  << " col " << setw(2) << (int) vpix[ipx].column()
180  << " row " << setw(2) << (int) vpix[ipx].row()
181  << " val " << setw(3) << (int) vpix[ipx].value();
182  }
183 
184  // check:
185  not_enough = 0;
186  too_much = 0;
187  for( size_t roc = 0; roc < nRocs; ++roc ) {
188  if( pix_ph[roc] <= 0 ) {
189  min_vcal[roc] += 2;
190  not_enough = 1;
191  }
192  if( min_vcal[roc] > 120 ) too_much = 1;
193  }
194  }
195  while( not_enough && !too_much );
196 
197  if( too_much ) {
198  LOG(logINFO)
199  << "[SetPh] Cannot find working Vcal for pixel "
200  << fPIX[fPIX.size()-1].first << "," << fPIX[fPIX.size()-1].second
201  << ". Please use other pixel or re-trim to lower threshold";
202  return;
203  }
204 
205  for( size_t roc = 0; roc < nRocs; ++roc ) {
206  min_vcal[roc] += 2; // safety
207  fApi->setDAC( "Vcal", min_vcal[roc], roc );
208  LOG(logINFO) << "ROC " << setw(2) << roc
209  << " min Vcal " << setw(2) << min_vcal[roc]
210  << " has Ph " << setw(3) << pix_ph[roc];
211  }
212 
213  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
214  // scan PH vs VOffsetRO for one pixel per ROC at min Vcal
215 
216  for( size_t roc = 0; roc < nRocs; ++roc )
217  fApi->setDAC( "Vcal", min_vcal[roc], roc );
218 
219  string dacName = "VOffsetRO";
220  vector<pair<uint8_t, vector<pixel> > > // dac and pix
221  result = fApi->getPulseheightVsDAC( dacName, 0, 255, flags, fParNtrig );
222 
223  // plot:
224 
225  vector<TH1D*> hmin;
226  TH1D *h1(0);
227 
228  for( size_t roc = 0; roc < nRocs; ++roc ) {
229 
230  h1 = new TH1D( Form( "PH_vs_%s_at_Vcal_%2d_c%02d_r%02d_C%02d",
231  dacName.c_str(), min_vcal[roc],
232  col, row, int(roc) ),
233  Form( "PH vs %s at Vcal %2d c%02d r%02d C%02d",
234  dacName.c_str(), min_vcal[roc],
235  col, row, int(roc) ),
236  256, -0.5, 255.5 );
237  h1->SetMinimum(0);
238  h1->SetMaximum(256);
239  setTitles( h1, Form( "%s [DAC]", dacName.c_str() ),
240  Form( "Vcal %2d <PH> [ADC]", min_vcal[roc] ) );
241  hmin.push_back(h1);
242  fHistList.push_back(h1);
243 
244  } // rocs
245 
246  // data:
247 
248  for( size_t i = 0; i < result.size(); ++i ) {
249 
250  int idac = result[i].first;
251 
252  vector<pixel> vpix = result[i].second;
253 
254  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
255 
256  uint8_t roc = vpix[ipx].roc();
257 
258  if( roc < nRocs &&
259  vpix[ipx].column() == col &&
260  vpix[ipx].row() == row ) {
261  h1 = hmin.at(roc);
262  h1->Fill( idac, vpix[ipx].value()); // already averaged
263  } // valid
264 
265  } // pix
266 
267  } // dac values
268 
269  for( size_t roc = 0; roc < nRocs; ++roc ) {
270  hmin[roc]->Draw();
271  PixTest::update();
272  }
273  fDisplayedHist = find( fHistList.begin(), fHistList.end(), hmin[nRocs-1] );
274 
275  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
276  // scan PH vs VOffsetRO for one pixel per ROC at max Vcal
277 
278  fApi->setDAC( "Vcal", max_vcal );
279 
280  result = fApi->getPulseheightVsDAC( dacName, 0, 255, flags, fParNtrig );
281 
282  // plot:
283 
284  vector<TH1D*> hmax;
285 
286  for( size_t roc = 0; roc < nRocs; ++roc ) {
287 
288  h1 = new TH1D( Form( "PH_vs_%s_at_Vcal_%2d_c%02d_r%02d_C%02d",
289  dacName.c_str(), max_vcal,
290  col, row, int(roc) ),
291  Form( "PH vs %s at Vcal %2d c%02d r%02d C%02d",
292  dacName.c_str(), max_vcal,
293  col, row, int(roc) ),
294  256, -0.5, 255.5 );
295  h1->SetMinimum(0);
296  h1->SetMaximum(256);
297  setTitles( h1, Form( "%s [DAC]", dacName.c_str() ),
298  Form( "Vcal %2d <PH> [ADC]", max_vcal ) );
299  hmax.push_back(h1);
300  fHistList.push_back(h1);
301 
302  } // rocs
303 
304  // data:
305 
306  for( size_t i = 0; i < result.size(); ++i ) {
307 
308  int idac = result[i].first;
309 
310  vector<pixel> vpix = result[i].second;
311 
312  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
313 
314  uint8_t roc = vpix[ipx].roc();
315 
316  if( roc < nRocs &&
317  vpix[ipx].column() == col &&
318  vpix[ipx].row() == row ) {
319  h1 = hmax.at(roc);
320  h1->Fill( idac, vpix[ipx].value()); // already averaged
321  } // valid
322 
323  } // pix
324 
325  } // dac values
326 
327  for( size_t roc = 0; roc < nRocs; ++roc ) {
328  hmax[roc]->Draw();
329  PixTest::update();
330  }
331  fDisplayedHist = find( fHistList.begin(), fHistList.end(), hmax[nRocs-1] );
332 
333  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
334  /* Find VOffsetRO value that puts the midpoint between
335  minimal and maximal Vcal to 133 */
336 
337  int voffset_opt[16];
338  for( size_t i = 0; i < 16; ++i )
339  voffset_opt[i] = -1;
340 
341  for( size_t roc = 0; roc < nRocs; ++roc ) {
342 
343  for( int i = 0; i < 256; ++i ) {
344  int ph0 = static_cast<int>(hmin[roc]->GetBinContent(i+1));
345  if( ph0 <= 0 ) continue;
346  int ph4 = static_cast<int>(hmax[roc]->GetBinContent(i+1));
347  if( ph4 <= 0 ) continue;
348  if( roc == 0 ) {
349  LOG(logINFO) << "VOffsetRO " << setw(3) << i
350  << ": min " << setw(3) << ph0
351  << ", max " << setw(3) << ph4
352  << ", mid " << setw(3) << (ph0+ph4)/2;
353  }
354  if( ( ph0 + ph4 ) / 2 < 133 ) {
355  voffset_opt[roc] = i;
356  break;
357  }
358  }
359  } // rocs
360 
361  // Abort if the mid VoffsetOp could not be found
362 
363  for( size_t roc = 0; roc < nRocs; ++roc ) {
364 
365  if( voffset_opt[roc] == -1 ) {
366  LOG(logINFO)
367  << "[SetPh] Warning: Cannot find VoffsetOp midpoint!";
368  return;
369  }
370 
371  LOG(logINFO)
372  << "[SetPh] Found VOffsetRO value: "
373  << voffset_opt[roc];
374 
375  fApi->setDAC( "VOffsetRO", voffset_opt[roc], roc );
376 
377  } // rocs
378 
379  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
380  // Scan VIref_ADC to stretch the pulse height at max Vcal
381 
382  LOG(logINFO)
383  << "[SetPh] Finding mid VIref_ADC value ...";
384 
385  // Find optimal VIref_ADC using a single pixel
386 
387  fApi->setDAC( "Vcal", max_vcal ); // all ROCs
388 
389  dacName = "VIref_ADC";
390 
391  result = fApi->getPulseheightVsDAC( dacName, 0, 255, flags, fParNtrig );
392 
393  // plot:
394 
395  vector<TH1D*> href;
396 
397  for( size_t roc = 0; roc < nRocs; ++roc ) {
398 
399  h1 = new TH1D( Form( "PH_vs_%s_at_Vcal_%2d_c%02d_r%02d_C%02d",
400  dacName.c_str(), max_vcal,
401  col, row, int(roc) ),
402  Form( "PH vs %s at Vcal %2d c%02d r%02d C%02d",
403  dacName.c_str(), max_vcal,
404  col, row, int(roc) ),
405  256, -0.5, 255.5 );
406  h1->SetMinimum(0);
407  h1->SetMaximum(256);
408  setTitles( h1, Form( "%s [DAC]", dacName.c_str() ),
409  Form( "Vcal %2d <PH> [ADC]", max_vcal ) );
410  href.push_back(h1);
411  fHistList.push_back(h1);
412 
413  } // rocs
414 
415  // data:
416 
417  for( size_t i = 0; i < result.size(); ++i ) {
418 
419  int idac = result[i].first;
420 
421  vector<pixel> vpix = result[i].second;
422 
423  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
424 
425  uint8_t roc = vpix[ipx].roc();
426 
427  if( roc < nRocs &&
428  vpix[ipx].column() == col &&
429  vpix[ipx].row() == row ) {
430  h1 = href.at(roc);
431  h1->Fill( idac, vpix[ipx].value()); // already averaged
432  } // valid
433 
434  } // pix
435 
436  } // dac values
437 
438  for( size_t roc = 0; roc < nRocs; ++roc ) {
439  href[roc]->Draw();
440  PixTest::update();
441  }
442  fDisplayedHist = find( fHistList.begin(), fHistList.end(), href[nRocs-1] );
443 
444  // Adjust VIref_ADC to have PH < 210 for this pixel
445 
446  int viref_adc_opt[16];
447  for( size_t i = 0; i < 16; ++i )
448  viref_adc_opt[i] = -1;
449 
450  for( size_t roc = 0; roc < nRocs; ++roc ) {
451  for( int i = 0; i < 256; ++i ) {
452  int ph = static_cast<int>(href[roc]->GetBinContent(i+1));
453  if( ph <= 0 ) continue;
454  if( ph < 210 ) {
455  viref_adc_opt[roc] = i;
456  break; // VIref_ADC has descending curve
457  }
458  }
459 
460  // Abort if optimal VIref_ADC value could not be found
461 
462  if( viref_adc_opt[roc] == -1 ) {
463  LOG(logINFO)
464  << "[SetPh] Warning: Cannot adjust pulse height range!";
465  return;
466  }
467  LOG(logINFO)
468  << "[SetPh] Found VIref_ADC value: "
469  << viref_adc_opt[roc];
470  fApi->setDAC( dacName, viref_adc_opt[roc], roc ); // for one pixel
471 
472  } // rocs
473 
474  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
475  // check all pixels:
476 
477  fApi->_dut->testAllPixels(true);
478 
479  // book maps per ROC:
480 
481  vector<TH2D*> maps9;
482  TH2D *h2(0);
483  vector<TH1D*> hsts9;
484  //TH1D *h1(0);
485 
486  for( size_t roc = 0; roc < nRocs; ++roc ) {
487 
488  h2 = new TH2D( Form( "maxPhMap_C%d", int(roc) ),
489  Form( "max PH map ROC %d", int(roc) ),
490  52, -0.5, 51.5, 80, -0.5, 79.5 );
491  h2->SetMinimum(0);
492  h2->SetMaximum(256);
493  setTitles( h2, "col", "row" );
494  h2->GetZaxis()->SetTitle( "<PH> [ADC]" );
495  h2->SetStats(0);
496  maps9.push_back(h2);
497  fHistList.push_back(h2);
498 
499  h1 = new TH1D( Form( "maxPhDistribution_C%d", int(roc) ),
500  Form( "max Pulse height distribution ROC %d", int(roc) ),
501  256, -0.5, 255.5 );
502  setTitles( h1, "<PH> [ADC]", "pixels" );
503  h1->SetStats(1);
504  hsts9.push_back(h1);
505  fHistList.push_back(h1);
506  }
507 
508  // measure:
509 
510  fApi->setDAC( "Vcal", max_vcal );
511 
512  bool again = 0;
513  do {
514 
515  vector<pixel> vpix = fApi->getPulseheightMap( flags, fParNtrig ); // all pixels, all ROCs
516 
517  LOG(logINFO) << "vpix.size() " << vpix.size();
518 
519  // data:
520 
521  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
522  h2 = maps9.at( vpix[ipx].roc() );
523  if( h2 ) h2->SetBinContent( vpix[ipx].column() + 1, vpix[ipx].row() + 1,
524  vpix[ipx].value());
525  h1 = hsts9.at( vpix[ipx].roc() );
526  if( h1 ) h1->Fill( vpix[ipx].value());
527  }
528 
529  for( size_t roc = 0; roc < nRocs; ++roc ) {
530  h2 = maps9[roc];
531  h2->Draw("colz");
532  PixTest::update();
533  }
534  fDisplayedHist = find( fHistList.begin(), fHistList.end(), h2 );
535 
536  // check against clipping (ADC overflow):
537 
538  again = 0;
539 
540  for( size_t roc = 0; roc < nRocs; ++roc ) {
541 
542  LOG(logINFO) << "max Ph map for ROC " << roc;
543 
544  Int_t locmaxx,locmaxy,locmaxz;
545  h2 = maps9[roc];
546  h2->GetMaximumBin( locmaxx, locmaxy,locmaxz );
547  double phmax = h2->GetBinContent( locmaxx, locmaxy );
548  LOG(logINFO)
549  << "Ph max " << setw(3) << phmax
550  << " at " << setw(2) << locmaxx-1 // bin counting starts at 1
551  << "," << setw(2) << locmaxy-1; // pixel counting starts at 0
552  if( phmax > 254.5 ) {
553  voffset_opt[roc] += 5; // reduce offset
554  viref_adc_opt[roc] += 3; // reduce gain
555  fApi->setDAC( "VOffsetRO", voffset_opt[roc], roc );
556  fApi->setDAC( "VIref_ADC", viref_adc_opt[roc], roc );
557  LOG(logINFO)
558  << "Found overflow "
559  << " VoffsetOp " << setw(3) << voffset_opt[roc]
560  << " VIref_ADC " << setw(3) << viref_adc_opt[roc];
561  if( voffset_opt[roc] < 251 && viref_adc_opt[roc] < 253 ) {
562  again = 1;
563  hsts9[roc]->Reset();
564  }
565  }
566  else {
567  fApi->_dut->testAllPixels( false, roc ); // remove ROC from list
568  }
569  } // rocs
570  } // do
571  while( again );
572 
573  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
574  // check for underflow:
575 
576  vector<TH2D*> maps0;
577  vector<TH1D*> hsts0;
578 
579  for( size_t roc = 0; roc < nRocs; ++roc ) {
580 
581  h2 = new TH2D( Form( "minPhMap_C%d", int(roc) ),
582  Form( "min PH map ROC %d", int(roc) ),
583  52, -0.5, 51.5, 80, -0.5, 79.5 );
584  h2->SetMinimum(0);
585  h2->SetMaximum(256);
586  setTitles( h2, "col", "row" );
587  h2->GetZaxis()->SetTitle( "<PH> [ADC]" );
588  h2->SetStats(0);
589  maps0.push_back(h2);
590  fHistList.push_back(h2);
591 
592  h1 = new TH1D( Form( "minPhDistribution_C%d", int(roc) ),
593  Form( "min Pulse height distribution ROC %d", int(roc) ),
594  256, -0.5, 255.5 );
595  setTitles( h1, "<PH> [ADC]", "pixels" );
596  h1->SetStats(1);
597  hsts0.push_back(h1);
598  fHistList.push_back(h1);
599  }
600 
601  fApi->_dut->testAllPixels(true);
602 
603  for( size_t roc = 0; roc < nRocs; ++roc )
604  fApi->setDAC( "Vcal", min_vcal[roc], roc );
605 
606  LOG(logINFO) << "check against underflow...";
607 
608  do {
609 
610  vector<pixel> vpix = fApi->getPulseheightMap( flags, fParNtrig );
611 
612  LOG(logINFO) << "vpix.size() " << vpix.size();
613 
614  // protection against non-responding pixels
615  // (distinguish PH zero from no entry)
616 
617  for( size_t roc = 0; roc < nRocs; ++roc ) {
618  h2 = maps0[roc];
619  for( int ix = 0; ix < h2->GetNbinsX(); ++ix )
620  for( int iy = 0; iy < h2->GetNbinsY(); ++iy )
621  h2->SetBinContent( ix + 1, iy + 1, 256 ); // set to max
622  }
623 
624  // data:
625 
626  for( size_t ipx = 0; ipx < vpix.size(); ++ipx ) {
627  if( vpix[ipx].roc() == 0 &&
628  vpix[ipx].column() == 0 &&
629  vpix[ipx].row() == 0 &&
630  vpix[ipx].value() == 0 ) {
631  LOG(logINFO) << "vpix[" << ipx << "] all zero, skipped";
632  continue;
633  }
634  h2 = maps0.at( vpix[ipx].roc() );
635  if( h2 ) h2->SetBinContent( vpix[ipx].column() + 1, vpix[ipx].row() + 1,
636  vpix[ipx].value());
637  h1 = hsts0.at( vpix[ipx].roc() );
638  if( h1 ) h1->Fill( vpix[ipx].value());
639  }
640 
641  for( size_t roc = 0; roc < nRocs; ++roc ) {
642  h2 = maps0[roc];
643  h2->Draw("colz");
644  PixTest::update();
645  }
646  fDisplayedHist = find( fHistList.begin(), fHistList.end(), h2 );
647 
648  // check against underflow:
649 
650  again = 0;
651 
652  for( size_t roc = 0; roc < nRocs; ++roc ) {
653 
654  LOG(logINFO) << "min Ph map for ROC " << roc;
655 
656  Int_t locminx,locminy,locminz;
657  h2 = maps0[roc];
658  h2->GetMinimumBin( locminx, locminy,locminz );
659  double phmin = h2->GetBinContent( locminx, locminy );
660  LOG(logINFO)
661  << "Ph min " << setw(3) << phmin
662  << " at " << setw(2) << locminx-1 // bin counting starts at 1
663  << "," << setw(2) << locminy-1; // pixel counting starts at 0
664  if( phmin < 0.5 ) {
665  voffset_opt[roc] -= 5; // increase offset
666  viref_adc_opt[roc] += 3; // reduce gain
667  fApi->setDAC( "VOffsetRO", voffset_opt[roc], roc );
668  fApi->setDAC( "VIref_ADC", viref_adc_opt[roc], roc );
669  LOG(logINFO)
670  << "Found underflow "
671  << " VoffsetOp " << setw(3) << voffset_opt[roc]
672  << " VIref_ADC " << setw(3) << viref_adc_opt[roc];
673  if( voffset_opt[roc] > 4 && viref_adc_opt[roc] < 253 ) {
674  again = 1;
675  hsts0[roc]->Reset();
676  }
677  }
678  else {
679  fApi->_dut->testAllPixels( false, roc ); // remove ROC from list
680  }
681  } // rocs
682  } // do
683  while( again );
684 
685  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
686  // We have two extreme points:
687  // the pixel with the highest pulse height
688  // the pixel with the lowest pulse height
689  // Two quantities:
690  // mean and range
691  // Two parameters:
692  // offset and gain
693  // Find optimum:
694  // mean = 133
695  // range = 200
696 
697  fApi->_dut->testAllPixels( false ); // mask and disable all
698 
699  for( size_t roc = 0; roc < nRocs; ++roc ) {
700 
701  LOG(logINFO) << "Ph range fine tuning for ROC " << roc;
702 
703  Int_t locminx,locminy,locminz;
704  h2 = maps0[roc];
705  h2->GetMinimumBin( locminx, locminy,locminz );
706  double min_ph = h2->GetBinContent( locminx, locminy );
707  uint32_t min_col = locminx - 1; // bin counting starts at 1
708  uint32_t min_row = locminy - 1; // pixel counting starts at 0
709  LOG(logINFO)
710  << "Ph min " << setw(3) << min_ph
711  << " at " << setw(2) << min_col
712  << "," << setw(2) << min_row;
713 
714  Int_t locmaxx,locmaxy,locmaxz;
715  h2 = maps9[roc];
716  h2->GetMaximumBin( locmaxx, locmaxy,locmaxz );
717  double max_ph = h2->GetBinContent( locmaxx, locmaxy );
718  uint32_t max_col = locmaxx - 1; // bin counting starts at 1
719  uint32_t max_row = locmaxy - 1; // pixel counting starts at 0
720  LOG(logINFO)
721  << "Ph max " << setw(3) << max_ph
722  << " at " << setw(2) << max_col
723  << "," << setw(2) << max_row;
724 
725  int range = static_cast<int>(max_ph - min_ph);
726  int mid = static_cast<int>(max_ph + min_ph)/2;
727  int iter = 0;
728 
729  // iterate:
730 
731  while( ( abs(range-200) > 5 || abs(mid-133) > 5 ) &&
732  voffset_opt[roc] < 255 &&
733  voffset_opt[roc] > 0 &&
734  viref_adc_opt[roc] < 255 &&
735  viref_adc_opt[roc] > 0 ) {
736 
737  LOG(logINFO)
738  << setw(2) << iter
739  << ". gain_dac " << setw(3) << viref_adc_opt[roc]
740  << ", offset_dac " << setw(3) << voffset_opt[roc]
741  << ": min_ph " << setw(3) << min_ph
742  << ", max_ph " << setw(3) << max_ph
743  << ": range " << setw(3) << range
744  << ", mid " << setw(3) << mid
745  << endl;
746 
747  iter++;
748 
749  int dmid = 133-mid;
750  if( abs(dmid) > 5 ) {
751  voffset_opt[roc] -= dmid/2; // slope -1/2;
752  if( voffset_opt[roc] < 0 )
753  voffset_opt[roc] = 0;
754  else if( voffset_opt[roc] > 255 )
755  voffset_opt[roc] = 255;
756  fApi->setDAC( "VOffsetRO", voffset_opt[roc] );
757  }
758 
759  if( range > 205 )
760  fApi->setDAC( "VIref_ADC", ++viref_adc_opt[roc], roc ); // negative slope
761  else if( range < 195 )
762  fApi->setDAC( "VIref_ADC", --viref_adc_opt[roc], roc ); // negative slope
763 
764  fApi->setDAC( "Vcal", min_vcal[roc], roc );
765  fApi->_dut->testPixel( min_col, min_row, true, roc );
766  vector<pixel> vpix0 = fApi->getPulseheightMap( flags, fParNtrig );
767 
768  for( size_t ipx = 0; ipx < vpix0.size(); ++ipx )
769  if( vpix0[ipx].roc() == roc &&
770  vpix0[ipx].column() == min_col &&
771  vpix0[ipx].row() == min_row )
772  min_ph = vpix0[ipx].value();
773  fApi->_dut->testPixel( min_col, min_row, false, roc );
774 
775  fApi->setDAC( "Vcal", max_vcal, roc );
776  fApi->_dut->testPixel( max_col, max_row, true, roc );
777  vector<pixel> vpix9 = fApi->getPulseheightMap( flags, fParNtrig );
778  for( size_t ipx = 0; ipx < vpix9.size(); ++ipx )
779  if( vpix9[ipx].roc() == roc &&
780  vpix9[ipx].column() == max_col &&
781  vpix9[ipx].row() == max_row )
782  max_ph = vpix9[ipx].value();
783  fApi->_dut->testPixel( max_col, max_row, false, roc );
784 
785  range = static_cast<int>(max_ph - min_ph);
786  mid = static_cast<int>(max_ph + min_ph)/2;
787 
788  } // while
789 
790  LOG(logINFO)
791  << setw(2) << iter
792  << ". gain_dac " << setw(3) << viref_adc_opt[roc]
793  << ", offset_dac " << setw(3) << voffset_opt[roc]
794  << ", min_ph " << setw(3) << min_ph
795  << ", max_ph " << setw(3) << max_ph
796  << ", range " << setw(3) << range
797  << ", mid " << setw(3) << mid
798  << endl;
799 
800  LOG(logINFO) << "SetPh Final for ROC " << setw(2) << roc;
801  LOG(logINFO) << " 17 VOffsetRO "
802  << setw(3) << (int) fApi->_dut->getDAC( roc, "VOffsetRO" );
803  LOG(logINFO) << " 20 VIref_ADC "
804  << setw(3) << (int) fApi->_dut->getDAC( roc, "VIref_ADC" );
805 
806  } // rocs
807 
808  fApi->setDAC( "Vcal", cal ); // restore
809  fApi->setDAC( "CtrlReg", ctl ); // restore
810  LOG(logINFO) << "back to CtrlReg " << int(ctl);
811 
812  LOG(logINFO) << "PixTestSetPh::doTest() done for " << nRocs << " ROCs";
813 }
std::vector< pixel > getPulseheightMap(uint16_t flags, uint16_t nTriggers)
Definition: api.cc:1024
std::vector< std::pair< uint8_t, std::vector< pixel > > > getPulseheightVsDAC(std::string dacName, uint8_t dacMin, uint8_t dacMax, uint16_t flags, uint16_t nTriggers)
Definition: api.cc:675
bool setDAC(std::string dacName, uint8_t dacValue, uint8_t rocI2C)
Definition: api.cc:546
PixSetup * fPixSetup
all necessary stuff in one place
Definition: PixTest.hh:290
std::vector< std::pair< int, int > > fPIX
range of enabled pixels for time-consuming tests
Definition: PixTest.hh:311
void testPixel(uint8_t column, uint8_t row, bool enable)
Definition: dut.cc:432
std::vector< std::pair< std::string, std::string > > fParameters
the parameters of this test
Definition: PixTest.hh:302
TDirectory * fDirectory
where the root histograms will end up
Definition: PixTest.hh:306
dut * _dut
Definition: api.h:728
void testAllPixels(bool enable)
Definition: dut.cc:503
std::list< TH1 * >::iterator fDisplayedHist
pointer to the histogram currently displayed
Definition: PixTest.hh:309
virtual bool setParameter(std::string parName, std::string sval)
set the string value of a parameter
Definition: PixTestSetPh.cc:30
std::list< TH1 * > fHistList
list of histograms available in PixTab::next and PixTab::previous
Definition: PixTest.hh:307
void setTitles(TH1 *h, const char *sx, const char *sy, float size=0.05, float xoff=1.1, float yoff=1.1, float lsize=0.05, int font=42)
utility to set histogram titles
Definition: PixTest.cc:649
void update()
signal to PixTab to update the canvas
Definition: PixTest.cc:569
uint8_t getDAC(size_t rocId, std::string dacName)
Definition: dut.cc:314
void setToolTips()
implement this to provide updated tool tips if the user changes test parameters
Definition: PixTestSetPh.cc:74
void doTest()
function connected to "DoTest" button of PixTab
pxar::pxarCore * fApi
pointer to the API
Definition: PixTest.hh:289
void init()
sets all test parameters
Definition: PixTest.cc:62