source: drsdaq/HVFeedback.cc@ 154

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