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

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