Changeset 17173 for trunk/FACT++


Ignore:
Timestamp:
09/19/13 16:13:22 (11 years ago)
Author:
tbretz
Message:
Use the new algorithm by default; implemented temperature correction per bias patch; the temp coefficient is now settable from the configuration database.
File:
1 edited

Legend:

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

    r17030 r17173  
    1010#include "Console.h"
    1111#include "externals/PixelMap.h"
     12#include "externals/Interpolator2D.h"
    1213
    1314#include "tools.h"
     
    3233
    3334    bool fIsVerbose;
    34     bool fEnableOldAlgorithm;
    3535
    3636    DimVersion fDim;
     
    5252    vector<float>    fVoltGapd;     // Nominal breakdown voltage + 1.1V
    5353    vector<float>    fBiasVolt;     // Output voltage as reported by bias crate (voltage between R10 and R8)
     54    vector<float>    fBiasR9;       //
    5455    vector<uint16_t> fBiasDac;      // Dac value corresponding to the voltage setting
    5556
     
    6465
    6566    double fUserOffset;
    66     double fTempOffset;
     67    vector<double> fTempOffset;
     68    float fTempOffsetAvg;
     69    float fTempOffsetRms;
     70    double fTempCoefficient;
    6771    double fTemp;
    6872
     
    109113        {
    110114            fVoltGapd.assign(evt.Ptr<float>(), evt.Ptr<float>()+416);
     115            fBiasR9.assign(evt.Ptr<float>()+2*416, evt.Ptr<float>()+3*416);
    111116            Info("Nominal bias voltages and calibration resistor received.");
    112117        }
     
    131136    int HandleCameraTemp(const EventImp &evt)
    132137    {
    133         if (!CheckEventSize(evt.GetSize(), "HandleCameraTemp", 60*sizeof(float)))
     138        if (!CheckEventSize(evt.GetSize(), "HandleCameraTemp", 323*sizeof(float)))
    134139        {
    135140            fTimeTemp = Time(Time::none);
     
    137142        }
    138143
    139         const float *ptr = evt.Ptr<float>();
    140 
    141         double avgt = 0;
    142         int    numt = 0;
    143         for (int i=1; i<32; i++)
    144             if (ptr[i]!=0)
    145             {
    146                 avgt += ptr[i];
    147                 numt++;
    148             }
    149 
    150         if (numt==0)
    151         {
    152             Warn("Received sensor temperatures all invalid.");
    153             return GetCurrentState();
    154         }
    155 
    156         avgt /= numt; // [deg C]
    157 
    158         fTimeTemp   = evt.GetTime();
    159         fTempOffset = (avgt-25)*0.0561765; // [V] From Hamamatsu datasheet
    160         fTemp       = avgt;
     144        //fTempOffset = (avgt-25)*0.0561765; // [V] From Hamamatsu datasheet
     145        //fTempOffset = (avgt-25)*0.05678; // [V] From Hamamatsu datasheet plus our own measurement (gein vs. temperature)
     146
     147        const float *ptr = evt.Ptr<float>(4);
     148
     149        fTimeTemp = evt.GetTime();
     150        fTemp     = evt.Get<float>(321*4);
     151
     152        fTempOffsetAvg = (fTemp-25)*fTempCoefficient;
     153        fTempOffsetRms =  evt.Get<float>(322*4)*fTempCoefficient;
     154
     155        fTempOffset.resize(320);
     156        for (int i=0; i<320; i++)
     157            fTempOffset[i] = (ptr[i]-25)*fTempCoefficient;
    161158
    162159        return GetCurrentState();
     
    183180        for (int i=0; i<BIAS::kNumChannels; i++)
    184181        {
    185             avg[i] = double(fCurrentsAvg[i])/fCursorCur * conv;
    186             rms[i] = double(fCurrentsRms[i])/fCursorCur * conv * conv;
    187 
    188             rms[i] = sqrt(rms[i]-avg[i]*avg[i]);
     182            avg[i]  = double(fCurrentsAvg[i])/fCursorCur * conv;
     183            rms[i]  = double(fCurrentsRms[i])/fCursorCur * conv * conv;
     184            rms[i] -= avg[i]*avg[i];
     185            rms[i]  = rms[i]<0 ? 0 : sqrt(rms[i]);
    189186        }
    190187
     
    235232        memcpy(cal.Irms, rms.data(),       416*sizeof(float));
    236233
    237         fDimCalibration2.setData(fCalibration);
     234        fDimCalibration2.setData(cal);
    238235        fDimCalibration2.Update(fTimeCalib);
    239236
     
    405402
    406403        data.Unom   = overvoltage;
    407         data.dUtemp = fTempOffset;
     404        data.dUtemp = fTempOffsetAvg;
    408405
    409406        vector<float> vec(416);
    410407
     408        /*
    411409        if (fEnableOldAlgorithm)
    412410        {
     411            // ================================= old =======================
    413412            // Pixel  583: 5 31 == 191 (5)  C2 B3 P3
    414413            // Pixel  830: 2  2 ==  66 (4)  C0 B8 P1
     
    445444
    446445                // Offset induced by the voltage above the calibration point
    447                 const double Ubd = fVoltGapd[i] + fTempOffset;
     446                const double Ubd = fVoltGapd[i] + fTempOffsets[i];
    448447                const double U0  = Ubd + overvoltage - fCalibVoltage[5][i]; // appliedOffset-fCalibrationOffset;
    449448                const double dI  = U0/Ravg[i]; // [V/Ohm]
     
    455454                // Make sure that the averaged resistor is valid
    456455                const double dU = Ravg[i]>10000 ? r*(I*1e-6 - dI) : 0;
    457 
    458                 if (i==2)
    459                     cout << setprecision(4)<< dU << endl;;
    460456
    461457                vec[i] = Ubd + overvoltage + dU;
     
    488484            }
    489485        }
    490         else
    491         {
    492             /* ================================= new ======================= */
    493 
    494             for (int i=0; i<320/*BIAS::kNumChannels*/; i++)
     486        */
     487
     488        for (int i=0; i<320/*BIAS::kNumChannels*/; i++)
     489        {
     490            const PixelMapEntry &hv = fMap.hv(i);
     491            if (!hv)
     492                continue;
     493
     494            // Number of G-APDs in this patch
     495            const int N = hv.count();
     496
     497            // Average measured ADC value for this channel
     498            const double adc = Imes[i]/* * (5e-3/4096)*/; // [A]
     499
     500            // Current through ~100 Ohm measurement resistor
     501            const double I8 = (adc-fCalibDeltaI[i])*fCalibR8[i]/100;
     502
     503            // Current through calibration resistors (R9)
     504                // This is uncalibrated, biut since the corresponding calibrated
     505            // value I8 is subtracted, the difference should yield a correct value
     506            const double I9 = fBiasDac[i] * (1e-3/4096);//U9/R9;   [A]
     507
     508            // Current in R4/R5 branch
     509            const double Iout = I8>I9 ? I8 - I9 : 0;
     510
     511            // Applied voltage at calibration resistors, according to biasctrl
     512            const double U9 = fBiasVolt[i];
     513
     514            // Serial resistors (one 1kOhm at the output of the bias crate, one 1kOhm in the camera)
     515            const double R4 = 2000;
     516
     517            // Serial resistor of the individual G-APDs
     518            double R5 = 3900./N;
     519
     520            // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
     521            if (i==66)                 // Pixel 830(66)
     522                R5 = 300;              // 2400 = 1/(3/3900 + 1/390)
     523            if (i==191 || i==193)      // Pixel 583(191) / Pixel 1401(193)
     524                R5 = 390/1.4;          // 379 = 1/(4/3900 + 1/390)
     525
     526            // The measurement resistor
     527            const double R8 = 100;
     528
     529            // Total resistance of branch with diodes (R4+R5)
     530            // Assuming that the voltage output of the OpAMP is linear
     531            // with the DAC setting and not the voltage at R9, the
     532            // additional voltage drop at R8 must be taken into account
     533            const double R = R4 + R5 + R8;
     534
     535            // For the patches with a broken resistor - ignoring the G-APD resistance -
     536            // we get:
     537            //
     538            // I[R=3900] =  Iout *      1/(10+(N-1))   = Iout        /(N+9)
     539            // I[R= 390] =  Iout * (1 - 1/ (10+(N-1))) = Iout * (N+8)/(N+9)
     540            //
     541            // I[R=390] / I[R=3900] = N+8
     542            //
     543            // Udrp = Iout*3900/(N+9) + Iout*1000 + Iout*1000 = Iout * R
     544
     545            // Voltage drop in R4/R5 branch (for the G-APDs with correct resistor)
     546            const double Udrp = R*Iout;
     547
     548            // Nominal breakdown voltage with correction for temperature dependence
     549            const double Ubd = fVoltGapd[i] + fTempOffset[i];
     550
     551            // Current overvoltage (at a G-APD with the correct 3900 Ohm resistor)
     552            const double Uov = U9-Udrp-Ubd>0 ? U9-Udrp-Ubd : 0;
     553
     554            // Iout linear with U9 above Ubd
     555            //
     556            //  Rx = (U9-Ubd)/Iout
     557            //  I' = (U9'-Ubd) / Rx
     558            //  Udrp' = R*I'
     559            //  Uov = U9' - Udrp' - Ubd
     560            //  Uov = overvoltage
     561            //
     562            //  overvoltage = U9' - Udrp' - Ubd
     563            //  overvoltage = U9' - R*I' - Ubd
     564            //  overvoltage = U9' - R*((U9'-Ubd)/Rx) - Ubd
     565            //  overvoltage = U9' - U9'*R/Rx + Ubd*R/Rx - Ubd
     566            //  overvoltage = U9'*(1 - R/Rx) + Ubd*R/Rx - Ubd
     567            //  overvoltage - Ubd*R/Rx +Ubd = U9'*(1 - R/Rx)
     568            //  U9' = [ overvoltage - Ubd*R/Rx +Ubd ] / (1 - R/Rx)
     569            //
     570
     571            // The current through one G-APD is the sum divided by the number of G-APDs
     572            // (assuming identical serial resistors)
     573            double Iapd = Iout/N;
     574
     575            // In this and the previosu case we neglect the resistance of the G-APDs, but we can make an
     576            // assumption: The differential resistance depends more on the NSB than on the PDE,
     577            // thus it is at least comparable for all G-APDs in the patch. In addition, although the
     578            // G-APD with the 390Ohm serial resistor has the wrong voltage applied, this does not
     579            // significantly influences the ohmic resistor or the G-APD because the differential
     580            // resistor is large enough that the increase of the overvoltage does not dramatically
     581            // increase the current flow as compared to the total current flow.
     582            if (i==66 || i==191 || i==193)
     583                Iapd = Iout/(N+9); // Iapd = R5*Iout/3900;
     584
     585            // The differential resistance of the G-APD, i.e. the dependence of the
     586            // current above the breakdown voltage, is given by
     587            //const double Rapd = Uov/Iapd;
     588            // This allows us to estimate the current Iov at the overvoltage we want to apply
     589            //const double Iov = overvoltage/Rapd;
     590
     591            // Estimate set point for over-voltage (voltage drop at the target point)
     592            //const double Uset = Ubd + overvoltage + R*Iov*N;
     593            const double Uset = Uov<0.3 ? Ubd + overvoltage + Udrp : Ubd + overvoltage + Udrp*pow(overvoltage/Uov, 1.66);
     594
     595            // Voltage set point
     596            vec[i] = Uset;
     597
     598            /*
     599             if (fDimBias.state()==BIAS::State::kVoltageOn && GetCurrentState()==Feedback::State::kInProgress &&
     600             fabs(Uov-overvoltage)>0.033)
     601             cout << setprecision(4) << setw(3) << i << ": Uov=" << Uov << " Udrp=" << Udrp << " Iapd=" << Iapd*1e6 << endl;
     602             */
     603
     604            // Calculate statistics only for channels with a valid calibration
     605            //if (Uov>0)
    495606            {
    496                 const PixelMapEntry &hv = fMap.hv(i);
    497                 if (!hv)
    498                     continue;
    499 
    500                 // Number of G-APDs in this patch
    501                 const int N = hv.count();
    502 
    503                 // Average measured ADC value for this channel
    504                 const double adc = Imes[i]/* * (5e-3/4096)*/; // [A]
    505 
    506                 // Current through ~100 Ohm measurement resistor
    507                 const double I8 = (adc-fCalibDeltaI[i])*fCalibR8[i]/100;
    508 
    509                 // Applied voltage at calibration resistors, according to biasctrl
    510                 const double U9 = fBiasVolt[i];
    511 
    512                 // Current through calibration resistors (R9)
    513                 // This is uncalibrated, biut since the corresponding calibrated
    514                 // value I8 is subtracted, the difference should yield a correct value
    515                 const double I9 = fBiasDac[i] * (1e-3/4096);//U9/R9;   [A]
    516 
    517                 // Current in R4/R5 branch
    518                 const double Iout = I8>I9 ? I8 - I9 : 0;
    519 
    520                 // Serial resistors (one 1kOhm at the output of the bias crate, one 1kOhm in the camera)
    521                 const double R4 = 2000;
    522 
    523                 // Serial resistor of the individual G-APDs
    524                 double R5 = 3900./N;
    525 
    526                 // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
    527                 if (i==66)                 // Pixel 830(66)
    528                     R5 = 300;              // 2400 = 1/(3/3900 + 1/390)
    529                 if (i==191 || i==193)      // Pixel 583(191) / Pixel 1401(193)
    530                     R5 = 390/1.4;          // 379 = 1/(4/3900 + 1/390)
    531 
    532                 // Total resistance of branch with diodes
    533                 const double R = R4+R5;
    534 
    535                 // For the patches with a broken resistor - ignoring the G-APD resistance -
    536                 // we get:
    537                 //
    538                 // I[R=3900] =  Iout *      1/(10+(N-1))   = Iout        /(N+9)
    539                 // I[R= 390] =  Iout * (1 - 1/ (10+(N-1))) = Iout * (N+8)/(N+9)
    540                 //
    541                 // I[R=390] / I[R=3900] = N+8
    542                 //
    543                 // Udrp = Iout*3900/(N+9) + Iout*1000 + Iout*1000 = Iout * R
    544 
    545                 // Voltage drop in R4/R5 branch (for the G-APDs with correct resistor)
    546                 const double Udrp = R*Iout;
    547 
    548                 // Nominal breakdown voltage with correction for temperature dependence
    549                 const double Ubd = fVoltGapd[i] + fTempOffset;
    550 
    551                 // Current overvoltage (at a G-APD with the correct 3900 Ohm resistor)
    552                 const double Uov = U9-Udrp-Ubd>0 ? U9-Udrp-Ubd : 0;
    553 
    554                 // Iout linear with U9 above Ubd
    555                 //
    556                 //  Rx = (U9-Ubd)/Iout
    557                 //  I' = (U9'-Ubd) / Rx
    558                 //  Udrp' = R*I'
    559                 //  Uov = U9' - Udrp' - Ubd
    560                 //  Uov = overvoltage
    561                 //
    562                 //  overvoltage = U9' - Udrp' - Ubd
    563                 //  overvoltage = U9' - R*I' - Ubd
    564                 //  overvoltage = U9' - R*((U9'-Ubd)/Rx) - Ubd
    565                 //  overvoltage = U9' - U9'*R/Rx + Ubd*R/Rx - Ubd
    566                 //  overvoltage = U9'*(1 - R/Rx) + Ubd*R/Rx - Ubd
    567                 //  overvoltage - Ubd*R/Rx +Ubd = U9'*(1 - R/Rx)
    568                 //  U9' = [ overvoltage - Ubd*R/Rx +Ubd ] / (1 - R/Rx)
    569                 //
    570 
    571                 // The current through one G-APD is the sum divided by the number of G-APDs
    572                 // (assuming identical serial resistors)
    573                 double Iapd = Iout/N;
    574 
    575                 // In this and the previosu case we neglect the resistance of the G-APDs, but we can make an
    576                 // assumption: The differential resistance depends more on the NSB than on the PDE,
    577                 // thus it is at least comparable for all G-APDs in the patch. In addition, although the
    578                 // G-APD with the 390Ohm serial resistor has the wrong voltage applied, this does not
    579                 // significantly influences the ohmic resistor or the G-APD because the differential
    580                 // resistor is large enough that the increase of the overvoltage does not dramatically
    581                 // increase the current flow as compared to the total current flow.
    582                 if (i==66 || i==191 || i==193)
    583                     Iapd = Iout/(N+9); // Iapd = R5*Iout/3900;
    584 
    585                 // The differential resistance of the G-APD, i.e. the dependence of the
    586                 // current above the breakdown voltage, is given by
    587                 //const double Rapd = Uov/Iapd;
    588                 // This allows us to estimate the current Iov at the overvoltage we want to apply
    589                 //const double Iov = overvoltage/Rapd;
    590 
    591                 // Estimate set point for over-voltage (voltage drop at the target point)
    592                 //const double Uset = Ubd + overvoltage + R*Iov*N;
    593                 const double Uset = Uov<0.3 ? Ubd + overvoltage + Udrp : Ubd + overvoltage + Udrp*pow(overvoltage/Uov, 1.66);
    594 
    595                 // Voltage set point
    596                 vec[i] = Uset;
    597 
    598                 if (fDimBias.state()==BIAS::State::kVoltageOn && GetCurrentState()==Feedback::State::kInProgress &&
    599                     fabs(Uov-overvoltage)>0.033)
    600                     cout << setprecision(4) << setw(3) << i << ": Uov=" << Uov << " Udrp=" << Udrp << " Iapd=" << Iapd*1e6 << endl;
    601 
    602 
    603                 // Calculate statistics only for channels with a valid calibration
    604                 //if (Uov>0)
    605                 {
    606                     const int g = hv.group();
    607 
    608                     med[g][num[g]] = Uov;
    609                     avg[g] += Uov;
    610                     num[g]++;
    611 
    612                     if (Uov<min[g])
    613                         min[g] = Uov;
    614                     if (Uov>max[g])
    615                         max[g] = Uov;
    616 
    617                     const double iapd = Iapd*1e6; // A --> uA
    618 
    619                     data.I[i]  = iapd;
    620                     data.Iavg += iapd;
    621                     data.Irms += iapd*iapd;
    622 
    623                     data.Uov[i] = Uov;
    624 
    625                     med[2][num[2]++] = iapd;
    626                 }
     607                const int g = hv.group();
     608
     609                med[g][num[g]] = Uov;
     610                avg[g] += Uov;
     611                num[g]++;
     612
     613                if (Uov<min[g])
     614                    min[g] = Uov;
     615                if (Uov>max[g])
     616                    max[g] = Uov;
     617
     618                const double iapd = Iapd*1e6; // A --> uA
     619
     620                data.I[i]  = iapd;
     621                data.Iavg += iapd;
     622                data.Irms += iapd*iapd;
     623
     624                data.Uov[i] = Uov;
     625
     626                med[2][num[2]++] = iapd;
    627627            }
    628628        }
     
    638638
    639639                ostringstream msg;
    640                 msg << setprecision(4) << "Sending new absolute offset: dU(" << fTemp << "degC)=" << fTempOffset << "V, Unom=" << overvoltage << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0);
     640                msg << setprecision(4) << "Sending new absolute offset: dU(" << fTemp << "degC)=" << fTempOffsetAvg << "V+-" << fTempOffsetRms << ", Unom=" << overvoltage << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0);
    641641                Info(msg);
    642642            }
     
    647647            {
    648648                ostringstream msg;
    649                 msg << setprecision(4) << "Current status: dU(" << fTemp << "degC)=" << fTempOffset << "V, Unom=" << overvoltage << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0);
     649                msg << setprecision(4) << "Current status: dU(" << fTemp << "degC)=" << fTempOffsetAvg << "V+-" << fTempOffsetRms << ", Unom=" << overvoltage << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0);
    650650                Info(msg);
    651651            }
     
    687687            data.Iavg /= num[2];
    688688            data.Irms /= num[2];
     689            data.Irms -= data.Iavg*data.Iavg;
    689690
    690691            data.N = num[2];
    691             data.Irms = sqrt(data.Irms-data.Iavg*data.Iavg);
     692            data.Irms = data.Irms<0 ? 0: sqrt(data.Irms);
    692693
    693694            sort(med[2].data(), med[2].data()+num[2]);
    694695
    695             data.Imed = num[2]%2 ? (med[2][num[2]/2-1]+med[2][num[2]/2])/2 : med[2][num[2]/2];
     696            data.Imed = num[2]%2 ? med[2][num[2]/2] : (med[2][num[2]/2-1]+med[2][num[2]/2])/2;
    696697
    697698            for (int i=0; i<num[2]; i++)
     
    768769    }
    769770
    770     int EnableOldAlgorithm(const EventImp &evt)
    771     {
    772         if (!CheckEventSize(evt.GetSize(), "EnableOldAlgorithm", 1))
    773             return kSM_FatalError;
    774 
    775         fEnableOldAlgorithm = evt.GetBool();
    776 
    777         return GetCurrentState();
    778     }
    779 
    780771    int SetVerbosity(const EventImp &evt)
    781772    {
     
    795786        fCurrentRequestInterval = evt.GetUShort();
    796787
    797         Out() << "New current request interval: " << fCurrentRequestInterval << "ms" << endl;
     788        Info("New current request interval: "+to_string(fCurrentRequestInterval)+"ms");
    798789
    799790        return GetCurrentState();
     
    901892public:
    902893    StateMachineFeedback(ostream &out=cout) : StateMachineDim(out, "FEEDBACK"),
    903         fIsVerbose(false), fEnableOldAlgorithm(true),
     894        fIsVerbose(false),
    904895        //---
    905896        fDimFSC("FSC_CONTROL"),
     
    953944        Subscribe("BIAS_CONTROL/NOMINAL")
    954945            (bind(&StateMachineFeedback::HandleBiasNom,     this, placeholders::_1));
    955         Subscribe("FSC_CONTROL/TEMPERATURE")
     946        Subscribe("FSC_CONTROL/BIAS_TEMP")
    956947            (bind(&StateMachineFeedback::HandleCameraTemp,  this, placeholders::_1));
    957948
     
    998989
    999990
    1000         AddEvent("ENABLE_OLD_ALRGORITHM", "B:1", Feedback::State::kConnected, Feedback::State::kCalibrated)
    1001             (bind(&StateMachineFeedback::EnableOldAlgorithm, this, placeholders::_1));
    1002 
    1003 
    1004991        AddEvent("PRINT")
    1005992            (bind(&StateMachineFeedback::Print, this))
     
    10291016        fNumCalibIgnore         = conf.Get<uint16_t>("num-calib-ignore");
    10301017        fNumCalibRequests       = conf.Get<uint16_t>("num-calib-average");
     1018        fTempCoefficient        = conf.Get<double>("temp-coefficient");
    10311019
    10321020        return -1;
     
    10531041        ("num-calib-ignore",    var<uint16_t>(30), "Number of current requests to be ignored before averaging")
    10541042        ("num-calib-average",   var<uint16_t>(300), "Number of current requests to be averaged")
     1043        ("temp-coefficient",    var<double>()->required(), "Temp. coefficient [V/K]")
    10551044        ;
    10561045
Note: See TracChangeset for help on using the changeset viewer.