source: trunk/FACT++/src/feedback.cc@ 12406

Last change on this file since 12406 was 12399, checked in by tbretz, 14 years ago
Added the possibility to calibrate the offset of the currents of the bias supply
File size: 30.3 KB
Line 
1#include <valarray>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "Connection.h"
8#include "Configuration.h"
9#include "Console.h"
10#include "Converter.h"
11#include "DimServiceInfoList.h"
12#include "PixelMap.h"
13
14#include "tools.h"
15
16#include "LocalControl.h"
17
18#include "HeadersFAD.h"
19#include "HeadersBIAS.h"
20
21namespace ba = boost::asio;
22namespace bs = boost::system;
23namespace dummy = ba::placeholders;
24
25using namespace std;
26
27// ------------------------------------------------------------------------
28
29#include "DimDescriptionService.h"
30
31// ------------------------------------------------------------------------
32
33class StateMachineFeedback : public StateMachineDim, public DimInfoHandler
34{
35 /*
36 int Wrap(boost::function<void()> f)
37 {
38 f();
39 return T::GetCurrentState();
40 }
41
42 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
43 {
44 return bind(&StateMachineMCP::Wrap, this, func);
45 }*/
46
47private:
48 enum states_t
49 {
50 kStateDimNetworkNA = 1,
51 kStateDisconnected,
52 kStateConnecting,
53 kStateConnected,
54 kStateTempCtrlIdle,
55 kStateFeedbackCtrlIdle,
56 kStateTempCtrlRunning,
57 kStateFeedbackCtrlRunning,
58 kStateCalibrating,
59 };
60
61 enum control_t
62 {
63 kIdle,
64 kTemp,
65 kFeedback
66 };
67
68 control_t fControlType;
69
70 PixelMap fMap;
71
72 DimServiceInfoList fNetwork;
73
74 pair<Time, int> fStatusDim;
75 pair<Time, int> fStatusFAD;
76 pair<Time, int> fStatusFSC;
77 pair<Time, int> fStatusBias;
78
79 DimStampedInfo fDim;
80 DimStampedInfo fFAD;
81 DimStampedInfo fFSC;
82 DimStampedInfo fBias;
83 DimStampedInfo fBiasA;
84
85 DimStampedInfo fBiasData;
86 DimStampedInfo fCameraTemp;
87
88 DimDescribedService fDimReference;
89 DimDescribedService fDimDeviation;
90 DimDescribedService fDimCalibration;
91
92 vector<int64_t> fCurrentsAvg;
93 vector<int64_t> fCurrentsRms;
94
95 vector<vector<float>> fData;
96
97 uint64_t fCursor;
98
99 Time fBiasLast;
100 Time fStartTime;
101
102 valarray<double> fPV[3]; // Process variable (intgerated/averaged amplitudes)
103 valarray<double> fSP; // Set point (target amplitudes)
104
105 double fKp; // Proportional constant
106 double fKi; // Integral constant
107 double fKd; // Derivative constant
108 double fT; // Time constant (cycle time)
109 double fGain; // Gain (conversion from a DRS voltage deviation into a BIAS voltage change at G-APD reference voltage)
110
111 double fT21;
112
113 double fBiasOffset;
114
115 bool fOutputEnabled;
116
117 pair<Time, int> GetNewState(DimStampedInfo &info) const
118 {
119 const bool disconnected = info.getSize()==0;
120
121 // Make sure getTimestamp is called _before_ getTimestampMillisecs
122 const int tsec = info.getTimestamp();
123 const int tms = info.getTimestampMillisecs();
124
125 return make_pair(Time(tsec, tms*1000),
126 disconnected ? -2 : info.getQuality());
127 }
128
129 void ResetData()
130 {
131 fData.clear();
132 fData.resize(500);
133 fCursor = 0;
134 fStartTime = Time();
135
136 fSP.resize(416);
137 fSP = valarray<double>(0., 416);
138
139 vector<float> vec(2*BIAS::kNumChannels);
140 fDimDeviation.Update(vec);
141
142 fPV[0].resize(0);
143 fPV[1].resize(0);
144 fPV[2].resize(0);
145
146 if (fKp==0 && fKi==0 && fKd==0)
147 Warn("Control loop parameters are all set to zero.");
148 }
149
150 void infoHandler()
151 {
152 DimInfo *curr = getInfo(); // get current DimInfo address
153 if (!curr)
154 return;
155
156 if (curr==&fBias)
157 {
158 fStatusBias = GetNewState(fBias);
159 return;
160 }
161
162 if (curr==&fFAD)
163 {
164 fStatusFAD = GetNewState(fFAD);
165 return;
166 }
167
168 if (curr==&fFSC)
169 {
170 fStatusFSC = GetNewState(fFSC);
171 return;
172 }
173
174 if (curr==&fDim)
175 {
176 fStatusDim = GetNewState(fDim);
177 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
178 return;
179 }
180
181 if (curr==&fCameraTemp)
182 {
183 if (curr->getSize()!=60*sizeof(float))
184 return;
185
186 const float *ptr = static_cast<float*>(curr->getData());
187
188 double avg = 0;
189 int num = 0;
190 for (int i=1; i<32; i++)
191 if (ptr[i]!=0)
192 {
193 avg += ptr[i];
194 num++;
195 }
196
197 if (num==0)
198 return;
199
200 avg /= num;
201
202
203 const float diff = (avg-25)*4./70 + fBiasOffset;
204
205 vector<float> vec(2*BIAS::kNumChannels);
206 for (int i=0; i<BIAS::kNumChannels; i++)
207 vec[i+416] = diff;
208
209 if (fControlType!=kTemp)
210 return;
211
212 fDimDeviation.Update(vec);
213
214 if (fOutputEnabled && fStatusBias.second==BIAS::kVoltageOn)
215 {
216 Info("Sending correction to feedback.");
217
218 DimClient::sendCommandNB((char*)"BIAS_CONTROL/SET_GAPD_REFERENCE_OFFSET",
219 (void*)&diff, sizeof(float));
220 }
221 }
222
223 if (curr==&fBiasA && fControlType==kTemp && GetCurrentState()==kStateCalibrating)
224 {
225 if (curr->getSize()!=416*sizeof(int16_t))
226 return;
227
228 if (fStatusBias.second==BIAS::kRamping)
229 return;
230
231 const int16_t *ptr = static_cast<int16_t*>(curr->getData());
232
233 for (int i=0; i<416; i++)
234 if (ptr[i]>0)
235 {
236 fCurrentsAvg[i] += ptr[i];
237 fCurrentsRms[i] += ptr[i]*ptr[i];
238 }
239
240 if (++fCursor<100)
241 {
242 DimClient::sendCommandNB("BIAS_CONTROL/REQUEST_STATUS", NULL, 0);
243 return;
244 }
245
246 vector<float> val(2*416, 0);
247 for (int i=0; i<416; i++)
248 {
249 val[i] = double(fCurrentsAvg[i])/fCursor;
250 val[i+416] = sqrt(double(fCurrentsRms[i])/fCursor-val[i]*val[i]);
251 }
252
253 fDimCalibration.Update(val);
254
255 fOutputEnabled = false;
256 fControlType = kIdle;
257 }
258
259 if (curr==&fBiasData && fControlType==kFeedback)
260 {
261 if (curr->getSize()!=1440*sizeof(float))
262 return;
263
264 // -------- Check age of last stored event --------
265
266 // Must be called in this order
267 const int tsec = curr->getTimestamp();
268 const int tms = curr->getTimestampMillisecs();
269
270 const Time tm(tsec, tms*1000);
271
272 if (Time()-fBiasLast>boost::posix_time::seconds(30))
273 {
274 Warn("Last received event data older than 30s... resetting average calculation.");
275 ResetData();
276 }
277 fBiasLast = tm;
278
279 // -------- Store new event --------
280
281 fData[fCursor%fData.size()].assign(reinterpret_cast<float*>(curr->getData()),
282 reinterpret_cast<float*>(curr->getData())+1440);
283
284
285 fCursor++;
286
287 if (fCursor<fData.size())
288 return;
289
290 // -------- Calculate statistics --------
291
292 valarray<double> med(1440);
293
294 for (int ch=0; ch<1440; ch++)
295 {
296 vector<float> arr(fData.size());
297 for (size_t i=0; i<fData.size(); i++)
298 arr[i] = fData[i][ch];
299
300 sort(arr.begin(), arr.end());
301
302 med[ch] = arr[arr.size()/2];
303 }
304
305 /*
306 vector<float> med(1440);
307 vector<float> rms(1440);
308 for (size_t i=0; i<fData.size(); i++)
309 {
310 if (fData[i].size()==0)
311 return;
312
313 for (int j=0; j<1440; j++)
314 {
315 med[j] += fData[i][j];
316 rms[j] += fData[i][j]*fData[i][j];
317 }
318 }
319 */
320
321 vector<double> avg(BIAS::kNumChannels);
322 vector<int> num(BIAS::kNumChannels);
323 for (int i=0; i<1440; i++)
324 {
325 const PixelMapEntry &ch = fMap.hw(i);
326
327 // FIXME: Add a consistency check if the median makes sense...
328 // FIXME: Add a consistency check to remove pixels with bright stars (median?)
329
330 avg[ch.hv()] += med[i];
331 num[ch.hv()]++;
332 }
333
334 for (int i=0; i<BIAS::kNumChannels; i++)
335 {
336 if (num[i])
337 avg[i] /= num[i];
338
339 }
340
341 // -------- Calculate correction --------
342
343 // http://bestune.50megs.com/typeABC.htm
344
345 // CO: Controller output
346 // PV: Process variable
347 // SP: Set point
348 // T: Sampling period (loop update period)
349 // e = SP - PV
350 //
351 // Kp : No units
352 // Ki : per seconds
353 // Kd : seconds
354
355 // CO(k)-CO(k-1) = - Kp[ PV(k) - PV(k-1) ] + Ki * T * (SP(k)-PV(k)) - Kd/T [ PV(k) - 2PV(k-1) + PV(k-2) ]
356
357 if (fCursor%fData.size()==0)
358 {
359 // FIXME: Take out broken / dead boards.
360
361 const Time tm0 = Time();
362
363 /*const*/ double T21 = fT>0 ? fT : (tm0-fStartTime).total_microseconds()/1000000.;
364 const double T10 = fT21;
365 fT21 = T21;
366
367 fStartTime = tm0;
368
369 ostringstream out;
370 out << "New " << fData.size() << " event received: " << fCursor << " / " << setprecision(3) << T21 << "s";
371 Info(out);
372
373 if (fPV[0].size()==0)
374 {
375 fPV[0].resize(avg.size());
376 fPV[0] = valarray<double>(avg.data(), avg.size());
377 }
378 else
379 if (fPV[1].size()==0)
380 {
381 fPV[1].resize(avg.size());
382 fPV[1] = valarray<double>(avg.data(), avg.size());
383 }
384 else
385 if (fPV[2].size()==0)
386 {
387 fPV[2].resize(avg.size());
388 fPV[2] = valarray<double>(avg.data(), avg.size());
389 }
390 else
391 {
392 fPV[0] = fPV[1];
393 fPV[1] = fPV[2];
394
395 fPV[2].resize(avg.size());
396 fPV[2] = valarray<double>(avg.data(), avg.size());
397
398 if (T10<=0 || T21<=0)
399 return;
400
401 cout << "Calculating (" << fCursor << ":" << T21 << ")... " << endl;
402
403 // fKi[j] = response[j]*gain;
404 // Kp = 0;
405 // Kd = 0;
406
407 // => Kp = 0.01 * gain = 0.00005
408 // => Ki = 0.8 * gain/20s = 0.00025
409 // => Kd = 0.1 * gain/20s = 0.00003
410
411 fKp = 0;
412 fKd = 0;
413 fKi = 0.00003*20;
414 T21 = 1;
415
416 //valarray<double> correction = - Kp*(PV[2] - PV[1]) + Ki * dT * (SP-PV[2]) - Kd/dT * (PV[2] - 2*PV[1] + PV[0]);
417 //valarray<double> correction =
418 // - Kp * (PV[2] - PV[1])
419 // + dT * Ki * (SP - PV[2])
420 // - Kd / dT * (PV[2] - 2*PV[1] + PV[0]);
421 //
422 // - (Kp+Kd/dT1) * (PV[2] - PV[1])
423 // + dT2 * Ki * (SP - PV[2])
424 // + Kd / dT1 * (PV[1] - PV[0]);
425 //
426 // - Kp * (PV[2] - PV[1])
427 // + Ki * (SP - PV[2])*dT
428 // - Kd * (PV[2] - PV[1])/dT
429 // + Kd * (PV[1] - PV[0])/dT;
430 //
431 //valarray<double> correction =
432 // - Kp*(PV[2] - PV[1]) + Ki * T21 * (SP-PV[2]) - Kd*(PV[2]-PV[1])/T21 - Kd*(PV[0]-PV[1])/T01;
433 const valarray<double> correction = fGain/1000*
434 (
435 - (fKp+fKd/T21)*(fPV[2] - fPV[1])
436 + fKi*T21*(fSP-fPV[2])
437 + fKd/T10*(fPV[1]-fPV[0])
438 );
439
440 /*
441 integral = 0
442 start:
443 integral += (fSP - fPV[2])*dt
444
445 output = Kp*(fSP - fPV[2]) + Ki*integral - Kd*(fPV[2] - fPV[1])/dt
446
447 wait(dt)
448
449 goto start
450 */
451
452 vector<float> vec(2*BIAS::kNumChannels);
453 for (int i=0; i<BIAS::kNumChannels; i++)
454 vec[i] = fPV[2][i]-fSP[i];
455
456 for (int i=0; i<BIAS::kNumChannels; i++)
457 vec[i+416] = avg[i]<5*2.5 ? 0 : correction[i];
458
459 fDimDeviation.Update(vec);
460
461 if (fOutputEnabled && fStatusBias.second==BIAS::kVoltageOn)
462 {
463 Info("Sending correction to feedback.");
464
465 DimClient::sendCommandNB((char*)"BIAS_CONTROL/ADD_REFERENCE_VOLTAGES",
466 (void*)(vec.data()+416), 416*sizeof(float));
467
468 /*
469 if (!Dim::SendCommand("BIAS_CONTROL/ADD_REFERENCE_VOLTAGES",
470 (const void*)(vec.data()+416), 416*sizeof(float)))
471 {
472 Error("Sending correction to bias control failed... switching off.");
473 fOutputEnabled=false;
474 }
475 else
476 Info("Success!");
477 */
478 }
479 }
480
481 }
482 }
483
484 }
485
486 bool CheckEventSize(size_t has, const char *name, size_t size)
487 {
488 if (has==size)
489 return true;
490
491 ostringstream msg;
492 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
493 Fatal(msg);
494 return false;
495 }
496
497 void PrintState(const pair<Time,int> &state, const char *server)
498 {
499 const State rc = fNetwork.GetState(server, state.second);
500
501 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
502 Out() << kBold << server << ": ";
503 Out() << rc.name << "[" << rc.index << "]";
504 Out() << kReset << " - " << kBlue << rc.comment << endl;
505 }
506
507 int Print()
508 {
509 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
510 Out() << kBold << "DIM_DNS: ";
511 if (fStatusDim.second==0)
512 Out() << "Offline" << endl;
513 else
514 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
515
516 PrintState(fStatusFAD, "FAD_CONTROL");
517 PrintState(fStatusFSC, "FSC_CONTROL");
518 PrintState(fStatusBias, "BIAS_CONTROL");
519
520 return GetCurrentState();
521 }
522
523 int SetConstant(const EventImp &evt, int constant)
524 {
525 if (!CheckEventSize(evt.GetSize(), "SetConstant", 8))
526 return kSM_FatalError;
527
528 switch (constant)
529 {
530 case 0: fKi = evt.GetDouble(); break;
531 case 1: fKp = evt.GetDouble(); break;
532 case 2: fKd = evt.GetDouble(); break;
533 case 3: fT = evt.GetDouble(); break;
534 case 4: fGain = evt.GetDouble(); break;
535 default:
536 Fatal("SetConstant got an unexpected constant id -- this is a program bug!");
537 return kSM_FatalError;
538 }
539
540 return GetCurrentState();
541 }
542
543 int EnableOutput(const EventImp &evt)
544 {
545 if (!CheckEventSize(evt.GetSize(), "EnableOutput", 1))
546 return kSM_FatalError;
547
548 fOutputEnabled = evt.GetBool();
549
550 return GetCurrentState();
551 }
552
553 int StartFeedback()
554 {
555 ResetData();
556
557 fControlType = kFeedback;
558
559 return GetCurrentState();
560 }
561
562 int StartTempCtrl(const EventImp &evt)
563 {
564 if (!CheckEventSize(evt.GetSize(), "StartTempCtrl", 4))
565 return kSM_FatalError;
566
567 ostringstream out;
568 out << "Starting temperature feedback with an offset of " << fBiasOffset << "V";
569 Message(out);
570
571 fBiasOffset = evt.GetFloat();
572 fControlType = kTemp;
573
574 return GetCurrentState();
575 }
576
577 int StopFeedback()
578 {
579 fControlType = kIdle;
580
581 return GetCurrentState();
582 }
583
584 int StoreReference()
585 {
586 if (!fPV[0].size() && !fPV[1].size() && !fPV[2].size())
587 {
588 Warn("No values in memory. Take enough events first!");
589 return GetCurrentState();
590 }
591
592 // FIXME: Check age
593
594 if (!fPV[1].size() && !fPV[2].size())
595 fSP = fPV[0];
596
597 if (!fPV[2].size())
598 fSP = fPV[1];
599 else
600 fSP = fPV[2];
601
602 vector<float> vec(BIAS::kNumChannels);
603 for (int i=0; i<BIAS::kNumChannels; i++)
604 vec[i] = fSP[i];
605 fDimReference.Update(vec);
606
607 return GetCurrentState();
608 }
609
610 int SetReference(const EventImp &evt)
611 {
612 if (!CheckEventSize(evt.GetSize(), "SetReference", 4))
613 return kSM_FatalError;
614
615 const float val = evt.GetFloat();
616 /*
617 if (!fPV[0].size() && !fPV[1].size() && !fPV[2].size())
618 {
619 Warn("No values in memory. Take enough events first!");
620 return GetCurrentState();
621 }*/
622
623 vector<float> vec(BIAS::kNumChannels);
624 for (int i=0; i<BIAS::kNumChannels; i++)
625 vec[i] = fSP[i] = val;
626 fDimReference.Update(vec);
627
628 return GetCurrentState();
629 }
630
631 int CalibrateCurrents()
632 {
633// if (!CheckEventSize(evt.GetSize(), "StartTempCtrl", 4))
634// return kSM_FatalError;
635
636 ostringstream out;
637 out << "Starting temperature feedback with an offset of -2V";
638 Message(out);
639
640 fBiasOffset = -2;
641 fControlType = kTemp;
642 fCursor = 0;
643 fCurrentsAvg.assign(416, 0);
644 fCurrentsRms.assign(416, 0);
645 fStartTime = Time();
646 fOutputEnabled = true;
647
648 return kStateCalibrating;
649 }
650
651 int Execute()
652 {
653 // Dispatch (execute) at most one handler from the queue. In contrary
654 // to run_one(), it doesn't wait until a handler is available
655 // which can be dispatched, so poll_one() might return with 0
656 // handlers dispatched. The handlers are always dispatched/executed
657 // synchronously, i.e. within the call to poll_one()
658 //poll_one();
659
660 if (fStatusDim.second==0)
661 return kStateDimNetworkNA;
662
663 // All subsystems are not connected
664 if (fStatusFAD.second<FAD::kConnected &&
665 fStatusBias.second<BIAS::kConnecting &&
666 fStatusFSC.second<2)
667 return kStateDisconnected;
668
669 // At least one subsystem is not connected
670 if (fStatusFAD.second<FAD::kConnected ||
671 fStatusBias.second<BIAS::kConnected ||
672 fStatusFSC.second<2)
673 return kStateConnecting;
674
675 if (GetCurrentState()==kStateCalibrating && fCursor<100)
676 return GetCurrentState();
677
678/*
679 // All subsystems are connected
680 if (GetCurrentStatus()==kStateConfiguringStep1)
681 {
682 if (fCursor<1)
683 return kStateConfiguringStep1;
684
685 if (fCursor==1)
686 {
687 fStartTime = Time();
688 return kStateConfiguringStep2;
689 }
690 }
691 if (GetCurrentStatus()==kStateConfiguringStep2)
692 {
693 if (fCursor==1)
694 {
695 if ((Time()-fStartTime).total_microseconds()/1000000.<1.5)
696 return kStateConfiguringStep2;
697
698 Dim::SendCommand("BIAS_CONTROL/REQUEST_STATUS");
699 }
700 if (fCursor==2)
701 {
702
703 int n=0;
704 double avg = 0;
705 for (size_t i=0; i<fCurrents.size(); i++)
706 if (fCurrents[i]>=0)
707 {
708 avg += fCurrents[i];
709 n++;
710 }
711
712 cout << avg/n << endl;
713 }
714 return kStateConnected;
715 }
716*/
717 if (fControlType==kFeedback)
718 return fOutputEnabled ? kStateFeedbackCtrlRunning : kStateFeedbackCtrlIdle;
719
720 if (fControlType==kTemp)
721 return fOutputEnabled ? kStateTempCtrlRunning : kStateTempCtrlIdle;
722
723 return kStateConnected;
724 }
725
726public:
727 StateMachineFeedback(ostream &out=cout) : StateMachineDim(out, "FEEDBACK"),
728 fStatusDim(make_pair(Time(), -2)),
729 fStatusFAD(make_pair(Time(), -2)),
730 fStatusBias(make_pair(Time(), -2)),
731 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
732 fFAD("FAD_CONTROL/STATE", (void*)NULL, 0, this),
733 fFSC("FSC_CONTROL/STATE", (void*)NULL, 0, this),
734 fBias("BIAS_CONTROL/STATE", (void*)NULL, 0, this),
735 fBiasA("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this),
736 fBiasData("FAD_CONTROL/FEEDBACK_DATA", (void*)NULL, 0, this),
737 fCameraTemp("FSC_CONTROL/TEMPERATURE", (void*)NULL, 0, this),
738 fDimReference("FEEDBACK/REFERENCE", "F:416", ""),
739 fDimDeviation("FEEDBACK/DEVIATION", "F:416;F:416", ""),
740 fDimCalibration("FEEDBACK/CALIBRATION", "F:416;F:416", ""),
741 fKp(0), fKi(0), fKd(0), fT(-1), fOutputEnabled(false)
742 {
743 // ba::io_service::work is a kind of keep_alive for the loop.
744 // It prevents the io_service to go to stopped state, which
745 // would prevent any consecutive calls to run()
746 // or poll() to do nothing. reset() could also revoke to the
747 // previous state but this might introduce some overhead of
748 // deletion and creation of threads and more.
749
750 // State names
751 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
752 "The Dim DNS is not reachable.");
753
754 AddStateName(kStateDisconnected, "Disconnected",
755 "The Dim DNS is reachable, but the required subsystems are not available.");
756
757 AddStateName(kStateConnecting, "Connecting",
758 "Not all subsystems (FAD, FSC, Bias) are connected to their hardware.");
759
760 AddStateName(kStateConnected, "Connected",
761 "All needed subsystems are connected to their hardware, no action is performed.");
762
763 AddStateName(kStateFeedbackCtrlIdle, "FeedbackIdle",
764 "Feedback control activated, but voltage output disabled.");
765
766 AddStateName(kStateTempCtrlIdle, "FeedbackIdle",
767 "Temperature control activated, but voltage output disabled.");
768
769 AddStateName(kStateFeedbackCtrlRunning, "FeedbackControl",
770 "Feedback control activated and voltage output enabled.");
771
772 AddStateName(kStateTempCtrlRunning, "TempControl",
773 "Temperature control activated and voltage output enabled.");
774
775 AddStateName(kStateCalibrating, "Calibrating",
776 "Calibrating current offsets.");
777
778 AddEvent("START_FEEDBACK_CONTROL", kStateConnected)
779 (bind(&StateMachineFeedback::StartFeedback, this))
780 ("Start the feedback control loop");
781
782 AddEvent("START_TEMP_CONTROL", "F:1", kStateConnected)
783 (bind(&StateMachineFeedback::StartTempCtrl, this, placeholders::_1))
784 ("Start the temperature control loop"
785 "|offset[V]:Offset from the nominal temperature corrected value in Volts");
786
787 // kStateTempCtrlIdle, kStateFeedbackCtrlIdle, kStateTempCtrlRunning, kStateFeedbackCtrlRunning
788 AddEvent("STOP")
789 (bind(&StateMachineFeedback::StopFeedback, this))
790 ("Stop any control loop");
791
792 AddEvent("ENABLE_OUTPUT", "B:1")//, kStateIdle)
793 (bind(&StateMachineFeedback::EnableOutput, this, placeholders::_1))
794 ("Enable sending of correction values caluclated by the control loop to the biasctrl");
795
796 AddEvent("STORE_REFERENCE")//, kStateIdle)
797 (bind(&StateMachineFeedback::StoreReference, this))
798 ("Store the last (averaged) value as new reference (for debug purpose only)");
799
800 AddEvent("SET_REFERENCE", "F:1")//, kStateIdle)
801 (bind(&StateMachineFeedback::SetReference, this, placeholders::_1))
802 ("Set a new global reference value (for debug purpose only)");
803
804 AddEvent("SET_Ki", "D:1")//, kStateIdle)
805 (bind(&StateMachineFeedback::SetConstant, this, placeholders::_1, 0))
806 ("Set integral constant Ki");
807
808 AddEvent("SET_Kp", "D:1")//, kStateIdle)
809 (bind(&StateMachineFeedback::SetConstant, this, placeholders::_1, 1))
810 ("Set proportional constant Kp");
811
812 AddEvent("SET_Kd", "D:1")//, kStateIdle)
813 (bind(&StateMachineFeedback::SetConstant, this, placeholders::_1, 2))
814 ("Set derivative constant Kd");
815
816 AddEvent("SET_T", "D:1")//, kStateIdle)
817 (bind(&StateMachineFeedback::SetConstant, this, placeholders::_1, 3))
818 ("Set time-constant. (-1 to use the cycle time, i.e. the time for the last average cycle, instead)");
819
820 AddEvent("CALIBRATE_CURRENTS", kStateConnected)//, kStateIdle)
821 (bind(&StateMachineFeedback::CalibrateCurrents, this))
822 ("");
823
824 // Verbosity commands
825// AddEvent("SET_VERBOSE", "B:1")
826// (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
827// ("set verbosity state"
828// "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
829
830 AddEvent("PRINT")
831 (bind(&StateMachineFeedback::Print, this))
832 ("");
833 }
834
835 int EvalOptions(Configuration &conf)
836 {
837 if (!fMap.Read(conf.Get<string>("pixel-map-file")))
838 {
839 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
840 return 1;
841 }
842
843 // -110 / -110 (-23 DAC / -0.51V)
844 // Reference voltage: -238 / -203
845 // -360 / -343 ( 23 DAC / 0.51V)
846
847 // 0.005 A/V
848 // 220 Amplitude / 1V
849
850 // Gain = 1V / 200 = 0.005
851
852 fGain = 5; // (BIAS)V / (DRS)V ( 1V / 0.22V )
853
854 fKp = 0;
855 fKd = 0;
856 fKi = 0.12;
857 fT = 1;
858
859 ostringstream msg;
860 msg << "Control loop parameters: ";
861 msg << "Kp=" << fKp << ", Kd=" << fKd << ", Ki=" << fKi << ", ";
862 if (fT>0)
863 msg << fT;
864 else
865 msg << "<auto>";
866 msg << ", Gain(BIAS/DRS)=" << fGain << "V/V";
867
868 Message(msg);
869
870 return -1;
871 }
872};
873
874// ------------------------------------------------------------------------
875
876#include "Main.h"
877
878template<class T>
879int RunShell(Configuration &conf)
880{
881 return Main::execute<T, StateMachineFeedback>(conf);
882}
883
884void SetupConfiguration(Configuration &conf)
885{
886 po::options_description control("Feedback options");
887 control.add_options()
888 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
889 ;
890
891 conf.AddOptions(control);
892}
893
894/*
895 Extract usage clause(s) [if any] for SYNOPSIS.
896 Translators: "Usage" and "or" here are patterns (regular expressions) which
897 are used to match the usage synopsis in program output. An example from cp
898 (GNU coreutils) which contains both strings:
899 Usage: cp [OPTION]... [-T] SOURCE DEST
900 or: cp [OPTION]... SOURCE... DIRECTORY
901 or: cp [OPTION]... -t DIRECTORY SOURCE...
902 */
903void PrintUsage()
904{
905 cout <<
906 "The feedback control the BIAS voltages based on the calibration signal.\n"
907 "\n"
908 "The default is that the program is started without user intercation. "
909 "All actions are supposed to arrive as DimCommands. Using the -c "
910 "option, a local shell can be initialized. With h or help a short "
911 "help message about the usuage can be brought to the screen.\n"
912 "\n"
913 "Usage: feedback [-c type] [OPTIONS]\n"
914 " or: feedback [OPTIONS]\n";
915 cout << endl;
916}
917
918void PrintHelp()
919{
920 Main::PrintHelp<StateMachineFeedback>();
921
922 /* Additional help text which is printed after the configuration
923 options goes here */
924
925 /*
926 cout << "bla bla bla" << endl << endl;
927 cout << endl;
928 cout << "Environment:" << endl;
929 cout << "environment" << endl;
930 cout << endl;
931 cout << "Examples:" << endl;
932 cout << "test exam" << endl;
933 cout << endl;
934 cout << "Files:" << endl;
935 cout << "files" << endl;
936 cout << endl;
937 */
938}
939
940int main(int argc, const char* argv[])
941{
942 Configuration conf(argv[0]);
943 conf.SetPrintUsage(PrintUsage);
944 Main::SetupConfiguration(conf);
945 SetupConfiguration(conf);
946
947 if (!conf.DoParse(argc, argv, PrintHelp))
948 return -1;
949
950 //try
951 {
952 // No console access at all
953 if (!conf.Has("console"))
954 {
955// if (conf.Get<bool>("no-dim"))
956// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
957// else
958 return RunShell<LocalStream>(conf);
959 }
960 // Cosole access w/ and w/o Dim
961/* if (conf.Get<bool>("no-dim"))
962 {
963 if (conf.Get<int>("console")==0)
964 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
965 else
966 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
967 }
968 else
969*/ {
970 if (conf.Get<int>("console")==0)
971 return RunShell<LocalShell>(conf);
972 else
973 return RunShell<LocalConsole>(conf);
974 }
975 }
976 /*catch (std::exception& e)
977 {
978 cerr << "Exception: " << e.what() << endl;
979 return -1;
980 }*/
981
982 return 0;
983}
Note: See TracBrowser for help on using the repository browser.