source: drsdaq/HVFeedback.cc@ 40

Last change on this file since 40 was 36, checked in by ogrimm, 16 years ago
Various changes, see History.txt
File size: 13.4 KB
Line 
1/********************************************************************\
2
3 HVFeedback.cc
4
5 Class handling the feedback of GAPD high voltage
6
7 Oliver Grimm
8
9\********************************************************************/
10
11#include "HVFeedback.h"
12#include "PixelMap.h"
13
14#include <sys/socket.h>
15#include <netdb.h>
16#include <signal.h>
17
18#define MAX_RETRY 5
19#define PIXMAP_LOCATION "../config/PixelMap.txt"
20
21//
22// Constructor: Initialise feedback
23//
24HVFeedback::HVFeedback(DAQReadout* DAQClass, char* Configfile) {
25 struct sockaddr_in SocketAddress;
26 char Filename[MAX_PATH];
27
28 m = DAQClass;
29 PixMap = new PixelMap(PIXMAP_LOCATION, false);
30
31 snprintf(Filename,sizeof(Filename),"%s/SlowData/", m->fRawDataPath);
32 SlowDataClass = new SlowData(m, "HVFB", Filename);
33
34 // Read configuration file
35 FILE *File;
36 if ((File = fopen(Configfile,"r")) == NULL) {
37 printf("Error: Could not open feedback configuration file '%s'\n", Configfile);
38 }
39 else {
40 printf("Reading feedback configuration file %s\n", Configfile);
41 ReadCard("TrigBoard", &fLedTrigBoard, 'I', File);
42 ReadCard("TrigChannel", &fLedTrigChannel, 'I', File);
43 ReadCard("TrigChip", &fLedTrigChip, 'I', File);
44 ReadCard("TrigSample", &fLedTrigSample, 'I', File);
45 ReadCard("TrigThreshold", &fLedTrigThreshold, 'f', File);
46 ReadCard("SignalSample", &fLedSignalSample, 'I', File);
47 ReadCard("BaselineSample", &fLedBaselineSample, 'I', File);
48 ReadCard("IntHalfWidth", &fIntHalfWidth, 'U', File);
49 ReadCard("DefaultNumAverage", &fDefaultNumAverage, 'I', File);
50 ReadCard("HVControlServer", fHVControlServer, 's', File);
51 ReadCard("HVControlPort", &fHVControlPort, 'I', File);
52 ReadCard("MaxCmdAckDelay", &fMaxCmdAckDelay, 'I', File);
53 fclose(File);
54 }
55 PrintConfig();
56
57 // Initialise
58 Average = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
59 Sigma = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
60 Response = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
61 Target = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
62 Buffer = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
63
64/* for (int i=m->FirstBoard; i<=m->LastBoard; i++)
65 for (int j=0; j<kNumberOfChips; j++)
66 for (int k=0; k<kNumberOfChannels; k++) {
67 Response[i][j][k] = 0.0;
68 Target[i][j][k] = 0.0;
69 }
70 */
71 Gain = 1;
72 SetFBMode(FB_Off);
73 SetNumAverages(fDefaultNumAverage);
74
75 // Opening socket client to HV control program
76 if ((SocketDescriptor = socket(PF_INET, SOCK_STREAM, 0)) == -1)
77 m->PrintMessage("Could not open client socket, no HV control available.\n");
78
79 // Resolve hostname and try to connect to server
80 struct hostent *hostent = gethostbyname(fHVControlServer);
81 if (hostent==0)
82 m->PrintMessage("Could not resolve HV server host name \"%s\".\n", fHVControlServer);
83 else {
84 SocketAddress.sin_family = PF_INET;
85 SocketAddress.sin_port = htons((unsigned short) fHVControlPort);
86 SocketAddress.sin_addr = *(struct in_addr*) hostent->h_addr;
87
88 if (connect(SocketDescriptor, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress))==-1)
89 m->PrintMessage("Could not connect to HV server %s at port %d (%s)\n", fHVControlServer, fHVControlPort, strerror(errno));
90 else m->PrintMessage("\nFeedback connected to HV server %s (port %d).\n", fHVControlServer, fHVControlPort);
91 signal(SIGPIPE,SIG_IGN); // Do not kill process if writing to closed socket
92 }
93}
94
95//
96// Destructor
97//
98HVFeedback::~HVFeedback() {
99 if (SocketDescriptor!=-1) {
100 close(SocketDescriptor);
101 m->PrintMessage("Feeback socket closed.\n");
102 }
103 delete[] Average; delete[] Response;
104 delete[] Target; delete[] Buffer;
105 delete SlowDataClass; delete PixMap;
106}
107
108//
109// Check if LED trigger present, if yes accumulate feedback data and
110// calculate new high voltages if the required number of events is reached.
111//
112bool HVFeedback::ProcessEvent() {
113 int i,j,k,q;
114 float Correction, Integral, Difference, EffectiveGain;
115
116 // Check for LED trigger channel on given channel and if feedback running
117 if (FBMode==FB_Off || m->WaveForm[fLedTrigBoard][fLedTrigChip][fLedTrigChannel][fLedTrigSample] < fLedTrigThreshold)
118 return false;
119
120 // Calculate average signal of LED pulse as integral of signal
121 for (i=m->FirstBoard; i<=m->LastBoard; i++)
122 for (j=0; j<kNumberOfChips; j++)
123 for (k=0; k<kNumberOfChannels; k++) {
124 for (Integral=0, q=-fIntHalfWidth; q<=(int) fIntHalfWidth; q++)
125 Integral += (m->WaveForm[i][j][k][fLedSignalSample+q] - m->WaveForm[i][j][k][fLedBaselineSample+q])*m->BStruct[i].ScaleFactor;
126 Integral /= 2*fIntHalfWidth+1;
127 Average[i][j][k] += Integral;
128 Sigma[i][j][k] += pow(Integral,2);
129 }
130
131 if (++Count<NumAverages) return false;
132
133 // Acquired number of event requires action
134 switch (FBMode) {
135 case FB_Active: SlowDataClass->NewEntry("Average"); break;
136 case FB_Targets: SlowDataClass->NewEntry("Target"); break;
137 case FB_ResponseSecond: SlowDataClass->NewEntry("Response"); SlowDataClass->AddToEntry("%.3f ",DiffVoltage); break;
138 default: break; // to suppress warning abount not handled enumeration value
139 }
140
141 for (i=m->FirstBoard; i<=m->LastBoard; i++)
142 for (j=0; j<kNumberOfChips; j++)
143 for (k=0; k<kNumberOfChannels; k++) {
144 Average[i][j][k] /= Count;
145 Sigma[i][j][k] = sqrt(Sigma[i][j][k]/Count-pow(Average[i][j][k],2))/sqrt(Count);
146 switch (FBMode) {
147 case FB_Active: // Determine correction from response maxtrix and change voltages
148 Difference = Target[i][j][k] - Average[i][j][k];
149 EffectiveGain = Gain*pow(0.5*(1+(Difference/Sigma[i][j][k]-1)/(Difference/Sigma[i][j][k]+1)),2);
150 Correction = -Difference*Response[i][j][k]*EffectiveGain;
151 if(Correction!=0 && Target[i][j][k]!=0 && !PixMap->DRS_to_Pixel(i,j,k).empty()) {
152 printf("Average of board %d, chip %d, channel %d is %.2f +/- %.2f Correction %.3f\n",i,j,k,Average[i][j][k],Sigma[i][j][k],Correction);
153 SlowDataClass->AddToEntry("%d %d %d %.3f %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k],Correction);
154 if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n");
155 else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(),Correction);
156 }
157 break;
158 case FB_Targets: // Take average as new targets
159 Target[i][j][k] = Average[i][j][k];
160 SlowDataClass->AddToEntry("%d %d %d %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k]);
161 break;
162 case FB_ResponseFirst: // First point of response measurement done
163 Buffer[i][j][k] = Average[i][j][k];
164 if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage);
165 break;
166 case FB_ResponseSecond: // Determine response from signal variation
167 if(Buffer[i][j][k] == Average[i][j][k]) {
168 m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k);
169 Response[i][j][k] = 0;
170 }
171 else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]);
172 SlowDataClass->AddToEntry("%d %d %d %.3f ", i,j,k,Response[i][j][k]);
173 if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2);
174 break;
175 default: break; // to suppress warning abount not handled enumeration value
176 }
177 }
178
179 switch (FBMode) {
180 case FB_Targets:
181 m->PrintMessage("HV Feedback: New targets set, switching off.\n");
182 FBMode = FB_Off;
183 break;
184 case FB_ResponseFirst:
185 FBMode = FB_ResponseSecond;
186 m->PrintMessage("HV Feedback: Increasing voltages by %f for response measurement, acquiring data.\n", DiffVoltage);
187 break;
188 case FB_ResponseSecond:
189 m->PrintMessage("HV Feedback: Response measurements finished, original voltages set, switching off.\n");
190 FBMode = FB_Off;
191 break;
192 default: break; // to suppress warning abount not handled enumeration value
193 }
194 ClearAverages();
195 return true;
196}
197
198//
199// Clear average values and event counter
200//
201void HVFeedback::ClearAverages() {
202 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
203 for (int j=0; j<kNumberOfChips; j++)
204 for (int k=0; k<kNumberOfChannels; k++) {
205 Average[i][j][k] = 0.0;
206 Sigma[i][j][k] = 0.0;
207 }
208 Count = 0;
209}
210
211//
212// Number of events to accumulate before correction acts
213//
214void HVFeedback::SetNumAverages(unsigned int Averages) {
215 NumAverages = Averages;
216}
217
218//
219// Get requested number of events
220//
221unsigned int HVFeedback::GetNumAverages() {
222 return NumAverages;
223}
224
225//
226// Set feedback gain
227//
228void HVFeedback::SetGain(float FBGain) {
229 Gain = FBGain;
230}
231
232//
233// Get feedback gain
234//
235float HVFeedback::GetGain() {
236 return Gain;
237}
238
239//
240// Set feedback mode and clear averages
241//
242void HVFeedback::SetFBMode(FBState Mode) {
243 if(Mode==FB_ResponseFirst || Mode==FB_ResponseFirst)
244 m->PrintMessage("Start reponse measurement by calling MeasureResponse().\n");
245 else {
246 FBMode = Mode;
247 ClearAverages();
248 }
249}
250
251//
252// Set feedback mode and clear averages
253//
254FBState HVFeedback::GetFBMode() {
255 switch (FBMode) {
256 case FB_Off: m->PrintMessage("Feedback off.\n"); break;
257 case FB_Active: m->PrintMessage("Feedback active.\n"); break;
258 case FB_Targets: m->PrintMessage("Feedback acquiring new targets.\n"); break;
259 case FB_ResponseFirst: m->PrintMessage("Feedback measuring response with first voltage.\n"); break;
260 case FB_ResponseSecond: m->PrintMessage("Feedback measuring response with second voltage.\n"); break;
261 }
262 return FBMode;
263}
264
265//
266// Return current number of events
267//
268unsigned int HVFeedback::GetCurrentCount() {
269 return Count;
270}
271
272//
273// Set target values
274//
275void HVFeedback::SetTarget(int Board, int Chip, int Channel, float TargetVal) {
276 if(Board<m->NumCMCBoards && Chip<kNumberOfChips && Channel<kNumberOfChannels)
277 Target[Board][Chip][Channel] = TargetVal;
278 else printf("Invalid board, chip or channel number.\n");
279}
280
281//
282// Print target values
283//
284void HVFeedback::GetTargets() {
285 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
286 for (int j=0; j<kNumberOfChips; j++)
287 for (int k=0; k<kNumberOfChannels; k++)
288 m->PrintMessage("Board %d, chip %d, channel %d: %.2f\n",i,j,k,Target[i][j][k]);
289}
290
291//
292// Measure response matrix
293//
294void HVFeedback::MeasureResponse(float U) {
295
296 if (U==0) m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n");
297 else {
298 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
299 for (int j=0; j<kNumberOfChips; j++)
300 for (int k=0; k<kNumberOfChannels-2; k++) {
301 if(PixMap->DRS_to_Pixel(i,j,k).empty()) m->PrintMessage("Could not find pixel ID of board %d, chip %d, channel %d\n",i,j,k);
302 else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2);
303 }
304 DiffVoltage = U;
305 FBMode = FB_ResponseFirst;
306 ClearAverages();
307 m->PrintMessage("HV Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2);
308 }
309}
310
311//
312// Print response values
313//
314void HVFeedback::GetResponse() {
315 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
316 for (int j=0; j<kNumberOfChips; j++)
317 for (int k=0; k<kNumberOfChannels; k++)
318 m->PrintMessage("Board %d, chip %d, channel %d: %.3f\n",i,j,k,Response[i][j][k]);
319}
320
321//
322// Write commmand to socket
323//
324bool HVFeedback::WriteHVCommand(const char *Format, ...) {
325 char Textbuffer[MAX_COM_SIZE];
326 fd_set SelectDescriptor;
327 int RetryCount=0;
328
329 do {
330 va_list ArgumentPointer; va_start(ArgumentPointer, Format);
331 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
332
333 // Write command to socket
334 if(write(SocketDescriptor, Textbuffer, strlen(Textbuffer)+1)!=(int) strlen(Textbuffer)+1) {
335 m->PrintMessage("Error: Could not write (entire) command to HV socket (%s)\n", strerror(errno));
336 return false;
337 }
338
339 // Wait for command acknowledge from hvcontrol program
340 FD_ZERO(&SelectDescriptor); FD_SET(SocketDescriptor, &SelectDescriptor);
341 struct timeval WaitTime = {fMaxCmdAckDelay, 0};
342 if (select(((int) SocketDescriptor)+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
343 m->PrintMessage("Error with select() in command acknowledge (%s)\n", strerror(errno));
344 return false;
345 }
346 if (!FD_ISSET(SocketDescriptor, &SelectDescriptor)) { // Time-out expired
347 m->PrintMessage("Time-out of %d seconds expired before receiving acknowledge from HV socket.\n", fMaxCmdAckDelay);
348 return false;
349 }
350 if (read(SocketDescriptor, Textbuffer, MAX_COM_SIZE) == -1) {
351 m->PrintMessage("Error reading acknowledge from HV socket (%s)\n", strerror(errno));
352 return false;
353 }
354 } while (strstr(Textbuffer,"WC ok")==NULL && ++RetryCount<=MAX_RETRY);
355 if(RetryCount==MAX_RETRY) {
356 m->PrintMessage("Could not set high voltage after %d tries.\n", MAX_RETRY);
357 return false;
358 }
359 return true;
360}
361
362//
363// Print feedback configuration
364//
365void HVFeedback::PrintConfig() {
366 m->PrintMessage("LedTrigBoard: %d\t\tLedTrigChip: %d\t\tLedTrigChannel: %d\n"
367 "LedTrigSample: %d\tLedTrigThreshold: %.2f\n"
368 "LedSignalSample: %d\tLedBaselineSample: %d\tDefaultNumAverage: %d\n"
369 "IntHalfWidth:%u\tHVControlServer: %s\tHVControlPort: %d\n"
370 "MaxCmdAckDelay: %d\n",
371 fLedTrigBoard, fLedTrigChip, fLedTrigChannel, fLedTrigSample,
372 fLedTrigThreshold, fLedSignalSample, fLedBaselineSample,
373 fDefaultNumAverage, fIntHalfWidth, fHVControlServer, fHVControlPort, fMaxCmdAckDelay);
374}
Note: See TracBrowser for help on using the repository browser.