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

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