FACT++  1.0
feedback.cc
Go to the documentation of this file.
1 #include <valarray>
2 #include <algorithm>
3 
4 #include "Dim.h"
5 #include "Event.h"
6 #include "Shell.h"
7 #include "StateMachineDim.h"
8 #include "Connection.h"
9 #include "Configuration.h"
10 #include "Console.h"
11 #include "externals/PixelMap.h"
12 
13 #include "tools.h"
14 
15 #include "LocalControl.h"
16 
17 #include "HeadersFSC.h"
18 #include "HeadersBIAS.h"
19 #include "HeadersFeedback.h"
20 
21 #include "DimState.h"
22 #include "DimDescriptionService.h"
23 
24 using namespace std;
25 
26 // ------------------------------------------------------------------------
27 
29 {
30 private:
32 
33  bool fIsVerbose;
34 
36 
39 
45 
46  vector<float> fCalibCurrentMes[6]; // Measured calibration current at six different levels
47  vector<float> fCalibVoltage[6]; // Corresponding voltage as reported by biasctrl
48 
49  vector<int64_t> fCurrentsAvg;
50  vector<int64_t> fCurrentsRms;
51 
52  vector<float> fVoltGapd; // Nominal breakdown voltage + 1.1V
53  vector<float> fBiasVolt; // Output voltage as reported by bias crate (voltage between R10 and R8)
54  vector<float> fBiasR9; //
55  vector<uint16_t> fBiasDac; // Dac value corresponding to the voltage setting
56 
57  vector<float> fCalibration;
58  vector<float> fCalibDeltaI;
59  vector<float> fCalibR8;
60 
61  int64_t fCursorCur;
62 
66 
67  double fUserOffset;
69  vector<double> fTempOffset;
73  double fTemp;
74 
75  vector<double> fVoltOffset;
76 
77  uint16_t fMoonMode;
78 
80  uint16_t fNumCalibIgnore;
82  uint16_t fCalibStep;
83 
84  uint16_t fTimeoutCritical;
85 
86  // ============================= Handle Services ========================
87 
89  {
90  if (fDimBias.state()==BIAS::State::kVoltageOn && GetCurrentState()==Feedback::State::kCalibrating)
91  {
92  Dim::SendCommandNB("BIAS_CONTROL/REQUEST_STATUS");
93  Info("Starting calibration step "+to_string(fCalibStep));
94  }
95 
96  if (fDimBias.state()==BIAS::State::kVoltageOff && GetCurrentState()>=Feedback::State::kInProgress)
98 
99  return GetCurrentState();
100  }
101  // ============================= Handle Services ========================
102 
103  bool CheckEventSize(size_t has, const char *name, size_t size)
104  {
105  if (has==size)
106  return true;
107 
108  // Disconnected
109  if (has==0)
110  return false;
111 
112  ostringstream msg;
113  msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
114  Fatal(msg);
115  return false;
116  }
117 
118  int HandleBiasNom(const EventImp &evt)
119  {
120  if (evt.GetSize()>=BIAS::kNumChannels*sizeof(float))
121  {
122  fVoltGapd.assign(evt.Ptr<float>(), evt.Ptr<float>()+BIAS::kNumChannels);
123  fBiasR9.assign(evt.Ptr<float>()+2*BIAS::kNumChannels, evt.Ptr<float>()+3*BIAS::kNumChannels);
124 
125  for (int i=0; i<320; i++)
126  fVoltGapd[i] += 1.1;
127 
128  Info("Nominal bias voltages and calibration resistor received.");
129  }
130 
131  return GetCurrentState();
132  }
133 
134  int HandleBiasVoltage(const EventImp &evt)
135  {
136  if (evt.GetSize()>=BIAS::kNumChannels*sizeof(float))
137  fBiasVolt.assign(evt.Ptr<float>(), evt.Ptr<float>()+BIAS::kNumChannels);
138  return GetCurrentState();
139  }
140 
141  int HandleBiasDac(const EventImp &evt)
142  {
143  if (evt.GetSize()>=BIAS::kNumChannels*sizeof(uint16_t))
144  fBiasDac.assign(evt.Ptr<uint16_t>(), evt.Ptr<uint16_t>()+BIAS::kNumChannels);
145  return GetCurrentState();
146  }
147 
148  int HandleCameraTemp(const EventImp &evt)
149  {
150  if (!CheckEventSize(evt.GetSize(), "HandleCameraTemp", 323*sizeof(float)))
151  {
152  fTimeTemp = Time(Time::none);
153  return GetCurrentState();
154  }
155 
156  //fTempOffset = (avgt-25)*0.0561765; // [V] From Hamamatsu datasheet
157  //fTempOffset = (avgt-25)*0.05678; // [V] From Hamamatsu datasheet plus our own measurement (gein vs. temperature)
158 
159  const float *ptr = evt.Ptr<float>(4);
160 
161  fTimeTemp = evt.GetTime();
162  fTemp = evt.Get<float>(321*4);
163 
164  fTempOffsetAvg = (fTemp-25)*fTempCoefficient;
165  fTempOffsetRms = evt.Get<float>(322*4)*fTempCoefficient;
166 
167  fTempOffset.resize(320);
168  for (int i=0; i<320; i++)
169  fTempOffset[i] = (ptr[i]-25)*fTempCoefficient;
170 
171  return GetCurrentState();
172  }
173 
174  pair<vector<float>, vector<float>> AverageCurrents(const int16_t *ptr, int n)
175  {
176  if (fCursorCur++>=0)
177  {
178  for (int i=0; i<BIAS::kNumChannels; i++)
179  {
180  fCurrentsAvg[i] += ptr[i];
181  fCurrentsRms[i] += ptr[i]*ptr[i];
182  }
183  }
184 
185  if (fCursorCur<n)
186  return make_pair(vector<float>(), vector<float>());
187 
188  const double conv = 5e-3/4096;
189 
190  vector<float> rms(BIAS::kNumChannels);
191  vector<float> avg(BIAS::kNumChannels);
192  for (int i=0; i<BIAS::kNumChannels; i++)
193  {
194  avg[i] = double(fCurrentsAvg[i])/fCursorCur * conv;
195  rms[i] = double(fCurrentsRms[i])/fCursorCur * conv * conv;
196  rms[i] -= avg[i]*avg[i];
197  rms[i] = rms[i]<0 ? 0 : sqrt(rms[i]);
198  }
199 
200  return make_pair(avg, rms);
201  }
202 
203  int HandleCalibration(const EventImp &evt)
204  {
205  if (fDimBias.state()!=BIAS::State::kVoltageOn)
206  return GetCurrentState();
207 
208  const uint16_t dac = 256+512*fCalibStep; // Command value
209 
210  // Only the channels which are no spare channels are ramped
211  // Due to the shortcut, only 319 channels are ramped, so only
212  // 320 and not 319 are expected to have the correct day setting
213  if (std::count(fBiasDac.begin(), fBiasDac.end(), dac)!=319/*320*/)
214  return GetCurrentState();
215 
216  const auto rc = AverageCurrents(evt.Ptr<int16_t>(), fNumCalibRequests);
217  if (rc.first.size()==0)
218  {
219  Dim::SendCommandNB("BIAS_CONTROL/REQUEST_STATUS");
220  return GetCurrentState();
221  }
222 
223  const vector<float> &avg = rc.first;
224  const vector<float> &rms = rc.second;
225 
226  // Current through resistor R8
227  fCalibCurrentMes[fCalibStep] = avg; // [A]
228  fCalibVoltage[fCalibStep] = fBiasVolt; // [V]
229 
230  // ------------------------- Update calibration data --------------------
231 
232  struct cal_data
233  {
234  uint32_t dac;
235  float U[BIAS::kNumChannels];
236  float Iavg[BIAS::kNumChannels];
237  float Irms[BIAS::kNumChannels];
238 
239  cal_data() { memset(this, 0, sizeof(cal_data)); }
240  } __attribute__((__packed__));
241 
242  cal_data cal;
243  cal.dac = dac;
244  memcpy(cal.U, fBiasVolt.data(), BIAS::kNumChannels*sizeof(float));
245  memcpy(cal.Iavg, avg.data(), BIAS::kNumChannels*sizeof(float));
246  memcpy(cal.Irms, rms.data(), BIAS::kNumChannels*sizeof(float));
247 
248  fDimCalibration2.setData(cal);
249  fDimCalibration2.Update(fTimeCalib);
250 
251  // -------------------- Start next calibration steo ---------------------
252 
253  if (++fCalibStep<6)
254  {
255  fCursorCur = -fNumCalibIgnore;
256  fCurrentsAvg.assign(BIAS::kNumChannels, 0);
257  fCurrentsRms.assign(BIAS::kNumChannels, 0);
258 
259  // Ramp all channels to the calibration setting except the one
260  // with a shortcut
261  vector<uint16_t> vec(BIAS::kNumChannels, uint16_t(256+512*fCalibStep));
262  vec[272] = 0;
263  Dim::SendCommandNB("BIAS_CONTROL/SET_ALL_CHANNELS_DAC", vec);
264 
265  //Dim::SendCommandNB("BIAS_CONTROL/SET_GLOBAL_DAC", uint16_t(256+512*fCalibStep));
266 
267  return GetCurrentState();
268  }
269 
270  // --------------- Calculate old style calibration ----------------------
271 
272  fCalibration.resize(BIAS::kNumChannels*4);
273 
274  float *pavg = fCalibration.data();
275  float *prms = fCalibration.data()+BIAS::kNumChannels;
276  float *pres = fCalibration.data()+BIAS::kNumChannels*2;
277  float *pUmes = fCalibration.data()+BIAS::kNumChannels*3;
278 
279  for (int i=0; i<BIAS::kNumChannels; i++)
280  {
281  const double I = fCalibCurrentMes[5][i]; // [A]
282  const double U = fBiasVolt[i]; // [V]
283 
284  pavg[i] = I*1e6; // [uA]
285  prms[i] = rms[i]*1e6; // [uA]
286  pres[i] = U/I; // [Ohm]
287  pUmes[i] = U; // [V]
288  }
289 
290  fDimCalibration.setData(fCalibration);
291  fDimCalibration.Update(fTimeCalib);
292 
293  // -------------------- New style calibration --------------------------
294 
295  fCalibDeltaI.resize(BIAS::kNumChannels);
296  fCalibR8.resize(BIAS::kNumChannels);
297 
298  // Linear regression of the values at 256+512*N for N={ 3, 4, 5 }
299  for (int i=0; i<BIAS::kNumChannels; i++)
300  {
301  // x: Idac
302  // y: Iadc
303 
304  double x = 0;
305  double y = 0;
306  double xx = 0;
307  double xy = 0;
308 
309  const int beg = 3;
310  const int end = 5;
311  const int len = end-beg+1;
312 
313  for (int j=beg; j<=end; j++)
314  {
315  const double Idac = (256+512*j)*1e-3/4096;
316 
317  x += Idac;
318  xx += Idac*Idac;
319  y += fCalibCurrentMes[j][i];
320  xy += fCalibCurrentMes[j][i]*Idac;
321  }
322 
323  const double m1 = xy - x*y / len;
324  const double m2 = xx - x*x / len;
325 
326  const double m = m2==0 ? 0 : m1/m2;
327 
328  const double t = (y - m*x) / len;
329 
330  fCalibDeltaI[i] = t; // [A]
331  fCalibR8[i] = 100/m; // [Ohm]
332  }
333 
334  vector<float> v;
335  v.reserve(BIAS::kNumChannels*2);
336  v.insert(v.end(), fCalibDeltaI.begin(), fCalibDeltaI.end());
337  v.insert(v.end(), fCalibR8.begin(), fCalibR8.end());
338 
339  fDimCalibrationR8.setData(v);
340  fDimCalibrationR8.Update(fTimeCalib);
341 
342  // ---------------------------------------------------------------------
343 
344  Info("Calibration successfully done.");
345  Dim::SendCommandNB("BIAS_CONTROL/SET_ZERO_VOLTAGE");
346 
348  }
349 
350  int CheckLimits(const float *I)
351  {
352  const float fAbsoluteMedianCurrentLimit = 85;
353  const float fRelativePixelCurrentLimit3 = 20;
354  const float fRelativePixelCurrentLimit0 = 45;
355 
356  const float fAbsolutePixelCurrentLimit3 = fAbsoluteMedianCurrentLimit + fRelativePixelCurrentLimit3;
357  const float fAbsolutePixelCurrentLimit0 = fAbsoluteMedianCurrentLimit + fRelativePixelCurrentLimit0;
358 
359  const float fRelativeCurrentLimitWarning = 10;//10;
360  const float fRelativeCurrentLimitCritical = 15;//20;
361  const float fRelativeCurrentLimitShutdown = 25;
362 
363  fTimeoutCritical = 3000; // 5s
364 
365  // Copy the calibrated currents
366  vector<float> v(I, I+320);
367 
368  // Exclude the crazy patches (that's currently the best which could be done)
369  v[66] = 0;
370  v[191] = 0;
371  v[193] = 0;
372 
373  sort(v.begin(), v.end());
374 
375  const float &imax0 = v[319];
376  const float &imax3 = v[316];
377  const float &imed = v[161];
378 
379  const bool shutdown =
380  imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitShutdown ||
381  imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitShutdown ||
382  imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitShutdown;
383 
384  const bool critical =
385  imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitCritical ||
386  imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitCritical ||
387  imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitCritical;
388 
389  const bool warning =
390  imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitWarning ||
391  imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitWarning ||
392  imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitWarning;
393 
394  bool standby = GetCurrentState()==Feedback::State::kOnStandby;
395 
396  if (standby)
397  {
398  // On Standby
399  if (fVoltageReduction==0 &&
400  imed <fAbsoluteMedianCurrentLimit &&
401  imax3<fAbsolutePixelCurrentLimit3 &&
402  imax0<fAbsolutePixelCurrentLimit0)
403  {
404  // Currents are back at nominal value and currents are again
405  // below the current limit, switching back to standard operation.
407  }
408  }
409 
410  // Shutdown level
411  if (!standby && shutdown)
412  {
413  // Currents exceed the shutdown limit, operation is switched
414  // immediately to voltage reduced operation
415 
416  // Just in case (FIXME: Is that really the right location?)
417  Dim::SendCommandNB("FAD_CONTROL/CLOSE_ALL_OPEN_FILES");
418 
419  Error("Current limit for shutdown exceeded.... switching to standby mode.");
420 
421  standby = true;
422  }
423 
424  // Critical level
425  if (!standby && critical)
426  {
427  // This is a state transition from InProgress or Warning to Critical.
428  // Keep the transition time.
429  if (GetCurrentState()==Feedback::State::kInProgress || GetCurrentState()==Feedback::State::kWarning)
430  {
431  Info("Critical current limit exceeded.... waiting for "+to_string(fTimeoutCritical)+" ms.");
432  fTimeCritical = Time();
433  }
434 
435  // Critical is only allowed for fTimeoutCritical milliseconds.
436  // After this time, the operation is changed to reduced voltage.
437  if (Time()<fTimeCritical+boost::posix_time::milliseconds(fTimeoutCritical))
439 
440  // Just in case (FIXME: Is that really the right location?)
441  Dim::SendCommandNB("FAD_CONTROL/CLOSE_ALL_OPEN_FILES");
442 
443  // Currents in critical state
444  Warn("Critical current limit exceeded timeout.... switching to standby mode.");
445 
446  standby = true;
447  }
448 
449  // Warning level (is just informational)
450  if (!standby && warning)
452 
453  // keep voltage
455  }
456 
457  int HandleBiasCurrent(const EventImp &evt)
458  {
459  if (!CheckEventSize(evt.GetSize(), "HandleBiasCurrent", BIAS::kNumChannels*sizeof(uint16_t)))
461 
462  if (GetCurrentState()<Feedback::State::kCalibrating)
463  return GetCurrentState();
464 
465  // ------------------------------- HandleCalibration -----------------------------------
466  if (GetCurrentState()==Feedback::State::kCalibrating)
467  return HandleCalibration(evt);
468 
469  // ---------------------- Calibrated, WaitingForData, InProgress -----------------------
470 
471  // We are waiting but no valid temperature yet, go on waiting
472  if (GetCurrentState()==Feedback::State::kWaitingForData &&
473  (!fTimeTemp.IsValid() || Time()-fTimeTemp>boost::posix_time::minutes(5)))
474  return GetCurrentState();
475 
476  // We are waiting but biasctrl is still in ramping (this might
477  // be the case if the feedback was started with a new overvoltage
478  // while the last ramping command was still in progress)
479  if (GetCurrentState()==Feedback::State::kWaitingForData &&
480  fDimBias.state()==BIAS::State::kRamping)
481  return GetCurrentState();
482 
483  // We are already in progress but no valid temperature update anymore
484  if (GetCurrentState()>=Feedback::State::kInProgress &&
485  (!fTimeTemp.IsValid() || Time()-fTimeTemp>boost::posix_time::minutes(5)))
486  {
487  Warn("Current control in progress, but last received temperature older than 5min... switching voltage off.");
488  Dim::SendCommandNB("BIAS_CONTROL/SET_ZERO_VOLTAGE");
490  }
491 
492  // ---------------------- Calibrated, WaitingForData, InProgress -----------------------
493 
494  const int Navg = fDimBias.state()!=BIAS::State::kVoltageOn ? 1 : 3;
495 
496  const vector<float> &Imes = AverageCurrents(evt.Ptr<int16_t>(), Navg).first;
497  if (Imes.size()==0)
498  return GetCurrentState();
499 
500  fCurrentsAvg.assign(BIAS::kNumChannels, 0);
501  fCurrentsRms.assign(BIAS::kNumChannels, 0);
502  fCursorCur = 0;
503 
504  // -------------------------------------------------------------------------------------
505  // Inner patches to be blocked (operated below the operation voltage) in moon mode
506 
507  static const array<int, 14> inner0 =
508  {{
509  62, 63, 130, 131, 132, 133, 134,
510  135, 222, 223, 292, 293, 294, 295,
511  }};
512 
513  static const array<int, 23> inner1 =
514  {{
515  58, 59, 60, 61, 129, 138, 139, 140, 141, 142, 143, 218,
516  219, 220, 221, 290, 291, 298, 299, 300, 301, 302, 303,
517  }};
518 
519  static const array<int, 43> inner2 =
520  {{
521  42, 43, 44, 45, 55, 56, 57, 70, 71, 78, 79,
522  96, 97, 98, 99, 102, 103, 128, 136, 137, 159, 202,
523  203, 204, 205, 214, 216, 217, 228, 230, 231, 256, 257,
524  258, 259, 262, 263, 288, 289, 296, 297, 310, 318
525  }};
526 
527  // -------------------------------------------------------------------------------------
528 
529  // Nominal overvoltage (w.r.t. the bias setup values)
530  const double voltageoffset = GetCurrentState()<Feedback::State::kWaitingForData ? 0 : fUserOffset;
531 
532  double avg[2] = { 0, 0 };
533  double min[2] = { 90, 90 };
534  double max[2] = { -90, -90 };
535  int num[3] = { 0, 0, 0 };
536 
537  vector<double> med[3];
538  med[0].resize(BIAS::kNumChannels);
539  med[1].resize(BIAS::kNumChannels);
540  med[2].resize(BIAS::kNumChannels);
541 
542  struct dim_data
543  {
544  float I[BIAS::kNumChannels];
545  float Iavg;
546  float Irms;
547  float Imed;
548  float Idev;
549  uint32_t N;
550  float Tdiff;
551  float Uov[BIAS::kNumChannels];
552  float Unom;
553  float dUtemp;
554 
555  dim_data() { memset(this, 0, sizeof(dim_data)); }
556  } __attribute__((__packed__));
557 
558  int Ndev[3] = { 0, 0, 0 };
559 
560  dim_data data;
561 
562  data.Unom = voltageoffset;
563  data.dUtemp = fTempOffsetAvg;
564 
565  vector<float> vec(BIAS::kNumChannels);
566 
567  // ================================= old =======================
568  // Pixel 583: 5 31 == 191 (5) C2 B3 P3
569  // Pixel 830: 2 2 == 66 (4) C0 B8 P1
570  // Pixel 1401: 6 1 == 193 (5) C2 B4 P0
571 
572  double UdrpAvg = 0;
573  double UdrpRms = 0;
574 
575  for (int i=0; i<320/*BIAS::kNumChannels*/; i++)
576  {
577  const PixelMapEntry &hv = fMap.hv(i);
578  if (!hv)
579  continue;
580 
581  // Check if this is a blocked channel
582  // 272 is the one with the shortcut
583  const bool blocked =
584  (fMoonMode>0 && std::find(inner0.begin(), inner0.end(), i)!=inner0.end()) ||
585  (fMoonMode>1 && std::find(inner1.begin(), inner1.end(), i)!=inner1.end()) ||
586  (fMoonMode>2 && std::find(inner2.begin(), inner2.end(), i)!=inner2.end()) ||
587  i==272;
588 
589  // Number of G-APDs in this patch
590  const int N = hv.count();
591 
592  // Average measured ADC value for this channel
593  // FIXME: This is a workaround for the problem with the
594  // readout of bias voltage channel 263
595  const double adc = Imes[i]/* * (5e-3/4096)*/; // [A]
596 
597  // Current through ~100 Ohm measurement resistor
598  //const double I8 = (adc-fCalibDeltaI[i])*fCalibR8[i]/100;
599  const double I8 = adc-fCalibDeltaI[i];
600 
601  // Current through calibration resistors (R9)
602  // This is uncalibrated, but since the corresponding calibrated
603  // value I8 is subtracted, the difference should yield a correct value
604  const double I9 = fBiasDac[i] * (1e-3/4096);//U9/R9; [A]
605 
606  // Current in R4/R5 branch
607  //const double Iout = I8 - I9;//I8>I9 ? I8 - I9 : 0;
608  const double Iout = I8 - I9*100/fCalibR8[i];//I8>I9 ? I8 - I9 : 0;
609 
610  // Applied voltage at calibration resistors, according to biasctrl
611  const double U9 = fBiasVolt[i];
612 
613  // new I8 - I9*100/fCalibR8 100
614  // change = --- = ---------------------- = -------- = 0.8
615  // old I8*fCalibR8/100 - I9 fCalibR8
616 
617  // Serial resistors (one 1kOhm at the output of the bias crate, one 1kOhm in the camera)
618  const double R4 = 2000;
619 
620  // Serial resistor of the individual G-APDs plus 50 Ohm termination
621  double R5 = 3900./N + 50;
622 
623  // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
624  if (i==66 || i==193) // Pixel 830(66) / Pixel 583(191)
625  R5 = 1./((N-1)/3900.+1/1000.);
626  if (i==191) // Pixel 1399(193)
627  R5 = 1./((N-1)/3900.+1/390.);
628  if (i==17 || i==206) // dead pixel 923(80) / dead pixel 424(927)
629  R5 = 3900./(N-1); // cannot identify third dead pixel in light-pulser data
630 
631  // The measurement resistor
632  const double R8 = 0;
633 
634  // Total resistance of branch with diodes (R4+R5)
635  // Assuming that the voltage output of the OpAMP is linear
636  // with the DAC setting and not the voltage at R9, the
637  // additional voltage drop at R8 must be taken into account
638  const double R = R4 + R5 + R8;
639 
640  // For the patches with a broken resistor - ignoring the G-APD resistance -
641  // we get:
642  //
643  // I[R=3900] = Iout * 1/(10+(N-1)) = Iout /(N+9)
644  // I[R= 390] = Iout * (1 - 1/(10+(N-1))) = Iout * (N+8)/(N+9)
645  //
646  // I[R=390] / I[R=3900] = N+8
647  //
648  // Udrp = Iout*3900/(N+9) + Iout*1000 + Iout*1000 = Iout * R
649 
650  // Voltage drop in R4/R5 branch (for the G-APDs with correct resistor)
651  // The voltage drop should not be <0, otherwise an unphysical value
652  // would be amplified when Uset is calculated.
653  const double Udrp = Iout<0 ? 0 : R*Iout;
654 
655  // Nominal operation voltage with correction for temperature dependence
656  const double Uop = fVoltGapd[i] + fVoltOffset[i] + fTempOffset[i]
657  + (blocked ? -5 : 0);
658 
659  // Current overvoltage (at a G-APD with the correct 3900 Ohm resistor)
660  // expressed w.r.t. to the operation voltage
661  const double Uov = (U9-Udrp)-Uop>-1.4 ? (U9-Udrp)-Uop : -1.4;
662 
663  // The current through one G-APD is the sum divided by the number of G-APDs
664  // (assuming identical serial resistors)
665  double Iapd = Iout/N;
666 
667  // Rtot = Uapd/Iout
668  // Ich = Uapd/Rch = (Rtot*Iout) / Rch = Rtot/Rch * Iout
669  //
670  // Rtot = 3900/N
671  // Rch = 3900
672  //
673  // Rtot = 1./((N-1)/3900 + 1/X) X=390 or X=1000
674  // Rch = 3900
675  //
676  // Rtot/Rch = 1/((N-1)/3900 + 1/X)/3900
677  // Rtot/Rch = 1/( [ X*(N-1) + 3900 ] / [ 3900 * X ])/3900
678  // Rtot/Rch = X/( [ X*(N-1)/3900 + 1 ] )/3900
679  // Rtot/Rch = X/( [ X*(N-1) + 3900 ] )
680  // Rtot/Rch = 1/( [ (N-1) + 3900/X ] )
681  //
682  // Rtot/Rch[390Ohm] = 1/( [ N + 9.0 ] )
683  // Rtot/Rch[1000Ohm] = 1/( [ N + 2.9 ] )
684  //
685  // In this and the previosu case we neglect the resistance of the G-APDs, but we can make an
686  // assumption: The differential resistance depends more on the NSB than on the PDE,
687  // thus it is at least comparable for all G-APDs in the patch. In addition, although the
688  // G-APD with the 390Ohm serial resistor has the wrong voltage applied, this does not
689  // significantly influences the ohmic resistor or the G-APD because the differential
690  // resistor is large enough that the increase of the overvoltage does not dramatically
691  // increase the current flow as compared to the total current flow.
692  if (i==66 || i==193) // Iout/13 15.8 / Iout/14 16.8
693  Iapd = Iout/(N+2.9);
694  if (i==191) // Iout/7.9 38.3
695  Iapd = Iout/(N+9);
696  if (i==17 || i==206)
697  Iapd = Iout/(N-1);
698 
699  // The differential resistance of the G-APD, i.e. the dependence of the
700  // current above the breakdown voltage, is given by
701  //const double Rapd = Uov/Iapd;
702  // This allows us to estimate the current Iov at the overvoltage we want to apply
703  //const double Iov = overvoltage/Rapd;
704 
705  // Estimate set point for over-voltage (voltage drop at the target point)
706  // This estimation is based on the linear increase of the
707  // gain with voltage and the increase of the crosstalk with
708  // voltage, as measured with the overvoltage-tests (OVTEST)
709  /*
710  Uov+0.44<0.022 ?
711  Ubd + overvoltage + Udrp*exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44), 0.6) :
712  Ubd + overvoltage + Udrp*exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44)/(Uov+0.44), 0.6);
713  */
714  const double Uset =
715  Uov+1.4<0.022 ?
716  Uop + voltageoffset + Udrp*exp(0.6*(voltageoffset-Uov))*pow((voltageoffset+1.4), 0.6) :
717  Uop + voltageoffset + Udrp*exp(0.6*(voltageoffset-Uov))*pow((voltageoffset+1.4)/(Uov+1.4), 0.6);
718 
719  if (fabs(voltageoffset-Uov)>0.033)
720  Ndev[0]++;
721  if (fabs(voltageoffset-Uov)>0.022)
722  Ndev[1]++;
723  if (fabs(voltageoffset-Uov)>0.011)
724  Ndev[2]++;
725 
726  // Voltage set point
727  vec[i] = Uset;
728 
729  const double iapd = Iapd*1e6; // A --> uA
730 
731  data.I[i] = iapd;
732  data.Uov[i] = Uov;
733 
734  if (!blocked)
735  {
736  const int g = hv.group();
737 
738  med[g][num[g]] = Uov;
739  avg[g] += Uov;
740  num[g]++;
741 
742  if (Uov<min[g])
743  min[g] = Uov;
744  if (Uov>max[g])
745  max[g] = Uov;
746 
747  data.Iavg += iapd;
748  data.Irms += iapd*iapd;
749 
750  med[2][num[2]++] = iapd;
751 
752  UdrpAvg += Udrp;
753  UdrpRms += Udrp*Udrp;
754  }
755  }
756 
757 
758  // ---------------------------- Calculate statistics ----------------------------------
759 
760  // average and rms
761  data.Iavg /= num[2];
762  data.Irms /= num[2];
763  data.Irms -= data.Iavg*data.Iavg;
764 
765  data.N = num[2];
766  data.Irms = data.Irms<0 ? 0: sqrt(data.Irms);
767 
768  // median
769  sort(med[2].data(), med[2].data()+num[2]);
770 
771  data.Imed = num[2]%2 ? med[2][num[2]/2] : (med[2][num[2]/2-1]+med[2][num[2]/2])/2;
772 
773  // deviation
774  for (int i=0; i<num[2]; i++)
775  med[2][i] = fabs(med[2][i]-data.Imed);
776 
777  sort(med[2].data(), med[2].data()+num[2]);
778 
779  data.Idev = med[2][uint32_t(0.682689477208650697*num[2])];
780 
781  // time difference to calibration
782  data.Tdiff = evt.GetTime().UnixTime()-fTimeCalib.UnixTime();
783 
784  // Average overvoltage
785  const double Uov = (avg[0]+avg[1])/(num[0]+num[1]);
786 
787  // ------------------------------- Update voltages ------------------------------------
788 
789  int newstate = GetCurrentState();
790 
791  if (GetCurrentState()!=Feedback::State::kCalibrated) // WaitingForData, OnStandby, InProgress, kWarning, kCritical
792  {
793  if (fDimBias.state()!=BIAS::State::kRamping)
794  {
795  newstate = CheckLimits(data.I);
796 
797  // standby and change reduction level of voltage
798  if (newstate==Feedback::State::kOnStandby)
799  {
800  // Calculate average applied overvoltage and estimate an offset
801  // to reach fAbsoluteMedianCurrentLimit
802  float fAbsoluteMedianCurrentLimit = 85;
803  const double deltaU = (Uov+1.4)*(1-pow(fAbsoluteMedianCurrentLimit/data.Imed, 1./1.7));
804 
805  if (fVoltageReduction+deltaU<0.033)
806  fVoltageReduction = 0;
807  else
808  {
809  fVoltageReduction += deltaU;
810 
811  for (int i=0; i<320; i++)
812  vec[i] -= fVoltageReduction;
813  }
814  }
815 
816  // FIXME: What if the brightest pixel gets too bright???
817  // FIXME: What if fVolatgeReduction > U1.4V?
818 
819  // set voltage in 262 -> current in 262/263
820  vec[263] = vec[262]-fVoltGapd[262]+fVoltGapd[263];
821 
822  // Do not ramp the channel with a shortcut
823  vec[272] = 0;
824 
825 // if (fDimBias.state()!=BIAS::State::kRamping)
826 // {
827  DimClient::sendCommandNB("BIAS_CONTROL/SET_ALL_CHANNELS_VOLTAGE",
828  vec.data(), BIAS::kNumChannels*sizeof(float));
829 
830  UdrpAvg /= 320;
831  UdrpRms /= 320;
832  UdrpRms -= UdrpAvg*UdrpAvg;
833  UdrpRms = UdrpRms<0 ? 0 : sqrt(UdrpRms);
834 
835  ostringstream msg;
836  msg << fixed;
837  msg << setprecision(2) << "dU(" << fTemp << "degC)="
838  << setprecision(3) << fTempOffsetAvg << "V+-" << fTempOffsetRms << " Udrp="
839  << UdrpAvg << "V+-" << UdrpRms;
840  msg.unsetf(ios_base::floatfield);
841 
842  if (fVoltageReduction==0)
843  msg << " Unom=" << voltageoffset << "V";
844  else
845  msg << " Ured=" << fVoltageReduction << "V";
846 
847  msg << " Uov=" << Uov;
848  msg << " Imed=" << data.Imed << "uA [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
849  Info(msg);
850  }
851  }
852  else
853  {
854  if (fDimBias.state()==BIAS::State::kVoltageOn)
855  {
856  ostringstream msg;
857  msg << setprecision(4) << "Current status: dU(" << fTemp << "degC)=" << fTempOffsetAvg << "V+-" << fTempOffsetRms << ", Unom=" << voltageoffset << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0) << " [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
858  Info(msg);
859  }
860  }
861 
862  //if (GetCurrentState()>=Feedback::State::kOnStandby &&
863  // fDimBias.state()==BIAS::State::kRamping)
864  // return newstate;
865 
866  // --------------------------------- Console out --------------------------------------
867 
868  if (fIsVerbose && fDimBias.state()!=BIAS::State::kRamping)
869  {
870  sort(med[0].begin(), med[0].begin()+num[0]);
871  sort(med[1].begin(), med[1].begin()+num[1]);
872 
873  ostringstream msg;
874  msg << " Avg0=" << setw(7) << avg[0]/num[0] << " | Avg1=" << setw(7) << avg[1]/num[1];
875  Debug(msg);
876 
877  msg.str("");
878  msg << " Med0=" << setw(7) << med[0][num[0]/2] << " | Med1=" << setw(7) << med[1][num[1]/2];
879  Debug(msg);
880 
881  msg.str("");
882  msg << " Min0=" << setw(7) << min[0] << " | Min1=" << setw(7) << min[1];
883  Debug(msg);
884 
885  msg.str("");
886  msg << " Max0=" << setw(7) << max[0] << " | Max1=" << setw(7) << max[1];
887  Debug(msg);
888  }
889 
890  // ---------------------------- Calibrated Currents -----------------------------------
891 
892  // FIXME:
893  // + Current overvoltage
894  // + Temp offset
895  // + User offset
896  // + Command overvoltage
897  fDimCurrents.setQuality(GetCurrentState());
898  fDimCurrents.setData(&data, sizeof(dim_data));
899  fDimCurrents.Update(evt.GetTime());
900 
901  // FIXME: To be checked
902  return GetCurrentState()==Feedback::State::kCalibrated ? Feedback::State::kCalibrated : newstate;
903  }
904 
905  // ======================================================================
906 
907  int Print() const
908  {
909  Out() << fDim << endl;
910  Out() << fDimFSC << endl;
911  Out() << fDimBias << endl;
912 
913  return GetCurrentState();
914  }
915 
917  {
918  /*
919  if (fCalibration.size()==0)
920  {
921  Out() << "No calibration performed so far." << endl;
922  return GetCurrentState();
923  }
924 
925  const float *avg = fCalibration.data();
926  const float *rms = fCalibration.data()+BIAS::kNumChannels;
927  const float *res = fCalibration.data()+BIAS::kNumChannels*2;
928 
929  Out() << "Average current at " << fCalibrationOffset << "V below G-APD operation voltage:\n";
930 
931  for (int k=0; k<13; k++)
932  for (int j=0; j<8; j++)
933  {
934  Out() << setw(2) << k << "|" << setw(2) << j*4 << "|";
935  for (int i=0; i<4; i++)
936  Out() << Tools::Form(" %6.1f+-%4.1f", avg[k*32+j*4+i], rms[k*32+j*4+i]);
937  Out() << '\n';
938  }
939  Out() << '\n';
940 
941  Out() << "Measured calibration resistor:\n";
942  for (int k=0; k<13; k++)
943  for (int j=0; j<4; j++)
944  {
945  Out() << setw(2) << k << "|" << setw(2) << j*8 << "|";
946  for (int i=0; i<8; i++)
947  Out() << Tools::Form(" %5.0f", res[k*32+j*8+i]);
948  Out() << '\n';
949  }
950 
951  Out() << flush;
952  */
953  return GetCurrentState();
954  }
955 
956  int SetVerbosity(const EventImp &evt)
957  {
958  if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
959  return kSM_FatalError;
960 
961  fIsVerbose = evt.GetBool();
962 
963  return GetCurrentState();
964  }
965 
967  {
968  if (!CheckEventSize(evt.GetSize(), "SetCurrentRequestInterval", 2))
969  return kSM_FatalError;
970 
971  fCurrentRequestInterval = evt.GetUShort();
972 
973  Info("New current request interval: "+to_string(fCurrentRequestInterval)+"ms");
974 
975  return GetCurrentState();
976  }
977 
978  int SetMoonMode(const EventImp &evt)
979  {
980  if (!CheckEventSize(evt.GetSize(), "SetMoonMode", 2))
981  return kSM_FatalError;
982 
983  fMoonMode = evt.GetUShort();
984  if (fMoonMode>3)
985  fMoonMode=3;
986 
987  Info("New moon mode: "+to_string(fMoonMode));
988 
989  return GetCurrentState();
990  }
991 
992  int Calibrate()
993  {
994  if (fDimBias.state()!=BIAS::State::kVoltageOff)
995  {
996  Warn("Calibration can only be started when biasctrl is in state VoltageOff.");
997  return GetCurrentState();
998  }
999 
1000  Message("Starting calibration (ignore="+to_string(fNumCalibIgnore)+", N="+to_string(fNumCalibRequests)+")");
1001 
1002  fCursorCur = -fNumCalibIgnore;
1003  fCurrentsAvg.assign(BIAS::kNumChannels, 0);
1004  fCurrentsRms.assign(BIAS::kNumChannels, 0);
1005 
1006  fBiasDac.assign(BIAS::kNumChannels, 0);
1007 
1008  fCalibStep = 3;
1009  fTimeCalib = Time();
1010 
1011  // Ramp all channels to the calibration setting except the one
1012  // with a shortcut
1013  vector<uint16_t> vec(BIAS::kNumChannels, uint16_t(256+512*fCalibStep));
1014  vec[272] = 0;
1015  Dim::SendCommandNB("BIAS_CONTROL/SET_ALL_CHANNELS_DAC", vec);
1016 
1017  //Dim::SendCommandNB("BIAS_CONTROL/SET_GLOBAL_DAC", uint16_t(256+512*fCalibStep));
1018 
1020  }
1021 
1022  int Start(const EventImp &evt)
1023  {
1024  if (!CheckEventSize(evt.GetSize(), "Start", 4))
1025  return kSM_FatalError;
1026 
1027  /*
1028  if (fDimBias.state()==BIAS::State::kRamping)
1029  {
1030  Warn("Feedback can not be started when biasctrl is in state Ramping.");
1031  return GetCurrentState();
1032  }*/
1033 
1034  fUserOffset = evt.GetFloat()-1.1;
1035  fVoltageReduction = 0;
1036 
1037  fCursorCur = 0;
1038 
1039  fCurrentsAvg.assign(BIAS::kNumChannels, 0);
1040  fCurrentsRms.assign(BIAS::kNumChannels, 0);
1041 
1042  ostringstream out;
1043  out << "Starting feedback with an offset of " << fUserOffset << "V";
1044  Message(out);
1045 
1046  if (fMoonMode>0)
1047  Message("Moon mode "+to_string(fMoonMode)+" turned on.");
1048 
1050  }
1051 
1053  {
1054  if (GetCurrentState()==Feedback::State::kCalibrating)
1056 
1057  if (GetCurrentState()>Feedback::State::kCalibrated)
1059 
1060  return GetCurrentState();
1061  }
1062 
1063  bool LoadOffsets(const string &file)
1064  {
1065  vector<double> data(BIAS::kNumChannels);
1066 
1067  ifstream fin(file);
1068 
1069  int cnt = 0;
1070  while (fin && cnt<320)
1071  fin >> data[cnt++];
1072 
1073  if (cnt!=320)
1074  {
1075  Error("Reading offsets from "+file+" failed [N="+to_string(cnt-1)+"]");
1076  return false;
1077  }
1078 
1079  fVoltOffset = data;
1080 
1081  fDimOffsets.Update(fVoltOffset);
1082 
1083  Info("New voltage offsets loaded from "+file);
1084  return true;
1085 
1086  }
1087 
1088  int LoadOffset(const EventImp &evt)
1089  {
1090  LoadOffsets(evt.GetText());
1091  return GetCurrentState();
1092  }
1093 
1095  {
1096  fVoltOffset.assign(BIAS::kNumChannels, 0);
1097 
1098  fDimOffsets.Update(fVoltOffset);
1099 
1100  Info("Voltage offsets resetted.");
1101  return GetCurrentState();
1102  }
1103 
1105  {
1106  ofstream fout("feedback-calib.bin");
1107 
1108  double mjd = fTimeCalib.Mjd();
1109  fout.write((char*)&mjd, sizeof(double));
1110  fout.write((char*)fCalibDeltaI.data(), BIAS::kNumChannels*sizeof(float));
1111  fout.write((char*)fCalibR8.data(), BIAS::kNumChannels*sizeof(float));
1112 
1113  return GetCurrentState();
1114  }
1115 
1117  {
1118  ifstream fin("feedback-calib.bin");
1119 
1120  double mjd;
1121 
1122  vector<float> di(BIAS::kNumChannels);
1123  vector<float> r8(BIAS::kNumChannels);
1124 
1125  fin.read((char*)&mjd, sizeof(double));
1126  fin.read((char*)di.data(), BIAS::kNumChannels*sizeof(float));
1127  fin.read((char*)r8.data(), BIAS::kNumChannels*sizeof(float));
1128 
1129  if (!fin)
1130  {
1131  Warn("Reading of calibration failed.");
1132  return GetCurrentState();
1133  }
1134 
1135  fTimeCalib.Mjd(mjd);
1136  fCalibDeltaI = di;
1137  fCalibR8 = r8;
1138 
1140  }
1141 
1142 
1143 
1144  int Execute()
1145  {
1146  if (!fDim.online())
1148 
1149  const bool bias = fDimBias.state() >= BIAS::State::kConnecting;
1150  const bool fsc = fDimFSC.state() >= FSC::State::kConnected;
1151 
1152  // All subsystems are not connected
1153  if (!bias && !fsc)
1155 
1156  // Not all subsystems are yet connected
1157  if (!bias || !fsc)
1159 
1160  if (GetCurrentState()<Feedback::State::kCalibrating)
1162 
1163  if (GetCurrentState()==Feedback::State::kConnected)
1164  return GetCurrentState();
1165  if (GetCurrentState()==Feedback::State::kCalibrating)
1166  return GetCurrentState();
1167 
1168  // kCalibrated, kWaitingForData, kInProgress
1169 
1170  if (fDimBias.state()==BIAS::State::kVoltageOn || (fDimBias.state()==BIAS::State::kVoltageOff && GetCurrentState()==Feedback::State::kWaitingForData))
1171  {
1172  static Time past;
1173  if (fCurrentRequestInterval>0 && Time()-past>boost::posix_time::milliseconds(fCurrentRequestInterval))
1174  {
1175  Dim::SendCommandNB("BIAS_CONTROL/REQUEST_STATUS");
1176  past = Time();
1177  }
1178  }
1179 
1180  return GetCurrentState();
1181  }
1182 
1183 public:
1184  StateMachineFeedback(ostream &out=cout) : StateMachineDim(out, "FEEDBACK"),
1185  fIsVerbose(false),
1186  //---
1187  fDimFSC("FSC_CONTROL"),
1188  fDimBias("BIAS_CONTROL"),
1189  //---
1190  fDimCalibration("FEEDBACK/CALIBRATION", "F:416;F:416;F:416;F:416",
1191  "Current offsets"
1192  "|Avg[uA]:Average offset at dac=256+5*512"
1193  "|Rms[uA]:Rms of Avg"
1194  "|R[Ohm]:Measured calibration resistor"
1195  "|U[V]:Corresponding voltage reported by biasctrl"),
1196  fDimCalibration2("FEEDBACK/CALIBRATION_STEPS", "I:1;F:416;F:416;F:416",
1197  "Calibration of the R8 resistor"
1198  "|DAC[dac]:DAC setting"
1199  "|U[V]:Corresponding voltages reported by biasctrl"
1200  "|Iavg[uA]:Averaged measured current"
1201  "|Irms[uA]:Rms measured current"),
1202  fDimCalibrationR8("FEEDBACK/CALIBRATION_R8", "F:416;F:416",
1203  "Calibration of R8"
1204  "|DeltaI[uA]:Average offset"
1205  "|R8[Ohm]:Measured effective resistor R8"),
1206  fDimCurrents("FEEDBACK/CALIBRATED_CURRENTS", "F:416;F:1;F:1;F:1;F:1;I:1;F:1;F:416;F:1;F:1",
1207  "Calibrated currents"
1208  "|I[uA]:Calibrated currents per pixel"
1209  "|I_avg[uA]:Average calibrated current (N channels)"
1210  "|I_rms[uA]:Rms of calibrated current (N channels)"
1211  "|I_med[uA]:Median calibrated current (N channels)"
1212  "|I_dev[uA]:Deviation of calibrated current (N channels)"
1213  "|N[uint16]:Number of valid values"
1214  "|T_diff[s]:Time difference to calibration"
1215  "|U_ov[V]:Calculated overvoltage w.r.t. operation voltage"
1216  "|U_nom[V]:Nominal overvoltage w.r.t. operation voltage"
1217  "|dU_temp[V]:Correction calculated from temperature"
1218  ),
1219  fDimOffsets("FEEDBACK/OFFSETS", "F:416",
1220  "Offsets operation voltages"
1221  "|U[V]:Offset per bias channels"),
1222  fVoltOffset(BIAS::kNumChannels),
1223  fMoonMode(0),
1224  fCurrentRequestInterval(0),
1225  fNumCalibIgnore(30),
1226  fNumCalibRequests(300)
1227  {
1228  fDim.Subscribe(*this);
1229  fDimFSC.Subscribe(*this);
1230  fDimBias.Subscribe(*this);
1231 
1233 
1234  Subscribe("BIAS_CONTROL/CURRENT")
1235  (bind(&StateMachineFeedback::HandleBiasCurrent, this, placeholders::_1));
1236  Subscribe("BIAS_CONTROL/VOLTAGE")
1237  (bind(&StateMachineFeedback::HandleBiasVoltage, this, placeholders::_1));
1238  Subscribe("BIAS_CONTROL/DAC")
1239  (bind(&StateMachineFeedback::HandleBiasDac, this, placeholders::_1));
1240  Subscribe("BIAS_CONTROL/NOMINAL")
1241  (bind(&StateMachineFeedback::HandleBiasNom, this, placeholders::_1));
1242  Subscribe("FSC_CONTROL/BIAS_TEMP")
1243  (bind(&StateMachineFeedback::HandleCameraTemp, this, placeholders::_1));
1244 
1245  // State names
1246  AddStateName(Feedback::State::kDimNetworkNA, "DimNetworkNotAvailable",
1247  "The Dim DNS is not reachable.");
1248 
1249  AddStateName(Feedback::State::kDisconnected, "Disconnected",
1250  "The Dim DNS is reachable, but the required subsystems are not available.");
1251  AddStateName(Feedback::State::kConnecting, "Connecting",
1252  "Either biasctrl or fscctrl not connected.");
1253  AddStateName(Feedback::State::kConnected, "Connected",
1254  "biasctrl and fscctrl are available and connected with their hardware.");
1255 
1256  AddStateName(Feedback::State::kCalibrating, "Calibrating",
1257  "Bias crate calibrating in progress.");
1258  AddStateName(Feedback::State::kCalibrated, "Calibrated",
1259  "Bias crate calibrated.");
1260 
1261  AddStateName(Feedback::State::kWaitingForData, "WaitingForData",
1262  "Current control started, waiting for valid temperature and current data.");
1263 
1264  AddStateName(Feedback::State::kOnStandby, "OnStandby",
1265  "Current control in progress but with limited voltage.");
1266  AddStateName(Feedback::State::kInProgress, "InProgress",
1267  "Current control in progress.");
1268  AddStateName(Feedback::State::kWarning, "Warning",
1269  "Current control in progress but current warning level exceeded.");
1270  AddStateName(Feedback::State::kCritical, "Critical",
1271  "Current control in progress but critical current limit exceeded.");
1272 
1273 
1274  /*
1275  AddEvent("SET_CURRENT_REQUEST_INTERVAL")
1276  (bind(&StateMachineFeedback::SetCurrentRequestInterval, this, placeholders::_1))
1277  ("|interval[ms]:Interval between two current requests in modes which need that.");
1278  */
1279 
1281  (bind(&StateMachineFeedback::Calibrate, this))
1282  ("");
1283 
1284  AddEvent("START", "F:1", Feedback::State::kCalibrated)
1285  (bind(&StateMachineFeedback::Start, this, placeholders::_1))
1286  ("Start the current/temperature control loop"
1287  "|Uov[V]:Overvoltage to be applied (standard value is 1.1V)");
1288 
1289  AddEvent("STOP")
1290  (bind(&StateMachineFeedback::StopFeedback, this))
1291  ("Stop any control loop");
1292 
1293  AddEvent("LOAD_OFFSETS", "C", Feedback::State::kConnected, Feedback::State::kCalibrated)
1294  (bind(&StateMachineFeedback::LoadOffset, this, placeholders::_1))
1295  ("");
1296  AddEvent("RESET_OFFSETS", Feedback::State::kConnected, Feedback::State::kCalibrated)
1297  (bind(&StateMachineFeedback::ResetOffset, this))
1298  ("");
1299 
1300 
1301  AddEvent("SAVE_CALIBRATION", Feedback::State::kCalibrated)
1303  ("");
1304  AddEvent("LOAD_CALIBRATION", Feedback::State::kConnected)
1306  ("");
1307 
1308  AddEvent("SET_MOON_MODE", "S:1", Feedback::State::kConnected, Feedback::State::kCalibrated)
1309  (bind(&StateMachineFeedback::SetMoonMode, this, placeholders::_1))
1310  ("Operate central pixels at 5V below nominal voltage. 0:off, 1:minimal, 2:medium, 3:maximum size.");
1311 
1312 
1313  AddEvent("PRINT")
1314  (bind(&StateMachineFeedback::Print, this))
1315  ("");
1316  AddEvent("PRINT_CALIBRATION")
1318  ("");
1319 
1320  // Verbosity commands
1321  AddEvent("SET_VERBOSE", "B:1")
1322  (bind(&StateMachineFeedback::SetVerbosity, this, placeholders::_1))
1323  ("set verbosity state"
1324  "|verbosity[bool]:disable or enable verbosity when calculating overvoltage");
1325  }
1326 
1328  {
1329  fIsVerbose = !conf.Get<bool>("quiet");
1330 
1331  if (!fMap.Read(conf.Get<string>("pixel-map-file")))
1332  {
1333  Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
1334  return 1;
1335  }
1336 
1337  fCurrentRequestInterval = conf.Get<uint16_t>("current-request-interval");
1338  fNumCalibIgnore = conf.Get<uint16_t>("num-calib-ignore");
1339  fNumCalibRequests = conf.Get<uint16_t>("num-calib-average");
1340  fTempCoefficient = conf.Get<double>("temp-coefficient");
1341 
1342  if (conf.Has("offset-file"))
1343  LoadOffsets(conf.Get<string>("offset-file"));
1344 
1345  return -1;
1346  }
1347 };
1348 
1349 // ------------------------------------------------------------------------
1350 
1351 #include "Main.h"
1352 
1353 template<class T>
1355 {
1356  return Main::execute<T, StateMachineFeedback>(conf);
1357 }
1358 
1360 {
1361  po::options_description control("Feedback options");
1362  control.add_options()
1363  ("quiet,q", po_bool(true), "Disable printing more information on average overvoltagecontents of all received messages (except dynamic data) in clear text.")
1364  ("pixel-map-file", var<string>()->required(), "Pixel mapping file. Used here to get the default reference voltage.")
1365  ("current-request-interval", var<uint16_t>(1000), "Interval between two current requests.")
1366  ("num-calib-ignore", var<uint16_t>(30), "Number of current requests to be ignored before averaging")
1367  ("num-calib-average", var<uint16_t>(300), "Number of current requests to be averaged")
1368  ("temp-coefficient", var<double>()->required(), "Temp. coefficient [V/K]")
1369  ("offset-file", var<string>(), "File with operation voltage offsets")
1370  ;
1371 
1372  conf.AddOptions(control);
1373 }
1374 
1375 /*
1376  Extract usage clause(s) [if any] for SYNOPSIS.
1377  Translators: "Usage" and "or" here are patterns (regular expressions) which
1378  are used to match the usage synopsis in program output. An example from cp
1379  (GNU coreutils) which contains both strings:
1380  Usage: cp [OPTION]... [-T] SOURCE DEST
1381  or: cp [OPTION]... SOURCE... DIRECTORY
1382  or: cp [OPTION]... -t DIRECTORY SOURCE...
1383  */
1385 {
1386  cout <<
1387  "The feedback control the BIAS voltages based on the calibration signal.\n"
1388  "\n"
1389  "The default is that the program is started without user intercation. "
1390  "All actions are supposed to arrive as DimCommands. Using the -c "
1391  "option, a local shell can be initialized. With h or help a short "
1392  "help message about the usuage can be brought to the screen.\n"
1393  "\n"
1394  "Usage: feedback [-c type] [OPTIONS]\n"
1395  " or: feedback [OPTIONS]\n";
1396  cout << endl;
1397 }
1398 
1400 {
1401  Main::PrintHelp<StateMachineFeedback>();
1402 
1403  /* Additional help text which is printed after the configuration
1404  options goes here */
1405 
1406  /*
1407  cout << "bla bla bla" << endl << endl;
1408  cout << endl;
1409  cout << "Environment:" << endl;
1410  cout << "environment" << endl;
1411  cout << endl;
1412  cout << "Examples:" << endl;
1413  cout << "test exam" << endl;
1414  cout << endl;
1415  cout << "Files:" << endl;
1416  cout << "files" << endl;
1417  cout << endl;
1418  */
1419 }
1420 
1421 int main(int argc, const char* argv[])
1422 {
1423  Configuration conf(argv[0]);
1424  conf.SetPrintUsage(PrintUsage);
1426  SetupConfiguration(conf);
1427 
1428  if (!conf.DoParse(argc, argv, PrintHelp))
1429  return 127;
1430 
1431  //try
1432  {
1433  // No console access at all
1434  if (!conf.Has("console"))
1435  {
1436 // if (conf.Get<bool>("no-dim"))
1437 // return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
1438 // else
1439  return RunShell<LocalStream>(conf);
1440  }
1441  // Cosole access w/ and w/o Dim
1442 /* if (conf.Get<bool>("no-dim"))
1443  {
1444  if (conf.Get<int>("console")==0)
1445  return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
1446  else
1447  return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
1448  }
1449  else
1450 */ {
1451  if (conf.Get<int>("console")==0)
1452  return RunShell<LocalShell>(conf);
1453  else
1454  return RunShell<LocalConsole>(conf);
1455  }
1456  }
1457  /*catch (std::exception& e)
1458  {
1459  cerr << "Exception: " << e.what() << endl;
1460  return -1;
1461  }*/
1462 
1463  return 0;
1464 }
DimDescribedService fDimOffsets
Definition: feedback.cc:44
DimDescribedState fDimBias
Definition: feedback.cc:38
int CheckLimits(const float *I)
Definition: feedback.cc:350
bool LoadOffsets(const string &file)
Definition: feedback.cc:1063
virtual void Subscribe(StateMachineImp &imp)
Definition: DimState.h:134
DimDescribedState fDimFSC
Definition: feedback.cc:37
DimVersion fDim
Definition: feedback.cc:35
float GetFloat() const
Definition: EventImp.h:97
A general base-class describing events issues in a state machine.
Definition: EventImp.h:11
const char * GetText() const
Definition: EventImp.h:88
bool CheckEventSize(size_t has, const char *name, size_t size)
Definition: feedback.cc:103
int HandleCalibration(const EventImp &evt)
Definition: feedback.cc:203
void SetupConfiguration(Configuration &conf)
Definition: Main.h:25
int i
Definition: db_dim_client.c:21
void setQuality(int quality)
Definition: discpp.cxx:1256
int group() const
Definition: PixelMap.h:40
int Print() const
Definition: feedback.cc:907
DimDescribedService fDimCalibration2
Definition: feedback.cc:41
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
DimDescribedService fDimCalibration
Definition: feedback.cc:40
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
uint16_t fCalibStep
Definition: feedback.cc:82
vector< float > fCalibR8
Definition: feedback.cc:59
STL namespace.
StateMachineFeedback(ostream &out=cout)
Definition: feedback.cc:1184
int HandleBiasDac(const EventImp &evt)
Definition: feedback.cc:141
double begin
const int32_t & state() const
Definition: DimState.h:80
vector< double > fTempOffset
Definition: feedback.cc:69
vector< int64_t > fCurrentsAvg
Definition: feedback.cc:49
vector< float > fCalibDeltaI
Definition: feedback.cc:58
int count() const
Definition: PixelMap.h:41
pair< vector< float >, vector< float > > AverageCurrents(const int16_t *ptr, int n)
Definition: feedback.cc:174
int EvalOptions(Configuration &conf)
Definition: feedback.cc:1327
int main(int argc, const char *argv[])
Definition: feedback.cc:1421
uint16_t fNumCalibIgnore
Definition: feedback.cc:80
uint16_t GetUShort() const
Definition: EventImp.h:92
void PrintUsage()
Definition: feedback.cc:1384
vector< float > fVoltGapd
Definition: feedback.cc:52
int SetCurrentRequestInterval(const EventImp &evt)
Definition: feedback.cc:966
uint16_t fCurrentRequestInterval
Definition: feedback.cc:79
bool Has(const std::string &var)
uint16_t fTimeoutCritical
Definition: feedback.cc:84
void AddOptions(const po::options_description &opt, bool visible=true)
Definition: Configuration.h:92
uint16_t fNumCalibRequests
Definition: feedback.cc:81
vector< uint16_t > fBiasDac
Definition: feedback.cc:55
int HandleBiasStateChange()
Definition: feedback.cc:88
void setData(const void *ptr, size_t sz)
double UnixTime() const
Definition: Time.cc:195
void Mjd(double mjd)
Definition: Time.cc:145
int HandleCameraTemp(const EventImp &evt)
Definition: feedback.cc:148
virtual Time GetTime() const
Definition: EventImp.h:57
static void sendCommandNB(const char *name, int data)
Definition: diccpp.cxx:1140
int HandleBiasVoltage(const EventImp &evt)
Definition: feedback.cc:134
int Execute()
Is called continously to execute actions in the current state.
Definition: feedback.cc:1144
DimDescribedService fDimCurrents
Definition: feedback.cc:43
double fTempCoefficient
Definition: feedback.cc:72
vector< int64_t > fCurrentsRms
Definition: feedback.cc:50
typedef __attribute__
void SendCommandNB(const std::string &command)
Definition: Dim.h:30
int Start(const EventImp &evt)
Definition: feedback.cc:1022
bool IsValid() const
Definition: Time.h:90
vector< double > fVoltOffset
Definition: feedback.cc:75
double end
int LoadOffset(const EventImp &evt)
Definition: feedback.cc:1088
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
int count
Definition: db_dim_server.c:18
vector< float > fCalibration
Definition: feedback.cc:57
int size
Definition: db_dim_server.c:17
float data[4 *1440]
virtual void Subscribe(StateMachineImp &imp)
Definition: DimState.h:68
double fVoltageReduction
Definition: feedback.cc:68
Class for a state machine implementation within a DIM network.
int SetMoonMode(const EventImp &evt)
Definition: feedback.cc:978
static int Debug
Definition: dns.c:78
bool GetBool() const
Definition: EventImp.h:90
TT t
Definition: test_client.c:26
bool online() const
Definition: DimState.h:82
Error()
Definition: HeadersFTM.h:197
int HandleBiasCurrent(const EventImp &evt)
Definition: feedback.cc:457
uint16_t fMoonMode
Definition: feedback.cc:77
po::typed_value< bool > * po_bool(bool def=false)
vector< float > fBiasVolt
Definition: feedback.cc:53
vector< float > fBiasR9
Definition: feedback.cc:54
int HandleBiasNom(const EventImp &evt)
Definition: feedback.cc:118
T Get(size_t offset=0) const
Definition: EventImp.h:66
bool Read(const std::string &fname)
Definition: PixelMap.h:56
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
DimDescribedService fDimCalibrationR8
Definition: feedback.cc:42
Do not initialize the time.
Definition: Time.h:51
int SetVerbosity(const EventImp &evt)
Definition: feedback.cc:956
void SetCallback(const callback &cb)
Definition: DimState.h:74
const T * Ptr(size_t offset=0) const
Definition: EventImp.h:74
int RunShell(Configuration &conf)
Definition: feedback.cc:1354
void SetupConfiguration(Configuration &conf)
Definition: feedback.cc:1359
const PixelMapEntry & hv(int board, int channel) const
Definition: PixelMap.h:139
virtual size_t GetSize() const
Definition: EventImp.h:55
void PrintHelp()
Definition: feedback.cc:1399