source: drsdaq/HVFeedback.cc@ 73

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