Ignore:
Timestamp:
04/26/12 10:51:16 (13 years ago)
Author:
tbretz
Message:
Receive nominal bias voltage; added an option to set the calibration offset; the calibration offset is now relative only to the nominal G-APD breakdown voltage rather than the temperature corrected one; from the calibration current a slope (calibration resistor) is caluclated and distributed via dim service; the calibration resistor is taken into account when calculating the current feedback value.
File:
1 edited

Legend:

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

    r13255 r13453  
    9090
    9191    DimStampedInfo fBiasData;
     92    DimStampedInfo fBiasNom;
    9293    DimStampedInfo fCameraTemp;
    9394
     
    100101
    101102    vector<float>    fCalibration;
     103    vector<float>    fVoltGapd;
    102104
    103105    vector<vector<float>> fData;
     
    122124
    123125    double fBiasOffset;
     126    double fCalibrationOffset;
     127    double fAppliedOffset;
    124128
    125129    uint16_t fCurrentRequestInterval;
     
    160164            return;
    161165
    162         avgt /= numt;
    163 
    164 
    165         const float diff = (avgt-25)*4./70 + fBiasOffset;
     166        avgt /= numt; // [deg C]
     167
     168        const double dUt = (avgt-25)*4./70; // [V]
     169
     170        if (GetCurrentState()==kStateCalibrating && fBiasOffset>dUt-1.2)
     171        {
     172            ostringstream msg;
     173            msg << " (applied calibration offset " << fBiasOffset << "V exceeds temperature correction " << avgt << "V - 1.2V.";
     174            Warn("Trying to calibrate above G-APD breakdown volatge!");
     175            Warn(msg);
     176            return;
     177        }
     178
     179        // FIXME: If calibrating do not wait for the temperature!
     180        fAppliedOffset = fBiasOffset;
     181        if (GetCurrentState()!=kStateCalibrating)
     182            fAppliedOffset += dUt;
    166183
    167184        vector<float> vec(2*BIAS::kNumChannels);
    168185        for (int i=0; i<BIAS::kNumChannels; i++)
    169             vec[i+BIAS::kNumChannels] = diff;
     186            vec[i+BIAS::kNumChannels] = fAppliedOffset;
    170187
    171188        double avg[2] = {   0,   0 };
     
    186203            }
    187204
    188             // Pixel  583: 5 31 == 191 (5)
    189             // Pixel  830: 2  2 ==  66 (4)
    190             // Pixel 1401: 6  1 == 193 (5)
    191 
    192205            // Convert from DAC counts to uA
    193206            const double conv = 5000e-6/4096;
     
    195208            // 3900 Ohm/n + 1000 Ohm + 1100 Ohm  (with n=4 or n=5)
    196209            const double R[2] = { 3075, 2870 };
     210
     211            const float *Iavg = fCalibration.data();                      // Offset at U=fCalibrationOffset
     212            const float *Ravg = fCalibration.data()+BIAS::kNumChannels*2; // Measured resistance
     213
     214            // U0 = fCalibrationOffset
     215            // dT = fAppliedVoltage
     216
     217            // Ifeedback = Im[i] - (U[i]-U0)/Ravg[i] - Iavg[i];
     218            // dUapplied[i] + dUneu[i] = R[g] * (Im[i] - (dUapplied[i]+dUneu[i]-U0+dT)/Ravg[i] - Iavg[i])
     219
     220            // The assumption here is that the offset calculated from the temperature
     221            // does not significanly change within a single step
     222
     223            // dU[i] := dUtotal[i] = dUapplied[i] + dUneu[i]
     224            // dU[i] / R[g]               = Im[i] - (dU[i]+dT-U0)/Ravg[i] - Iavg[i]
     225            // dU[i]/R[g] + dU[i]/Ravg[i] = Im[i] + U0/Ravg[i] - dT/Ravg[i] - Iavg[i]
     226            // dU[i]*(1/R[g]+1/Ravg[i])   = Im[i] - Iavg[i] + U0/Ravg[i] - dT/Ravg[i]
     227            // dU[i]   = (Im[i] - Iavg[i] + U0/Ravg[i] - dT/Ravg[i]) / (1/R[g]+1/Ravg[i])
     228            // dU[i] = { Im[i] - Iavg[i] + (U0-dT)/Ravg[i] } * r    with   r := 1 / (1/R[g]+1/Ravg[i])
     229
     230            const double U0 = fCalibrationOffset-fAppliedOffset;
    197231
    198232            for (int i=0; i<BIAS::kNumChannels; i++)
     
    202236                    continue;
    203237
     238                // Average measured current
     239                const double Im = double(fCurrentsAvg[i])/fCursorCur; // [dac]
     240
     241                // Group index (0 or 1) of the of the pixel (4 or 5 pixel patch)
    204242                const int g = hv.group();
    205243
    206                 const double Im = double(fCurrentsAvg[i])/fCursorCur;
    207                 const double I  = Im>fCalibration[i] ? Im-fCalibration[i] : 0;
    208 
    209                 double U  = R[g] * I*conv;
    210 
    211                 // 510 / 390    1.30 ^1.66 =  1.55
    212                 // 470 / 380    1.23       =  1.41
    213                 // 450 / 360    1.25       =  1.45
    214 
    215                 // This is assuming that the broken pixels
    216                 // have a 1kOhm instead of 390 Ohm serial resistor
    217                 if (i==66)
    218                     U *= 2400./R[0];    // (1k)2665 / (390)2400 / (~0)2100
    219                 if (i==191)
    220                     U *= 2320./R[1];    // (1k)2794 / (390)2320 / (~0)2100
    221                 if (i==193)
    222                     U *= 2320./R[1];    // (1k)2665 / (390)2400 / (~0)2100
    223 
    224                 vec[i+BIAS::kNumChannels] += U;
    225 
    226                 if (fCalibration[i]>0)
     244                // Serial resistors in front of the G-APD
     245                double Rg = R[g];
     246
     247                // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
     248                if (i==66)                // Pixel 830(66)
     249                    Rg = 2400;            // 2400 = (3/3900 + 1/390) + 1000 + 1100
     250                if (i==191 || i==193)     // Pixel 583(191) / Pixel 1401(193)
     251                    Rg = 2379;            // 2379 = (4/3900 + 1/390) + 1000 + 1100
     252
     253                const double r = 1./(1./Rg + 1./Ravg[i]); // [Ohm]
     254
     255                // Offset induced by the voltage above the calibration point
     256                const double dI = U0/Ravg[i]; // [V/Ohm]
     257
     258                // Offset at the calibration point (make sure that the calibration is
     259                // valid (Im[i]>Iavg[i]) and we operate above the calibration point)
     260                const double I = Im>Iavg[i] ? (Im - Iavg[i])*conv : 0; // [A]
     261
     262                // Make sure that the averaged resistor is valid
     263                const double dU = Ravg[i]>0 ? r*(I+dI) : 0;
     264
     265                vec[i+BIAS::kNumChannels] += dU;
     266
     267                // Calculate statistics only for channels with a valid calibration
     268                if (Iavg[i]>0)
    227269                {
    228                     med[g][num[g]] = U;
    229                     avg[g] += U;
     270                    med[g][num[g]] = dU;
     271                    avg[g] += dU;
    230272                    num[g]++;
    231273
    232                     if (U<min[g])
    233                         min[g] = U;
    234                     if (U>max[g])
    235                         max[g] = U;
     274                    if (dU<min[g])
     275                        min[g] = dU;
     276                    if (dU>max[g])
     277                        max[g] = dU;
    236278                }
    237279            }
     
    258300
    259301        ostringstream msg;
    260         msg << setprecision(4) << "Sending new absolute offset (" << diff << "V+" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0) << "V) to biasctrl.";
     302        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.";
    261303        Info(msg);
    262304
     
    325367            return;
    326368
    327         fCalibration.resize(BIAS::kNumChannels*2);
     369        fCalibration.resize(BIAS::kNumChannels*3);
     370
     371        float *avg = fCalibration.data();
     372        float *rms = fCalibration.data()+BIAS::kNumChannels;
     373        float *res = fCalibration.data()+BIAS::kNumChannels*2;
     374
    328375        for (int i=0; i<BIAS::kNumChannels; i++)
    329376        {
    330             fCalibration[i]                    = double(fCurrentsAvg[i])/fCursorCur;
    331             fCalibration[i+BIAS::kNumChannels] = sqrt(double(fCurrentsRms[i])/fCursorCur-fCalibration[i]*fCalibration[i]);
     377            const double I = double(fCurrentsAvg[i])/fCursorCur;
     378
     379            res[i] = fVoltGapd[i]/I * 4096/5000e-6;
     380            avg[i] = I;
     381            rms[i] = sqrt(double(fCurrentsRms[i])/fCursorCur-I*I);
    332382        }
    333383
     
    720770        }
    721771
     772        if (curr==&fBiasNom)
     773        {
     774            const float *ptr = reinterpret_cast<float*>(fBiasNom.getData());
     775            fVoltGapd.assign(ptr, ptr+416);
     776            return;
     777        }
     778
    722779        if (curr==&fCameraTemp && (fControlType==kTemp || fControlType==kCurrents))
    723780            HandleCameraTemp();
     
    781838        }
    782839
     840        const float *avg = fCalibration.data();
     841        const float *rms = fCalibration.data()+BIAS::kNumChannels;
     842        const float *res = fCalibration.data()+BIAS::kNumChannels*2;
     843
     844        Out() << "Average current at " << fCalibrationOffset << "V below G-APD operation voltage:\n";
     845
    783846        for (int k=0; k<13; k++)
    784847            for (int j=0; j<8; j++)
     
    786849                Out() << setw(2) << k << "|" << setw(2) << j*4 << "|";
    787850                for (int i=0; i<4; i++)
    788                     Out() << Tools::Form(" %6.1f+-%4.1f", fCalibration[k*32+j*4+i], fCalibration[k*32+j*4+i+BIAS::kNumChannels]);
    789                 Out() << endl;
     851                    Out() << Tools::Form(" %6.1f+-%4.1f", avg[k*32+j*4+i], rms[k*32+j*4+i]);
     852                Out() << '\n';
    790853            }
     854        Out() << '\n';
     855
     856        Out() << "Measured calibration resistor:\n";
     857        for (int k=0; k<13; k++)
     858            for (int j=0; j<4; j++)
     859            {
     860                Out() << setw(2) << k << "|" << setw(2) << j*8 << "|";
     861                for (int i=0; i<8; i++)
     862                    Out() << Tools::Form(" %5.0f", res[k*32+j*8+i]);
     863                Out() << '\n';
     864            }
     865
     866        Out() << flush;
    791867
    792868        return GetCurrentState();
     
    9821058        }
    9831059
     1060        if (fVoltGapd.size()==0)
     1061        {
     1062            Error("No G-APD reference voltages received yet (BIAS_CONTROL/NOMINAL).");
     1063            return GetCurrentState();
     1064        }
     1065
    9841066        ostringstream out;
    9851067        out << "Starting temperature feedback for calibration with an offset of -2V";
    9861068        Message(out);
    9871069
    988         fBiasOffset = -2;
     1070        fBiasOffset = fCalibrationOffset;
    9891071        fControlType = kTemp;
    9901072        fCursorCur  = -fNumCalibIgnore;
     
    11341216                      "|DeltaAmpl[mV]:Amplitude offset measures"
    11351217                      "|DeltaBias[mV]:Correction value calculated"),
    1136         fDimCalibration("FEEDBACK/CALIBRATION", "F:416;F:416",
     1218        fDimCalibration("FEEDBACK/CALIBRATION", "F:416;F:416;F:416",
    11371219                        "Current offsets"
    11381220                        "|Avg[dac]:Average offset (5000uA/4096dac)"
    11391221                        "|Rms[dac]:Rms of offset (5000uA/4096dac)"),
     1222                        "|R[Ohm]:Measured calibration resistor",
    11401223        fSP(BIAS::kNumChannels),
    11411224        fKp(0), fKi(0), fKd(0), fT(-1),
     1225        fCalibrationOffset(-3),
    11421226        fCurrentRequestInterval(0),
    11431227        fNumCalibIgnore(30),
     
    13001384
    13011385        fCurrentRequestInterval = conf.Get<uint16_t>("current-request-interval");
    1302         fNumCalibIgnore   = conf.Get<uint16_t>("num-calib-ignore");
    1303         fNumCalibRequests = conf.Get<uint16_t>("num-calib-average");
     1386        fNumCalibIgnore         = conf.Get<uint16_t>("num-calib-ignore");
     1387        fNumCalibRequests       = conf.Get<uint16_t>("num-calib-average");
     1388        fCalibrationOffset      = conf.Get<float>("calibration-offset");
    13041389
    13051390        return -1;
     
    13211406    po::options_description control("Feedback options");
    13221407    control.add_options()
    1323         ("pixel-map-file",  var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
     1408        ("pixel-map-file",      var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
    13241409        ("current-request-interval",  var<uint16_t>(1000), "Interval between two current requests.")
    1325         ("num-calib-ignore",  var<uint16_t>(30), "Number of current requests to be ignored before averaging")
    1326         ("num-calib-average",  var<uint16_t>(300), "Number of current requests to be averaged")
     1410        ("num-calib-ignore",    var<uint16_t>(30), "Number of current requests to be ignored before averaging")
     1411        ("num-calib-average",   var<uint16_t>(300), "Number of current requests to be averaged")
     1412        ("calibration-offset",  var<float>(-3), "Absolute offset relative to the G-APD operation voltage when calibrating")
    13271413        ;
    13281414
Note: See TracChangeset for help on using the changeset viewer.