- Timestamp:
- 05/28/13 17:52:26 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/FACT++/src/feedback.cc
r16282 r16412 37 37 kFeedbackGlobal, 38 38 kCurrents, 39 kCurrentsNew,40 39 }; 41 40 … … 95 94 int HandleCameraTemp(const EventImp &evt) 96 95 { 97 if (fControlType!=kTemp && fControlType!=kCurrents && fControlType!=kCurrentsNew)96 if (fControlType!=kTemp && fControlType!=kCurrents) 98 97 return GetCurrentState(); 99 98 … … 124 123 fCursorTemp++; 125 124 126 return fControlType==kCurrentsNew ? HandleCurrentControlNew() : HandleCurrentControl(); 127 } 128 129 int HandleCurrentControlNew() 130 { 131 if (GetCurrentState()==Feedback::State::kCalibrating && fBiasOffset>fTempOffset-1.2) 132 { 133 fCursorTemp = 0; 134 135 ostringstream msg; 136 msg << " (applied calibration offset " << fBiasOffset << "V exceeds temperature correction " << fTempOffset << "V - 1.2V."; 137 Warn("Trying to calibrate above G-APD breakdown volatge!"); 138 Warn(msg); 139 return GetCurrentState(); 140 } 141 142 double avg[2] = { 0, 0 }; 143 double min[2] = { 90, 90 }; 144 double max[2] = { -90, -90 }; 145 int num[2] = { 0, 0 }; 146 147 vector<double> med[2]; 148 med[0].resize(416); 149 med[1].resize(416); 150 151 const float *Ravg = fCalibration.data()+BIAS::kNumChannels*2; // Measured resistance 152 153 vector<float> vec(2*BIAS::kNumChannels+2); 154 155 vec[BIAS::kNumChannels*2] = fTempOffset; 156 vec[BIAS::kNumChannels*2+1] = fBiasOffset; 157 158 float *Uoff = vec.data()+BIAS::kNumChannels; 159 160 if (GetCurrentState()==Feedback::State::kCalibrating) 161 for (int i=0; i<BIAS::kNumChannels; i++) 162 Uoff[i] = fBiasOffset; 163 else 164 for (int i=0; i<BIAS::kNumChannels; i++) 165 Uoff[i] = fTempOffset+fBiasOffset; 166 167 if (fControlType==kCurrentsNew) 168 { 169 // Would be a devision by zero. We need informations first. 170 if (fCursorCur==0) 171 return GetCurrentState(); 172 173 for (int i=0; i<BIAS::kNumChannels; i++) 174 { 175 const PixelMapEntry &hv = fMap.hv(i); 176 if (!hv) 177 continue; 178 179 // Nominal breakdown voltage (includes overvoltage already) 180 double Ubd = fVoltGapd[i]; 181 182 // Nominal breakdown voltage excluding overvoltage of 1.1V 183 Ubd -= 1.1; 184 185 // Correct breakdown voltage for temperature dependence 186 Ubd += fTempOffset; 187 188 // Number of G-APDs in this patch 189 const int N = hv.group() ? 5 : 4; 190 191 // 100 Ohm measurement resistor for current measurement 192 const double R2 = 100; 193 194 // Serial resistors (one 1kOhm at the output of the bias crate, one 1kOhm in the camera) 195 const double R4 = 2000; 196 197 // Serial resistor of the individual G-APDs 198 double R5 = 3900/N; 199 200 // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor 201 if (i==66) // Pixel 830(66) 202 R5 = 300; // 2400 = 1/(3/3900 + 1/390) 203 if (i==191 || i==193) // Pixel 583(191) / Pixel 1401(193) 204 R5 = 390/1.4; // 379 = 1/(4/3900 + 1/390) 205 206 // Total resistance of branch with diode 207 const double R3 = R4+R5; 208 209 // Measured calibration resistor 210 const double R1 = Ravg[i] - R2; 211 212 // Voltage output of bias crate 213 const double Uout = fBiasVolt[i]; 214 215 // Average current measured for this channel 216 const double Imes = double(fCurrentsAvg[i])/fCursorCur * (5000/4096.); // [uA] 217 218 // Voltage drop at measurement resistor R2 is define 219 // bythe measured current and the resistor 220 const double U2 = R2*Imes; 221 222 // The voltage seen by the calibration resistor R1 is defined by the 223 // bias crate output voltage minus the drop at the measurement resistor R2 224 const double U1 = Uout - U2; 225 226 // The current through the resistor R1 is defined 227 // by the applied voltage and the resistor 228 const double I1 = U1/R1; 229 230 // The current through the diode branch is the measured current 231 // minus the current through the calibration resistor R1 232 const double I3 = Imes - I1; 233 234 // The voltage drop in the diode branch (without the diode) is defined by the 235 // resistor and the current. It is 0 below the breakdown voltage of the G-APD 236 // is reached at the G-APD. This is the case when the output voltage minus 237 // the voltage drop at the calibration resistor reaches the breakdown voltage. 238 const double U3 = Uout-U2<Ubd ? 0 : R3*I3; 239 240 // Voltage drop at measurement resistor R2 and 241 // the total serial resistor R3 in the diode branch 242 const double Udrp = U2 + U3; 243 244 // Voltage finally at each G-APD (bias crate output voltage minus voltage drop) 245 const double Uapd = Uout - Udrp; 246 247 // The over-voltage seen by the G-APD (the voltage above the breakdown voltage) is 248 const double Uov = Uapd<Ubd ? 0 : Uapd - Ubd; 249 250 // The current through one G-APD is the sum divided by the number of G-APDs 251 // (assuming identical serial resistors) 252 double Iapd = I3/N; 253 254 // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor 255 // In this and the previosu case we neglect the resistance of the G-APDs, but we can make an 256 // assumption: The differential resistance depends more on the NSB than on the PDE, 257 // thus it is at least comparable for all G-APDs in the patch. In addition, although the 258 // G-APD with the 390Ohm serial resistor has the wrong voltage applied, this does not 259 // significantly influences the ohmic resistor or the G-APD because the differential 260 // resistor is large enough that the increase of the overvoltage does not dramatically 261 // increase the current flow as compared to the total current flow. 262 if (i==66) 263 Iapd *= 1.3; 264 if (i==191 || i==193) 265 Iapd *= 1.4; 266 267 // If the G-APD voltage is above the breakdown voltage we have the current through the 268 // G-APD and the over-voltage applied to the G-APD to calculate its differential resistor. 269 if (Uapd>Ubd) 270 { 271 // The differential resistance of the G-APD, i.e. the dependence of the 272 // current above the breakdown voltage, is given by 273 const double Rapd = Uov/Iapd; 274 275 // This allows us to estimate the current Iov at the overvoltage we want to apply 276 const double Iov = (1.1+fBiasOffset)/Rapd; 277 278 // This gives us an ohmic resistance Rov of the G-APD at the set-point 279 const double Rest = (Ubd+1.1+fBiasOffset)/Iov; 280 281 // This lets us estimate the total resistance Rtot of the circuit at the set-point 282 const double R3b = R4 + (R5+Rest)/N; 283 const double Rtot = R2 + 1/(1/R1 + 1/R3b); 284 285 // From this we can estimate the output voltage we need to get the 286 // over-voltage at the G-APD as anticipated 287 const double r = 1 + R3/R1 - (R2 + R3 + R3*R2/R1)/Rtot; 288 const double Uset = (Ubd+1.1+fBiasOffset)/r; 289 290 Uoff[i] = Uset - fVoltGapd[i]; 291 } 292 293 // Calculate statistics only for channels with a valid calibration 294 if (Uov>0) 295 { 296 const int g = hv.group(); 297 298 med[g][num[g]] = Uov; 299 avg[g] += Uov; 300 num[g]++; 301 302 if (Uov<min[g]) 303 min[g] = Uov; 304 if (Uov>max[g]) 305 max[g] = Uov; 306 } 307 } 308 309 sort(med[0].begin(), med[0].begin()+num[0]); 310 sort(med[1].begin(), med[1].begin()+num[1]); 311 312 fCurrentsAvg.assign(BIAS::kNumChannels, 0); 313 fCursorCur = 0; 314 } 315 316 fDimDeviation.setQuality(fControlType); 317 fDimDeviation.Update(vec); 318 319 // Warning: Here it is assumed that the ramp up and down is done properly 320 // within the time between two new temperatures and that the calibration 321 // is finished within that time. 322 if (GetCurrentState()!=Feedback::State::kCalibrating || 323 fDimBias.state()!=BIAS::State::kVoltageOff || 324 fCursorTemp!=1 || !fOutputEnabled) 325 { 326 if (!fOutputEnabled || fDimBias.state()!=BIAS::State::kVoltageOn) 327 return GetCurrentState(); 328 329 // Trigger calibration 330 if (GetCurrentState()==Feedback::State::kCalibrating && fCursorTemp==2) 331 { 332 DimClient::sendCommandNB("BIAS_CONTROL/REQUEST_STATUS", NULL, 0); 333 return GetCurrentState(); 334 } 335 } 336 337 ostringstream msg; 338 msg << setprecision(4) << "Sending new absolute offset (" << fAppliedOffset << "V+" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0) << "V) to biasctrl."; 339 Info(msg); 340 341 if (fControlType==kCurrents && num[0]>0 && num[1]>0) 342 { 343 msg.str(""); 344 msg << " Avg0=" << setw(7) << avg[0]/num[0] << " | Avg1=" << setw(7) << avg[1]/num[1]; 345 Debug(msg); 346 347 msg.str(""); 348 msg << " Med0=" << setw(7) << med[0][num[0]/2] << " | Med1=" << setw(7) << med[1][num[1]/2]; 349 Debug(msg); 350 351 msg.str(""); 352 msg << " Min0=" << setw(7) << min[0] << " | Min1=" << setw(7) << min[1]; 353 Debug(msg); 354 355 msg.str(""); 356 msg << " Max0=" << setw(7) << max[0] << " | Max1=" << setw(7) << max[1]; 357 Debug(msg); 358 } 359 360 DimClient::sendCommandNB("BIAS_CONTROL/SET_ALL_CHANNELS_OFFSET", 361 vec.data()+BIAS::kNumChannels, BIAS::kNumChannels*sizeof(float)); 362 363 return GetCurrentState(); 125 return HandleCurrentControl(); 364 126 } 365 127 … … 965 727 void HandleCalibrateCurrents(const EventImp &evt) 966 728 { 967 if (fBiasVolt. empty() || fCalibration.empty()|| evt.GetSize()<416*sizeof(int16_t))729 if (fBiasVolt.size()==0 || fCalibration.size()==0 || evt.GetSize()<416*sizeof(int16_t)) 968 730 return; 969 731 … … 1044 806 HandleCalibration(evt); 1045 807 1046 if (fControlType==kFeedbackGlobal || fControlType==kCurrents || fControlType==kCurrentsNew)808 if (fControlType==kFeedbackGlobal || fControlType==kCurrents) 1047 809 AverageCurrents(evt); 1048 810 … … 1113 875 int PrintCalibration() 1114 876 { 1115 if (fCalibration. empty())877 if (fCalibration.size()==0) 1116 878 { 1117 879 Out() << "No calibration performed so far." << endl; … … 1191 953 fOutputEnabled = evt.GetBool(); 1192 954 1193 if (fControlType==kCurrents || fControlType==kCurrentsNew)955 if (fControlType==kCurrents) 1194 956 if (fCursorTemp>1) 1195 957 fCursorTemp = 1; … … 1281 1043 return kSM_FatalError; 1282 1044 1283 if (fCalibration. empty())1045 if (fCalibration.size()==0) 1284 1046 { 1285 1047 Warn("Current control needs a bias crate calibration first... command ignored."); … … 1301 1063 } 1302 1064 1303 int StartNewCurrentCtrl(const EventImp &evt)1304 {1305 if (!CheckEventSize(evt.GetSize(), "StartNewCurrentCtrl", 4))1306 return kSM_FatalError;1307 1308 if (fCalibration.empty())1309 {1310 Warn("Current control needs a bias crate calibration first... command ignored.");1311 return GetCurrentState();1312 }1313 1314 WarnState(true, false);1315 1316 fBiasOffset = evt.GetFloat();1317 fTempOffset = -3;1318 ResetData(0);1319 fControlType = kCurrentsNew;1320 1321 ostringstream out;1322 out << "Starting new current/temp feedback with an offset of " << fBiasOffset << "V";1323 Message(out);1324 1325 return GetCurrentState();1326 }1327 1328 1065 int StopFeedback() 1329 1066 { … … 1393 1130 } 1394 1131 1395 if (fVoltGapd. empty())1132 if (fVoltGapd.size()==0) 1396 1133 { 1397 1134 Error("No G-APD reference voltages received yet (BIAS_CONTROL/NOMINAL)."); … … 1511 1248 return fOutputEnabled ? Feedback::State::kTempCtrlRunning : Feedback::State::kTempCtrlIdle; 1512 1249 } 1513 if (fControlType==kCurrents || fControlType==kCurrentsNew)1250 if (fControlType==kCurrents) 1514 1251 { 1515 1252 static Time past;
Note:
See TracChangeset
for help on using the changeset viewer.