source: drsdaq/HVFeedback.cc@ 97

Last change on this file since 97 was 92, checked in by ogrimm, 16 years ago
Added some configuration parameters. Log file written outside of repository.
File size: 14.1 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
27 m = DAQClass;
28 PixMap = new PixelMap(PIXMAP_LOCATION, false);
29
30 // Create instance of slow data class for feedback
31 SlowDataClass = new SlowData("HVFB", m->fSlowDataPath);
32 if (SlowDataClass->ErrorCode != 0) {
33 m->PrintMessage("Warning: Could not open feedback slowdata file (%s)\n", strerror(SlowDataClass->ErrorCode));
34 }
35 SlowDataClass->NewEntry("Average-Info", "Feedback regulation occurred: Board Chip Channel Average Sigma Correction-Value");
36 SlowDataClass->NewEntry("Target-Info", "New Target values acquired: Board Chip Channel Target Sigma");
37 SlowDataClass->NewEntry("Response-Info", "New response measurement: Board Chip Channel Response");
38
39 // Initialise with zero content
40 Average = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels]();
41 Sigma = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels]();
42 Response = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels]();
43 Target = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels]();
44 Buffer = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels]();
45
46 // Read configuration file
47 FILE *File;
48 if ((File = fopen(Configfile,"r")) == NULL) {
49 printf("Error: Could not open feedback configuration file '%s'\n", Configfile);
50 }
51 else {
52 printf("Reading feedback configuration file %s\n", Configfile);
53 ReadCard("TrigBoard", &fLedTrigBoard, 'I', File);
54 ReadCard("TrigChannel", &fLedTrigChannel, 'I', File);
55 ReadCard("TrigChip", &fLedTrigChip, 'I', File);
56 ReadCard("TrigSample", &fLedTrigSample, 'I', File);
57 ReadCard("TrigThreshold", &fLedTrigThreshold, 'f', File);
58 ReadCard("SignalSample", &fLedSignalSample, 'I', File);
59 ReadCard("BaselineSample", &fLedBaselineSample, 'I', File);
60 ReadCard("IntHalfWidth", &fIntHalfWidth, 'U', File);
61 ReadCard("DefaultNumAverage", &fDefaultNumAverage, 'I', File);
62 ReadCard("HVControlServer", fHVControlServer, 's', File);
63 ReadCard("HVControlPort", &fHVControlPort, 'I', File);
64 ReadCard("MaxCmdAckDelay", &fMaxCmdAckDelay, 'I', File);
65 ReadCard("DefaultResponse", Response, 'f', File, m->NumBoards*kNumberOfChips*kNumberOfChannels);
66 fclose(File);
67 }
68 PrintConfig(MsgToLog);
69
70 // Initial state
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");
136 break;
137 case FB_Targets: SlowDataClass->NewEntry("Target");
138 break;
139 case FB_ResponseSecond: SlowDataClass->NewEntry("Response");
140 SlowDataClass->AddToEntry("%.3f ",DiffVoltage);
141 break;
142 default: break; // to suppress warning abount not handled enumeration value
143 }
144
145 for (i=m->FirstBoard; i<=m->LastBoard; i++) {
146 for (j=0; j<kNumberOfChips; j++) {
147 for (k=0; k<kNumberOfChannels; k++) {
148 Average[i][j][k] /= Count;
149 Sigma[i][j][k] = sqrt(Sigma[i][j][k]/Count-pow(Average[i][j][k],2))/sqrt(Count);
150 switch (FBMode) {
151 case FB_Active: // Determine correction from response maxtrix and change voltages
152 Difference = Target[i][j][k] - Average[i][j][k];
153 EffectiveGain = Gain*pow(0.5*(1+(Difference/Sigma[i][j][k]-1)/(Difference/Sigma[i][j][k]+1)),2);
154 Correction = -Difference*Response[i][j][k]*EffectiveGain;
155 if(Correction!=0 && Target[i][j][k]!=0 && !PixMap->DRS_to_Pixel(i,j,k).empty()) {
156 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);
157 SlowDataClass->AddToEntry("%d %d %d %.3f %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k],Correction);
158 if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n");
159 else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(),Correction);
160 }
161 break;
162 case FB_Targets: // Take average as new targets
163 Target[i][j][k] = Average[i][j][k];
164 SlowDataClass->AddToEntry("%d %d %d %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k]);
165 break;
166 case FB_ResponseFirst: // First point of response measurement done
167 Buffer[i][j][k] = Average[i][j][k];
168 if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage);
169 break;
170 case FB_ResponseSecond: // Determine response from signal variation
171 if(Buffer[i][j][k] == Average[i][j][k]) {
172 m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k);
173 Response[i][j][k] = 0;
174 }
175 else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]);
176 SlowDataClass->AddToEntry("%d %d %d %.3f ", i,j,k,Response[i][j][k]);
177 if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2);
178 break;
179 default: break; // to suppress warning abount not handled enumeration value
180 }
181 }
182 }
183 }
184
185 switch (FBMode) {
186 case FB_Targets:
187 m->PrintMessage("HV Feedback: New targets set, switching off.\n");
188 FBMode = FB_Off;
189 break;
190 case FB_ResponseFirst:
191 FBMode = FB_ResponseSecond;
192 m->PrintMessage("HV Feedback: Increasing voltages by %f for response measurement, acquiring data.\n", DiffVoltage);
193 break;
194 case FB_ResponseSecond:
195 m->PrintMessage("HV Feedback: Response measurements finished, original voltages set, switching off.\n");
196 FBMode = FB_Off;
197 break;
198 default: break; // to suppress warning abount not handled enumeration value
199 }
200
201 if(m->SlowDataClass->ErrorCode != 0) {
202 m->PrintMessage("Error, could not write feedback slow data to file (%s), file closed.\n", strerror(m->SlowDataClass->ErrorCode));
203 }
204 ClearAverages();
205
206 return true;
207}
208
209//
210// Clear average values and event counter
211//
212void HVFeedback::ClearAverages() {
213 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
214 for (int j=0; j<kNumberOfChips; j++)
215 for (int k=0; k<kNumberOfChannels; k++) {
216 Average[i][j][k] = 0.0;
217 Sigma[i][j][k] = 0.0;
218 }
219 Count = 0;
220}
221
222//
223// Number of events to accumulate before correction acts
224//
225void HVFeedback::SetNumAverages(unsigned int Averages) {
226 NumAverages = Averages;
227}
228
229//
230// Get requested number of events
231//
232unsigned int HVFeedback::GetNumAverages() {
233 return NumAverages;
234}
235
236//
237// Set feedback gain
238//
239void HVFeedback::SetGain(float FBGain) {
240 Gain = FBGain;
241}
242
243//
244// Get feedback gain
245//
246float HVFeedback::GetGain() {
247 return Gain;
248}
249
250//
251// Set feedback mode and clear averages
252//
253void HVFeedback::SetFBMode(FBState Mode) {
254 if(Mode==FB_ResponseFirst || Mode==FB_ResponseFirst)
255 m->PrintMessage("Start reponse measurement by calling MeasureResponse().\n");
256 else {
257 FBMode = Mode;
258 ClearAverages();
259 }
260}
261
262//
263// Set feedback mode and clear averages
264//
265FBState HVFeedback::GetFBMode() {
266 switch (FBMode) {
267 case FB_Off: m->PrintMessage("Feedback off.\n"); break;
268 case FB_Active: m->PrintMessage("Feedback active.\n"); break;
269 case FB_Targets: m->PrintMessage("Feedback acquiring new targets.\n"); break;
270 case FB_ResponseFirst: m->PrintMessage("Feedback measuring response with first voltage.\n"); break;
271 case FB_ResponseSecond: m->PrintMessage("Feedback measuring response with second voltage.\n"); break;
272 }
273 return FBMode;
274}
275
276//
277// Return current number of events
278//
279unsigned int HVFeedback::GetCurrentCount() {
280 return Count;
281}
282
283//
284// Set target values
285//
286void HVFeedback::SetTarget(int Board, int Chip, int Channel, float TargetVal) {
287 if(Board<m->NumBoards && Chip<kNumberOfChips && Channel<kNumberOfChannels)
288 Target[Board][Chip][Channel] = TargetVal;
289 else printf("Invalid board, chip or channel number.\n");
290}
291
292//
293// Print target values
294//
295void HVFeedback::GetTargets() {
296 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
297 for (int j=0; j<kNumberOfChips; j++)
298 for (int k=0; k<kNumberOfChannels; k++)
299 m->PrintMessage("Board %d, chip %d, channel %d: %.2f\n",i,j,k,Target[i][j][k]);
300}
301
302//
303// Measure response matrix
304//
305void HVFeedback::MeasureResponse(float U) {
306
307 if (U==0) m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n");
308 else {
309 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
310 for (int j=0; j<kNumberOfChips; j++)
311 for (int k=0; k<kNumberOfChannels-2; k++) {
312 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);
313 else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2);
314 }
315 DiffVoltage = U;
316 FBMode = FB_ResponseFirst;
317 ClearAverages();
318 m->PrintMessage("HV Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2);
319 }
320}
321
322//
323// Print response values
324//
325void HVFeedback::GetResponse() {
326 for (int i=m->FirstBoard; i<=m->LastBoard; i++)
327 for (int j=0; j<kNumberOfChips; j++)
328 for (int k=0; k<kNumberOfChannels; k++)
329 m->PrintMessage("Board %d, chip %d, channel %d: %.3f\n",i,j,k,Response[i][j][k]);
330}
331
332//
333// Write commmand to socket
334//
335bool HVFeedback::WriteHVCommand(const char *Format, ...) {
336 char Textbuffer[MAX_COM_SIZE];
337 fd_set SelectDescriptor;
338 int RetryCount=0;
339
340 do {
341 va_list ArgumentPointer; va_start(ArgumentPointer, Format);
342 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
343
344 // Write command to socket
345 if(write(SocketDescriptor, Textbuffer, strlen(Textbuffer)+1)!=(int) strlen(Textbuffer)+1) {
346 m->PrintMessage("Error: Could not write (entire) command to HV socket (%s)\n", strerror(errno));
347 return false;
348 }
349
350 // Wait for command acknowledge from hvcontrol program
351 FD_ZERO(&SelectDescriptor); FD_SET(SocketDescriptor, &SelectDescriptor);
352 struct timeval WaitTime = {fMaxCmdAckDelay, 0};
353 if (select(((int) SocketDescriptor)+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
354 m->PrintMessage("Error with select() in command acknowledge (%s)\n", strerror(errno));
355 return false;
356 }
357 if (!FD_ISSET(SocketDescriptor, &SelectDescriptor)) { // Time-out expired
358 m->PrintMessage("Time-out of %d seconds expired before receiving acknowledge from HV socket.\n", fMaxCmdAckDelay);
359 return false;
360 }
361 if (read(SocketDescriptor, Textbuffer, MAX_COM_SIZE) == -1) {
362 m->PrintMessage("Error reading acknowledge from HV socket (%s)\n", strerror(errno));
363 return false;
364 }
365 } while (strstr(Textbuffer,"WC ok")==NULL && ++RetryCount<=MAX_RETRY);
366 if(RetryCount==MAX_RETRY) {
367 m->PrintMessage("Could not set high voltage after %d tries.\n", MAX_RETRY);
368 return false;
369 }
370 return true;
371}
372
373//
374// Print feedback configuration
375//
376void HVFeedback::PrintConfig(int Target) {
377 m->PrintMessage(Target, "LedTrigBoard: %d\t\tLedTrigChip: %d\t\tLedTrigChannel: %d\n"
378 "LedTrigSample: %d\tLedTrigThreshold: %.2f\n"
379 "LedSignalSample: %d\tLedBaselineSample: %d\tDefaultNumAverage: %d\n"
380 "IntHalfWidth:%u\tHVControlServer: %s\tHVControlPort: %d\n"
381 "MaxCmdAckDelay: %d\n",
382 fLedTrigBoard, fLedTrigChip, fLedTrigChannel, fLedTrigSample,
383 fLedTrigThreshold, fLedSignalSample, fLedBaselineSample,
384 fDefaultNumAverage, fIntHalfWidth, fHVControlServer, fHVControlPort, fMaxCmdAckDelay);
385}
Note: See TracBrowser for help on using the repository browser.