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

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