source: drsdaq/HVFeedback.cc@ 138

Last change on this file since 138 was 110, checked in by ogrimm, 15 years ago
DAQ can run without writing data to disk, bug fix to RawDataCTX reading routine
File size: 14.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 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 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("Feedback 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+m->TriggerCell[fLedTrigBoard][fLedTrigChip])%kNumberOfBins] < 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->TriggerCell[i][j])%kNumberOfBins] - m->WaveForm[i][j][k][(fLedBaselineSample+q+m->TriggerCell[i][j])%kNumberOfBins])*m->drs->GetBoard(i)->GetPrecision();
126 Integral /= 2*fIntHalfWidth+1;
127 Average[i][j][k] += Integral;
128 Sigma[i][j][k] += pow(Integral,2);
129 }
130
131 // Check if acquired number of event requires action
132 if (++Count<NumAverages) return false;
133
134 // Make entry in slow data file
135 switch (FBMode) {
136 case FB_Active: SlowDataClass->NewEntry("Average");
137 break;
138 case FB_Targets: SlowDataClass->NewEntry("Target");
139 break;
140 case FB_ResponseSecond: SlowDataClass->NewEntry("Response");
141 SlowDataClass->AddToEntry("%.3f ",DiffVoltage);
142 break;
143 default: break; // to suppress warning abount not handled enumeration value
144 }
145
146 // Feedback action
147 for (i=m->FirstBoard; i<=m->LastBoard; i++) {
148 for (j=0; j<kNumberOfChips; j++) {
149 for (k=0; k<kNumberOfChannels; k++) {
150 Average[i][j][k] /= Count;
151 Sigma[i][j][k] = sqrt(Sigma[i][j][k]/Count-pow(Average[i][j][k],2))/sqrt(Count);
152 switch (FBMode) {
153 case FB_Active: // Determine correction from response maxtrix and change voltages
154 Difference = Target[i][j][k] - Average[i][j][k];
155 EffectiveGain = Gain*pow(0.5*(1+(Difference/Sigma[i][j][k]-1)/(Difference/Sigma[i][j][k]+1)),2);
156 Correction = -Difference*Response[i][j][k]*EffectiveGain;
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.