Ignore:
Timestamp:
06/09/13 13:10:56 (11 years ago)
Author:
tbretz
Message:
Implemented the algorithms needed for the new type current control (there was a bug in the old one which actually stopped when the voltage was 'target voltage minus next step' which is about 1.0V. The new current control is not yet enabled, it is only there as code. It needs to be tested and then all depending values need adaption.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/feedback.cc

    r16413 r16781  
    3737        kFeedbackGlobal,
    3838        kCurrents,
     39        kCurrentsNew,
    3940    };
    4041
     
    9495    int HandleCameraTemp(const EventImp &evt)
    9596    {
    96         if (fControlType!=kTemp && fControlType!=kCurrents)
     97        if (fControlType!=kTemp && fControlType!=kCurrents && fControlType!=kCurrentsNew)
    9798            return GetCurrentState();
    9899
     
    123124        fCursorTemp++;
    124125
    125         return HandleCurrentControl();
     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();
    126364    }
    127365
     
    8061044            HandleCalibration(evt);
    8071045
    808         if (fControlType==kFeedbackGlobal || fControlType==kCurrents)
     1046        if (fControlType==kFeedbackGlobal || fControlType==kCurrents || fControlType==kCurrentsNew)
    8091047            AverageCurrents(evt);
    8101048
     
    9531191        fOutputEnabled = evt.GetBool();
    9541192
    955         if (fControlType==kCurrents)
     1193        if (fControlType==kCurrents || fControlType==kCurrentsNew)
    9561194            if (fCursorTemp>1)
    9571195                fCursorTemp = 1;
     
    10581296        ostringstream out;
    10591297        out << "Starting current/temp feedback with an offset of " << fBiasOffset << "V";
     1298        Message(out);
     1299
     1300        return GetCurrentState();
     1301    }
     1302
     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";
    10601323        Message(out);
    10611324
     
    12481511                return fOutputEnabled ? Feedback::State::kTempCtrlRunning : Feedback::State::kTempCtrlIdle;
    12491512            }
    1250             if (fControlType==kCurrents)
     1513            if (fControlType==kCurrents || fControlType==kCurrentsNew)
    12511514            {
    12521515                static Time past;
Note: See TracChangeset for help on using the changeset viewer.