Changeset 18191


Ignore:
Timestamp:
06/01/15 12:10:01 (9 years ago)
Author:
tbretz
Message:
This implements th epossibility to load and save calibrations, an automatic current control in case of too high currents, it adds the missing 50 ohm termination in the calculation (note that this is only a 3% effect at high currents (200uA/G-APD) and corresponds well with the decrease of amplitude we still found in the feedback paper.
Location:
trunk/FACT++/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/HeadersFeedback.h

    r17025 r18191  
    1818            kWaitingForData,
    1919            kInProgress,
     20
     21            kWarning,
     22            kCritical,
     23            kOnStandby,
     24
     25
    2026        };
    2127    }
  • trunk/FACT++/src/feedback.cc

    r17647 r18191  
    6363    Time fTimeCalib;
    6464    Time fTimeTemp;
     65    Time fTimeCritical;
    6566
    6667    double fUserOffset;
     68    double fVoltageReduction;
    6769    vector<double> fTempOffset;
    6870    float fTempOffsetAvg;
     
    7880    uint16_t fCalibStep;
    7981
     82    uint16_t fTimeoutCritical;
     83
    8084    // ============================= Handle Services ========================
    8185
     
    8892        }
    8993
    90         if (fDimBias.state()==BIAS::State::kVoltageOff && GetCurrentState()==Feedback::State::kInProgress)
     94        if (fDimBias.state()==BIAS::State::kVoltageOff && GetCurrentState()>=Feedback::State::kInProgress)
    9195            return Feedback::State::kCalibrated;
    9296
     
    116120            fVoltGapd.assign(evt.Ptr<float>(), evt.Ptr<float>()+416);
    117121            fBiasR9.assign(evt.Ptr<float>()+2*416, evt.Ptr<float>()+3*416);
     122
     123            for (int i=0; i<320; i++)
     124                fVoltGapd[i] += 1.1;
     125
    118126            Info("Nominal bias voltages and calibration resistor received.");
    119127        }
     
    330338    }
    331339
     340    int CheckLimits(const float *I)
     341    {
     342        const float fAbsoluteMedianCurrentLimit   = 85;
     343        const float fRelativePixelCurrentLimit3   = 20;
     344        const float fRelativePixelCurrentLimit0   = 45;
     345
     346        const float fAbsolutePixelCurrentLimit3   = fAbsoluteMedianCurrentLimit + fRelativePixelCurrentLimit3;
     347        const float fAbsolutePixelCurrentLimit0   = fAbsoluteMedianCurrentLimit + fRelativePixelCurrentLimit0;
     348
     349        const float fRelativeCurrentLimitWarning  = 10;//10;
     350        const float fRelativeCurrentLimitCritical = 15;//20;
     351        const float fRelativeCurrentLimitShutdown = 25;
     352
     353        fTimeoutCritical = 3000; // 5s
     354
     355        // Copy the calibrated currents
     356        vector<float> v(I, I+320);
     357
     358        // Exclude the crazy patches (that's currently the best which could be done)
     359        v[66]  = 0;
     360        v[191] = 0;
     361        v[193] = 0;
     362
     363        sort(v.begin(), v.end());
     364
     365        const float &imax0 = v[319];
     366        const float &imax3 = v[316];
     367        const float &imed  = v[161];
     368
     369        const bool shutdown =
     370            imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitShutdown ||
     371            imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitShutdown ||
     372            imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitShutdown;
     373
     374        const bool critical =
     375            imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitCritical ||
     376            imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitCritical ||
     377            imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitCritical;
     378
     379        const bool warning =
     380            imed >fAbsoluteMedianCurrentLimit+fRelativeCurrentLimitWarning ||
     381            imax3>fAbsolutePixelCurrentLimit3+fRelativeCurrentLimitWarning ||
     382            imax0>fAbsolutePixelCurrentLimit0+fRelativeCurrentLimitWarning;
     383
     384        bool standby = GetCurrentState()==Feedback::State::kOnStandby;
     385
     386        if (standby)
     387        {
     388            // On Standby
     389            if (fVoltageReduction==0 &&
     390                imed <fAbsoluteMedianCurrentLimit &&
     391                imax3<fAbsolutePixelCurrentLimit3 &&
     392                imax0<fAbsolutePixelCurrentLimit0)
     393            {
     394                // Currents are back at nominal value and currents are again
     395                // below the current limit, switching back to standard operation.
     396                return Feedback::State::kInProgress;
     397            }
     398        }
     399
     400        // Shutdown level
     401        if (!standby && shutdown)
     402        {
     403            // Currents exceed the shutdown limit, operation is switched
     404            // immediately to voltage reduced operation
     405
     406            // Just in case (FIXME: Is that really the right location?)
     407            Dim::SendCommandNB("FAD_CONTROL/CLOSE_ALL_OPEN_FILES");
     408
     409            Error("Current limit for shutdown exceeded.... swtching to standby mode.");
     410
     411            standby = true;
     412        }
     413
     414        // Critical level
     415        if (!standby && critical)
     416        {
     417            // This is a state transition from InProgress or Warning to Critical.
     418            // Keep the transition time.
     419            if (GetCurrentState()==Feedback::State::kInProgress || GetCurrentState()==Feedback::State::kWarning)
     420            {
     421                Info("Critical current limit exceeded.... waiting for "+to_string(fTimeoutCritical)+" ms.");
     422                fTimeCritical = Time();
     423            }
     424
     425            // Critical is only allowed for fTimeoutCritical milliseconds.
     426            // After this time, the operation is changed to reduced voltage.
     427            if (Time()<fTimeCritical+boost::posix_time::milliseconds(fTimeoutCritical))
     428                return Feedback::State::kCritical;
     429
     430            // Just in case (FIXME: Is that really the right location?)
     431            Dim::SendCommandNB("FAD_CONTROL/CLOSE_ALL_OPEN_FILES");
     432
     433            // Currents in critical state
     434            Warn("Critical current limit exceeded timeout.... switching to standby mode.");
     435
     436            standby = true;
     437        }
     438
     439        // Warning level (is just informational)
     440        if (!standby && warning)
     441            return Feedback::State::kWarning;
     442
     443        // keep voltage
     444        return standby ? Feedback::State::kOnStandby : Feedback::State::kInProgress;
     445    }
     446
    332447    int HandleBiasCurrent(const EventImp &evt)
    333448    {
     
    349464            return GetCurrentState();
    350465
     466        // We are waiting but biasctrl is still in ramping (this might
     467        // be the case if the feedback was started with a new overvoltage
     468        // while the last ramping command was still in progress)
     469        if (GetCurrentState()==Feedback::State::kWaitingForData &&
     470            fDimBias.state()==BIAS::State::kRamping)
     471            return GetCurrentState();
     472
    351473        // We are already in progress but no valid temperature update anymore
    352         if (GetCurrentState()==Feedback::State::kInProgress &&
     474        if (GetCurrentState()>=Feedback::State::kInProgress &&
    353475            (!fTimeTemp.IsValid() || Time()-fTimeTemp>boost::posix_time::minutes(5)))
    354476        {
     
    373495
    374496        // Nominal overvoltage (w.r.t. the bias setup values)
    375         const double overvoltage = GetCurrentState()<Feedback::State::kWaitingForData ? 0 : fUserOffset;
     497        const double voltageoffset = GetCurrentState()<Feedback::State::kWaitingForData ? 0 : fUserOffset;
    376498
    377499        double avg[2] = {   0,   0 };
     
    405527        dim_data data;
    406528
    407         data.Unom   = overvoltage;
     529        data.Unom   = voltageoffset;
    408530        data.dUtemp = fTempOffsetAvg;
    409531
    410532        vector<float> vec(416);
    411533
    412         /*
    413         if (fEnableOldAlgorithm)
    414         {
    415             // ================================= old =======================
    416             // Pixel  583: 5 31 == 191 (5)  C2 B3 P3
    417             // Pixel  830: 2  2 ==  66 (4)  C0 B8 P1
    418             // Pixel 1401: 6  1 == 193 (5)  C2 B4 P0
    419 
    420             // 3900 Ohm/n + 1000 Ohm + 1100 Ohm  (with n=4 or n=5)
    421             const double R[2] = { 3075, 2870 };
    422 
    423             const float *Iavg = fCalibration.data();                      // Offset at U=fCalibrationOffset
    424             const float *Ravg = fCalibration.data()+BIAS::kNumChannels*2; // Measured resistance
    425 
    426             for (int i=0; i<320; i++)
    427             {
    428                 const PixelMapEntry &hv = fMap.hv(i);
    429                 if (!hv)
    430                     continue;
    431 
    432                 // Average measured current
    433                 const double Im = Imes[i] * 1e6; // [uA]
    434 
    435                 // Group index (0 or 1) of the of the pixel (4 or 5 pixel patch)
    436                 const int g = hv.group();
    437 
    438                 // Serial resistors in front of the G-APD
    439                 double Rg = R[g];
    440 
    441                 // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
    442                 if (i==66)                // Pixel 830(66)
    443                     Rg = 2400;            // 2400 = (3/3900 + 1/390) + 1000 + 1100
    444                 if (i==191 || i==193)     // Pixel 583(191) / Pixel 1401(193)
    445                     Rg = 2379;            // 2379 = (4/3900 + 1/390) + 1000 + 1100
    446 
    447                 const double r = 1./(1./Rg + 1./Ravg[i]); // [Ohm]
    448 
    449                 // Offset induced by the voltage above the calibration point
    450                 const double Ubd = fVoltGapd[i] + fTempOffsets[i];
    451                 const double U0  = Ubd + overvoltage - fCalibVoltage[5][i]; // appliedOffset-fCalibrationOffset;
    452                 const double dI  = U0/Ravg[i]; // [V/Ohm]
    453 
    454                 // Offset at the calibration point (make sure that the calibration is
    455                 // valid (Im[i]>Iavg[i]) and we operate above the calibration point)
    456                 const double I = Im>Iavg[i] ? Im - Iavg[i] : 0; // [uA]
    457 
    458                 // Make sure that the averaged resistor is valid
    459                 const double dU = Ravg[i]>10000 ? r*(I*1e-6 - dI) : 0;
    460 
    461                 vec[i] = Ubd + overvoltage + dU;
    462 
    463                 // Calculate statistics only for channels with a valid calibration
    464                 if (Iavg[i]>0)
    465                 {
    466                     med[g][num[g]] = dU;
    467                     avg[g] += dU;
    468                     num[g]++;
    469 
    470                     if (dU<min[g])
    471                         min[g] = dU;
    472                     if (dU>max[g])
    473                         max[g] = dU;
    474 
    475                     data.I[i]  = Imes[i]*1e6 - fBiasVolt[i]/Ravg[i]*1e6;
    476                     data.I[i] /= hv.count();
    477 
    478                     if (i==66)
    479                         data.I[i] /= 1.3;
    480                     if (i==191 || i==193)
    481                         data.I[i] /= 1.4;
    482 
    483                     data.Iavg += data.I[i];
    484                     data.Irms += data.I[i]*data.I[i];
    485 
    486                     med[2][num[2]++] = data.I[i];
    487                 }
    488             }
    489         }
    490         */
     534        // ================================= old =======================
     535        // Pixel  583: 5 31 == 191 (5)  C2 B3 P3
     536        // Pixel  830: 2  2 ==  66 (4)  C0 B8 P1
     537        // Pixel 1401: 6  1 == 193 (5)  C2 B4 P0
    491538
    492539        double UdrpAvg = 0;
     
    503550
    504551            // Average measured ADC value for this channel
     552            // FIXME: This is a workaround for the problem with the
     553            // readout of bias voltage channel 263
    505554            const double adc = Imes[i]/* * (5e-3/4096)*/; // [A]
    506555
     
    521570            const double U9 = fBiasVolt[i];
    522571
     572            //          new    I8 - I9*100/fCalibR8       100
     573            // change = --- = ---------------------- =  --------  = 0.8
     574            //          old    I8*fCalibR8/100 - I9     fCalibR8
     575
    523576            // Serial resistors (one 1kOhm at the output of the bias crate, one 1kOhm in the camera)
    524577            const double R4 = 2000;
    525578
    526             // Serial resistor of the individual G-APDs
    527             double R5 = 3900./N;
     579            // Serial resistor of the individual G-APDs plus 50 Ohm termination
     580            double R5 = 3900./N + 50;
    528581
    529582            // This is assuming that the broken pixels have a 390 Ohm instead of 3900 Ohm serial resistor
     
    559612            const double Udrp = Iout<0 ? 0 : R*Iout;
    560613
    561             // Nominal breakdown voltage with correction for temperature dependence
    562             const double Ubd = fVoltGapd[i] + fVoltOffset[i] + fTempOffset[i];
     614            // Nominal operation voltage with correction for temperature dependence
     615            const double Uop = fVoltGapd[i] + fVoltOffset[i] + fTempOffset[i];
    563616
    564617            // Current overvoltage (at a G-APD with the correct 3900 Ohm resistor)
    565             //const double Uov = U9-Udrp-Ubd>0 ? U9-Udrp-Ubd : 0;
    566             const double Uov = U9-Udrp-Ubd>-0.44/*-0.34*/ ? U9-Udrp-Ubd : -0.44/*-0.34*/;
    567 
    568             // Iout linear with U9 above Ubd
    569             //
    570             //  Rx = (U9-Ubd)/Iout
    571             //  I' = (U9'-Ubd) / Rx
    572             //  Udrp' = R*I'
    573             //  Uov = U9' - Udrp' - Ubd
    574             //  Uov = overvoltage
    575             //
    576             //  overvoltage = U9' - Udrp' - Ubd
    577             //  overvoltage = U9' - R*I' - Ubd
    578             //  overvoltage = U9' - R*((U9'-Ubd)/Rx) - Ubd
    579             //  overvoltage = U9' - U9'*R/Rx + Ubd*R/Rx - Ubd
    580             //  overvoltage = U9'*(1 - R/Rx) + Ubd*R/Rx - Ubd
    581             //  overvoltage - Ubd*R/Rx +Ubd = U9'*(1 - R/Rx)
    582             //  U9' = [ overvoltage - Ubd*R/Rx +Ubd ] / (1 - R/Rx)
    583             //
     618            // expressed w.r.t. to the operation voltage
     619            const double Uov = (U9-Udrp)-Uop>-1.4 ? (U9-Udrp)-Uop : -1.4;
    584620
    585621            // The current through one G-APD is the sum divided by the number of G-APDs
     
    619655                Iapd = Iout/(N-1);
    620656
    621 
    622             // 3900   +   Rapd  = I0   ->  Uapd = Utot - 3900*I0
    623             // 3900   +   Rapd  = I0   ->  Uapd = Utot - 3900*I0
    624             // 3900   +   Rapd  = I0   ->  Uapd = Utot - 3900*I0
    625             // 390    +   Rx    = Ix   ->  Uapd = Utot -  390*Ix
    626 
    627             // Iout = N*I0 + Ix
    628 
    629657            // The differential resistance of the G-APD, i.e. the dependence of the
    630658            // current above the breakdown voltage, is given by
     
    634662
    635663            // Estimate set point for over-voltage (voltage drop at the target point)
    636             //const double Uset = Ubd + overvoltage + R*Iov*N;
    637             //const double Uset = Uov<0.3 ? Ubd + overvoltage + Udrp : Ubd + overvoltage + Udrp*pow(overvoltage/Uov, 1.66);
    638             const double Uset =
    639 
    640                 // Uov<0 ?
    641                 //   Ubd + overvoltage + Udrp*pow(overvoltage/0.44/*0.34*/+1, 1.85/*1.66*/) :
    642                 //   Ubd + overvoltage + Udrp*pow((overvoltage+0.44/*0.34*/)/(Uov+0.44/*0.34*/), 1.85/*1.66*/);
    643 
    644                 // Uov<0 ?
    645                 //   Ubd + overvoltage + Udrp*pow(overvoltage+0.44, 1.3213+0.2475*(overvoltage+0.44)) :
    646                 //   Ubd + overvoltage + Udrp*pow(overvoltage+0.44, 1.3213+0.2475*(overvoltage+0.44))/pow(Uov+0.44, 1.3213+0.2475*(Uov+0.44));
    647 
    648                 // This estimation is based on the linear increase of the
    649                 // gain with voltage and the increase of the crosstalk with
    650                 // voltage, as measured with the overvoltage-tests (OVTEST)
    651 
    652                 Uov+0.44<0.022 ?
    653             Ubd + overvoltage + Udrp*
    654                 exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44), 0.6) :
    655             Ubd + overvoltage + Udrp*
    656                 exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44)/(Uov+0.44), 0.6);
    657 
    658 
    659 
    660 
    661             if (fabs(overvoltage-Uov)>0.033)
     664            // This estimation is based on the linear increase of the
     665            // gain with voltage and the increase of the crosstalk with
     666            // voltage, as measured with the overvoltage-tests (OVTEST)
     667            /*
     668             Uov+0.44<0.022 ?
     669                Ubd + overvoltage + Udrp*exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44), 0.6) :
     670                Ubd + overvoltage + Udrp*exp(0.6*(overvoltage-Uov))*pow((overvoltage+0.44)/(Uov+0.44), 0.6);
     671             */
     672            const double Uset =
     673                Uov+1.4<0.022 ?
     674                Uop + voltageoffset + Udrp*exp(0.6*(voltageoffset-Uov))*pow((voltageoffset+1.4),           0.6) :
     675                Uop + voltageoffset + Udrp*exp(0.6*(voltageoffset-Uov))*pow((voltageoffset+1.4)/(Uov+1.4), 0.6);
     676
     677            if (fabs(voltageoffset-Uov)>0.033)
    662678                Ndev[0]++;
    663             if (fabs(overvoltage-Uov)>0.022)
     679            if (fabs(voltageoffset-Uov)>0.022)
    664680                Ndev[1]++;
    665             if (fabs(overvoltage-Uov)>0.011)
     681            if (fabs(voltageoffset-Uov)>0.011)
    666682                Ndev[2]++;
    667683
    668684            // Voltage set point
    669685            vec[i] = Uset;
    670 
    671             /*
    672              if (fDimBias.state()==BIAS::State::kVoltageOn && GetCurrentState()==Feedback::State::kInProgress &&
    673              fabs(Uov-overvoltage)>0.033)
    674              cout << setprecision(4) << setw(3) << i << ": Uov=" << Uov << " Udrp=" << Udrp << " Iapd=" << Iapd*1e6 << endl;
    675              */
    676686
    677687            // Calculate statistics only for channels with a valid calibration
     
    704714        }
    705715
     716
     717        // ---------------------------- Calculate statistics ----------------------------------
     718
     719        // average and rms
     720        data.Iavg /= num[2];
     721        data.Irms /= num[2];
     722        data.Irms -= data.Iavg*data.Iavg;
     723
     724        data.N = num[2];
     725        data.Irms = data.Irms<0 ? 0: sqrt(data.Irms);
     726
     727        // median
     728        sort(med[2].data(), med[2].data()+num[2]);
     729
     730        data.Imed = num[2]%2 ? med[2][num[2]/2] : (med[2][num[2]/2-1]+med[2][num[2]/2])/2;
     731
     732        // deviation
     733        for (int i=0; i<num[2]; i++)
     734            med[2][i] = fabs(med[2][i]-data.Imed);
     735
     736        sort(med[2].data(), med[2].data()+num[2]);
     737
     738        data.Idev = med[2][uint32_t(0.682689477208650697*num[2])];
     739
     740        // time difference to calibration
     741        data.Tdiff = evt.GetTime().UnixTime()-fTimeCalib.UnixTime();
     742
     743        // Average overvoltage
     744        const double Uov = (avg[0]+avg[1])/(num[0]+num[1]);
     745
    706746        // ------------------------------- Update voltages ------------------------------------
    707747
    708         if (GetCurrentState()!=Feedback::State::kCalibrated) // WaitingForData, InProgress
     748        int newstate = GetCurrentState();
     749
     750        if (GetCurrentState()!=Feedback::State::kCalibrated) // WaitingForData, OnStandby, InProgress, kWarning, kCritical
    709751        {
    710752            if (fDimBias.state()!=BIAS::State::kRamping)
    711753            {
     754                newstate = CheckLimits(data.I);
     755
     756                // standby and change reduction level of voltage
     757                if (newstate==Feedback::State::kOnStandby)
     758                {
     759                    // Calculate average applied overvoltage and estimate an offset
     760                    // to reach fAbsoluteMedianCurrentLimit
     761                    float fAbsoluteMedianCurrentLimit = 85;
     762                    const double deltaU = (Uov+1.4)*(1-pow(fAbsoluteMedianCurrentLimit/data.Imed, 1./1.7));
     763
     764                    if (fVoltageReduction+deltaU<0.033)
     765                        fVoltageReduction = 0;
     766                    else
     767                    {
     768                        fVoltageReduction += deltaU;
     769
     770                        for (int i=0; i<320; i++)
     771                            vec[i] -= fVoltageReduction;
     772                    }
     773                }
     774
     775                // FIXME: What if the brightest pixel gets too bright???
     776                // FIXME: What if fVolatgeReduction > U1.4V?
     777
     778                // set voltage in 262 -> current in 262/263
     779                vec[263] = vec[262]-fVoltGapd[262]+fVoltGapd[263];
     780
     781//            if (fDimBias.state()!=BIAS::State::kRamping)
     782//            {
    712783                DimClient::sendCommandNB("BIAS_CONTROL/SET_ALL_CHANNELS_VOLTAGE",
    713784                                         vec.data(), BIAS::kNumChannels*sizeof(float));
     
    720791                ostringstream msg;
    721792                msg << fixed;
    722                 msg << setprecision(2) << "Sending U: dU(" << fTemp << "degC)="
     793                msg << setprecision(2) << "dU(" << fTemp << "degC)="
    723794                    << setprecision(3) << fTempOffsetAvg << "V+-" << fTempOffsetRms << "  Udrp="
    724795                    << UdrpAvg << "V+-" << UdrpRms;
    725796                msg.unsetf(ios_base::floatfield);
    726                 msg << " Unom=" << overvoltage << "V Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0) << " [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
     797
     798                if (fVoltageReduction==0)
     799                    msg << " Unom=" << voltageoffset << "V";
     800                else
     801                    msg << " Ured=" << fVoltageReduction << "V";
     802
     803                msg << " Uov=" << Uov;
     804                msg << " Imed=" << data.Imed << "uA [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
    727805                Info(msg);
    728806            }
     
    733811            {
    734812                ostringstream msg;
    735                 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) << " [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
     813                msg << setprecision(4) << "Current status: dU(" << fTemp << "degC)=" << fTempOffsetAvg << "V+-" << fTempOffsetRms << ", Unom=" << voltageoffset << "V, Uov=" << (num[0]+num[1]>0?(avg[0]+avg[1])/(num[0]+num[1]):0) << " [N=" << Ndev[0] << "/" << Ndev[1] << "/" << Ndev[2] << "]";
    736814                Info(msg);
    737815            }
    738 
    739         }
    740 
    741         if (GetCurrentState()==Feedback::State::kInProgress &&
    742             fDimBias.state()==BIAS::State::kRamping)
    743             return GetCurrentState();
     816        }
     817
     818        //if (GetCurrentState()>=Feedback::State::kOnStandby &&
     819        //    fDimBias.state()==BIAS::State::kRamping)
     820        //    return newstate;
    744821
    745822        // --------------------------------- Console out --------------------------------------
    746823
    747         if (num[0]>0 && num[1]>0 && fIsVerbose && !fDimBias.state()==BIAS::State::kRamping)
     824        if (fIsVerbose && !fDimBias.state()==BIAS::State::kRamping)
    748825        {
    749826            sort(med[0].begin(), med[0].begin()+num[0]);
     
    769846        // ---------------------------- Calibrated Currents -----------------------------------
    770847
    771         if (num[2]>0)
    772         {
    773             data.Iavg /= num[2];
    774             data.Irms /= num[2];
    775             data.Irms -= data.Iavg*data.Iavg;
    776 
    777             data.N = num[2];
    778             data.Irms = data.Irms<0 ? 0: sqrt(data.Irms);
    779 
    780             sort(med[2].data(), med[2].data()+num[2]);
    781 
    782             data.Imed = num[2]%2 ? med[2][num[2]/2] : (med[2][num[2]/2-1]+med[2][num[2]/2])/2;
    783 
    784             for (int i=0; i<num[2]; i++)
    785                 med[2][i] = fabs(med[2][i]-data.Imed);
    786 
    787             sort(med[2].data(), med[2].data()+num[2]);
    788 
    789             data.Idev = med[2][uint32_t(0.682689477208650697*num[2])];
    790 
    791             data.Tdiff = evt.GetTime().UnixTime()-fTimeCalib.UnixTime();
    792 
    793             // FIXME:
    794             //  + Current overvoltage
    795             //  + Temp offset
    796             //  + User offset
    797             //  + Command overvoltage
    798             fDimCurrents.setQuality(GetCurrentState());
    799             fDimCurrents.setData(&data, sizeof(dim_data));
    800             fDimCurrents.Update(evt.GetTime());
    801         }
    802 
    803         return GetCurrentState()==Feedback::State::kCalibrated ? Feedback::State::kCalibrated : Feedback::State::kInProgress;
     848        // FIXME:
     849        //  + Current overvoltage
     850        //  + Temp offset
     851        //  + User offset
     852        //  + Command overvoltage
     853        fDimCurrents.setQuality(GetCurrentState());
     854        fDimCurrents.setData(&data, sizeof(dim_data));
     855        fDimCurrents.Update(evt.GetTime());
     856
     857        // FIXME: To be checked
     858        return GetCurrentState()==Feedback::State::kCalibrated ? Feedback::State::kCalibrated : newstate;
    804859    }
    805860
     
    906961            return kSM_FatalError;
    907962
     963        /*
    908964        if (fDimBias.state()==BIAS::State::kRamping)
    909965        {
    910966            Warn("Feedback can not be started when biasctrl is in state Ramping.");
    911967            return GetCurrentState();
    912         }
    913 
    914         fUserOffset = evt.GetFloat();
     968        }*/
     969
     970        fUserOffset = evt.GetFloat()-1.1;
     971        fVoltageReduction = 0;
    915972
    916973        fCursorCur = 0;
     
    9771034        return GetCurrentState();
    9781035    }
     1036
     1037    int SaveCalibration()
     1038    {
     1039        ofstream fout("feedback-calib.bin");
     1040
     1041        double mjd = fTimeCalib.Mjd();
     1042        fout.write((char*)&mjd, sizeof(double));
     1043        fout.write((char*)fCalibDeltaI.data(), BIAS::kNumChannels*sizeof(float));
     1044        fout.write((char*)fCalibR8.data(),     BIAS::kNumChannels*sizeof(float));
     1045
     1046        return GetCurrentState();
     1047    }
     1048
     1049    int LoadCalibration()
     1050    {
     1051        ifstream fin("feedback-calib.bin");
     1052
     1053        double mjd;
     1054
     1055        vector<float> di(BIAS::kNumChannels);
     1056        vector<float> r8(BIAS::kNumChannels);
     1057
     1058        fin.read((char*)&mjd, sizeof(double));
     1059        fin.read((char*)di.data(), BIAS::kNumChannels*sizeof(float));
     1060        fin.read((char*)r8.data(), BIAS::kNumChannels*sizeof(float));
     1061
     1062        if (!fin)
     1063        {
     1064            Warn("Reading of calibration failed.");
     1065            return GetCurrentState();
     1066        }
     1067
     1068        fTimeCalib.Mjd(mjd);
     1069        fCalibDeltaI = di;
     1070        fCalibR8 = r8;
     1071
     1072        return Feedback::State::kCalibrated;
     1073    }
     1074
    9791075
    9801076
     
    10401136                          "Calibration of R8"
    10411137                          "|DeltaI[uA]:Average offset"
    1042                           "|R8[uA]:Measured effective resistor R8"),
     1138                          "|R8[Ohm]:Measured effective resistor R8"),
    10431139        fDimCurrents("FEEDBACK/CALIBRATED_CURRENTS", "F:416;F:1;F:1;F:1;F:1;I:1;F:1;F:416;F:1;F:1",
    10441140                     "Calibrated currents"
     
    10501146                     "|N[uint16]:Number of valid values"
    10511147                     "|T_diff[s]:Time difference to calibration"
    1052                      "|U_ov[V]:Calculated overvoltage"
    1053                      "|U_nom[V]:Nominal overvoltage"
     1148                     "|U_ov[V]:Calculated overvoltage w.r.t. operation voltage"
     1149                     "|U_nom[V]:Nominal overvoltage w.r.t. operation voltage"
    10541150                     "|dU_temp[V]:Correction calculated from temperature"
    10551151                    ),
     
    10971193        AddStateName(Feedback::State::kWaitingForData, "WaitingForData",
    10981194                     "Current control started, waiting for valid temperature and current data.");
     1195
     1196        AddStateName(Feedback::State::kOnStandby, "OnStandby",
     1197                     "Current control in progress but with limited voltage.");
    10991198        AddStateName(Feedback::State::kInProgress, "InProgress",
    11001199                     "Current control in progress.");
     1200        AddStateName(Feedback::State::kWarning, "Warning",
     1201                     "Current control in progress but current warning level exceeded.");
     1202        AddStateName(Feedback::State::kCritical, "Critical",
     1203                     "Current control in progress but critical current limit exceeded.");
    11011204
    11021205
     
    11251228        AddEvent("RESET_OFFSETS", Feedback::State::kConnected, Feedback::State::kCalibrated)
    11261229            (bind(&StateMachineFeedback::ResetOffset, this))
     1230            ("");
     1231
     1232
     1233        AddEvent("SAVE_CALIBRATION", Feedback::State::kCalibrated)
     1234            (bind(&StateMachineFeedback::SaveCalibration, this))
     1235            ("");
     1236        AddEvent("LOAD_CALIBRATION", Feedback::State::kConnected)
     1237            (bind(&StateMachineFeedback::LoadCalibration, this))
    11271238            ("");
    11281239
Note: See TracChangeset for help on using the changeset viewer.