source: drsdaq/HVFeedback.cc@ 51

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